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 15 #define WIDTH 80 16 #define TAB 4 17 #define WORD_ALLOC_QUANTA 1024 18 #define ALLOC_QUANTA 4096 19 20 int linewidth=WIDTH; 21 int mintab=1; 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 int tabwidth=0; 32 Font *font; 33 Biobuf bin; 34 Biobuf bout; 35 36 void getwidth(void), readbuf(int), error(char *); 37 void scanwords(void), columnate(void), morechars(void); 38 int wordwidth(Rune*, int); 39 int nexttab(int); 40 41 void 42 main(int argc, char *argv[]) 43 { 44 int i; 45 int lineset; 46 int ifd; 47 48 lineset = 0; 49 Binit(&bout, 1, OWRITE); 50 while(argc > 1 && argv[1][0] == '-'){ 51 --argc; argv++; 52 switch(argv[0][1]){ 53 case '\0': 54 colonflag = 1; 55 break; 56 case 't': 57 tabflag = 0; 58 break; 59 default: 60 linewidth = atoi(&argv[0][1]); 61 if(linewidth <= 1) 62 linewidth = WIDTH; 63 lineset = 1; 64 break; 65 } 66 } 67 if(lineset == 0){ 68 getwidth(); 69 if(linewidth <= 1){ 70 linewidth = WIDTH; 71 font = nil; 72 } 73 } 74 75 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf)); 76 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word)); 77 if(word == 0 || cbuf == 0) 78 error("out of memory"); 79 if(argc == 1) 80 readbuf(0); 81 else{ 82 for(i = 1; i < argc; i++){ 83 if((ifd = open(*++argv, OREAD)) == -1) 84 fprint(2, "mc: can't open %s (%r)\n", *argv); 85 else{ 86 readbuf(ifd); 87 Bflush(&bin); 88 close(ifd); 89 } 90 } 91 } 92 columnate(); 93 exits(0); 94 } 95 void 96 error(char *s) 97 { 98 fprint(2, "mc: %s\n", s); 99 exits(s); 100 } 101 void 102 readbuf(int fd) 103 { 104 int lastwascolon = 0; 105 long c; 106 int linesiz = 0; 107 108 Binit(&bin, fd, OREAD); 109 do{ 110 if(nchars++ >= nalloc) 111 morechars(); 112 *cbufp++ = c = Bgetrune(&bin); 113 linesiz++; 114 if(c == '\t') { 115 cbufp[-1] = L' '; 116 while(linesiz%TAB != 0) { 117 if(nchars++ >= nalloc) 118 morechars(); 119 *cbufp++ = L' '; 120 linesiz++; 121 } 122 } 123 if(colonflag && c == ':') 124 lastwascolon++; 125 else if(lastwascolon){ 126 if(c == '\n'){ 127 --nchars; /* skip newline */ 128 *cbufp = L'\0'; 129 while(nchars > 0 && cbuf[--nchars] != '\n') 130 ; 131 if(nchars) 132 nchars++; 133 columnate(); 134 if (nchars) 135 Bputc(&bout, '\n'); 136 Bprint(&bout, "%S", cbuf+nchars); 137 nchars = 0; 138 cbufp = cbuf; 139 } 140 lastwascolon = 0; 141 } 142 if(c == '\n') 143 linesiz = 0; 144 }while(c >= 0); 145 } 146 void 147 scanwords(void) 148 { 149 Rune *p, *q; 150 int i, w; 151 152 nwords=0; 153 maxwidth=0; 154 for(p = q = cbuf, i = 0; i < nchars; i++){ 155 if(*p++ == L'\n'){ 156 if(nwords >= nwalloc){ 157 nwalloc += WORD_ALLOC_QUANTA; 158 if((word = realloc(word, nwalloc*sizeof(*word)))==0) 159 error("out of memory"); 160 } 161 word[nwords++] = q; 162 p[-1] = L'\0'; 163 w = wordwidth(q, p-q-1); 164 if(w > maxwidth) 165 maxwidth = w; 166 q = p; 167 } 168 } 169 } 170 171 void 172 columnate(void) 173 { 174 int i, j; 175 int words_per_line; 176 int nlines; 177 int col; 178 int endcol; 179 180 181 scanwords(); 182 if(nwords==0) 183 return; 184 maxwidth = nexttab(maxwidth+mintab-1); 185 words_per_line = linewidth/maxwidth; 186 if(words_per_line <= 0) 187 words_per_line = 1; 188 nlines=(nwords+words_per_line-1)/words_per_line; 189 for(i = 0; i < nlines; i++){ 190 col = endcol = 0; 191 for(j = i; j < nwords; j += nlines){ 192 endcol += maxwidth; 193 Bprint(&bout, "%S", word[j]); 194 col += wordwidth(word[j], runestrlen(word[j])); 195 if(j+nlines < nwords){ 196 if(tabflag) { 197 while(col < endcol){ 198 Bputc(&bout, '\t'); 199 col = nexttab(col); 200 } 201 }else{ 202 while(col < endcol){ 203 Bputc(&bout, ' '); 204 col++; 205 } 206 } 207 } 208 } 209 Bputc(&bout, '\n'); 210 } 211 } 212 213 int 214 wordwidth(Rune *w, int nw) 215 { 216 if(font) 217 return runestringnwidth(font, w, nw); 218 return nw; 219 } 220 221 int 222 nexttab(int col) 223 { 224 if(tabwidth){ 225 col += tabwidth; 226 col -= col%tabwidth; 227 return col; 228 } 229 return col+1; 230 } 231 232 void 233 morechars(void) 234 { 235 nalloc += ALLOC_QUANTA; 236 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0) 237 error("out of memory"); 238 cbufp = cbuf+nchars-1; 239 } 240 241 /* 242 * These routines discover the width of the display. 243 * It takes some work. If we do the easy calls to the 244 * draw library, the screen flashes due to repainting 245 * when mc exits. 246 */ 247 248 jmp_buf drawjmp; 249 250 void 251 terror(Display*, char*) 252 { 253 longjmp(drawjmp, 1); 254 } 255 256 void 257 getwidth(void) 258 { 259 int n, fd; 260 char buf[128], *f[10], *p; 261 262 if(access("/dev/acme", OREAD) >= 0){ 263 if((fd = open("/dev/acme/ctl", OREAD)) < 0) 264 return; 265 n = read(fd, buf, sizeof buf-1); 266 close(fd); 267 if(n <= 0) 268 return; 269 buf[n] = 0; 270 n = tokenize(buf, f, nelem(f)); 271 if(n < 7) 272 return; 273 if((font = openfont(nil, f[6])) == nil) 274 return; 275 if(n >= 8) 276 tabwidth = atoi(f[7]); 277 else 278 tabwidth = 4*stringwidth(font, "0"); 279 mintab = stringwidth(font, "0"); 280 linewidth = atoi(f[5]); 281 tabflag = 1; 282 return; 283 } 284 285 if((p = getenv("font")) == nil) 286 return; 287 if((font = openfont(nil, p)) == nil) 288 return; 289 if((fd = open("/dev/window", OREAD)) < 0){ 290 font = nil; 291 return; 292 } 293 n = read(fd, buf, 5*12); 294 close(fd); 295 if(n < 5*12){ 296 font = nil; 297 return; 298 } 299 buf[n] = 0; 300 301 /* window stucture: 302 4 bit left edge 303 1 bit gap 304 12 bit scrollbar 305 4 bit gap 306 text 307 4 bit right edge 308 */ 309 linewidth = atoi(buf+3*12) - atoi(buf+1*12) - (4+1+12+4+4); 310 mintab = stringwidth(font, "0"); 311 if((p = getenv("tabstop")) != nil) 312 tabwidth = atoi(p)*stringwidth(font, "0"); 313 if(tabwidth == 0) 314 tabwidth = 4*stringwidth(font, "0"); 315 tabflag = 1; 316 } 317