]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/col.c
sshfs: usage
[plan9front.git] / sys / src / cmd / col.c
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
33 usage(void)
34 {
35         fprint(2, "usage: %s [-bfx]\n", argv0);
36         exits("usage");
37 }
38
39 void
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
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
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
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
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
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
289 decr(void)
290 {
291         if (ll > mustwr - PL) {
292                 store(ll--);
293                 fetch(ll);
294         }
295 }