975
|
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/
|
|
6 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
|
|
7
|
|
8 USE_NL(NEWTOY(nl, "Eb:n:s:w#", TOYFLAG_BIN))
|
|
9
|
|
10 config NL
|
|
11 bool "nl"
|
|
12 default n
|
|
13 help
|
|
14 usage: nl [-E] [-b mode] [-n (r|l)(n|z)] [-s separator] [-w width]
|
|
15
|
|
16 modes: give numbers to
|
|
17 a: all lines
|
|
18 t: non-empty lines
|
|
19 n: no lines
|
|
20 pRE: lines what match regex RE
|
|
21
|
|
22 flags:
|
|
23 E: extended RE syntax
|
|
24 */
|
|
25
|
|
26 #define FOR_nl
|
|
27 #include "toys.h"
|
|
28 #include <regex.h>
|
|
29
|
|
30 GLOBALS(
|
|
31 long wArgu;
|
|
32 char *sArgu, *nArgu, *bArgu, *re_xs;
|
|
33 char fmt[5];
|
|
34 )
|
|
35
|
|
36 char s = '\t';
|
|
37 long width = 6;
|
|
38 regex_t re; /* fails in GLOBALS */
|
|
39
|
|
40 void do_nl (int fd, char *name) {
|
|
41 char *x;
|
|
42 FILE *f;
|
|
43 long n = 0;
|
|
44
|
|
45 f = fdopen (fd, "r");
|
|
46 if (!f) perror_exit ("failed to open %s", name);
|
|
47
|
|
48 x = 0;
|
|
49 for (;;) {
|
|
50 size_t l;
|
|
51 if (getline (&x, &l, f) < 0) {
|
|
52 if (feof (f)) break;
|
|
53 perror_exit ("failed to read");
|
|
54 }
|
|
55 if (TT.re_xs && regexec (&re, x, 0, 0, 0) == 0) printf (TT.fmt, width, ++n);
|
|
56 printf ("%c%s", s, x);
|
|
57 }
|
|
58
|
|
59 free (x);
|
|
60 fclose (f);
|
|
61 }
|
|
62
|
|
63 void nl_main (void) {
|
|
64 if (toys.optflags & FLAG_w) width = TT.wArgu;
|
|
65
|
|
66 if (TT.sArgu) s = TT.sArgu[0];
|
|
67
|
|
68 if (!TT.nArgu) TT.nArgu = "rn";
|
|
69
|
|
70 if (TT.bArgu) switch (TT.bArgu[0]) {
|
|
71 case 'a':
|
|
72 TT.re_xs = "";
|
|
73 break;
|
|
74 case 't':
|
|
75 TT.re_xs = ".\n";
|
|
76 break;
|
|
77 case 'n':
|
|
78 TT.re_xs = 0;
|
|
79 break;
|
|
80 case 'p':
|
|
81 TT.re_xs = TT.bArgu + 1;
|
|
82 break;
|
|
83 default:
|
|
84 error_exit ("bad mode: %c", TT.bArgu[0]);
|
|
85 }
|
|
86 else TT.re_xs = ".\n";
|
|
87
|
|
88 if (TT.re_xs &&
|
|
89 regcomp (&re, TT.re_xs,
|
|
90 REG_NOSUB |
|
|
91 (toys.optflags & FLAG_E ? REG_EXTENDED : 0)) != 0) {
|
|
92 error_exit ("bad RE");
|
|
93 }
|
|
94
|
|
95 strcpy (TT.fmt, "%");
|
|
96 if (TT.nArgu[0] == 'l') strcat (TT.fmt, "-");
|
|
97 if (TT.nArgu[1] == 'z') strcat (TT.fmt, "0");
|
|
98 strcat (TT.fmt, "*d");
|
|
99
|
|
100 loopfiles (toys.optargs, do_nl);
|
|
101 }
|