13e12c5d1SDavid du Colombier /* 23e12c5d1SDavid du Colombier * mc - columnate 33e12c5d1SDavid du Colombier * 43e12c5d1SDavid du Colombier * mc[-][-LINEWIDTH][-t][file...] 53e12c5d1SDavid du Colombier * - causes break on colon 63e12c5d1SDavid du Colombier * -LINEWIDTH sets width of line in which to columnate(default 80) 73e12c5d1SDavid du Colombier * -t suppresses expanding multiple blanks into tabs 83e12c5d1SDavid du Colombier * 93e12c5d1SDavid du Colombier */ 103e12c5d1SDavid du Colombier #include <u.h> 113e12c5d1SDavid du Colombier #include <libc.h> 123e12c5d1SDavid du Colombier #include <libg.h> 133e12c5d1SDavid du Colombier #include <bio.h> 143e12c5d1SDavid du Colombier 153e12c5d1SDavid du Colombier #define WIDTH 80 163e12c5d1SDavid du Colombier #define WORD_ALLOC_QUANTA 1024 173e12c5d1SDavid du Colombier #define ALLOC_QUANTA 4096 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier int linewidth=WIDTH; 203e12c5d1SDavid du Colombier int colonflag=0; 21*219b2ee8SDavid du Colombier int tabflag=0; /* -t flag turned off forever */ 223e12c5d1SDavid du Colombier Rune *cbuf, *cbufp; 233e12c5d1SDavid du Colombier Rune **word; 243e12c5d1SDavid du Colombier int maxwidth=0; 253e12c5d1SDavid du Colombier int nalloc=ALLOC_QUANTA; 263e12c5d1SDavid du Colombier int nwalloc=WORD_ALLOC_QUANTA; 273e12c5d1SDavid du Colombier int nchars=0; 283e12c5d1SDavid du Colombier int nwords=0; 293e12c5d1SDavid du Colombier Biobuf bin; 303e12c5d1SDavid du Colombier Biobuf bout; 313e12c5d1SDavid du Colombier 32bd389b36SDavid du Colombier void getwidth(void), readbuf(int), error(char *); 333e12c5d1SDavid du Colombier void scanwords(void), columnate(void), morechars(void); 343e12c5d1SDavid du Colombier 353e12c5d1SDavid du Colombier void 363e12c5d1SDavid du Colombier main(int argc, char *argv[]) 373e12c5d1SDavid du Colombier { 383e12c5d1SDavid du Colombier int i; 393e12c5d1SDavid du Colombier int lineset; 40bd389b36SDavid du Colombier int ifd; 41bd389b36SDavid du Colombier 423e12c5d1SDavid du Colombier lineset = 0; 433e12c5d1SDavid du Colombier Binit(&bout, 1, OWRITE); 443e12c5d1SDavid du Colombier while(argc > 1 && argv[1][0] == '-'){ 453e12c5d1SDavid du Colombier --argc; argv++; 463e12c5d1SDavid du Colombier switch(argv[0][1]){ 473e12c5d1SDavid du Colombier case '\0': 483e12c5d1SDavid du Colombier colonflag = 1; 493e12c5d1SDavid du Colombier break; 503e12c5d1SDavid du Colombier case 't': 513e12c5d1SDavid du Colombier tabflag = 0; 523e12c5d1SDavid du Colombier break; 533e12c5d1SDavid du Colombier default: 543e12c5d1SDavid du Colombier linewidth = atoi(&argv[0][1]); 553e12c5d1SDavid du Colombier if(linewidth <= 1) 563e12c5d1SDavid du Colombier linewidth = WIDTH; 573e12c5d1SDavid du Colombier lineset = 1; 583e12c5d1SDavid du Colombier break; 593e12c5d1SDavid du Colombier } 603e12c5d1SDavid du Colombier } 613e12c5d1SDavid du Colombier if(lineset == 0) 623e12c5d1SDavid du Colombier getwidth(); 633e12c5d1SDavid du Colombier cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf)); 643e12c5d1SDavid du Colombier word = malloc(WORD_ALLOC_QUANTA*(sizeof *word)); 653e12c5d1SDavid du Colombier if(word == 0 || cbuf == 0) 663e12c5d1SDavid du Colombier error("out of memory"); 673e12c5d1SDavid du Colombier if(argc == 1) 68bd389b36SDavid du Colombier readbuf(0); 693e12c5d1SDavid du Colombier else{ 703e12c5d1SDavid du Colombier for(i = 1; i < argc; i++){ 71bd389b36SDavid du Colombier if((ifd = open(*++argv, OREAD)) == -1) 72bd389b36SDavid du Colombier fprint(2, "mc: can't open %s (%r)\n", *argv); 733e12c5d1SDavid du Colombier else{ 74bd389b36SDavid du Colombier readbuf(ifd); 75bd389b36SDavid du Colombier Bflush(&bin); 76bd389b36SDavid du Colombier close(ifd); 773e12c5d1SDavid du Colombier } 783e12c5d1SDavid du Colombier } 793e12c5d1SDavid du Colombier } 803e12c5d1SDavid du Colombier columnate(); 813e12c5d1SDavid du Colombier exits(0); 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier void 843e12c5d1SDavid du Colombier error(char *s) 853e12c5d1SDavid du Colombier { 863e12c5d1SDavid du Colombier fprint(2, "mc: %s\n", s); 873e12c5d1SDavid du Colombier exits(s); 883e12c5d1SDavid du Colombier } 893e12c5d1SDavid du Colombier void 90bd389b36SDavid du Colombier readbuf(int fd) 913e12c5d1SDavid du Colombier { 923e12c5d1SDavid du Colombier int lastwascolon = 0; 933e12c5d1SDavid du Colombier long c; 943e12c5d1SDavid du Colombier int linesiz = 0; 953e12c5d1SDavid du Colombier 96bd389b36SDavid du Colombier Binit(&bin, fd, OREAD); 973e12c5d1SDavid du Colombier do{ 983e12c5d1SDavid du Colombier if(nchars++ >= nalloc) 993e12c5d1SDavid du Colombier morechars(); 1003e12c5d1SDavid du Colombier *cbufp++ = c = Bgetrune(&bin); 1013e12c5d1SDavid du Colombier linesiz++; 1023e12c5d1SDavid du Colombier if(c == '\t') { 1033e12c5d1SDavid du Colombier cbufp[-1] = L' '; 1043e12c5d1SDavid du Colombier while(linesiz%8 != 0) { 1053e12c5d1SDavid du Colombier if(nchars++ >= nalloc) 1063e12c5d1SDavid du Colombier morechars(); 1073e12c5d1SDavid du Colombier *cbufp++ = L' '; 1083e12c5d1SDavid du Colombier linesiz++; 1093e12c5d1SDavid du Colombier } 1103e12c5d1SDavid du Colombier } 1113e12c5d1SDavid du Colombier if(colonflag && c == ':') 1123e12c5d1SDavid du Colombier lastwascolon++; 1133e12c5d1SDavid du Colombier else if(lastwascolon){ 1143e12c5d1SDavid du Colombier if(c == '\n'){ 1153e12c5d1SDavid du Colombier --nchars; /* skip newline */ 1163e12c5d1SDavid du Colombier *cbufp = L'\0'; 1173e12c5d1SDavid du Colombier while(nchars > 0 && cbuf[--nchars] != '\n') 1183e12c5d1SDavid du Colombier ; 1193e12c5d1SDavid du Colombier if(nchars) 1203e12c5d1SDavid du Colombier nchars++; 1213e12c5d1SDavid du Colombier columnate(); 1223e12c5d1SDavid du Colombier if (nchars) 1233e12c5d1SDavid du Colombier BPUTC(&bout, '\n'); 1243e12c5d1SDavid du Colombier Bprint(&bout, "%S", cbuf+nchars); 1253e12c5d1SDavid du Colombier nchars = 0; 1263e12c5d1SDavid du Colombier cbufp = cbuf; 1273e12c5d1SDavid du Colombier } 1283e12c5d1SDavid du Colombier lastwascolon = 0; 1293e12c5d1SDavid du Colombier } 1303e12c5d1SDavid du Colombier if(c == '\n') 1313e12c5d1SDavid du Colombier linesiz = 0; 1323e12c5d1SDavid du Colombier }while(c >= 0); 1333e12c5d1SDavid du Colombier } 1343e12c5d1SDavid du Colombier void 1353e12c5d1SDavid du Colombier scanwords(void) 1363e12c5d1SDavid du Colombier { 1373e12c5d1SDavid du Colombier Rune *p, *q; 1383e12c5d1SDavid du Colombier int i; 1393e12c5d1SDavid du Colombier 1403e12c5d1SDavid du Colombier nwords=0; 1413e12c5d1SDavid du Colombier maxwidth=0; 1423e12c5d1SDavid du Colombier for(p = q = cbuf, i = 0; i < nchars; i++){ 1433e12c5d1SDavid du Colombier if(*p++ == L'\n'){ 1443e12c5d1SDavid du Colombier if(nwords >= nwalloc){ 1453e12c5d1SDavid du Colombier nwalloc += WORD_ALLOC_QUANTA; 1463e12c5d1SDavid du Colombier if((word = realloc(word, nwalloc*sizeof(*word)))==0) 1473e12c5d1SDavid du Colombier error("out of memory"); 1483e12c5d1SDavid du Colombier } 1493e12c5d1SDavid du Colombier word[nwords++] = q; 1503e12c5d1SDavid du Colombier p[-1] = L'\0'; 1513e12c5d1SDavid du Colombier if(p-q > maxwidth) 1523e12c5d1SDavid du Colombier maxwidth = p-q; 1533e12c5d1SDavid du Colombier q = p; 1543e12c5d1SDavid du Colombier } 1553e12c5d1SDavid du Colombier } 1563e12c5d1SDavid du Colombier } 1573e12c5d1SDavid du Colombier 1583e12c5d1SDavid du Colombier void 1593e12c5d1SDavid du Colombier columnate(void) 1603e12c5d1SDavid du Colombier { 1613e12c5d1SDavid du Colombier int i, j; 1623e12c5d1SDavid du Colombier int words_per_line; 1633e12c5d1SDavid du Colombier int nlines; 1643e12c5d1SDavid du Colombier int col; 1653e12c5d1SDavid du Colombier int endcol; 1663e12c5d1SDavid du Colombier 1673e12c5d1SDavid du Colombier 1683e12c5d1SDavid du Colombier scanwords(); 1693e12c5d1SDavid du Colombier if(nwords==0) 1703e12c5d1SDavid du Colombier return; 1713e12c5d1SDavid du Colombier words_per_line = linewidth/maxwidth; 1723e12c5d1SDavid du Colombier if(words_per_line <= 0) 1733e12c5d1SDavid du Colombier words_per_line = 1; 1743e12c5d1SDavid du Colombier nlines=(nwords+words_per_line-1)/words_per_line; 1753e12c5d1SDavid du Colombier for(i = 0; i < nlines; i++){ 1763e12c5d1SDavid du Colombier col = endcol = 0; 1773e12c5d1SDavid du Colombier for(j = i; j < nwords; j += nlines){ 1783e12c5d1SDavid du Colombier endcol += maxwidth; 1793e12c5d1SDavid du Colombier Bprint(&bout, "%S", word[j]); 1803e12c5d1SDavid du Colombier col += word[j+1]-word[j]-1; 1813e12c5d1SDavid du Colombier if(j+nlines < nwords){ 1823e12c5d1SDavid du Colombier if(tabflag) { 1833e12c5d1SDavid du Colombier int tabcol = (col|07)+1; 1843e12c5d1SDavid du Colombier while(tabcol <= endcol){ 1853e12c5d1SDavid du Colombier BPUTC(&bout, '\t'); 1863e12c5d1SDavid du Colombier col = tabcol; 1873e12c5d1SDavid du Colombier tabcol += 8; 1883e12c5d1SDavid du Colombier } 1893e12c5d1SDavid du Colombier } 1903e12c5d1SDavid du Colombier while(col < endcol){ 1913e12c5d1SDavid du Colombier BPUTC(&bout, ' '); 1923e12c5d1SDavid du Colombier col++; 1933e12c5d1SDavid du Colombier } 1943e12c5d1SDavid du Colombier } 1953e12c5d1SDavid du Colombier } 1963e12c5d1SDavid du Colombier BPUTC(&bout, '\n'); 1973e12c5d1SDavid du Colombier } 1983e12c5d1SDavid du Colombier } 1993e12c5d1SDavid du Colombier 2003e12c5d1SDavid du Colombier void 2013e12c5d1SDavid du Colombier morechars(void) 2023e12c5d1SDavid du Colombier { 2033e12c5d1SDavid du Colombier nalloc += ALLOC_QUANTA; 2043e12c5d1SDavid du Colombier if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0) 2053e12c5d1SDavid du Colombier error("out of memory"); 2063e12c5d1SDavid du Colombier cbufp = cbuf+nchars-1; 2073e12c5d1SDavid du Colombier } 2083e12c5d1SDavid du Colombier 2093e12c5d1SDavid du Colombier void 2103e12c5d1SDavid du Colombier getwidth(void) 2113e12c5d1SDavid du Colombier { 2123e12c5d1SDavid du Colombier Rectangle r; 2133e12c5d1SDavid du Colombier char buf[5*12]; 2143e12c5d1SDavid du Colombier int fd, width; 2153e12c5d1SDavid du Colombier 2163e12c5d1SDavid du Colombier /* window stucture: 2173e12c5d1SDavid du Colombier 4 bit left edge 2183e12c5d1SDavid du Colombier 1 bit gap 2193e12c5d1SDavid du Colombier 12 bit scrollbar 2203e12c5d1SDavid du Colombier 4 bit gap 2213e12c5d1SDavid du Colombier text 2223e12c5d1SDavid du Colombier 4 bit right edge 2233e12c5d1SDavid du Colombier */ 2243e12c5d1SDavid du Colombier fd = open("/dev/window", OREAD); 2253e12c5d1SDavid du Colombier if(fd < 0) 2263e12c5d1SDavid du Colombier fd = open("/dev/screen", OREAD); 2273e12c5d1SDavid du Colombier if(fd < 0) 2283e12c5d1SDavid du Colombier return; 2293e12c5d1SDavid du Colombier if(read(fd, buf, sizeof buf) != sizeof buf){ 2303e12c5d1SDavid du Colombier close(fd); 2313e12c5d1SDavid du Colombier return; 2323e12c5d1SDavid du Colombier } 2333e12c5d1SDavid du Colombier close(fd); 2343e12c5d1SDavid du Colombier r.min.x = atoi(buf+1*12); 2353e12c5d1SDavid du Colombier r.min.y = atoi(buf+2*12); 2363e12c5d1SDavid du Colombier r.max.x = atoi(buf+3*12); 2373e12c5d1SDavid du Colombier r.max.y = atoi(buf+4*12); 2383e12c5d1SDavid du Colombier fd = open("/dev/bitblt", ORDWR); 2393e12c5d1SDavid du Colombier if(fd < 0) 2403e12c5d1SDavid du Colombier width = 9; 2413e12c5d1SDavid du Colombier else{ 2423e12c5d1SDavid du Colombier close(fd); 2433e12c5d1SDavid du Colombier binit(0, 0, 0); 2443e12c5d1SDavid du Colombier width = charwidth(font, ' '); 2453e12c5d1SDavid du Colombier bclose(); 2463e12c5d1SDavid du Colombier } 2473e12c5d1SDavid du Colombier linewidth = (r.max.x-r.min.x-(4+1+12+4+4))/width; 2483e12c5d1SDavid du Colombier } 249