unexpand.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
unexpand.c (3318B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <stdint.h> | |
3 #include <stdlib.h> | |
4 #include <string.h> | |
5 | |
6 #include "utf.h" | |
7 #include "util.h" | |
8 | |
9 static int aflag = 0; | |
10 static size_t *tablist = NULL; | |
11 static size_t tablistlen = 8; | |
12 | |
13 static size_t | |
14 parselist(const char *s) | |
15 { | |
16 size_t i; | |
17 char *p, *tmp; | |
18 | |
19 tmp = estrdup(s); | |
20 for (i = 0; (p = strsep(&tmp, " ,")); i++) { | |
21 if (*p == '\0') | |
22 eprintf("empty field in tablist\n"); | |
23 tablist = ereallocarray(tablist, i + 1, sizeof(*tablist)… | |
24 tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX)); | |
25 if (i > 0 && tablist[i - 1] >= tablist[i]) | |
26 eprintf("tablist must be ascending\n"); | |
27 } | |
28 tablist = ereallocarray(tablist, i + 1, sizeof(*tablist)); | |
29 | |
30 return i; | |
31 } | |
32 | |
33 static void | |
34 unexpandspan(size_t last, size_t col) | |
35 { | |
36 size_t off, i, j; | |
37 Rune r; | |
38 | |
39 if (tablistlen == 1) { | |
40 i = 0; | |
41 off = last % tablist[i]; | |
42 | |
43 if ((col - last) + off >= tablist[i] && last < col) | |
44 last -= off; | |
45 | |
46 r = '\t'; | |
47 for (; last + tablist[i] <= col; last += tablist[i]) | |
48 efputrune(&r, stdout, "<stdout>"); | |
49 r = ' '; | |
50 for (; last < col; last++) | |
51 efputrune(&r, stdout, "<stdout>"); | |
52 } else { | |
53 for (i = 0; i < tablistlen; i++) | |
54 if (col < tablist[i]) | |
55 break; | |
56 for (j = 0; j < tablistlen; j++) | |
57 if (last < tablist[j]) | |
58 break; | |
59 r = '\t'; | |
60 for (; j < i; j++) { | |
61 efputrune(&r, stdout, "<stdout>"); | |
62 last = tablist[j]; | |
63 } | |
64 r = ' '; | |
65 for (; last < col; last++) | |
66 efputrune(&r, stdout, "<stdout>"); | |
67 } | |
68 } | |
69 | |
70 static void | |
71 unexpand(const char *file, FILE *fp) | |
72 { | |
73 Rune r; | |
74 size_t last = 0, col = 0, i; | |
75 int bol = 1; | |
76 | |
77 while (efgetrune(&r, fp, file)) { | |
78 switch (r) { | |
79 case ' ': | |
80 if (!bol && !aflag) | |
81 last++; | |
82 col++; | |
83 break; | |
84 case '\t': | |
85 if (tablistlen == 1) { | |
86 if (!bol && !aflag) | |
87 last += tablist[0] - col % tabli… | |
88 col += tablist[0] - col % tablist[0]; | |
89 } else { | |
90 for (i = 0; i < tablistlen; i++) | |
91 if (col < tablist[i]) | |
92 break; | |
93 if (!bol && !aflag) | |
94 last = tablist[i]; | |
95 col = tablist[i]; | |
96 } | |
97 break; | |
98 case '\b': | |
99 if (bol || aflag) | |
100 unexpandspan(last, col); | |
101 col -= (col > 0); | |
102 last = col; | |
103 bol = 0; | |
104 break; | |
105 case '\n': | |
106 if (bol || aflag) | |
107 unexpandspan(last, col); | |
108 last = col = 0; | |
109 bol = 1; | |
110 break; | |
111 default: | |
112 if (bol || aflag) | |
113 unexpandspan(last, col); | |
114 last = ++col; | |
115 bol = 0; | |
116 break; | |
117 } | |
118 if ((r != ' ' && r != '\t') || (!aflag && !bol)) | |
119 efputrune(&r, stdout, "<stdout>"); | |
120 } | |
121 if (last < col && (bol || aflag)) | |
122 unexpandspan(last, col); | |
123 } | |
124 | |
125 static void | |
126 usage(void) | |
127 { | |
128 eprintf("usage: %s [-a] [-t tablist] [file ...]\n", argv0); | |
129 } | |
130 | |
131 int | |
132 main(int argc, char *argv[]) | |
133 { | |
134 FILE *fp; | |
135 int ret = 0; | |
136 char *tl = "8"; | |
137 | |
138 ARGBEGIN { | |
139 case 't': | |
140 tl = EARGF(usage()); | |
141 if (!*tl) | |
142 eprintf("tablist cannot be empty\n"); | |
143 /* Fallthrough: -t implies -a */ | |
144 case 'a': | |
145 aflag = 1; | |
146 break; | |
147 default: | |
148 usage(); | |
149 } ARGEND | |
150 | |
151 tablistlen = parselist(tl); | |
152 | |
153 if (!argc) { | |
154 unexpand("<stdin>", stdin); | |
155 } else { | |
156 for (; *argv; argc--, argv++) { | |
157 if (!strcmp(*argv, "-")) { | |
158 *argv = "<stdin>"; | |
159 fp = stdin; | |
160 } else if (!(fp = fopen(*argv, "r"))) { | |
161 weprintf("fopen %s:", *argv); | |
162 ret = 1; | |
163 continue; | |
164 } | |
165 unexpand(*argv, fp); | |
166 if (fp != stdin && fshut(fp, *argv)) | |
167 ret = 1; | |
168 } | |
169 } | |
170 | |
171 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); | |
172 | |
173 return ret; | |
174 } |