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 <sys/ioctl.h>12 #include <sys/termios.h>13 #include <libc.h>14 #include <draw.h>15 #include <bio.h>17 #define WIDTH 8018 #define TAB 419 #define WORD_ALLOC_QUANTA 102420 #define ALLOC_QUANTA 409622 int linewidth=WIDTH;23 int colonflag=0;24 int tabflag=0; /* -t flag turned off forever */25 Rune *cbuf, *cbufp;26 Rune **word;27 int maxwidth=0;28 int nalloc=ALLOC_QUANTA;29 int nwalloc=WORD_ALLOC_QUANTA;30 int nchars=0;31 int nwords=0;32 Biobuf bin;33 Biobuf bout;35 void getwidth(void), readbuf(int), error(char *);36 void scanwords(void), columnate(void), morechars(void);38 void39 main(int argc, char *argv[])40 {41 int i;42 int lineset;43 int ifd;45 lineset = 0;46 Binit(&bout, 1, OWRITE);47 while(argc > 1 && argv[1][0] == '-'){48 --argc; argv++;49 switch(argv[0][1]){50 case '\0':51 colonflag = 1;52 break;53 case 't':54 tabflag = 0;55 break;56 default:57 linewidth = atoi(&argv[0][1]);58 if(linewidth <= 1)59 linewidth = WIDTH;60 lineset = 1;61 break;62 }63 }64 if(lineset == 0)65 getwidth();66 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));67 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));68 if(word == 0 || cbuf == 0)69 error("out of memory");70 if(argc == 1)71 readbuf(0);72 else{73 for(i = 1; i < argc; i++){74 if((ifd = open(*++argv, OREAD)) == -1)75 fprint(2, "mc: can't open %s (%r)\n", *argv);76 else{77 readbuf(ifd);78 Bflush(&bin);79 close(ifd);80 }81 }82 }83 columnate();84 exits(0);85 }86 void87 error(char *s)88 {89 fprint(2, "mc: %s\n", s);90 exits(s);91 }92 void93 readbuf(int fd)94 {95 int lastwascolon = 0;96 long c;97 int linesiz = 0;99 Binit(&bin, fd, OREAD);100 do{101 if(nchars++ >= nalloc)102 morechars();103 *cbufp++ = c = Bgetrune(&bin);104 linesiz++;105 if(c == '\t') {106 cbufp[-1] = L' ';107 while(linesiz%TAB != 0) {108 if(nchars++ >= nalloc)109 morechars();110 *cbufp++ = L' ';111 linesiz++;112 }113 }114 if(colonflag && c == ':')115 lastwascolon++;116 else if(lastwascolon){117 if(c == '\n'){118 --nchars; /* skip newline */119 *cbufp = L'\0';120 while(nchars > 0 && cbuf[--nchars] != '\n')121 ;122 if(nchars)123 nchars++;124 columnate();125 if (nchars)126 Bputc(&bout, '\n');127 Bprint(&bout, "%S", cbuf+nchars);128 nchars = 0;129 cbufp = cbuf;130 }131 lastwascolon = 0;132 }133 if(c == '\n')134 linesiz = 0;135 }while(c >= 0);136 }137 void138 scanwords(void)139 {140 Rune *p, *q;141 int i;143 nwords=0;144 maxwidth=0;145 for(p = q = cbuf, i = 0; i < nchars; i++){146 if(*p++ == L'\n'){147 if(nwords >= nwalloc){148 nwalloc += WORD_ALLOC_QUANTA;149 if((word = realloc(word, nwalloc*sizeof(*word)))==0)150 error("out of memory");151 }152 word[nwords++] = q;153 p[-1] = L'\0';154 if(p-q > maxwidth)155 maxwidth = p-q;156 q = p;157 }158 }159 }161 void162 columnate(void)163 {164 int i, j;165 int words_per_line;166 int nlines;167 int col;168 int endcol;171 scanwords();172 if(nwords==0)173 return;174 words_per_line = linewidth/maxwidth;175 if(words_per_line <= 0)176 words_per_line = 1;177 nlines=(nwords+words_per_line-1)/words_per_line;178 for(i = 0; i < nlines; i++){179 col = endcol = 0;180 for(j = i; j < nwords; j += nlines){181 endcol += maxwidth;182 Bprint(&bout, "%S", word[j]);183 col += word[j+1]-word[j]-1;184 if(j+nlines < nwords){185 if(tabflag) {186 int tabcol = (col|(TAB-1))+1;187 while(tabcol <= endcol){188 Bputc(&bout, '\t');189 col = tabcol;190 tabcol += TAB;191 }192 }193 while(col < endcol){194 Bputc(&bout, ' ');195 col++;196 }197 }198 }199 Bputc(&bout, '\n');200 }201 }203 void204 morechars(void)205 {206 nalloc += ALLOC_QUANTA;207 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)208 error("out of memory");209 cbufp = cbuf+nchars-1;210 }212 /*213 * These routines discover the width of the display.214 * It takes some work. If we do the easy calls to the215 * draw library, the screen flashes due to repainting216 * when mc exits.217 */219 int220 windowrect(struct winsize *ws)221 {222 int tty;224 if((tty = open("/dev/tty", OWRITE)) < 0)225 tty = 1;227 if(ioctl(tty, TIOCGWINSZ, ws) < 0){228 if(tty != 1)229 close(tty);230 return -1;231 }232 if(tty != 1)233 close(tty);234 return 0;235 }237 void238 getwidth(void)239 {240 struct winsize ws;242 if(windowrect(&ws) < 0)243 return;244 linewidth = ws.ws_col;245 }