diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/mc.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/mc.c')
-rwxr-xr-x | sys/src/cmd/mc.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/sys/src/cmd/mc.c b/sys/src/cmd/mc.c new file mode 100755 index 000000000..f48fbbf94 --- /dev/null +++ b/sys/src/cmd/mc.c @@ -0,0 +1,316 @@ +/* + * mc - columnate + * + * mc[-][-LINEWIDTH][-t][file...] + * - causes break on colon + * -LINEWIDTH sets width of line in which to columnate(default 80) + * -t suppresses expanding multiple blanks into tabs + * + */ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <bio.h> + +#define WIDTH 80 +#define TAB 4 +#define WORD_ALLOC_QUANTA 1024 +#define ALLOC_QUANTA 4096 + +int linewidth=WIDTH; +int mintab=1; +int colonflag=0; +int tabflag=0; /* -t flag turned off forever */ +Rune *cbuf, *cbufp; +Rune **word; +int maxwidth=0; +int nalloc=ALLOC_QUANTA; +int nwalloc=WORD_ALLOC_QUANTA; +int nchars=0; +int nwords=0; +int tabwidth=0; +Font *font; +Biobuf bin; +Biobuf bout; + +void getwidth(void), readbuf(int), error(char *); +void scanwords(void), columnate(void), morechars(void); +int wordwidth(Rune*, int); +int nexttab(int); + +void +main(int argc, char *argv[]) +{ + int i; + int lineset; + int ifd; + + lineset = 0; + Binit(&bout, 1, OWRITE); + while(argc > 1 && argv[1][0] == '-'){ + --argc; argv++; + switch(argv[0][1]){ + case '\0': + colonflag = 1; + break; + case 't': + tabflag = 0; + break; + default: + linewidth = atoi(&argv[0][1]); + if(linewidth <= 1) + linewidth = WIDTH; + lineset = 1; + break; + } + } + if(lineset == 0){ + getwidth(); + if(linewidth <= 1){ + linewidth = WIDTH; + font = nil; + } + } + + cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf)); + word = malloc(WORD_ALLOC_QUANTA*(sizeof *word)); + if(word == 0 || cbuf == 0) + error("out of memory"); + if(argc == 1) + readbuf(0); + else{ + for(i = 1; i < argc; i++){ + if((ifd = open(*++argv, OREAD)) == -1) + fprint(2, "mc: can't open %s (%r)\n", *argv); + else{ + readbuf(ifd); + Bflush(&bin); + close(ifd); + } + } + } + columnate(); + exits(0); +} +void +error(char *s) +{ + fprint(2, "mc: %s\n", s); + exits(s); +} +void +readbuf(int fd) +{ + int lastwascolon = 0; + long c; + int linesiz = 0; + + Binit(&bin, fd, OREAD); + do{ + if(nchars++ >= nalloc) + morechars(); + *cbufp++ = c = Bgetrune(&bin); + linesiz++; + if(c == '\t') { + cbufp[-1] = L' '; + while(linesiz%TAB != 0) { + if(nchars++ >= nalloc) + morechars(); + *cbufp++ = L' '; + linesiz++; + } + } + if(colonflag && c == ':') + lastwascolon++; + else if(lastwascolon){ + if(c == '\n'){ + --nchars; /* skip newline */ + *cbufp = L'\0'; + while(nchars > 0 && cbuf[--nchars] != '\n') + ; + if(nchars) + nchars++; + columnate(); + if (nchars) + Bputc(&bout, '\n'); + Bprint(&bout, "%S", cbuf+nchars); + nchars = 0; + cbufp = cbuf; + } + lastwascolon = 0; + } + if(c == '\n') + linesiz = 0; + }while(c >= 0); +} +void +scanwords(void) +{ + Rune *p, *q; + int i, w; + + nwords=0; + maxwidth=0; + for(p = q = cbuf, i = 0; i < nchars; i++){ + if(*p++ == L'\n'){ + if(nwords >= nwalloc){ + nwalloc += WORD_ALLOC_QUANTA; + if((word = realloc(word, nwalloc*sizeof(*word)))==0) + error("out of memory"); + } + word[nwords++] = q; + p[-1] = L'\0'; + w = wordwidth(q, p-q-1); + if(w > maxwidth) + maxwidth = w; + q = p; + } + } +} + +void +columnate(void) +{ + int i, j; + int words_per_line; + int nlines; + int col; + int endcol; + + + scanwords(); + if(nwords==0) + return; + maxwidth = nexttab(maxwidth+mintab-1); + words_per_line = linewidth/maxwidth; + if(words_per_line <= 0) + words_per_line = 1; + nlines=(nwords+words_per_line-1)/words_per_line; + for(i = 0; i < nlines; i++){ + col = endcol = 0; + for(j = i; j < nwords; j += nlines){ + endcol += maxwidth; + Bprint(&bout, "%S", word[j]); + col += wordwidth(word[j], runestrlen(word[j])); + if(j+nlines < nwords){ + if(tabflag) { + while(col < endcol){ + Bputc(&bout, '\t'); + col = nexttab(col); + } + }else{ + while(col < endcol){ + Bputc(&bout, ' '); + col++; + } + } + } + } + Bputc(&bout, '\n'); + } +} + +int +wordwidth(Rune *w, int nw) +{ + if(font) + return runestringnwidth(font, w, nw); + return nw; +} + +int +nexttab(int col) +{ + if(tabwidth){ + col += tabwidth; + col -= col%tabwidth; + return col; + } + return col+1; +} + +void +morechars(void) +{ + nalloc += ALLOC_QUANTA; + if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0) + error("out of memory"); + cbufp = cbuf+nchars-1; +} + +/* + * These routines discover the width of the display. + * It takes some work. If we do the easy calls to the + * draw library, the screen flashes due to repainting + * when mc exits. + */ + +jmp_buf drawjmp; + +void +terror(Display*, char*) +{ + longjmp(drawjmp, 1); +} + +void +getwidth(void) +{ + int n, fd; + char buf[128], *f[10], *p; + + if(access("/dev/acme", OREAD) >= 0){ + if((fd = open("/dev/acme/ctl", OREAD)) < 0) + return; + n = read(fd, buf, sizeof buf-1); + close(fd); + if(n <= 0) + return; + buf[n] = 0; + n = tokenize(buf, f, nelem(f)); + if(n < 7) + return; + if((font = openfont(nil, f[6])) == nil) + return; + if(n >= 8) + tabwidth = atoi(f[7]); + else + tabwidth = 4*stringwidth(font, "0"); + mintab = stringwidth(font, "0"); + linewidth = atoi(f[5]); + tabflag = 1; + return; + } + + if((p = getenv("font")) == nil) + return; + if((font = openfont(nil, p)) == nil) + return; + if((fd = open("/dev/window", OREAD)) < 0){ + font = nil; + return; + } + n = read(fd, buf, 5*12); + close(fd); + if(n < 5*12){ + font = nil; + return; + } + buf[n] = 0; + + /* window stucture: + 4 bit left edge + 1 bit gap + 12 bit scrollbar + 4 bit gap + text + 4 bit right edge + */ + linewidth = atoi(buf+3*12) - atoi(buf+1*12) - (4+1+12+4+4); + mintab = stringwidth(font, "0"); + if((p = getenv("tabstop")) != nil) + tabwidth = atoi(p)*stringwidth(font, "0"); + if(tabwidth == 0) + tabwidth = 4*stringwidth(font, "0"); + tabflag = 1; +} |