xref: /aosp_15_r20/external/toybox/toys/posix/expand.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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