Support NUL containing lines in join(1)

while also simplyfing the line-field-parser.
This commit is contained in:
FRIGN 2016-03-09 15:56:59 +01:00 committed by sin
parent d7741c7725
commit c25996924b
2 changed files with 31 additions and 45 deletions

2
README
View File

@ -43,7 +43,7 @@ The following tools are implemented:
0=*|o head . 0=*|o head .
0=*|x hostname . 0=*|x hostname .
0=*|x install . 0=*|x install .
=* o join . 0=* o join .
0=*|o kill . 0=*|o kill .
0=*|o link . 0=*|o link .
0=*|o ln . 0=*|o ln .

74
join.c
View File

@ -27,7 +27,7 @@ struct field {
}; };
struct jline { struct jline {
char *text; struct line text;
size_t nf; size_t nf;
size_t maxf; size_t maxf;
struct field *fields; struct field *fields;
@ -144,18 +144,14 @@ prjoin(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
} }
} }
} }
putchar('\n'); putchar('\n');
} }
static void static void
prline(struct jline *lp) prline(struct jline *lp)
{ {
size_t len = strlen(lp->text); if (fwrite(lp->text.data, 1, lp->text.len, stdout) != lp->text.len)
if (fwrite(lp->text, 1, len, stdout) != len)
eprintf("fwrite:"); eprintf("fwrite:");
putchar('\n'); putchar('\n');
} }
@ -166,12 +162,12 @@ jlinecmp(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
/* return FIELD_ERROR if both lines are short */ /* return FIELD_ERROR if both lines are short */
if (jfa >= la->nf) { if (jfa >= la->nf) {
status = jfb >= lb->nf ? FIELD_ERROR : -1; status = (jfb >= lb->nf) ? FIELD_ERROR : -1;
} else if (jfb >= lb->nf) { } else if (jfb >= lb->nf) {
status = 1; status = 1;
} else { } else {
status = memcmp(la->fields[jfa].s, lb->fields[jfb].s, status = memcmp(la->fields[jfa].s, lb->fields[jfb].s,
MAX (la->fields[jfa].len, lb->fields[jfb].len)); MAX(la->fields[jfa].len, lb->fields[jfb].len));
LIMIT(status, -1, 1); LIMIT(status, -1, 1);
} }
@ -205,53 +201,43 @@ static struct jline *
makeline(char *s, size_t len) makeline(char *s, size_t len)
{ {
struct jline *lp; struct jline *lp;
char *sp, *beg, *end; char *tmp;
size_t i; size_t i, end;
int eol = 0;
if (s[len-1] == '\n') if (s[len - 1] == '\n')
s[len-1] = '\0'; s[--len] = '\0';
lp = ereallocarray(NULL, INIT, sizeof(struct jline)); lp = ereallocarray(NULL, INIT, sizeof(struct jline));
lp->text = s; lp->text.data = s;
lp->text.len = len;
lp->fields = ereallocarray(NULL, INIT, sizeof(struct field)); lp->fields = ereallocarray(NULL, INIT, sizeof(struct field));
lp->nf = 0; lp->nf = 0;
lp->maxf = INIT; lp->maxf = INIT;
for (sp = lp->text; isblank(*sp); sp++) for (i = 0; i < lp->text.len && isblank(lp->text.data[i]); i++)
; ;
while (i < lp->text.len) {
while (!eol) {
beg = sp;
if (sep) { if (sep) {
if (!(end = utfutf(sp, sep))) if ((lp->text.len - i) < seplen ||
eol = 1; !(tmp = memmem(lp->text.data + i,
lp->text.len - i, sep, seplen))) {
if (!eol) { goto eol;
addfield(lp, beg, end - beg);
for (i = 0; i < seplen; i++)
end++;
} }
end = tmp - lp->text.data;
addfield(lp, lp->text.data + i, end - i);
i = end + seplen;
} else { } else {
for (end = sp; !(isblank(*end)); end++) { for (end = i; !(isblank(lp->text.data[end])); end++) {
if (*end == '\0') { if (end + 1 == lp->text.len)
eol = 1; goto eol;
break;
}
} }
addfield(lp, lp->text.data + i, end - i);
if (!eol) for (i = end; isblank(lp->text.data[i]); i++)
addfield(lp, beg, end - beg);
while (isblank(*++end))
; ;
} }
if (eol)
addfield(lp, beg, strlen(sp));
sp = end;
} }
eol:
addfield(lp, lp->text.data + i, lp->text.len - i);
return lp; return lp;
} }
@ -260,9 +246,10 @@ static int
addtospan(struct span *sp, FILE *fp, int reset) addtospan(struct span *sp, FILE *fp, int reset)
{ {
char *newl = NULL; char *newl = NULL;
size_t len, size = 0; ssize_t len;
size_t size = 0;
if ((len = getline(&newl, &size, fp)) == (size_t)-1) { if ((len = getline(&newl, &size, fp)) < 0) {
if (ferror(fp)) if (ferror(fp))
eprintf("getline:"); eprintf("getline:");
else else
@ -298,9 +285,8 @@ freespan(struct span *sp)
for (i = 0; i < sp->nl; i++) { for (i = 0; i < sp->nl; i++) {
free(sp->lines[i]->fields); free(sp->lines[i]->fields);
free(sp->lines[i]->text); free(sp->lines[i]->text.data);
} }
free(sp->lines); free(sp->lines);
} }