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