nl.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. * Deviations from posix: only one logical page (no -ip), no sections (-dfh),
  8. * add -E, support multiple FILE, -n output is long not int.
  9. USE_NL(NEWTOY(nl, "v#=1l#w#<0=6b:n:s:E", TOYFLAG_USR|TOYFLAG_BIN))
  10. config NL
  11. bool "nl"
  12. default y
  13. help
  14. usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-v #] [-w WIDTH] [FILE...]
  15. Number lines of input.
  16. -E Use extended regex syntax (when doing -b pREGEX)
  17. -b Which lines to number: a (all) t (non-empty, default) pREGEX (pattern)
  18. -l Only count last of this many consecutive blank lines
  19. -n Number STYLE: ln (left justified) rn (right justified) rz (zero pad)
  20. -s Separator to use between number and line (instead of TAB)
  21. -v Starting line number for each section (default 1)
  22. -w Width of line numbers (default 6)
  23. */
  24. #define FOR_nl
  25. #include "toys.h"
  26. GLOBALS(
  27. char *s, *n, *b;
  28. long w, l, v;
  29. // Count of consecutive blank lines for -l has to persist between files
  30. long lcount, slen;
  31. )
  32. static void do_nl(char **pline, long len)
  33. {
  34. char *line;
  35. int match = *TT.b != 'n';
  36. if (!pline) return;
  37. line = *pline;
  38. if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
  39. if (TT.l || *TT.b == 't')
  40. if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
  41. if (match) {
  42. TT.lcount = 0;
  43. printf(toybuf, TT.w, TT.v++, TT.s);
  44. } else printf("%*c", (int)(TT.w+TT.slen), ' ');
  45. xprintf("%s", line);
  46. }
  47. void nl_main(void)
  48. {
  49. char *clip = "";
  50. if (!TT.s) TT.s = "\t";
  51. TT.slen = strlen(TT.s);
  52. if (!TT.n || !strcmp(TT.n, "rn")); // default
  53. else if (!strcmp(TT.n, "ln")) clip = "-";
  54. else if (!strcmp(TT.n, "rz")) clip = "0";
  55. else error_exit("bad -n '%s'", TT.n);
  56. sprintf(toybuf, "%%%s%s", clip, "*ld%s");
  57. if (!TT.b) TT.b = "t";
  58. if (*TT.b=='p' && TT.b[1])
  59. xregcomp((void *)(toybuf+16), TT.b+1, REG_NOSUB|FLAG(E)*REG_EXTENDED);
  60. else if (!TT.b[0] || TT.b[1] || !strchr("atn", *TT.b))
  61. error_exit("bad -b '%s'", TT.b);
  62. loopfiles_lines(toys.optargs, do_nl);
  63. }