1*cf5a6c84SAndroid Build Coastguard Worker /* expand.c - expands tabs to space
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Jonathan Clairembault <jonathan at clairembault dot fr>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config EXPAND
10*cf5a6c84SAndroid Build Coastguard Worker bool "expand"
11*cf5a6c84SAndroid Build Coastguard Worker default y
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: expand [-t TABLIST] [FILE...]
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker Expand tabs to spaces according to tabstops.
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker -t TABLIST
18*cf5a6c84SAndroid Build Coastguard Worker
19*cf5a6c84SAndroid Build Coastguard Worker Specify tab stops, either a single number instead of the default 8,
20*cf5a6c84SAndroid Build Coastguard Worker or a comma separated list of increasing numbers representing tabstop
21*cf5a6c84SAndroid Build Coastguard Worker positions (absolute, not increments) with each additional tab beyond
22*cf5a6c84SAndroid Build Coastguard Worker that becoming one space.
23*cf5a6c84SAndroid Build Coastguard Worker */
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Worker #define FOR_expand
26*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
29*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *t;
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker unsigned tabcount, *tab;
32*cf5a6c84SAndroid Build Coastguard Worker )
33*cf5a6c84SAndroid Build Coastguard Worker
do_expand(int fd,char * name)34*cf5a6c84SAndroid Build Coastguard Worker static void do_expand(int fd, char *name)
35*cf5a6c84SAndroid Build Coastguard Worker {
36*cf5a6c84SAndroid Build Coastguard Worker int i, len, x=0, stop = 0;
37*cf5a6c84SAndroid Build Coastguard Worker
38*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
39*cf5a6c84SAndroid Build Coastguard Worker len = readall(fd, toybuf, sizeof(toybuf));
40*cf5a6c84SAndroid Build Coastguard Worker if (len<0) {
41*cf5a6c84SAndroid Build Coastguard Worker perror_msg_raw(name);
42*cf5a6c84SAndroid Build Coastguard Worker return;
43*cf5a6c84SAndroid Build Coastguard Worker }
44*cf5a6c84SAndroid Build Coastguard Worker if (!len) break;
45*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<len; i++) {
46*cf5a6c84SAndroid Build Coastguard Worker unsigned blah;
47*cf5a6c84SAndroid Build Coastguard Worker int width = utf8towc(&blah, toybuf+i, len-i);
48*cf5a6c84SAndroid Build Coastguard Worker char c;
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker if (width > 1) {
51*cf5a6c84SAndroid Build Coastguard Worker if (width != fwrite(toybuf+i, width, 1, stdout))
52*cf5a6c84SAndroid Build Coastguard Worker perror_exit("stdout");
53*cf5a6c84SAndroid Build Coastguard Worker i += width-1;
54*cf5a6c84SAndroid Build Coastguard Worker x++;
55*cf5a6c84SAndroid Build Coastguard Worker continue;
56*cf5a6c84SAndroid Build Coastguard Worker } else if (width == -2) break;
57*cf5a6c84SAndroid Build Coastguard Worker else if (width == -1) continue;
58*cf5a6c84SAndroid Build Coastguard Worker c = toybuf[i];
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker if (c != '\t') {
61*cf5a6c84SAndroid Build Coastguard Worker if (EOF == putc(c, stdout)) perror_exit(0);
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker if (c == '\b' && x) width = -1;
64*cf5a6c84SAndroid Build Coastguard Worker if (c == '\n') {
65*cf5a6c84SAndroid Build Coastguard Worker x = stop = 0;
66*cf5a6c84SAndroid Build Coastguard Worker continue;
67*cf5a6c84SAndroid Build Coastguard Worker }
68*cf5a6c84SAndroid Build Coastguard Worker } else {
69*cf5a6c84SAndroid Build Coastguard Worker if (TT.tabcount < 2) {
70*cf5a6c84SAndroid Build Coastguard Worker width = TT.tabcount ? *TT.tab : 8;
71*cf5a6c84SAndroid Build Coastguard Worker width -= x%width;
72*cf5a6c84SAndroid Build Coastguard Worker } else while (stop < TT.tabcount) {
73*cf5a6c84SAndroid Build Coastguard Worker if (TT.tab[stop] > x) {
74*cf5a6c84SAndroid Build Coastguard Worker width = TT.tab[stop] - x;
75*cf5a6c84SAndroid Build Coastguard Worker break;
76*cf5a6c84SAndroid Build Coastguard Worker } else stop++;
77*cf5a6c84SAndroid Build Coastguard Worker }
78*cf5a6c84SAndroid Build Coastguard Worker xprintf("%*c", width, ' ');
79*cf5a6c84SAndroid Build Coastguard Worker }
80*cf5a6c84SAndroid Build Coastguard Worker x += width;
81*cf5a6c84SAndroid Build Coastguard Worker }
82*cf5a6c84SAndroid Build Coastguard Worker }
83*cf5a6c84SAndroid Build Coastguard Worker }
84*cf5a6c84SAndroid Build Coastguard Worker
85*cf5a6c84SAndroid Build Coastguard Worker // Parse -t options to fill out unsigned array in tablist (if not NULL)
86*cf5a6c84SAndroid Build Coastguard Worker // return number of entries in tablist
parse_tablist(unsigned * tablist)87*cf5a6c84SAndroid Build Coastguard Worker static int parse_tablist(unsigned *tablist)
88*cf5a6c84SAndroid Build Coastguard Worker {
89*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *tabs;
90*cf5a6c84SAndroid Build Coastguard Worker int tabcount = 0;
91*cf5a6c84SAndroid Build Coastguard Worker
92*cf5a6c84SAndroid Build Coastguard Worker for (tabs = TT.t; tabs; tabs = tabs->next) {
93*cf5a6c84SAndroid Build Coastguard Worker char *s = tabs->arg;
94*cf5a6c84SAndroid Build Coastguard Worker
95*cf5a6c84SAndroid Build Coastguard Worker while (*s) {
96*cf5a6c84SAndroid Build Coastguard Worker int count;
97*cf5a6c84SAndroid Build Coastguard Worker unsigned x, *t = tablist ? tablist+tabcount : &x;
98*cf5a6c84SAndroid Build Coastguard Worker
99*cf5a6c84SAndroid Build Coastguard Worker if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
100*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(s, "%u%n", t, &count) != 1) break;
101*cf5a6c84SAndroid Build Coastguard Worker if (tabcount++ && tablist && *(t-1) >= *t) break;
102*cf5a6c84SAndroid Build Coastguard Worker s += count;
103*cf5a6c84SAndroid Build Coastguard Worker if (*s==' ' || *s==',') s++;
104*cf5a6c84SAndroid Build Coastguard Worker else break;
105*cf5a6c84SAndroid Build Coastguard Worker }
106*cf5a6c84SAndroid Build Coastguard Worker if (*s) error_exit("bad tablist");
107*cf5a6c84SAndroid Build Coastguard Worker }
108*cf5a6c84SAndroid Build Coastguard Worker
109*cf5a6c84SAndroid Build Coastguard Worker return tabcount;
110*cf5a6c84SAndroid Build Coastguard Worker }
111*cf5a6c84SAndroid Build Coastguard Worker
expand_main(void)112*cf5a6c84SAndroid Build Coastguard Worker void expand_main(void)
113*cf5a6c84SAndroid Build Coastguard Worker {
114*cf5a6c84SAndroid Build Coastguard Worker TT.tabcount = parse_tablist(NULL);
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker // Determine size of tablist, allocate memory, fill out tablist
117*cf5a6c84SAndroid Build Coastguard Worker if (TT.tabcount) {
118*cf5a6c84SAndroid Build Coastguard Worker TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
119*cf5a6c84SAndroid Build Coastguard Worker parse_tablist(TT.tab);
120*cf5a6c84SAndroid Build Coastguard Worker }
121*cf5a6c84SAndroid Build Coastguard Worker
122*cf5a6c84SAndroid Build Coastguard Worker loopfiles(toys.optargs, do_expand);
123*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) free(TT.tab);
124*cf5a6c84SAndroid Build Coastguard Worker }
125