URI:
       tcol.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tcol.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 }