sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

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:
MLICENSE | 1+
MREADME | 2+-
Mnl.1 | 26++++++++++++++++++++++++--
Mnl.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, &section)) { + 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;