Introduction
Introduction Statistics Contact Development Disclaimer Help
nl.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
nl.c (4369B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <limits.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "text.h"
9 #include "utf.h"
10 #include "util.h"
11
12 static size_t startnum = 1;
13 static size_t incr = 1;
14 static size_t blines = 1;
15 static size_t delimlen = 2;
16 static size_t seplen = 1;
17 static int width = 6;
18 static int pflag = 0;
19 static char type[] = { 'n', 't', 'n' }; /* footer, body, header */
20 static char *delim = "\\:";
21 static char format[6] = "%*ld";
22 static char *sep = "\t";
23 static regex_t preg[3];
24
25 static int
26 getsection(struct line *l, int *section)
27 {
28 size_t i;
29 int sectionchanged = 0, newsection = *section;
30
31 for (i = 0; (l->len - i) >= delimlen &&
32 !memcmp(l->data + i, delim, delimlen); i += delimlen) {
33 if (!sectionchanged) {
34 sectionchanged = 1;
35 newsection = 0;
36 } else {
37 newsection = (newsection + 1) % 3;
38 }
39 }
40
41 if (!(l->len - i) || l->data[i] == '\n')
42 *section = newsection;
43 else
44 sectionchanged = 0;
45
46 return sectionchanged;
47 }
48
49 static void
50 nl(const char *fname, FILE *fp)
51 {
52 static struct line line;
53 static size_t size;
54 size_t number = startnum, bl = 1;
55 ssize_t len;
56 int donumber, oldsection, section = 1;
57
58 while ((len = getline(&line.data, &size, fp)) > 0) {
59 line.len = len;
60 donumber = 0;
61 oldsection = section;
62
63 if (getsection(&line, &section)) {
64 if ((section >= oldsection) && !pflag)
65 number = startnum;
66 continue;
67 }
68
69 switch (type[section]) {
70 case 't':
71 if (line.data[0] != '\n')
72 donumber = 1;
73 break;
74 case 'p':
75 if (!regexec(preg + section, line.data, 0, NULL,…
76 donumber = 1;
77 break;
78 case 'a':
79 if (line.data[0] == '\n' && bl < blines) {
80 ++bl;
81 } else {
82 donumber = 1;
83 bl = 1;
84 }
85 }
86
87 if (donumber) {
88 printf(format, width, number);
89 fwrite(sep, 1, seplen, stdout);
90 number += incr;
91 }
92 fwrite(line.data, 1, line.len, stdout);
93 }
94 free(line.data);
95 if (ferror(fp))
96 eprintf("getline %s:", fname);
97 }
98
99 static void
100 usage(void)
101 {
102 eprintf("usage: %s [-p] [-b type] [-d delim] [-f type]\n"
103 " [-h type] [-i num] [-l num] [-n format]\n"
104 " [-s sep] [-v num] [-w num] [file]\n", argv0);
105 }
106
107 static char
108 getlinetype(char *type, regex_t *preg)
109 {
110 if (type[0] == 'p')
111 eregcomp(preg, type + 1, REG_NOSUB);
112 else if (!type[0] || !strchr("ant", type[0]))
113 usage();
114
115 return type[0];
116 }
117
118 int
119 main(int argc, char *argv[])
120 {
121 FILE *fp = NULL;
122 size_t s;
123 int ret = 0;
124 char *d, *formattype, *formatblit;
125
126 ARGBEGIN {
127 case 'd':
128 switch (utflen((d = EARGF(usage())))) {
129 case 0:
130 eprintf("empty logical page delimiter\n");
131 case 1:
132 s = strlen(d);
133 delim = emalloc(s + 1 + 1);
134 estrlcpy(delim, d, s + 1 + 1);
135 estrlcat(delim, ":", s + 1 + 1);
136 delimlen = s + 1;
137 break;
138 default:
139 delim = d;
140 delimlen = strlen(delim);
141 break;
142 }
143 break;
144 case 'f':
145 type[0] = getlinetype(EARGF(usage()), preg);
146 break;
147 case 'b':
148 type[1] = getlinetype(EARGF(usage()), preg + 1);
149 break;
150 case 'h':
151 type[2] = getlinetype(EARGF(usage()), preg + 2);
152 break;
153 case 'i':
154 incr = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_…
155 break;
156 case 'l':
157 blines = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZ…
158 break;
159 case 'n':
160 formattype = EARGF(usage());
161 estrlcpy(format, "%", sizeof(format));
162
163 if (!strcmp(formattype, "ln")) {
164 formatblit = "-";
165 } else if (!strcmp(formattype, "rn")) {
166 formatblit = "";
167 } else if (!strcmp(formattype, "rz")) {
168 formatblit = "0";
169 } else {
170 eprintf("%s: bad format\n", formattype);
171 }
172
173 estrlcat(format, formatblit, sizeof(format));
174 estrlcat(format, "*ld", sizeof(format));
175 break;
176 case 'p':
177 pflag = 1;
178 break;
179 case 's':
180 sep = EARGF(usage());
181 seplen = unescape(sep);
182 break;
183 case 'v':
184 startnum = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, S…
185 break;
186 case 'w':
187 width = estrtonum(EARGF(usage()), 1, INT_MAX);
188 break;
189 default:
190 usage();
191 } ARGEND
192
193 if (argc > 1)
194 usage();
195
196 if (!argc) {
197 nl("<stdin>", stdin);
198 } else {
199 if (!strcmp(argv[0], "-")) {
200 argv[0] = "<stdin>";
201 fp = stdin;
202 } else if (!(fp = fopen(argv[0], "r"))) {
203 eprintf("fopen %s:", argv[0]);
204 }
205 nl(argv[0], fp);
206 }
207
208 ret |= fp && fp != stdin && fshut(fp, argv[0]);
209 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
210
211 return ret;
212 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.