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
7 USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
8
9 config 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
28 GLOBALS(
29 struct arg_list *t;
30
31 unsigned tabcount, *tab;
32 )
33
do_expand(int fd,char * name)34 static 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 wchar_t blah;
47 int width = utf8towc(&blah, toybuf+i, len-i);
48 char c;
49
50 if (width > 1) {
51 if (width != fwrite(toybuf+i, width, 1, stdout))
52 perror_exit("stdout");
53 i += width-1;
54 x++;
55 continue;
56 } else if (width == -2) break;
57 else if (width == -1) continue;
58 c = toybuf[i];
59
60 if (c != '\t') {
61 if (EOF == putc(c, stdout)) perror_exit(0);
62
63 if (c == '\b' && x) width = -1;
64 if (c == '\n') {
65 x = stop = 0;
66 continue;
67 }
68 } else {
69 if (TT.tabcount < 2) {
70 width = TT.tabcount ? *TT.tab : 8;
71 width -= x%width;
72 } else while (stop < TT.tabcount) {
73 if (TT.tab[stop] > x) {
74 width = TT.tab[stop] - x;
75 break;
76 } else stop++;
77 }
78 xprintf("%*c", width, ' ');
79 }
80 x += width;
81 }
82 }
83 }
84
85 // Parse -t options to fill out unsigned array in tablist (if not NULL)
86 // return number of entries in tablist
parse_tablist(unsigned * tablist)87 static int parse_tablist(unsigned *tablist)
88 {
89 struct arg_list *tabs;
90 int tabcount = 0;
91
92 for (tabs = TT.t; tabs; tabs = tabs->next) {
93 char *s = tabs->arg;
94
95 while (*s) {
96 int count;
97 unsigned x, *t = tablist ? tablist+tabcount : &x;
98
99 if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
100 if (sscanf(s, "%u%n", t, &count) != 1) break;
101 if (tabcount++ && tablist && *(t-1) >= *t) break;
102 s += count;
103 if (*s==' ' || *s==',') s++;
104 else break;
105 }
106 if (*s) error_exit("bad tablist");
107 }
108
109 return tabcount;
110 }
111
expand_main(void)112 void expand_main(void)
113 {
114 TT.tabcount = parse_tablist(NULL);
115
116 // Determine size of tablist, allocate memory, fill out tablist
117 if (TT.tabcount) {
118 TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
119 parse_tablist(TT.tab);
120 }
121
122 loopfiles(toys.optargs, do_expand);
123 if (CFG_TOYBOX_FREE) free(TT.tab);
124 }
125