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 <libg.h> 13 #include <bio.h> 14 15 #define WIDTH 80 16 #define WORD_ALLOC_QUANTA 1024 17 #define ALLOC_QUANTA 4096 18 19 int linewidth=WIDTH; 20 int colonflag=0; 21 int tabflag=0; /* -t flag turned off forever */ 22 Rune *cbuf, *cbufp; 23 Rune **word; 24 int maxwidth=0; 25 int nalloc=ALLOC_QUANTA; 26 int nwalloc=WORD_ALLOC_QUANTA; 27 int nchars=0; 28 int nwords=0; 29 Biobuf bin; 30 Biobuf bout; 31 32 void getwidth(void), readbuf(int), error(char *); 33 void scanwords(void), columnate(void), morechars(void); 34 35 void 36 main(int argc, char *argv[]) 37 { 38 int i; 39 int lineset; 40 int ifd; 41 42 lineset = 0; 43 Binit(&bout, 1, OWRITE); 44 while(argc > 1 && argv[1][0] == '-'){ 45 --argc; argv++; 46 switch(argv[0][1]){ 47 case '\0': 48 colonflag = 1; 49 break; 50 case 't': 51 tabflag = 0; 52 break; 53 default: 54 linewidth = atoi(&argv[0][1]); 55 if(linewidth <= 1) 56 linewidth = WIDTH; 57 lineset = 1; 58 break; 59 } 60 } 61 if(lineset == 0) 62 getwidth(); 63 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf)); 64 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word)); 65 if(word == 0 || cbuf == 0) 66 error("out of memory"); 67 if(argc == 1) 68 readbuf(0); 69 else{ 70 for(i = 1; i < argc; i++){ 71 if((ifd = open(*++argv, OREAD)) == -1) 72 fprint(2, "mc: can't open %s (%r)\n", *argv); 73 else{ 74 readbuf(ifd); 75 Bflush(&bin); 76 close(ifd); 77 } 78 } 79 } 80 columnate(); 81 exits(0); 82 } 83 void 84 error(char *s) 85 { 86 fprint(2, "mc: %s\n", s); 87 exits(s); 88 } 89 void 90 readbuf(int fd) 91 { 92 int lastwascolon = 0; 93 long c; 94 int linesiz = 0; 95 96 Binit(&bin, fd, OREAD); 97 do{ 98 if(nchars++ >= nalloc) 99 morechars(); 100 *cbufp++ = c = Bgetrune(&bin); 101 linesiz++; 102 if(c == '\t') { 103 cbufp[-1] = L' '; 104 while(linesiz%8 != 0) { 105 if(nchars++ >= nalloc) 106 morechars(); 107 *cbufp++ = L' '; 108 linesiz++; 109 } 110 } 111 if(colonflag && c == ':') 112 lastwascolon++; 113 else if(lastwascolon){ 114 if(c == '\n'){ 115 --nchars; /* skip newline */ 116 *cbufp = L'\0'; 117 while(nchars > 0 && cbuf[--nchars] != '\n') 118 ; 119 if(nchars) 120 nchars++; 121 columnate(); 122 if (nchars) 123 BPUTC(&bout, '\n'); 124 Bprint(&bout, "%S", cbuf+nchars); 125 nchars = 0; 126 cbufp = cbuf; 127 } 128 lastwascolon = 0; 129 } 130 if(c == '\n') 131 linesiz = 0; 132 }while(c >= 0); 133 } 134 void 135 scanwords(void) 136 { 137 Rune *p, *q; 138 int i; 139 140 nwords=0; 141 maxwidth=0; 142 for(p = q = cbuf, i = 0; i < nchars; i++){ 143 if(*p++ == L'\n'){ 144 if(nwords >= nwalloc){ 145 nwalloc += WORD_ALLOC_QUANTA; 146 if((word = realloc(word, nwalloc*sizeof(*word)))==0) 147 error("out of memory"); 148 } 149 word[nwords++] = q; 150 p[-1] = L'\0'; 151 if(p-q > maxwidth) 152 maxwidth = p-q; 153 q = p; 154 } 155 } 156 } 157 158 void 159 columnate(void) 160 { 161 int i, j; 162 int words_per_line; 163 int nlines; 164 int col; 165 int endcol; 166 167 168 scanwords(); 169 if(nwords==0) 170 return; 171 words_per_line = linewidth/maxwidth; 172 if(words_per_line <= 0) 173 words_per_line = 1; 174 nlines=(nwords+words_per_line-1)/words_per_line; 175 for(i = 0; i < nlines; i++){ 176 col = endcol = 0; 177 for(j = i; j < nwords; j += nlines){ 178 endcol += maxwidth; 179 Bprint(&bout, "%S", word[j]); 180 col += word[j+1]-word[j]-1; 181 if(j+nlines < nwords){ 182 if(tabflag) { 183 int tabcol = (col|07)+1; 184 while(tabcol <= endcol){ 185 BPUTC(&bout, '\t'); 186 col = tabcol; 187 tabcol += 8; 188 } 189 } 190 while(col < endcol){ 191 BPUTC(&bout, ' '); 192 col++; 193 } 194 } 195 } 196 BPUTC(&bout, '\n'); 197 } 198 } 199 200 void 201 morechars(void) 202 { 203 nalloc += ALLOC_QUANTA; 204 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0) 205 error("out of memory"); 206 cbufp = cbuf+nchars-1; 207 } 208 209 void 210 getwidth(void) 211 { 212 Rectangle r; 213 char buf[5*12]; 214 int fd, width; 215 216 /* window stucture: 217 4 bit left edge 218 1 bit gap 219 12 bit scrollbar 220 4 bit gap 221 text 222 4 bit right edge 223 */ 224 fd = open("/dev/window", OREAD); 225 if(fd < 0) 226 fd = open("/dev/screen", OREAD); 227 if(fd < 0) 228 return; 229 if(read(fd, buf, sizeof buf) != sizeof buf){ 230 close(fd); 231 return; 232 } 233 close(fd); 234 r.min.x = atoi(buf+1*12); 235 r.min.y = atoi(buf+2*12); 236 r.max.x = atoi(buf+3*12); 237 r.max.y = atoi(buf+4*12); 238 fd = open("/dev/bitblt", ORDWR); 239 if(fd < 0) 240 width = 9; 241 else{ 242 close(fd); 243 binit(0, 0, 0); 244 width = charwidth(font, ' '); 245 bclose(); 246 } 247 linewidth = (r.max.x-r.min.x-(4+1+12+4+4))/width; 248 } 249