Support NUL containing lines in cut(1)

This commit is contained in:
FRIGN 2016-03-07 12:34:41 +01:00 committed by sin
parent 5ad71a466b
commit cc3aefa488
2 changed files with 39 additions and 31 deletions

2
README
View File

@ -25,7 +25,7 @@ The following tools are implemented:
0=*|o comm . 0=*|o comm .
0=*|o cp (-i) 0=*|o cp (-i)
0=*|x cron . 0=*|x cron .
#*|o cut . 0#*|o cut .
0=*|o date . 0=*|o date .
0=*|o dirname . 0=*|o dirname .
0=*|o du . 0=*|o du .

68
cut.c
View File

@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "text.h"
#include "utf.h" #include "utf.h"
#include "util.h" #include "util.h"
@ -70,71 +71,78 @@ parselist(char *str)
} }
static size_t static size_t
seek(const char *s, size_t pos, size_t *prev, size_t count) seek(struct line *s, size_t pos, size_t *prev, size_t count)
{ {
const char *t; size_t n = pos - *prev, i, j;
size_t n = pos - *prev, i;
if (mode == 'b') { if (mode == 'b') {
if ((t = memchr(s, '\0', n))) if (n >= s->len)
return t - s; return s->len;
if (nflag) if (nflag)
while (n && !UTF8_POINT(s[n])) while (n && !UTF8_POINT(s->data[n]))
n--; n--;
*prev += n; *prev += n;
return n; return n;
} else if (mode == 'c') { } else if (mode == 'c') {
for (n++, t = s; *t; t++) for (n++, i = 0; i < s->len; i++)
if (UTF8_POINT(*t) && !--n) if (UTF8_POINT(s->data[i]) && !--n)
break; break;
} else { } else {
for (t = (count < delimlen + 1) ? s : s + delimlen; n && *t; ) { for (i = (count < delimlen + 1) ? 0 : delimlen; n && i < s->len; ) {
if (!strncmp(t, delim, delimlen)) { if ((s->len - i) >= delimlen &&
!memcmp(s->data + i, delim, delimlen)) {
if (!--n && count) if (!--n && count)
break; break;
t += delimlen; i += delimlen;
continue; continue;
} }
for (i = 1; !fullrune(t, i); i++); for (j = 1; j + i <= s->len && !fullrune(s->data + i, j); j++);
t += i; i += j;
} }
} }
*prev = pos; *prev = pos;
return t - s; return i;
} }
static void static void
cut(FILE *fp, const char *fname) cut(FILE *fp, const char *fname)
{ {
static char *buf = NULL; Range *r;
static size_t size = 0; struct line s;
char *s; static struct line line;
static size_t size;
size_t i, n, p; size_t i, n, p;
ssize_t len; ssize_t len;
Range *r;
while ((len = getline(&buf, &size, fp)) > 0) { while ((len = getline(&line.data, &size, fp)) > 0) {
if (len && buf[len - 1] == '\n') line.len = len;
buf[len - 1] = '\0'; if (line.data[line.len - 1] == '\n')
if (mode == 'f' && !utfutf(buf, delim)) { line.data[--line.len] = '\0';
if (!sflag) if (mode == 'f' && !memmem(line.data, line.len, delim, delimlen)) {
puts(buf); if (!sflag) {
fwrite(line.data, 1, line.len, stdout);
fputc('\n', stdout);
}
continue; continue;
} }
for (i = 0, p = 1, s = buf, r = list; r; r = r->next, s += n) { for (i = 0, p = 1, s = line, r = list; r; r = r->next) {
s += seek(s, r->min, &p, i); n = seek(&s, r->min, &p, i);
s.data += n;
s.len -= n;
i += (mode == 'f') ? delimlen : 1; i += (mode == 'f') ? delimlen : 1;
if (!*s) if (!s.len)
break; break;
if (!r->max) { if (!r->max) {
fputs(s, stdout); fwrite(s.data, 1, s.len, stdout);
break; break;
} }
n = seek(s, r->max + 1, &p, i); n = seek(&s, r->max + 1, &p, i);
i += (mode == 'f') ? delimlen : 1; i += (mode == 'f') ? delimlen : 1;
if (fwrite(s, 1, n, stdout) != n) if (fwrite(s.data, 1, n, stdout) != n)
eprintf("fwrite <stdout>:"); eprintf("fwrite <stdout>:");
s.data += n;
s.len -= n;
} }
putchar('\n'); putchar('\n');
} }