col.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* col - eliminate reverse line feeds */
  2. #include <u.h>
  3. #include <libc.h>
  4. #include <ctype.h>
  5. #include <bio.h>
  6. enum {
  7. ESC = '\033',
  8. RLF = '\013',
  9. PL = 256,
  10. LINELN = 800,
  11. Tabstop = 8, /* must be power of 2 */
  12. };
  13. static int bflag, xflag, fflag;
  14. static int cp, lp;
  15. static int half;
  16. static int ll, llh, mustwr;
  17. static int pcp = 0;
  18. static char *page[PL];
  19. static char *line;
  20. static char lbuff[LINELN];
  21. static Biobuf bin, bout;
  22. void emit(char *s, int lineno);
  23. void incr(void), decr(void);
  24. void outc(Rune);
  25. static void
  26. usage(void)
  27. {
  28. fprint(2, "usage: %s [-bfx]\n", argv0);
  29. exits("usage");
  30. }
  31. void
  32. main(int argc, char **argv)
  33. {
  34. int i, lno;
  35. long ch;
  36. Rune c;
  37. ARGBEGIN{
  38. case 'b':
  39. bflag++;
  40. break;
  41. case 'f':
  42. fflag++;
  43. break;
  44. case 'x':
  45. xflag++;
  46. break;
  47. default:
  48. usage();
  49. }ARGEND;
  50. for (ll=0; ll < PL; ll++)
  51. page[ll] = nil;
  52. cp = 0;
  53. ll = 0;
  54. mustwr = PL;
  55. line = lbuff;
  56. Binit(&bin, 0, OREAD);
  57. Binit(&bout, 1, OWRITE);
  58. while ((ch = Bgetrune(&bin)) != Beof) {
  59. c = ch;
  60. switch (c) {
  61. case '\n':
  62. incr();
  63. incr();
  64. cp = 0;
  65. break;
  66. case '\0':
  67. break;
  68. case ESC:
  69. c = Bgetrune(&bin);
  70. switch (c) {
  71. case '7': /* reverse full line feed */
  72. decr();
  73. decr();
  74. break;
  75. case '8': /* reverse half line feed */
  76. if (fflag)
  77. decr();
  78. else
  79. if (--half < -1) {
  80. decr();
  81. decr();
  82. half += 2;
  83. }
  84. break;
  85. case '9': /* forward half line feed */
  86. if (fflag)
  87. incr();
  88. else
  89. if (++half > 0) {
  90. incr();
  91. incr();
  92. half -= 2;
  93. }
  94. break;
  95. }
  96. break;
  97. case RLF:
  98. decr();
  99. decr();
  100. break;
  101. case '\r':
  102. cp = 0;
  103. break;
  104. case '\t':
  105. cp = (cp + Tabstop) & -Tabstop;
  106. break;
  107. case '\b':
  108. if (cp > 0)
  109. cp--;
  110. break;
  111. case ' ':
  112. cp++;
  113. break;
  114. default:
  115. if (!isascii(c) || isprint(c)) {
  116. outc(c);
  117. cp++;
  118. }
  119. break;
  120. }
  121. }
  122. for (i=0; i < PL; i++) {
  123. lno = (mustwr+i) % PL;
  124. if (page[lno] != 0)
  125. emit(page[lno], mustwr+i-PL);
  126. }
  127. emit(" ", (llh + 1) & -2);
  128. exits(0);
  129. }
  130. void
  131. outc(Rune c)
  132. {
  133. if (lp > cp) {
  134. line = lbuff;
  135. lp = 0;
  136. }
  137. while (lp < cp) {
  138. switch (*line) {
  139. case '\0':
  140. *line = ' ';
  141. lp++;
  142. break;
  143. case '\b':
  144. lp--;
  145. break;
  146. default:
  147. lp++;
  148. break;
  149. }
  150. line++;
  151. }
  152. while (*line == '\b')
  153. line += 2;
  154. if (bflag || *line == '\0' || *line == ' ')
  155. *line = c;
  156. else {
  157. char c1, c2, c3;
  158. c1 = *++line;
  159. *line++ = '\b';
  160. c2 = *line;
  161. *line++ = c;
  162. while (c1) {
  163. c3 = *line;
  164. *line++ = c1;
  165. c1 = c2;
  166. c2 = c3;
  167. }
  168. lp = 0;
  169. line = lbuff;
  170. }
  171. }
  172. void
  173. store(int lno)
  174. {
  175. lno %= PL;
  176. if (page[lno] != nil)
  177. free(page[lno]);
  178. page[lno] = malloc((unsigned)strlen(lbuff) + 2);
  179. if (page[lno] == nil)
  180. sysfatal("out of memory");
  181. strcpy(page[lno], lbuff);
  182. }
  183. void
  184. fetch(int lno)
  185. {
  186. char *p;
  187. lno %= PL;
  188. p = lbuff;
  189. while (*p)
  190. *p++ = '\0';
  191. line = lbuff;
  192. lp = 0;
  193. if (page[lno])
  194. strcpy(line, page[lno]);
  195. }
  196. void
  197. emit(char *s, int lineno)
  198. {
  199. int ncp;
  200. char *p;
  201. static int cline = 0;
  202. if (*s) {
  203. while (cline < lineno - 1) {
  204. Bputrune(&bout, '\n');
  205. pcp = 0;
  206. cline += 2;
  207. }
  208. if (cline != lineno) {
  209. Bputrune(&bout, ESC);
  210. Bputrune(&bout, '9');
  211. cline++;
  212. }
  213. if (pcp)
  214. Bputrune(&bout, '\r');
  215. pcp = 0;
  216. p = s;
  217. while (*p) {
  218. ncp = pcp;
  219. while (*p++ == ' ')
  220. if ((++ncp & 7) == 0 && !xflag) {
  221. pcp = ncp;
  222. Bputrune(&bout, '\t');
  223. }
  224. if (!*--p)
  225. break;
  226. while (pcp < ncp) {
  227. Bputrune(&bout, ' ');
  228. pcp++;
  229. }
  230. Bputrune(&bout, *p);
  231. if (*p++ == '\b')
  232. pcp--;
  233. else
  234. pcp++;
  235. }
  236. }
  237. }
  238. void
  239. incr(void)
  240. {
  241. int lno;
  242. store(ll++);
  243. if (ll > llh)
  244. llh = ll;
  245. lno = ll % PL;
  246. if (ll >= mustwr && page[lno]) {
  247. emit(page[lno], ll - PL);
  248. mustwr++;
  249. free(page[lno]);
  250. page[lno] = nil;
  251. }
  252. fetch(ll);
  253. }
  254. void
  255. decr(void)
  256. {
  257. if (ll > mustwr - PL) {
  258. store(ll--);
  259. fetch(ll);
  260. }
  261. }