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 void33 usage(void)34 {35 fprint(2, "usage: %s [-bfx]\n", argv0);36 exits("usage");37 }39 void40 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 else94 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 else105 if (++half > 0) {106 incr();107 incr();108 half -= 2;109 }110 break;111 }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++;140 }141 break;142 }143 }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 }154 void155 outc(Rune c)156 {157 if (lp > cp) {158 line = lbuff;159 lp = 0;160 }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;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 }199 void200 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 }211 void212 fetch(int lno)213 {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]);224 }226 void227 emit(char *s, int lineno)228 {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;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 else265 pcp++;266 }267 }268 }270 void271 incr(void)272 {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;284 }285 fetch(ll);286 }288 void289 decr(void)290 {291 if (ll > mustwr - PL) {292 store(ll--);293 fetch(ll);294 }295 }