Blob


1 /* col - eliminate reverse line feeds */
2 #include <u.h>
3 #include <libc.h>
4 #include <ctype.h>
5 #include <bio.h>
7 enum {
8 ESC = '\033',
9 RLF = '\013',
11 PL = 256,
12 LINELN = 800,
14 Tabstop = 8, /* must be power of 2 */
15 };
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;
23 static char *page[PL];
24 static char *line;
25 static char lbuff[LINELN];
26 static Biobuf bin, bout;
28 void emit(char *s, int lineno);
29 void incr(void), decr(void);
30 void outc(Rune);
32 static void
33 usage(void)
34 {
35 fprint(2, "usage: %s [-bfx]\n", argv0);
36 exits("usage");
37 }
39 void
40 main(int argc, char **argv)
41 {
42 int i, lno;
43 long ch;
44 Rune c;
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;
60 for (ll=0; ll < PL; ll++)
61 page[ll] = nil;
63 cp = 0;
64 ll = 0;
65 mustwr = PL;
66 line = lbuff;
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;
79 case '\0':
80 break;
82 case ESC:
83 c = Bgetrune(&bin);
84 switch (c) {
85 case '7': /* reverse full line feed */
86 decr();
87 decr();
88 break;
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;
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;
110 break;
112 break;
114 case RLF:
115 decr();
116 decr();
117 break;
119 case '\r':
120 cp = 0;
121 break;
123 case '\t':
124 cp = (cp + Tabstop) & -Tabstop;
125 break;
127 case '\b':
128 if (cp > 0)
129 cp--;
130 break;
132 case ' ':
133 cp++;
134 break;
136 default:
137 if (!isascii(c) || isprint(c)) {
138 outc(c);
139 cp++;
141 break;
145 for (i=0; i < PL; i++) {
146 lno = (mustwr+i) % PL;
147 if (page[lno] != 0)
148 emit(page[lno], mustwr+i-PL);
150 emit(" ", (llh + 1) & -2);
151 exits(0);
154 void
155 outc(Rune c)
157 if (lp > cp) {
158 line = lbuff;
159 lp = 0;
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;
175 line++;
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;
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;
194 lp = 0;
195 line = lbuff;
199 void
200 store(int lno)
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);
211 void
212 fetch(int lno)
214 char *p;
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]);
226 void
227 emit(char *s, int lineno)
229 int ncp;
230 char *p;
231 static int cline = 0;
233 if (*s) {
234 while (cline < lineno - 1) {
235 Bputc(&bout, '\n');
236 pcp = 0;
237 cline += 2;
239 if (cline != lineno) {
240 Bputc(&bout, ESC);
241 Bputc(&bout, '9');
242 cline++;
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');
255 if (!*--p)
256 break;
257 while (pcp < ncp) {
258 Bputc(&bout, ' ');
259 pcp++;
261 Bputc(&bout, *p);
262 if (*p++ == '\b')
263 pcp--;
264 else
265 pcp++;
270 void
271 incr(void)
273 int lno;
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;
285 fetch(ll);
288 void
289 decr(void)
291 if (ll > mustwr - PL) {
292 store(ll--);
293 fetch(ll);