123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- * 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;
- }
|