mc.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * mc - columnate
  3. *
  4. * mc[-][-LINEWIDTH][-t][file...]
  5. * - causes break on colon
  6. * -LINEWIDTH sets width of line in which to columnate(default 80)
  7. * -t suppresses expanding multiple blanks into tabs
  8. *
  9. */
  10. #include <u.h>
  11. #include <libc.h>
  12. #include <draw.h>
  13. #include <bio.h>
  14. #define WIDTH 80
  15. #define TAB 4
  16. #define WORD_ALLOC_QUANTA 1024
  17. #define ALLOC_QUANTA 4096
  18. int linewidth=WIDTH;
  19. int colonflag=0;
  20. int tabflag=0; /* -t flag turned off forever */
  21. Rune *cbuf, *cbufp;
  22. Rune **word;
  23. int maxwidth=0;
  24. int nalloc=ALLOC_QUANTA;
  25. int nwalloc=WORD_ALLOC_QUANTA;
  26. int nchars=0;
  27. int nwords=0;
  28. Biobuf bin;
  29. Biobuf bout;
  30. void getwidth(void), readbuf(int), error(char *);
  31. void scanwords(void), columnate(void), morechars(void);
  32. void
  33. main(int argc, char *argv[])
  34. {
  35. int i;
  36. int lineset;
  37. int ifd;
  38. lineset = 0;
  39. Binit(&bout, 1, OWRITE);
  40. while(argc > 1 && argv[1][0] == '-'){
  41. --argc; argv++;
  42. switch(argv[0][1]){
  43. case '\0':
  44. colonflag = 1;
  45. break;
  46. case 't':
  47. tabflag = 0;
  48. break;
  49. default:
  50. linewidth = atoi(&argv[0][1]);
  51. if(linewidth <= 1)
  52. linewidth = WIDTH;
  53. lineset = 1;
  54. break;
  55. }
  56. }
  57. if(lineset == 0)
  58. getwidth();
  59. cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
  60. word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
  61. if(word == 0 || cbuf == 0)
  62. error("out of memory");
  63. if(argc == 1)
  64. readbuf(0);
  65. else{
  66. for(i = 1; i < argc; i++){
  67. if((ifd = open(*++argv, OREAD)) == -1)
  68. fprint(2, "mc: can't open %s (%r)\n", *argv);
  69. else{
  70. readbuf(ifd);
  71. Bflush(&bin);
  72. close(ifd);
  73. }
  74. }
  75. }
  76. columnate();
  77. exits(0);
  78. }
  79. void
  80. error(char *s)
  81. {
  82. fprint(2, "mc: %s\n", s);
  83. exits(s);
  84. }
  85. void
  86. readbuf(int fd)
  87. {
  88. int lastwascolon = 0;
  89. long c;
  90. int linesiz = 0;
  91. Binit(&bin, fd, OREAD);
  92. do{
  93. if(nchars++ >= nalloc)
  94. morechars();
  95. *cbufp++ = c = Bgetrune(&bin);
  96. linesiz++;
  97. if(c == '\t') {
  98. cbufp[-1] = L' ';
  99. while(linesiz%TAB != 0) {
  100. if(nchars++ >= nalloc)
  101. morechars();
  102. *cbufp++ = L' ';
  103. linesiz++;
  104. }
  105. }
  106. if(colonflag && c == ':')
  107. lastwascolon++;
  108. else if(lastwascolon){
  109. if(c == '\n'){
  110. --nchars; /* skip newline */
  111. *cbufp = L'\0';
  112. while(nchars > 0 && cbuf[--nchars] != '\n')
  113. ;
  114. if(nchars)
  115. nchars++;
  116. columnate();
  117. if (nchars)
  118. Bputc(&bout, '\n');
  119. Bprint(&bout, "%S", cbuf+nchars);
  120. nchars = 0;
  121. cbufp = cbuf;
  122. }
  123. lastwascolon = 0;
  124. }
  125. if(c == '\n')
  126. linesiz = 0;
  127. }while(c >= 0);
  128. }
  129. void
  130. scanwords(void)
  131. {
  132. Rune *p, *q;
  133. int i;
  134. nwords=0;
  135. maxwidth=0;
  136. for(p = q = cbuf, i = 0; i < nchars; i++){
  137. if(*p++ == L'\n'){
  138. if(nwords >= nwalloc){
  139. nwalloc += WORD_ALLOC_QUANTA;
  140. if((word = realloc(word, nwalloc*sizeof(*word)))==0)
  141. error("out of memory");
  142. }
  143. word[nwords++] = q;
  144. p[-1] = L'\0';
  145. if(p-q > maxwidth)
  146. maxwidth = p-q;
  147. q = p;
  148. }
  149. }
  150. }
  151. void
  152. columnate(void)
  153. {
  154. int i, j;
  155. int words_per_line;
  156. int nlines;
  157. int col;
  158. int endcol;
  159. scanwords();
  160. if(nwords==0)
  161. return;
  162. words_per_line = linewidth/maxwidth;
  163. if(words_per_line <= 0)
  164. words_per_line = 1;
  165. nlines=(nwords+words_per_line-1)/words_per_line;
  166. for(i = 0; i < nlines; i++){
  167. col = endcol = 0;
  168. for(j = i; j < nwords; j += nlines){
  169. endcol += maxwidth;
  170. Bprint(&bout, "%S", word[j]);
  171. col += word[j+1]-word[j]-1;
  172. if(j+nlines < nwords){
  173. if(tabflag) {
  174. int tabcol = (col|(TAB-1))+1;
  175. while(tabcol <= endcol){
  176. Bputc(&bout, '\t');
  177. col = tabcol;
  178. tabcol += TAB;
  179. }
  180. }
  181. while(col < endcol){
  182. Bputc(&bout, ' ');
  183. col++;
  184. }
  185. }
  186. }
  187. Bputc(&bout, '\n');
  188. }
  189. }
  190. void
  191. morechars(void)
  192. {
  193. nalloc += ALLOC_QUANTA;
  194. if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
  195. error("out of memory");
  196. cbufp = cbuf+nchars-1;
  197. }
  198. /*
  199. * These routines discover the width of the display.
  200. * It takes some work. If we do the easy calls to the
  201. * draw library, the screen flashes due to repainting
  202. * when mc exits.
  203. */
  204. jmp_buf drawjmp;
  205. void
  206. terror(Display*, char*)
  207. {
  208. longjmp(drawjmp, 1);
  209. }
  210. Image*
  211. window(void)
  212. {
  213. int n, fd;
  214. char buf[128];
  215. /* under acme, don't want to read whole screen width */
  216. if(access("/dev/acme", OREAD) == 0)
  217. return nil;
  218. display = initdisplay("/dev", "/dev", terror);
  219. if(display == nil)
  220. return nil;
  221. snprint(buf, sizeof buf, "%s/winname", display->windir);
  222. fd = open(buf, OREAD);
  223. if(fd<0 || (n=read(fd, buf, 64))<=0){
  224. return nil;
  225. }
  226. close(fd);
  227. buf[n] = 0;
  228. return namedimage(display, buf);
  229. }
  230. void
  231. getwidth(void)
  232. {
  233. Image *w;
  234. int width, fd, n;
  235. char fontname[256];
  236. if(setjmp(drawjmp))
  237. return;
  238. w = window();
  239. if(w == nil)
  240. return;
  241. fd = open("/env/font", OREAD);
  242. if(fd < 0)
  243. return;
  244. n = read(fd, fontname, sizeof(fontname)-1);
  245. close(fd);
  246. if(n < 0)
  247. return;
  248. fontname[n] = 0;
  249. if(fontname[0] == 0)
  250. return;
  251. font = openfont(display, fontname);
  252. if(font == nil)
  253. return;
  254. width = stringwidth(font, " ");
  255. /* window stucture:
  256. 4 bit left edge
  257. 1 bit gap
  258. 12 bit scrollbar
  259. 4 bit gap
  260. text
  261. 4 bit right edge
  262. */
  263. linewidth = (Dx(w->r)-(4+1+12+4+4))/width;
  264. }