view toys/posix/expand.c @ 1061:ed2694ccf2ae draft

Minor cosmetic tweaks to expand. Working my way through the to-review list that predates the "pending" directory. This gets expand off my to-review list. (Proof that "need to review" doesn't mean it's in bad shape, this command was fine. Changed capitalization in the help text because I'm trying to have "user supplies this value" be all caps, switched a read() to readall() although I'm not sure modern kernels actually allow -EINTR to generate zero length reads anymore, and since most of the loopfiles() target functions are called do_commandname() changed the name to that just so it's regular. None of the changes are actually important. :)
author Rob Landley <rob@landley.net>
date Mon, 09 Sep 2013 05:52:49 -0500
parents 6cc69be43c42
children 3b85d2ce34aa
line wrap: on
line source

/* expand.c - expands tabs to space
 *
 * Copyright 2012 Jonathan Clairembault <jonathan at clairembault dot fr>
 *
 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html

USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN))

config EXPAND
  bool "expand"
  default y
  help
    usage: expand [-t TABLIST] [FILE...]

    Expand tabs to spaces according to tabstops.

    -t	TABLIST

    Specify tab stops, either a single number instead of the default 8,
    or a comma separated list of increasing numbers representing tabstop
    positions (absolute, not increments) with each additional tab beyound
    that becoming one space.
*/

#define FOR_expand
#include "toys.h"

GLOBALS(
  struct arg_list *tabs;

  unsigned tabcount, *tab;
)

static void do_expand(int fd, char *name)
{
  int i, len, x=0, stop = 0;

  for (;;) {
    len = readall(fd, toybuf, sizeof(toybuf));
    if (len<0) {
      perror_msg("%s", name);
      return;
    }
    if (!len) break;
    for (i=0; i<len; i++) {
      int width = 1;
      char c;

      if (CFG_TOYBOX_I18N) {
        wchar_t blah;

        width = mbrtowc(&blah, toybuf+i, len-i, 0);
        if (width > 1) {
          if (width != fwrite(toybuf+i, width, 1, stdout))
            perror_exit("stdout");
          i += width-1;
          x++;
          continue;
        } else if (width == -2) break;
        else if (width == -1) continue;
      }
      c = toybuf[i];

      if (c != '\t') {
        if (EOF == putc(c, stdout)) perror_exit(0);

        if (c == '\b' && x) width = -1;
        if (c == '\n') {
          x = stop = 0;
          continue;
        }
      } else {
        if (TT.tabcount < 2) {
          width = TT.tabcount ? *TT.tab : 8;
          width -= x%width;
        } else while (stop < TT.tabcount) {
          if (TT.tab[stop] > x) {
            width = TT.tab[stop] - x;
            break;
          } else stop++;
        }
        xprintf("%*c", width, ' ');
      }
      x += width;
    }
  }
}

// Parse -t options to fill out unsigned array in tablist (if not NULL)
// return number of entries in tablist
static int parse_tablist(unsigned *tablist)
{
  struct arg_list *tabs;
  int tabcount = 0;

  for (tabs = TT.tabs; tabs; tabs = tabs->next) {
    char *s = tabs->arg;

    while (*s) {
      int count;
      unsigned x, *t = tablist ? tablist+tabcount : &x;

      if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
      if (sscanf(s, "%u%n", t, &count) != 1) break;
      if (tabcount++ && tablist && *(t-1) >= *t) break;
      s += count;
      if (*s==' ' || *s==',') s++;
      else break;
    }
    if (*s) error_exit("bad tablist");
  }

  return tabcount;
}

void expand_main(void)
{
  TT.tabcount = parse_tablist(NULL);

  // Determine size of tablist, allocate memory, fill out tablist
  if (TT.tabcount) {
    TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
    parse_tablist(TT.tab);
  }

  loopfiles(toys.optargs, do_expand);
  if (CFG_TOYBOX_FREE) free(TT.tab);
}