col.c (3850B)
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 }