expand.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /* expand.c - expands tabs to space
  2. *
  3. * Copyright 2012 Jonathan Clairembault <jonathan at clairembault dot fr>
  4. *
  5. * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html
  6. USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
  7. config EXPAND
  8. bool "expand"
  9. default y
  10. help
  11. usage: expand [-t TABLIST] [FILE...]
  12. Expand tabs to spaces according to tabstops.
  13. -t TABLIST
  14. Specify tab stops, either a single number instead of the default 8,
  15. or a comma separated list of increasing numbers representing tabstop
  16. positions (absolute, not increments) with each additional tab beyond
  17. that becoming one space.
  18. */
  19. #define FOR_expand
  20. #include "toys.h"
  21. GLOBALS(
  22. struct arg_list *t;
  23. unsigned tabcount, *tab;
  24. )
  25. static void do_expand(int fd, char *name)
  26. {
  27. int i, len, x=0, stop = 0;
  28. for (;;) {
  29. len = readall(fd, toybuf, sizeof(toybuf));
  30. if (len<0) {
  31. perror_msg_raw(name);
  32. return;
  33. }
  34. if (!len) break;
  35. for (i=0; i<len; i++) {
  36. unsigned blah;
  37. int width = utf8towc(&blah, toybuf+i, len-i);
  38. char c;
  39. if (width > 1) {
  40. if (width != fwrite(toybuf+i, width, 1, stdout))
  41. perror_exit("stdout");
  42. i += width-1;
  43. x++;
  44. continue;
  45. } else if (width == -2) break;
  46. else if (width == -1) continue;
  47. c = toybuf[i];
  48. if (c != '\t') {
  49. if (EOF == putc(c, stdout)) perror_exit(0);
  50. if (c == '\b' && x) width = -1;
  51. if (c == '\n') {
  52. x = stop = 0;
  53. continue;
  54. }
  55. } else {
  56. if (TT.tabcount < 2) {
  57. width = TT.tabcount ? *TT.tab : 8;
  58. width -= x%width;
  59. } else while (stop < TT.tabcount) {
  60. if (TT.tab[stop] > x) {
  61. width = TT.tab[stop] - x;
  62. break;
  63. } else stop++;
  64. }
  65. xprintf("%*c", width, ' ');
  66. }
  67. x += width;
  68. }
  69. }
  70. }
  71. // Parse -t options to fill out unsigned array in tablist (if not NULL)
  72. // return number of entries in tablist
  73. static int parse_tablist(unsigned *tablist)
  74. {
  75. struct arg_list *tabs;
  76. int tabcount = 0;
  77. for (tabs = TT.t; tabs; tabs = tabs->next) {
  78. char *s = tabs->arg;
  79. while (*s) {
  80. int count;
  81. unsigned x, *t = tablist ? tablist+tabcount : &x;
  82. if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
  83. if (sscanf(s, "%u%n", t, &count) != 1) break;
  84. if (tabcount++ && tablist && *(t-1) >= *t) break;
  85. s += count;
  86. if (*s==' ' || *s==',') s++;
  87. else break;
  88. }
  89. if (*s) error_exit("bad tablist");
  90. }
  91. return tabcount;
  92. }
  93. void expand_main(void)
  94. {
  95. TT.tabcount = parse_tablist(NULL);
  96. // Determine size of tablist, allocate memory, fill out tablist
  97. if (TT.tabcount) {
  98. TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
  99. parse_tablist(TT.tab);
  100. }
  101. loopfiles(toys.optargs, do_expand);
  102. if (CFG_TOYBOX_FREE) free(TT.tab);
  103. }