Blob
1 /*2 * mc - columnate3 *4 * mc[-][-LINEWIDTH][-t][file...]5 * - causes break on colon6 * -LINEWIDTH sets width of line in which to columnate(default 80)7 * -t suppresses expanding multiple blanks into tabs8 *9 */10 #include <u.h>11 #include <libc.h>12 #include <draw.h>13 #include <bio.h>14 #include <sys/ioctl.h>16 #define WIDTH 8017 #define TAB 418 #define WORD_ALLOC_QUANTA 102419 #define ALLOC_QUANTA 409621 int linewidth=WIDTH;22 int colonflag=0;23 int tabflag=0; /* -t flag turned off forever */24 Rune *cbuf, *cbufp;25 Rune **word;26 int maxwidth=0;27 int nalloc=ALLOC_QUANTA;28 int nwalloc=WORD_ALLOC_QUANTA;29 int nchars=0;30 int nwords=0;31 Biobuf bin;32 Biobuf bout;34 void getwidth(void), readbuf(int), error(char *);35 void scanwords(void), columnate(void), morechars(void);37 void38 main(int argc, char *argv[])39 {40 int i;41 int lineset;42 int ifd;44 lineset = 0;45 Binit(&bout, 1, OWRITE);46 while(argc > 1 && argv[1][0] == '-'){47 --argc; argv++;48 switch(argv[0][1]){49 case '\0':50 colonflag = 1;51 break;52 case 't':53 tabflag = 0;54 break;55 default:56 linewidth = atoi(&argv[0][1]);57 if(linewidth <= 1)58 linewidth = WIDTH;59 lineset = 1;60 break;61 }62 }63 if(lineset == 0)64 getwidth();65 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));66 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));67 if(word == 0 || cbuf == 0)68 error("out of memory");69 if(argc == 1)70 readbuf(0);71 else{72 for(i = 1; i < argc; i++){73 if((ifd = open(*++argv, OREAD)) == -1)74 fprint(2, "mc: can't open %s (%r)\n", *argv);75 else{76 readbuf(ifd);77 Bflush(&bin);78 close(ifd);79 }80 }81 }82 columnate();83 exits(0);84 }85 void86 error(char *s)87 {88 fprint(2, "mc: %s\n", s);89 exits(s);90 }91 void92 readbuf(int fd)93 {94 int lastwascolon = 0;95 long c;96 int linesiz = 0;98 Binit(&bin, fd, OREAD);99 do{100 if(nchars++ >= nalloc)101 morechars();102 *cbufp++ = c = Bgetrune(&bin);103 linesiz++;104 if(c == '\t') {105 cbufp[-1] = L' ';106 while(linesiz%TAB != 0) {107 if(nchars++ >= nalloc)108 morechars();109 *cbufp++ = L' ';110 linesiz++;111 }112 }113 if(colonflag && c == ':')114 lastwascolon++;115 else if(lastwascolon){116 if(c == '\n'){117 --nchars; /* skip newline */118 *cbufp = L'\0';119 while(nchars > 0 && cbuf[--nchars] != '\n')120 ;121 if(nchars)122 nchars++;123 columnate();124 if (nchars)125 Bputc(&bout, '\n');126 Bprint(&bout, "%S", cbuf+nchars);127 nchars = 0;128 cbufp = cbuf;129 }130 lastwascolon = 0;131 }132 if(c == '\n')133 linesiz = 0;134 }while(c >= 0);135 }136 void137 scanwords(void)138 {139 Rune *p, *q;140 int i;142 nwords=0;143 maxwidth=0;144 for(p = q = cbuf, i = 0; i < nchars; i++){145 if(*p++ == L'\n'){146 if(nwords >= nwalloc){147 nwalloc += WORD_ALLOC_QUANTA;148 if((word = realloc(word, nwalloc*sizeof(*word)))==0)149 error("out of memory");150 }151 word[nwords++] = q;152 p[-1] = L'\0';153 if(p-q > maxwidth)154 maxwidth = p-q;155 q = p;156 }157 }158 }160 void161 columnate(void)162 {163 int i, j;164 int words_per_line;165 int nlines;166 int col;167 int endcol;170 scanwords();171 if(nwords==0)172 return;173 words_per_line = linewidth/maxwidth;174 if(words_per_line <= 0)175 words_per_line = 1;176 nlines=(nwords+words_per_line-1)/words_per_line;177 for(i = 0; i < nlines; i++){178 col = endcol = 0;179 for(j = i; j < nwords; j += nlines){180 endcol += maxwidth;181 Bprint(&bout, "%S", word[j]);182 col += word[j+1]-word[j]-1;183 if(j+nlines < nwords){184 if(tabflag) {185 int tabcol = (col|(TAB-1))+1;186 while(tabcol <= endcol){187 Bputc(&bout, '\t');188 col = tabcol;189 tabcol += TAB;190 }191 }192 while(col < endcol){193 Bputc(&bout, ' ');194 col++;195 }196 }197 }198 Bputc(&bout, '\n');199 }200 }202 void203 morechars(void)204 {205 nalloc += ALLOC_QUANTA;206 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)207 error("out of memory");208 cbufp = cbuf+nchars-1;209 }211 /*212 * These routines discover the width of the display.213 * It takes some work. If we do the easy calls to the214 * draw library, the screen flashes due to repainting215 * when mc exits.216 */218 int219 windowrect(struct winsize *ws)220 {221 int tty;223 if((tty = open("/dev/tty", OWRITE)) < 0)224 tty = 1;226 if(ioctl(tty, TIOCGWINSZ, ws) < 0){227 if(tty != 1)228 close(tty);229 return -1;230 }231 if(tty != 1)232 close(tty);233 return 0;234 }236 void237 getwidth(void)238 {239 struct winsize ws;241 if(windowrect(&ws) < 0)242 return;243 linewidth = ws.ws_col;244 }