URI:
       tmc.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmc.c (6417B)
       ---
            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        <sys/ioctl.h>
           12 #include        <termios.h>
           13 #ifdef HAS_SYS_TERMIOS
           14 #include        <sys/termios.h>
           15 #endif
           16 #include        <libc.h>
           17 #include        <draw.h>
           18 #include        <bio.h>
           19 #include        <fcall.h>
           20 #include        <9pclient.h>
           21 #include        <thread.h>
           22 
           23 #define        WIDTH                        80
           24 #define        TAB        4
           25 #define        WORD_ALLOC_QUANTA        1024
           26 #define        ALLOC_QUANTA                4096
           27 
           28 int wordsize(Rune*, int);
           29 int nexttab(int);
           30 
           31 int tabwid;
           32 int mintab = 1;
           33 int linewidth=WIDTH;
           34 int colonflag=0;
           35 int tabflag=0;        /* -t flag turned off forever, except in acme */
           36 Rune *cbuf, *cbufp;
           37 Rune **word;
           38 int maxwidth=0;
           39 int nalloc=ALLOC_QUANTA;
           40 int nwalloc=WORD_ALLOC_QUANTA;
           41 int nchars=0;
           42 int nwords=0;
           43 Biobuf        bin;
           44 Biobuf        bout;
           45 
           46 void getwidth(void), readbuf(int), error(char *);
           47 void scanwords(void), columnate(void), morechars(void);
           48 
           49 void
           50 threadmain(int argc, char *argv[])
           51 {
           52         int i;
           53         int lineset;
           54         int ifd;
           55 
           56         lineset = 0;
           57         Binit(&bout, 1, OWRITE);
           58         while(argc > 1 && argv[1][0] == '-'){
           59                 --argc; argv++;
           60                 switch(argv[0][1]){
           61                 case '\0':
           62                         colonflag = 1;
           63                         break;
           64                 case 't':
           65                         tabflag = 0;
           66                         break;
           67                 default:
           68                         linewidth = atoi(&argv[0][1]);
           69                         if(linewidth <= 1)
           70                                 linewidth = WIDTH;
           71                         lineset = 1;
           72                         break;
           73                 }
           74         }
           75         if(lineset == 0)
           76                 getwidth();
           77         cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));
           78         word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));
           79         if(word == 0 || cbuf == 0)
           80                 error("out of memory");
           81         if(argc == 1)
           82                 readbuf(0);
           83         else{
           84                 for(i = 1; i < argc; i++){
           85                         if((ifd = open(*++argv, OREAD)) == -1)
           86                                 fprint(2, "mc: can't open %s (%r)\n", *argv);
           87                         else{
           88                                 readbuf(ifd);
           89                                 Bflush(&bin);
           90                                 close(ifd);
           91                         }
           92                 }
           93         }
           94         columnate();
           95         Bflush(&bout);
           96         threadexitsall(0);
           97 }
           98 void
           99 error(char *s)
          100 {
          101         fprint(2, "mc: %s\n", s);
          102         threadexitsall(s);
          103 }
          104 void
          105 readbuf(int fd)
          106 {
          107         int lastwascolon = 0;
          108         long c;
          109         int linesiz = 0;
          110 
          111         Binit(&bin, fd, OREAD);
          112         do{
          113                 if(nchars++ >= nalloc)
          114                         morechars();
          115                 *cbufp++ = c = Bgetrune(&bin);
          116                 linesiz++;
          117                 if(c == '\t') {
          118                         cbufp[-1] = L' ';
          119                         while(linesiz%TAB != 0) {
          120                                 if(nchars++ >= nalloc)
          121                                         morechars();
          122                                 *cbufp++ = L' ';
          123                                 linesiz++;
          124                         }
          125                 }
          126                 if(colonflag && c == ':')
          127                         lastwascolon++;
          128                 else if(lastwascolon){
          129                         if(c == '\n'){
          130                                 --nchars;         /* skip newline */
          131                                 *cbufp = L'\0';
          132                                 while(nchars > 0 && cbuf[--nchars] != '\n')
          133                                         ;
          134                                 if(nchars)
          135                                         nchars++;
          136                                 columnate();
          137                                 if (nchars)
          138                                         Bputc(&bout, '\n');
          139                                 Bprint(&bout, "%S", cbuf+nchars);
          140                                 nchars = 0;
          141                                 cbufp = cbuf;
          142                         }
          143                         lastwascolon = 0;
          144                 }
          145                 if(c == '\n')
          146                         linesiz = 0;
          147         }while(c >= 0);
          148 }
          149 void
          150 scanwords(void)
          151 {
          152         Rune *p, *q;
          153         int i, w;
          154 
          155         nwords=0;
          156         maxwidth=0;
          157         for(p = q = cbuf, i = 0; i < nchars; i++){
          158                 if(*p++ == L'\n'){
          159                         if(nwords >= nwalloc){
          160                                 nwalloc += WORD_ALLOC_QUANTA;
          161                                 if((word = realloc(word, nwalloc*sizeof(*word)))==0)
          162                                         error("out of memory");
          163                         }
          164                         word[nwords++] = q;
          165                         p[-1] = L'\0';
          166                         w = wordsize(q, p-q-1);
          167                         if(w > maxwidth)
          168                                 maxwidth = w;
          169                         q = p;
          170                 }
          171         }
          172 }
          173 
          174 void
          175 columnate(void)
          176 {
          177         int i, j;
          178         int words_per_line;
          179         int nlines;
          180         int col;
          181         int endcol;
          182 
          183 
          184         scanwords();
          185         if(nwords==0)
          186                 return;
          187         maxwidth = nexttab(maxwidth+mintab-1);
          188         words_per_line = linewidth/maxwidth;
          189         if(words_per_line <= 0)
          190                 words_per_line = 1;
          191         nlines=(nwords+words_per_line-1)/words_per_line;
          192         for(i = 0; i < nlines; i++){
          193                 col = endcol = 0;
          194                 for(j = i; j < nwords; j += nlines){
          195                         endcol += maxwidth;
          196                         Bprint(&bout, "%S", word[j]);
          197                         col += wordsize(word[j], runestrlen(word[j]));
          198                         if(j+nlines < nwords){
          199                                 if(tabflag) {
          200                                         while(col < endcol){
          201                                                 Bputc(&bout, '\t');
          202                                                 col = nexttab(col);
          203                                         }
          204                                 }else{
          205                                         while(col < endcol){
          206                                                 Bputc(&bout, ' ');
          207                                                 col++;
          208                                         }
          209                                 }
          210                         }
          211                 }
          212                 Bputc(&bout, '\n');
          213         }
          214 }
          215 
          216 int
          217 wordsize(Rune *w, int nw)
          218 {
          219         if(nw < 0)
          220                 abort();
          221         if(font)
          222                 return runestringnwidth(font, w, nw);
          223         return nw;
          224 }
          225 
          226 int
          227 nexttab(int col)
          228 {
          229         if(tabwid){
          230                 col += tabwid;
          231                 col -= col%tabwid;
          232                 return col;
          233         }
          234         return col+1;
          235 }
          236 
          237 void
          238 morechars(void)
          239 {
          240         nalloc += ALLOC_QUANTA;
          241         if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)
          242                 error("out of memory");
          243         cbufp = cbuf+nchars-1;
          244 }
          245 
          246 /*
          247  * These routines discover the width of the display.
          248  * It takes some work.  If we do the easy calls to the
          249  * draw library, the screen flashes due to repainting
          250  * when mc exits.
          251  */
          252 int
          253 windowrect(struct winsize *ws)
          254 {
          255         int tty;
          256 
          257         if((tty = open("/dev/tty", OWRITE)) < 0)
          258                 tty = 1;
          259 
          260         if(ioctl(tty, TIOCGWINSZ, ws) < 0){
          261                 if(tty != 1)
          262                         close(tty);
          263                 return -1;
          264         }
          265         if(tty != 1)
          266                 close(tty);
          267         return 0;
          268 }
          269 
          270 void
          271 getwidth(void)
          272 {
          273         CFsys *fs;
          274         char buf[500], *p, *q, *f[10], *fname;
          275         int fd, n, nf, scale;
          276         struct winsize ws;
          277         Font *f1;
          278 
          279         if((p = getenv("winid")) != nil){
          280                 fs = nsmount("acme", "");
          281                 if(fs == nil)
          282                         return;
          283                 snprint(buf, sizeof buf, "acme/%d/ctl", atoi(p));
          284                 if((fd = fsopenfd(fs, buf, OREAD)) < 0)
          285                         return;
          286                 if((n=readn(fd, buf, sizeof buf-1)) <= 0)
          287                         return;
          288                 buf[n] = 0;
          289                 if((nf=tokenize(buf, f, nelem(f))) < 7)
          290                         return;
          291                 // hidpi font in stringwidth(3) will call scalesubfont,
          292                 // which aborts in bytesperline, due to unknow depth,
          293                 // without initdraw.  We scale by ourselves.
          294                 scale = parsefontscale(f[6], &fname);
          295                 tabwid = 0;
          296                 if(nf >= 8 && (tabwid = atoi(f[7])/scale) == 0)
          297                         return;
          298                 if((font = openfont(nil, fname)) == nil)
          299                         return;
          300                 mintab = stringwidth(font, "0");
          301                 if(tabwid == 0)
          302                         tabwid = mintab*4;
          303                 linewidth = atoi(f[5]) / scale;
          304                 tabflag = 1;
          305                 return;
          306         }
          307 
          308         if((p = getenv("termprog")) != nil && strcmp(p, "9term") == 0)
          309         if((p = getenv("font")) != nil)
          310                 font = openfont(nil, p);
          311 
          312         if(windowrect(&ws) < 0)
          313                 return;
          314         if(ws.ws_xpixel == 0)
          315                 font = nil;
          316         if(font){
          317                 // 9term leaves "is this a hidpi display" in the low bit of the ypixel height.
          318                 if(ws.ws_ypixel&1) {
          319                         // need hidpi font.
          320                         // loadhifpi creates a font that crashes in stringwidth,
          321                         // for reasons i don't understand.
          322                         // do it ourselves
          323                         p = getenv("font");
          324                         q = strchr(p, ',');
          325                         f1 = nil;
          326                         if(q != nil)
          327                                 f1 = openfont(nil, q+1);
          328                         if(f1 != nil)
          329                                 font = f1;
          330                         else
          331                                 ws.ws_xpixel /= 2;
          332                 }
          333                 mintab = stringwidth(font, "0");
          334                 if((p = getenv("tabstop")) != nil)
          335                         tabwid = atoi(p)*mintab;
          336                 else
          337                         tabwid = 4*mintab;
          338                 tabflag = 1;
          339                 linewidth = ws.ws_xpixel;
          340         }else
          341                 linewidth = ws.ws_col;
          342 }