aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2012-11-30 02:41:52 -0600
committerRob Landley <rob@landley.net>2012-11-30 02:41:52 -0600
commit3cbe8d52155ff4dfb6b3184ed5cdb66688de9753 (patch)
tree502d55de9c1875d430cba0e1d2a193b0ea22ae2f
parent4d904aa766f5052745ee4e5f8381b64bfde6a779 (diff)
downloadtoybox-3cbe8d52155ff4dfb6b3184ed5cdb66688de9753.tar.gz
Largeish rewrite of expand, mostly described on the mailing list.
-rw-r--r--toys/posix/expand.c158
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);
}