Mercurial > hg > toybox
view toys/posix/expand.c @ 717:54294a48a09b
First round of expand cleanups.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 27 Nov 2012 13:55:57 -0600 |
parents | 8c10cf7bace0 |
children | 08d538115f39 |
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 list of increasing numbers (comma or space separated, after which each additional tab becomes one space). */ #define FOR_expand #include "toys.h" GLOBALS( char *t_flags; struct offset_list tablist; ) static void build_tablist(char *tabstops) { 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"); } tablist->next = xzalloc(sizeof(*tablist)); tablist->next->off = stop; tablist = tablist->next; } free(ref); } static void expand_file(int fd, char *name) { 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; } } } } while (rdn == rdbuflen); /* flush last expand buffer */ writeall(STDOUT_FILENO, wrbuf, wrbufi); } void expand_main(void) { build_tablist((toys.optflags & FLAG_t) ? TT.t_flags : "8"); loopfiles(toys.optargs, expand_file); if (CFG_TOYBOX_FREE) llist_traverse(TT.tablist.next, free); }