xref: /aosp_15_r20/external/toybox/toys/posix/nl.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* nl.c - print line numbers
2  *
3  * Copyright 2013 CE Strake <[email protected]>
4  *
5  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nl.html
6  *
7  * Deviations from posix: only one logical page (no -ip), no sections (-dfh),
8  * add -E, support multiple FILE, -n output is long not int.
9 
10 USE_NL(NEWTOY(nl, "v#=1l#w#<0=6b:n:s:E", TOYFLAG_USR|TOYFLAG_BIN))
11 
12 config NL
13   bool "nl"
14   default y
15   help
16     usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-v #] [-w WIDTH] [FILE...]
17 
18     Number lines of input.
19 
20     -E	Use extended regex syntax (when doing -b pREGEX)
21     -b	Which lines to number: a (all) t (non-empty, default) pREGEX (pattern)
22     -l	Only count last of this many consecutive blank lines
23     -n	Number STYLE: ln (left justified) rn (right justified) rz (zero pad)
24     -s	Separator to use between number and line (instead of TAB)
25     -v	Starting line number for each section (default 1)
26     -w	Width of line numbers (default 6)
27 */
28 
29 #define FOR_nl
30 #include "toys.h"
31 
32 GLOBALS(
33   char *s, *n, *b;
34   long w, l, v;
35 
36   // Count of consecutive blank lines for -l has to persist between files
37   long lcount, slen;
38 )
39 
do_nl(char ** pline,long len)40 static void do_nl(char **pline, long len)
41 {
42   char *line;
43   int match = *TT.b != 'n';
44 
45   if (!pline) return;
46   line = *pline;
47 
48   if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
49   if (TT.l || *TT.b == 't')
50     if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
51   if (match) {
52     TT.lcount = 0;
53     printf(toybuf, TT.w, TT.v++, TT.s);
54   } else printf("%*c", (int)(TT.w+TT.slen), ' ');
55   xprintf("%s", line);
56 }
57 
nl_main(void)58 void nl_main(void)
59 {
60   char *clip = "";
61 
62   if (!TT.s) TT.s = "\t";
63   TT.slen = strlen(TT.s);
64 
65   if (!TT.n || !strcmp(TT.n, "rn")); // default
66   else if (!strcmp(TT.n, "ln")) clip = "-";
67   else if (!strcmp(TT.n, "rz")) clip = "0";
68   else error_exit("bad -n '%s'", TT.n);
69 
70   sprintf(toybuf, "%%%s%s", clip, "*ld%s");
71 
72   if (!TT.b) TT.b = "t";
73   if (*TT.b=='p' && TT.b[1])
74     xregcomp((void *)(toybuf+16), TT.b+1, REG_NOSUB|FLAG(E)*REG_EXTENDED);
75   else if (!TT.b[0] || TT.b[1] || !strchr("atn", *TT.b))
76     error_exit("bad -b '%s'", TT.b);
77 
78   loopfiles_lines(toys.optargs, do_nl);
79 }
80