commit 787d99d896e06b2383da763df695b9e9496bdff5
parent 3111908b034c73673a2f079b2b13a88c18379baa
Author: Quentin Rameau <quinq@quinq.eu.org>
Date: Wed, 18 Mar 2015 17:58:09 +0100
nl: add -d -p -f -h options
Diffstat:
M | LICENSE | | | 1 | + |
M | README | | | 2 | +- |
M | nl.1 | | | 26 | ++++++++++++++++++++++++-- |
M | nl.c | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
4 files changed, 104 insertions(+), 20 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -56,3 +56,4 @@ Authors/contributors include:
© 2014 Adria Garriga <rhaps0dy@installgentoo.com>
© 2014 Greg Reagle <greg.reagle@umbc.edu>
© 2015 Tai Chi Minh Ralph Eastwood <tcmreastwood@gmail.com>
+© 2015 Quentin Rameau <quinq@quinq.eu.org>
diff --git a/README b/README
@@ -49,7 +49,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support,
=*| mktemp non-posix none
=*| mv yes none (-i)
=*| nice yes none
-= nl no -d, -f, -h, -p
+=* nl yes none
=*| nohup yes none
#*| paste yes none
=*| printenv non-posix none
diff --git a/nl.1 b/nl.1
@@ -1,4 +1,4 @@
-.Dd February 20, 2015
+.Dd March 18, 2015
.Dt NL 1
.Os sbase
.Sh NAME
@@ -6,7 +6,11 @@
.Nd line numbering filter
.Sh SYNOPSIS
.Nm
+.Op Fl p
.Op Fl b Ar type
+.Op Fl d Ar delim
+.Op Fl f Ar type
+.Op Fl h Ar type
.Op Fl i Ar incr
.Op Fl l Ar num
.Op Fl n Ar format
@@ -25,8 +29,10 @@ is given
reads from stdin.
.Sh OPTIONS
.Bl -tag -width Ds
+.It Fl p
+Do not reset number for logical pages
.It Fl b Ar type
-Defines which lines will be numbered:
+Defines which lines will be numbered for body sections:
.Bl -tag -width pstringXX
.It a
All lines.
@@ -40,6 +46,16 @@ Only lines which match
a regular expression as defined in
.Xr regex 7 .
.El
+.It Fl d Ar delim
+Specify the two characters delimiter (default is "\\:"). If only one character is specified, the second remains ':'.
+.It Fl f Ar type
+Same as
+.Fl b
+except for footer sections.
+.It Fl h Ar type
+Same as
+.Fl b
+except for header sections.
.It Fl i Ar incr
Defines the increment between numbered lines.
.It Fl l Ar num
@@ -76,3 +92,9 @@ The default is 6.
.El
.Sh SEE ALSO
.Xr pr 1
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2008
+specification.
diff --git a/nl.c b/nl.c
@@ -13,29 +13,64 @@
#define FORMAT_RN "%*ld%s"
#define FORMAT_RZ "%0*ld%s"
-static char mode = 't';
-static int blines = 1;
+static char type[] = { 'n', 't', 'n' }; /* footer, body, header */
+static char delim[] = { '\\', ':' };
static const char *format = FORMAT_RN;
static const char *sep = "\t";
static int width = 6;
+static int pflag = 0;
static size_t startnum = 1;
static size_t incr = 1;
-static regex_t preg;
+static size_t blines = 1;
+static regex_t preg[3];
+
+static int
+getsection(char *buf, int *section)
+{
+ int sectionchanged = 0;
+ int newsection = *section;
+
+ while (!strncmp(buf, delim, 2)) {
+ if (!sectionchanged) {
+ sectionchanged = 1;
+ newsection = 0;
+ } else {
+ ++newsection;
+ newsection %= 3;
+ }
+ buf += 2;
+ }
+
+ if (buf && buf[0] == '\n')
+ *section = newsection;
+ else
+ sectionchanged = 0;
+
+ return sectionchanged;
+}
static void
nl(const char *name, FILE *fp)
{
char *buf = NULL;
- int donumber, bl = 1;
- size_t size = 0;
+ int donumber, oldsection, section = 1, bl = 1;
+ size_t number = startnum, size = 0;
while (getline(&buf, &size, fp) != -1) {
donumber = 0;
+ oldsection = section;
+
+ if (getsection(buf, §ion)) {
+ if ((section >= oldsection) && !pflag)
+ number = startnum;
+ continue;
+ }
- if ((mode == 't' && buf[0] != '\n')
- || (mode == 'p' && !regexec(&preg, buf, 0, NULL, 0))) {
+ if ((type[section] == 't' && buf[0] != '\n')
+ || (type[section] == 'p' &&
+ !regexec(&preg[section], buf, 0, NULL, 0))) {
donumber = 1;
- } else if (mode == 'a') {
+ } else if (type[section] == 'a') {
if (buf[0] == '\n' && bl < blines) {
++bl;
} else {
@@ -45,8 +80,8 @@ nl(const char *name, FILE *fp)
}
if (donumber) {
- printf(format, width, startnum, sep);
- startnum += incr;
+ printf(format, width, number, sep);
+ number += incr;
} else {
printf("%*s", width, "");
}
@@ -60,23 +95,46 @@ nl(const char *name, FILE *fp)
static void
usage(void)
{
- eprintf("usage: %s [-b type] [-i incr] [-l num] [-n format] [-s sep] [-v startnum] [-w width] [file]\n", argv0);
+ eprintf("usage: %s [-p] [-b type] [-d delim] [-f type] "
+ "[-h type] [-i incr] [-l num]\n[-n format] [-s sep] "
+ "[-v startnum] [-w width] [file]\n", argv0);
+}
+static char
+getlinetype(char *type, regex_t *preg)
+{
+ if (type[0] == 'p')
+ eregcomp(preg, &type[1], REG_NOSUB);
+ else if (!strchr("ant", type[0]))
+ usage();
+
+ return type[0];
}
int
main(int argc, char *argv[])
{
FILE *fp;
- char *r;
+ char *d;
ARGBEGIN {
case 'b':
- r = EARGF(usage());
- mode = r[0];
- if (r[0] == 'p')
- eregcomp(&preg, &r[1], REG_NOSUB);
- else if (!strchr("ant", mode))
+ type[1] = getlinetype(EARGF(usage()), &preg[1]);
+ break;
+ case 'd':
+ d = EARGF(usage());
+ if (strlen(d) > 2) {
usage();
+ } else if (d[0] != '\0') {
+ delim[0] = d[0];
+ if (d[1])
+ delim[1] = d[1];
+ }
+ break;
+ case 'f':
+ type[0] = getlinetype(EARGF(usage()), &preg[0]);
+ break;
+ case 'h':
+ type[2] = getlinetype(EARGF(usage()), &preg[2]);
break;
case 'i':
incr = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
@@ -95,6 +153,9 @@ main(int argc, char *argv[])
else
eprintf("%s: bad format\n", format);
break;
+ case 'p':
+ pflag = 1;
+ break;
case 's':
sep = EARGF(usage());
break;