tmc.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
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        
    11 #include        
    12 #include        
    13 #ifdef HAS_SYS_TERMIOS
    14 #include        
    15 #endif
    16 #include        
    17 #include        
    18 #include        
    19 #include        
    20 #include        <9pclient.h>
    21 #include        
    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 }