changeset 1099:71326585c02d draft

Cleanup nl, add support for more bits of posix.
author Rob Landley <rob@landley.net>
date Sun, 27 Oct 2013 02:48:13 -0500
parents 46d83f3c7546
children b50e00c9df4b
files toys/pending/nl.c
diffstat 1 files changed, 61 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/nl.c	Sun Oct 27 19:11:07 2013 -0500
+++ b/toys/pending/nl.c	Sun Oct 27 02:48:13 2013 -0500
@@ -2,100 +2,93 @@
  *
  * Copyright 2013 CE Strake <strake888@gmail.com>
  *
- * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
- * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nl.html
+ *
+ * This implements a subset: only one logical page (-ip), no sections (-dfh).
+ * todo: -lv
 
-USE_NL(NEWTOY(nl, "Eb:n:s:w#", TOYFLAG_BIN))
+USE_NL(NEWTOY(nl, "v#<1=1l#b:n:s:w#<0=6E", TOYFLAG_BIN))
 
 config NL
   bool "nl"
   default n
   help
-    usage: nl [-E] [-b mode] [-n (r|l)(n|z)] [-s separator] [-w width]
+    usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-w WIDTH] [FILE...]
+
+    Number lines of input.
 
-    modes: give numbers to
-      a:   all lines
-      t:   non-empty lines
-      n:   no lines
-      pRE: lines what match regex RE
-
-    flags:
-      E:   extended RE syntax
+    -E	Use extended regex syntax (when doing -b pREGEX)
+    -b	which lines to number: a (all) t (non-empty, default) pREGEX (pattern)
+    -l	Only count last of this many consecutive blank lines
+    -n	number STYLE: ln (left justified) rn (right justified) rz (zero pad)
+    -s	Separator to use between number and line (instead of TAB)
+    -w	Width of line numbers (default 6)
 */
 
 #define FOR_nl
 #include "toys.h"
-#include <regex.h>
+#include "lib/xregcomp.h"
 
 GLOBALS(
-  long wArgu;
-  char *sArgu, *nArgu, *bArgu, *re_xs;
-  char fmt[5];
+  long w;
+  char *s;
+  char *n;
+  char *b;
+  long l;
+  long v;
+
+  // Count of consecutive blank lines for -l has to persist between files
+  long lcount;
 )
 
-char s = '\t';
-long width = 6;
-regex_t re; /* fails in GLOBALS */
+void do_nl(int fd, char *name)
+{
+  FILE *f = xfdopen(fd, "r");
+  int w = TT.w, slen = strlen(TT.s);
 
-void do_nl (int fd, char *name) {
-  char *x;
-  FILE *f;
-  long n = 0;
+  for (;;) {
+    char *line = 0;
+    size_t temp;
+    int match = *TT.b != 'n';
 
-  f = fdopen (fd, "r");
-  if (!f) perror_exit ("failed to open %s", name);
+    if (getline(&line, &temp, f) < 1) {
+      if (ferror(f)) perror_msg("%s", name);
+      break;
+    }
 
-  x = 0;
-  for (;;) {
-    size_t l;
-    if (getline (&x, &l, f) < 0) {
-      if (feof (f)) break;
-      perror_exit ("failed to read");
-    }
-    if (TT.re_xs && regexec (&re, x, 0, 0, 0) == 0) printf (TT.fmt, width, ++n);
-    printf ("%c%s", s, x);
+    if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
+    if (TT.l || *TT.b == 't')
+      if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
+    if (match) {
+      TT.lcount = 0;
+      printf(toybuf, w, TT.v++, TT.s);
+    } else printf("%*c", (int)w+slen, ' ');
+    xprintf("%s", line);
+
+    free(line);
   }
 
-  free (x);
-  fclose (f);
+  fclose(f);
 }
 
-void nl_main (void) {
-  if (toys.optflags & FLAG_w) width = TT.wArgu;
+void nl_main(void)
+{
+  char *clip = "";
 
-  if (TT.sArgu) s = TT.sArgu[0];
-
-  if (!TT.nArgu) TT.nArgu = "rn";
+  if (!TT.s) TT.s = "\t";
 
-  if (TT.bArgu) switch (TT.bArgu[0]) {
-  case 'a':
-    TT.re_xs = "";
-    break;
-  case 't':
-    TT.re_xs = ".\n";
-    break;
-  case 'n':
-    TT.re_xs = 0;
-    break;
-  case 'p':
-    TT.re_xs = TT.bArgu + 1;
-    break;
-  default:
-    error_exit ("bad mode: %c", TT.bArgu[0]);
-  }
-  else TT.re_xs = ".\n";
+  if (!TT.n || !strcmp(TT.n, "rn")); // default
+  else if (!strcmp(TT.n, "ln")) clip = "-";
+  else if (!strcmp(TT.n, "rz")) clip = "0";
+  else error_exit("bad -n '%s'", TT.n);
 
-  if (TT.re_xs &&
-      regcomp (&re, TT.re_xs,
-               REG_NOSUB |
-               (toys.optflags & FLAG_E ? REG_EXTENDED : 0)) != 0) {
-    error_exit ("bad RE");
-  }
+  sprintf(toybuf, "%%%s%s", clip, "*ld%s");
 
-  strcpy (TT.fmt, "%");
-  if (TT.nArgu[0] == 'l') strcat (TT.fmt, "-");
-  if (TT.nArgu[1] == 'z') strcat (TT.fmt, "0");
-  strcat (TT.fmt, "*d");
+  if (!TT.b) TT.b = "t";
+  if (*TT.b == 'p' && TT.b[1])
+    xregcomp((void *)(toybuf+16), TT.b+1,
+      REG_NOSUB | (toys.optflags&FLAG_E)*REG_EXTENDED);
+  else if (!strchr("atn", *TT.b)) error_exit("bad -b '%s'", TT.b);
 
   loopfiles (toys.optargs, do_nl);
 }