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      int width = 1;
  47      char c;
  48
  49      if (CFG_TOYBOX_I18N) {
  50        wchar_t blah;
  51
  52        width = utf8towc(&blah, toybuf+i, len-i);
  53        if (width > 1) {
  54          if (width != fwrite(toybuf+i, width, 1, stdout))
  55            perror_exit("stdout");
  56          i += width-1;
  57          x++;
  58          continue;
  59        } else if (width == -2) break;
  60        else if (width == -1) continue;
  61      }
  62      c = toybuf[i];
  63
  64      if (c != '\t') {
  65        if (EOF == putc(c, stdout)) perror_exit(0);
  66
  67        if (c == '\b' && x) width = -1;
  68        if (c == '\n') {
  69          x = stop = 0;
  70          continue;
  71        }
  72      } else {
  73        if (TT.tabcount < 2) {
  74          width = TT.tabcount ? *TT.tab : 8;
  75          width -= x%width;
  76        } else while (stop < TT.tabcount) {
  77          if (TT.tab[stop] > x) {
  78            width = TT.tab[stop] - x;
  79            break;
  80          } else stop++;
  81        }
  82        xprintf("%*c", width, ' ');
  83      }
  84      x += width;
  85    }
  86  }
  87}
  88
  89// Parse -t options to fill out unsigned array in tablist (if not NULL)
  90// return number of entries in tablist
  91static int parse_tablist(unsigned *tablist)
  92{
  93  struct arg_list *tabs;
  94  int tabcount = 0;
  95
  96  for (tabs = TT.t; tabs; tabs = tabs->next) {
  97    char *s = tabs->arg;
  98
  99    while (*s) {
 100      int count;
 101      unsigned x, *t = tablist ? tablist+tabcount : &x;
 102
 103      if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
 104      if (sscanf(s, "%u%n", t, &count) != 1) break;
 105      if (tabcount++ && tablist && *(t-1) >= *t) break;
 106      s += count;
 107      if (*s==' ' || *s==',') s++;
 108      else break;
 109    }
 110    if (*s) error_exit("bad tablist");
 111  }
 112
 113  return tabcount;
 114}
 115
 116void expand_main(void)
 117{
 118  TT.tabcount = parse_tablist(NULL);
 119
 120  // Determine size of tablist, allocate memory, fill out tablist
 121  if (TT.tabcount) {
 122    TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
 123    parse_tablist(TT.tab);
 124  }
 125
 126  loopfiles(toys.optargs, do_expand);
 127  if (CFG_TOYBOX_FREE) free(TT.tab);
 128}
 129