diff options
-rw-r--r-- | toys/posix/expand.c | 158 |
1 files changed, 70 insertions, 88 deletions
diff --git a/toys/posix/expand.c b/toys/posix/expand.c index a322926a..b29a98f4 100644 --- a/toys/posix/expand.c +++ b/toys/posix/expand.c @@ -4,7 +4,7 @@ * * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html -USE_EXPAND(NEWTOY(expand, "t:", TOYFLAG_USR|TOYFLAG_BIN)) +USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN)) config EXPAND bool "expand" @@ -17,112 +17,94 @@ config EXPAND -t tablist Specify tab stops, either a single number instead of the default 8, - or a list of increasing numbers (comma or space separated, after which - each additional tab becomes one space). + 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( - char *t_flags; - struct offset_list tablist; + struct arg_list *tabs; + + unsigned tabcount, *tab; ) -static void build_tablist(char *tabstops) +static void expand_file(int fd, char *name) { - char *ctx; - struct offset_list *tablist = &TT.tablist; - char *s, *ref; - off_t stop, last_stop; - - /* for every tabstop decode and add to list */ - for (stop = last_stop = 0, s = ref = xstrdup(tabstops); ; - last_stop = stop, s = NULL) { - char *tabstop = strtok_r(s, " ,", &ctx); - - if (!tabstop) return; - - stop = xstrtoul(tabstop, NULL, 0); - if (stop <= last_stop) { - free(ref); - toys.exithelp = 1; - error_exit("tablist ascending order"); + int i, len, x=0, stop = 0; + + for (;;) { + len = read(fd, toybuf, sizeof(toybuf)); + if (len<0) { + perror_msg("%s", name); + toys.exitval = 1; + return; + } + if (!len) break; + for (i=0; i<len; i++) { + int len = 1; + if (toybuf[i] != '\t') { + if (EOF == putc(toybuf[i], stdout)) perror_exit(0); + if (toybuf[i] == '\n') { + x = stop = 0; + continue; + } + } else { + if (TT.tabcount < 2) { + len = TT.tabcount ? *TT.tab : 8; + len -= x%len; + } else while (stop < TT.tabcount) { + if (TT.tab[stop] > x) { + len = TT.tab[stop] - x; + break; + } else stop++; + } + xprintf("%*c", len, ' '); + } + x += len; } - tablist->next = xzalloc(sizeof(*tablist)); - tablist->next->off = stop; - tablist = tablist->next; } - - free(ref); } -static void expand_file(int fd, char *name) +// 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) { - ssize_t rdn; - char *rdbuf, *wrbuf; - size_t wrbuflen, rdbuflen; - ssize_t rdbufi = 0, wrbufi = 0; - ssize_t wrlinei; - int hastablist = !!TT.tablist.next->next; - struct offset_list *tablist = TT.tablist.next; - ssize_t stop = tablist->off; - - wrbuflen = rdbuflen = ARRAY_LEN(toybuf)/2; - rdbuf = toybuf; - wrbuf = toybuf + rdbuflen; - do { - rdn = readall(fd, rdbuf, rdbuflen); - if (rdn < 0) perror_exit("%s", name); - for (rdbufi=0, wrbufi=0; rdbufi<rdn; rdbufi++) { - if (wrbufi == wrbuflen) { /* flush expand buffer when full */ - writeall(STDOUT_FILENO, wrbuf, wrbuflen); - wrbufi = 0; - } - if (rdbuf[rdbufi] == '\t') { /* expand tab */ - size_t count; - size_t tabsize; - - /* search next tab stop */ - while(tablist && (stop <= wrlinei)) { - stop = hastablist ? tablist->off : stop + tablist->off; - tablist = hastablist ? tablist->next : tablist; - } - tabsize = ((stop - wrlinei < 2)) ? 1 : stop - wrlinei; - while (tabsize) { /* long expand */ - count = min(tabsize, wrbuflen - wrbufi); - memset(wrbuf + wrbufi, ' ', count); - tabsize -= count; - if (tabsize) { /* flush expand buffer when full */ - writeall(STDOUT_FILENO, wrbuf, wrbuflen); - wrbufi = 0; - } else wrbufi += count; - } - wrlinei += count; - } else { /* copy input to output */ - wrbuf[wrbufi++] = rdbuf[rdbufi]; - if (rdbuf[rdbufi] == '\b') /* go back one column on backspace */ - wrlinei -= !!wrlinei; /* do not go below zero */ - else - wrlinei += 1; - /* flush expand buffer and reset tablist at newline */ - if (rdbuf[rdbufi] == '\n') { - writeall(STDOUT_FILENO, wrbuf, wrbufi); - tablist = TT.tablist.next; - stop = tablist->off; - wrbufi = wrlinei = 0; - } - } + 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; } - } while (rdn == rdbuflen); - /* flush last expand buffer */ - writeall(STDOUT_FILENO, wrbuf, wrbufi); + if (*s) error_exit("bad tablist"); + } + + return tabcount; } void expand_main(void) { - build_tablist((toys.optflags & FLAG_t) ? TT.t_flags : "8"); + 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, expand_file); - if (CFG_TOYBOX_FREE) llist_traverse(TT.tablist.next, free); + if (CFG_TOYBOX_FREE) free(TT.tab); } |