toybox/toys/posix/nl.c
<<
>>
Prefs
   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/nl.html
   6 *
   7 * This implements a subset: only one logical page (-ip), no sections (-dfh).
   8 * todo: -lv
   9
  10USE_NL(NEWTOY(nl, "v#<1=1l#b:n:s:w#<0=6E", TOYFLAG_BIN))
  11
  12config NL
  13  bool "nl"
  14  default y
  15  help
  16    usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-w WIDTH] [FILE...]
  17
  18    Number lines of input.
  19
  20    -E  Use extended regex syntax (when doing -b pREGEX)
  21    -b  which lines to number: a (all) t (non-empty, default) pREGEX (pattern)
  22    -l  Only count last of this many consecutive blank lines
  23    -n  number STYLE: ln (left justified) rn (right justified) rz (zero pad)
  24    -s  Separator to use between number and line (instead of TAB)
  25    -w  Width of line numbers (default 6)
  26*/
  27
  28#define FOR_nl
  29#include "toys.h"
  30
  31GLOBALS(
  32  long w;
  33  char *s;
  34  char *n;
  35  char *b;
  36  long l;
  37  long v;
  38
  39  // Count of consecutive blank lines for -l has to persist between files
  40  long lcount;
  41)
  42
  43static void do_nl(int fd, char *name)
  44{
  45  FILE *f = xfdopen(fd, "r");
  46  int w = TT.w, slen = strlen(TT.s);
  47
  48  for (;;) {
  49    char *line = 0;
  50    size_t temp;
  51    int match = *TT.b != 'n';
  52
  53    if (getline(&line, &temp, f) < 1) {
  54      if (ferror(f)) perror_msg_raw(name);
  55      break;
  56    }
  57
  58    if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
  59    if (TT.l || *TT.b == 't')
  60      if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
  61    if (match) {
  62      TT.lcount = 0;
  63      printf(toybuf, w, TT.v++, TT.s);
  64    } else printf("%*c", (int)w+slen, ' ');
  65    xprintf("%s", line);
  66
  67    free(line);
  68  }
  69
  70  fclose(f);
  71}
  72
  73void nl_main(void)
  74{
  75  char *clip = "";
  76
  77  if (!TT.s) TT.s = "\t";
  78
  79  if (!TT.n || !strcmp(TT.n, "rn")); // default
  80  else if (!strcmp(TT.n, "ln")) clip = "-";
  81  else if (!strcmp(TT.n, "rz")) clip = "0";
  82  else error_exit("bad -n '%s'", TT.n);
  83
  84  sprintf(toybuf, "%%%s%s", clip, "*ld%s");
  85
  86  if (!TT.b) TT.b = "t";
  87  if (*TT.b == 'p' && TT.b[1])
  88    xregcomp((void *)(toybuf+16), TT.b+1,
  89      REG_NOSUB | (toys.optflags&FLAG_E)*REG_EXTENDED);
  90  else if (!strchr("atn", *TT.b)) error_exit("bad -b '%s'", TT.b);
  91
  92  loopfiles (toys.optargs, do_nl);
  93}
  94