1 /* col - eliminate reverse line feeds */
2 #include <u.h>
3 #include <libc.h>
4 #include <ctype.h>
5 #include <bio.h>
6
7 enum {
8 ESC = '\033',
9 RLF = '\013',
10
11 PL = 256,
12 LINELN = 800,
13
14 Tabstop = 8, /* must be power of 2 */
15 };
16
17 static int bflag, xflag, fflag;
18 static int cp, lp;
19 static int half;
20 static int ll, llh, mustwr;
21 static int pcp = 0;
22
23 static char *page[PL];
24 static char *line;
25 static char lbuff[LINELN];
26 static Biobuf bin, bout;
27
28 void emit(char *s, int lineno);
29 void incr(void), decr(void);
30 void outc(Rune);
31
32 static void
usage(void)33 usage(void)
34 {
35 fprint(2, "usage: %s [-bfx]\n", argv0);
36 exits("usage");
37 }
38
39 void
main(int argc,char ** argv)40 main(int argc, char **argv)
41 {
42 int i, lno;
43 long ch;
44 Rune c;
45
46 ARGBEGIN{
47 case 'b':
48 bflag++;
49 break;
50 case 'f':
51 fflag++;
52 break;
53 case 'x':
54 xflag++;
55 break;
56 default:
57 usage();
58 }ARGEND;
59
60 for (ll=0; ll < PL; ll++)
61 page[ll] = nil;
62
63 cp = 0;
64 ll = 0;
65 mustwr = PL;
66 line = lbuff;
67
68 Binit(&bin, 0, OREAD);
69 Binit(&bout, 1, OWRITE);
70 while ((ch = Bgetrune(&bin)) != Beof) {
71 c = ch;
72 switch (c) {
73 case '\n':
74 incr();
75 incr();
76 cp = 0;
77 break;
78
79 case '\0':
80 break;
81
82 case ESC:
83 c = Bgetrune(&bin);
84 switch (c) {
85 case '7': /* reverse full line feed */
86 decr();
87 decr();
88 break;
89
90 case '8': /* reverse half line feed */
91 if (fflag)
92 decr();
93 else
94 if (--half < -1) {
95 decr();
96 decr();
97 half += 2;
98 }
99 break;
100
101 case '9': /* forward half line feed */
102 if (fflag)
103 incr();
104 else
105 if (++half > 0) {
106 incr();
107 incr();
108 half -= 2;
109 }
110 break;
111 }
112 break;
113
114 case RLF:
115 decr();
116 decr();
117 break;
118
119 case '\r':
120 cp = 0;
121 break;
122
123 case '\t':
124 cp = (cp + Tabstop) & -Tabstop;
125 break;
126
127 case '\b':
128 if (cp > 0)
129 cp--;
130 break;
131
132 case ' ':
133 cp++;
134 break;
135
136 default:
137 if (!isascii(c) || isprint(c)) {
138 outc(c);
139 cp++;
140 }
141 break;
142 }
143 }
144
145 for (i=0; i < PL; i++) {
146 lno = (mustwr+i) % PL;
147 if (page[lno] != 0)
148 emit(page[lno], mustwr+i-PL);
149 }
150 emit(" ", (llh + 1) & -2);
151 exits(0);
152 }
153
154 void
outc(Rune c)155 outc(Rune c)
156 {
157 if (lp > cp) {
158 line = lbuff;
159 lp = 0;
160 }
161
162 while (lp < cp) {
163 switch (*line) {
164 case '\0':
165 *line = ' ';
166 lp++;
167 break;
168 case '\b':
169 lp--;
170 break;
171 default:
172 lp++;
173 break;
174 }
175 line++;
176 }
177 while (*line == '\b')
178 line += 2;
179 if (bflag || *line == '\0' || *line == ' ')
180 cp += runetochar(line, &c) - 1;
181 else {
182 char c1, c2, c3;
183
184 c1 = *++line;
185 *line++ = '\b';
186 c2 = *line;
187 *line++ = c;
188 while (c1) {
189 c3 = *line;
190 *line++ = c1;
191 c1 = c2;
192 c2 = c3;
193 }
194 lp = 0;
195 line = lbuff;
196 }
197 }
198
199 void
store(int lno)200 store(int lno)
201 {
202 lno %= PL;
203 if (page[lno] != nil)
204 free(page[lno]);
205 page[lno] = malloc((unsigned)strlen(lbuff) + 2);
206 if (page[lno] == nil)
207 sysfatal("out of memory");
208 strcpy(page[lno], lbuff);
209 }
210
211 void
fetch(int lno)212 fetch(int lno)
213 {
214 char *p;
215
216 lno %= PL;
217 p = lbuff;
218 while (*p)
219 *p++ = '\0';
220 line = lbuff;
221 lp = 0;
222 if (page[lno])
223 strcpy(line, page[lno]);
224 }
225
226 void
emit(char * s,int lineno)227 emit(char *s, int lineno)
228 {
229 int ncp;
230 char *p;
231 static int cline = 0;
232
233 if (*s) {
234 while (cline < lineno - 1) {
235 Bputc(&bout, '\n');
236 pcp = 0;
237 cline += 2;
238 }
239 if (cline != lineno) {
240 Bputc(&bout, ESC);
241 Bputc(&bout, '9');
242 cline++;
243 }
244 if (pcp)
245 Bputc(&bout, '\r');
246 pcp = 0;
247 p = s;
248 while (*p) {
249 ncp = pcp;
250 while (*p++ == ' ')
251 if ((++ncp & 7) == 0 && !xflag) {
252 pcp = ncp;
253 Bputc(&bout, '\t');
254 }
255 if (!*--p)
256 break;
257 while (pcp < ncp) {
258 Bputc(&bout, ' ');
259 pcp++;
260 }
261 Bputc(&bout, *p);
262 if (*p++ == '\b')
263 pcp--;
264 else
265 pcp++;
266 }
267 }
268 }
269
270 void
incr(void)271 incr(void)
272 {
273 int lno;
274
275 store(ll++);
276 if (ll > llh)
277 llh = ll;
278 lno = ll % PL;
279 if (ll >= mustwr && page[lno]) {
280 emit(page[lno], ll - PL);
281 mustwr++;
282 free(page[lno]);
283 page[lno] = nil;
284 }
285 fetch(ll);
286 }
287
288 void
decr(void)289 decr(void)
290 {
291 if (ll > mustwr - PL) {
292 store(ll--);
293 fetch(ll);
294 }
295 }
296