expand.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
expand.c (2300B)
---
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 iflag = 0;
10 static size_t *tablist = NULL;
11 static size_t tablistlen = 0;
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 /* tab length = 1 for the overflowing case later in the matcher */
30 tablist[i] = 1;
31
32 return i;
33 }
34
35 static int
36 expand(const char *file, FILE *fp)
37 {
38 size_t bol = 1, col = 0, i;
39 Rune r;
40
41 while (efgetrune(&r, fp, file)) {
42 switch (r) {
43 case '\t':
44 if (tablistlen == 1)
45 i = 0;
46 else for (i = 0; i < tablistlen; i++)
47 if (col < tablist[i])
48 break;
49 if (bol || !iflag) {
50 do {
51 col++;
52 putchar(' ');
53 } while (col % tablist[i]);
54 } else {
55 putchar('\t');
56 col = tablist[i];
57 }
58 break;
59 case '\b':
60 bol = 0;
61 if (col)
62 col--;
63 putchar('\b');
64 break;
65 case '\n':
66 bol = 1;
67 col = 0;
68 putchar('\n');
69 break;
70 default:
71 col++;
72 if (r != ' ')
73 bol = 0;
74 efputrune(&r, stdout, "<stdout>");
75 break;
76 }
77 }
78
79 return 0;
80 }
81
82 static void
83 usage(void)
84 {
85 eprintf("usage: %s [-i] [-t tablist] [file ...]\n", argv0);
86 }
87
88 int
89 main(int argc, char *argv[])
90 {
91 FILE *fp;
92 int ret = 0;
93 char *tl = "8";
94
95 ARGBEGIN {
96 case 'i':
97 iflag = 1;
98 break;
99 case 't':
100 tl = EARGF(usage());
101 if (!*tl)
102 eprintf("tablist cannot be empty\n");
103 break;
104 default:
105 usage();
106 } ARGEND
107
108 tablistlen = parselist(tl);
109
110 if (!argc) {
111 expand("<stdin>", stdin);
112 } else {
113 for (; *argv; argc--, argv++) {
114 if (!strcmp(*argv, "-")) {
115 *argv = "<stdin>";
116 fp = stdin;
117 } else if (!(fp = fopen(*argv, "r"))) {
118 weprintf("fopen %s:", *argv);
119 ret = 1;
120 continue;
121 }
122 expand(*argv, fp);
123 if (fp != stdin && fshut(fp, *argv))
124 ret = 1;
125 }
126 }
127
128 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
129
130 return ret;
131 }