xref: /third_party/toybox/toys/posix/nl.c (revision 0f66f451)
1/* nl.c - print line numbers
2 *
3 * Copyright 2013 CE Strake <strake888@gmail.com>
4 *
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nl.html
6 *
7 * This implements a subset: only one logical page (-ip), no sections (-dfh).
8 * todo: -l
9
10USE_NL(NEWTOY(nl, "v#=1l#w#<0=6Eb:n:s:", TOYFLAG_USR|TOYFLAG_BIN))
11
12config 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
32GLOBALS(
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;
38  long slen;
39)
40
41static void do_nl(char **pline, long len)
42{
43  char *line;
44  int match = *TT.b != 'n';
45
46  if (!pline) return;
47  line = *pline;
48
49  if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
50  if (TT.l || *TT.b == 't')
51    if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
52  if (match) {
53    TT.lcount = 0;
54    printf(toybuf, TT.w, TT.v++, TT.s);
55  } else printf("%*c", (int)(TT.w+TT.slen), ' ');
56  xprintf("%s", line);
57}
58
59void nl_main(void)
60{
61  char *clip = "";
62
63  if (!TT.s) TT.s = "\t";
64  TT.slen = strlen(TT.s);
65
66  if (!TT.n || !strcmp(TT.n, "rn")); // default
67  else if (!strcmp(TT.n, "ln")) clip = "-";
68  else if (!strcmp(TT.n, "rz")) clip = "0";
69  else error_exit("bad -n '%s'", TT.n);
70
71  sprintf(toybuf, "%%%s%s", clip, "*ld%s");
72
73  if (!TT.b) TT.b = "t";
74  if (*TT.b == 'p' && TT.b[1])
75    xregcomp((void *)(toybuf+16), TT.b+1,
76      REG_NOSUB | (toys.optflags&FLAG_E)*REG_EXTENDED);
77  else if (!strchr("atn", *TT.b)) error_exit("bad -b '%s'", TT.b);
78
79  loopfiles_lines(toys.optargs, do_nl);
80}
81