/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include "utf.h" #include "util.h" struct fdescr { FILE *fp; const char *name; }; static void sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen) { Rune c, last; size_t i, d; for (i = 0; i < fdescrlen; i++) { d = 0; last = 0; while (readrune(dsc[i].name, dsc[i].fp, &c)) { if (last == '\n') { if (delim[d] != '\0') writerune("", stdout, &delim[d]); d = (d + 1) % delimlen; } if (c != '\n') writerune("", stdout, &c); last = c; } if (last == '\n') writerune("", stdout, &last); } } static void parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen) { Rune c, d; size_t i, m; ssize_t last; nextline: last = -1; for (i = 0; i < fdescrlen; i++) { d = delim[i % delimlen]; c = 0; for (; readrune(dsc[i].name, dsc[i].fp, &c) ;) { for (m = last + 1; m < i; m++) writerune("", stdout, &(delim[m % delimlen])); last = i; if (c == '\n') { if (i != fdescrlen - 1) c = d; writerune("", stdout, &c); break; } writerune("", stdout, &c); } if (c == 0 && last != -1) { if (i == fdescrlen - 1) putchar('\n'); else writerune("", stdout, &d); last++; } } if (last != -1) goto nextline; } static void usage(void) { eprintf("usage: %s [-s] [-d list] file ...\n", argv0); } int main(int argc, char *argv[]) { struct fdescr *dsc; Rune *delim; size_t i, len; int seq = 0; char *adelim = "\t"; ARGBEGIN { case 's': seq = 1; break; case 'd': adelim = EARGF(usage()); break; default: usage(); } ARGEND; if (argc == 0) usage(); /* populate delimiters */ unescape(adelim); len = chartorunearr(adelim, &delim); /* populate file list */ dsc = emalloc(argc * sizeof(*dsc)); for (i = 0; i < argc; i++) { if (strcmp(argv[i], "-") == 0) dsc[i].fp = stdin; else dsc[i].fp = fopen(argv[i], "r"); if (!dsc[i].fp) eprintf("fopen %s:", argv[i]); dsc[i].name = argv[i]; } if (seq) sequential(dsc, argc, delim, len); else parallel(dsc, argc, delim, len); for (i = 0; i < argc; i++) fclose(dsc[i].fp); return 0; }