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 unsigned 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