diff options
Diffstat (limited to 'toys/posix')
-rw-r--r-- | toys/posix/nl.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/toys/posix/nl.c b/toys/posix/nl.c new file mode 100644 index 00000000..b462cddd --- /dev/null +++ b/toys/posix/nl.c @@ -0,0 +1,94 @@ +/* nl.c - print line numbers + * + * Copyright 2013 CE Strake <strake888@gmail.com> + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nl.html + * + * This implements a subset: only one logical page (-ip), no sections (-dfh). + * todo: -lv + +USE_NL(NEWTOY(nl, "v#<1=1l#b:n:s:w#<0=6E", TOYFLAG_BIN)) + +config NL + bool "nl" + default y + help + usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-w WIDTH] [FILE...] + + Number lines of input. + + -E Use extended regex syntax (when doing -b pREGEX) + -b which lines to number: a (all) t (non-empty, default) pREGEX (pattern) + -l Only count last of this many consecutive blank lines + -n number STYLE: ln (left justified) rn (right justified) rz (zero pad) + -s Separator to use between number and line (instead of TAB) + -w Width of line numbers (default 6) +*/ + +#define FOR_nl +#include "toys.h" +#include "lib/xregcomp.h" + +GLOBALS( + long w; + char *s; + char *n; + char *b; + long l; + long v; + + // Count of consecutive blank lines for -l has to persist between files + long lcount; +) + +void do_nl(int fd, char *name) +{ + FILE *f = xfdopen(fd, "r"); + int w = TT.w, slen = strlen(TT.s); + + for (;;) { + char *line = 0; + size_t temp; + int match = *TT.b != 'n'; + + if (getline(&line, &temp, f) < 1) { + if (ferror(f)) perror_msg("%s", name); + break; + } + + if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0); + if (TT.l || *TT.b == 't') + if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l; + if (match) { + TT.lcount = 0; + printf(toybuf, w, TT.v++, TT.s); + } else printf("%*c", (int)w+slen, ' '); + xprintf("%s", line); + + free(line); + } + + fclose(f); +} + +void nl_main(void) +{ + char *clip = ""; + + if (!TT.s) TT.s = "\t"; + + if (!TT.n || !strcmp(TT.n, "rn")); // default + else if (!strcmp(TT.n, "ln")) clip = "-"; + else if (!strcmp(TT.n, "rz")) clip = "0"; + else error_exit("bad -n '%s'", TT.n); + + sprintf(toybuf, "%%%s%s", clip, "*ld%s"); + + if (!TT.b) TT.b = "t"; + if (*TT.b == 'p' && TT.b[1]) + xregcomp((void *)(toybuf+16), TT.b+1, + REG_NOSUB | (toys.optflags&FLAG_E)*REG_EXTENDED); + else if (!strchr("atn", *TT.b)) error_exit("bad -b '%s'", TT.b); + + loopfiles (toys.optargs, do_nl); +} |