URI:
       tfmt.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
       ---
       tfmt.c (3820B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ctype.h>
            5 
            6 /*
            7  * block up paragraphs, possibly with indentation
            8  */
            9 
           10 int extraindent = 0;                /* how many spaces to indent all lines */
           11 int indent = 0;                        /* current value of indent, before extra indent */
           12 int length = 70;                /* how many columns per output line */
           13 int join = 1;                        /* can lines be joined? */
           14 int maxtab = 8;
           15 Biobuf bin;
           16 Biobuf bout;
           17 
           18 typedef struct Word Word;
           19 struct Word{
           20         int        bol;
           21         int        indent;
           22         char        text[1];
           23 };
           24 
           25 void        fmt(void);
           26 
           27 void
           28 usage(void)
           29 {
           30         fprint(2, "usage: %s [-j] [-i indent] [-l length] [file...]\n", argv0);
           31         exits("usage");
           32 }
           33 
           34 void
           35 main(int argc, char **argv)
           36 {
           37         int i, f;
           38         char *s, *err;
           39 
           40         ARGBEGIN{
           41         case 'i':
           42                 extraindent = atoi(EARGF(usage()));
           43                 break;
           44         case 'j':
           45                 join = 0;
           46                 break;
           47         case 'w':
           48         case 'l':
           49                 length = atoi(EARGF(usage()));
           50                 break;
           51         default:
           52                 usage();
           53         }ARGEND
           54 
           55         if(length <= indent){
           56                 fprint(2, "%s: line length<=indentation\n", argv0);
           57                 exits("length");
           58         }
           59 
           60         s=getenv("tabstop");
           61         if(s!=nil && atoi(s)>0)
           62                 maxtab=atoi(s);
           63         err = nil;
           64         Binit(&bout, 1, OWRITE);
           65         if(argc <= 0){
           66                 Binit(&bin, 0, OREAD);
           67                 fmt();
           68         }else{
           69                 for(i=0; i<argc; i++){
           70                         f = open(argv[i], OREAD);
           71                         if(f < 0){
           72                                 fprint(2, "%s: can't open %s: %r\n", argv0, argv[i]);
           73                                 err = "open";
           74                         }else{
           75                                 Binit(&bin, f, OREAD);
           76                                 fmt();
           77                                 Bterm(&bin);
           78                                 if(i != argc-1)
           79                                         Bputc(&bout, '\n');
           80                         }
           81                 }
           82         }
           83         exits(err);
           84 }
           85 
           86 int
           87 indentof(char **linep)
           88 {
           89         int i, ind;
           90         char *line;
           91 
           92         ind = 0;
           93         line = *linep;
           94         for(i=0; line[i]; i++)
           95                 switch(line[i]){
           96                 default:
           97                         *linep = line;
           98                         return ind;
           99                 case ' ':
          100                         ind++;
          101                         break;
          102                 case '\t':
          103                         ind += maxtab;
          104                         ind -= ind%maxtab;
          105                         break;
          106                 }
          107 
          108         /* plain white space doesn't change the indent */
          109         *linep = "";
          110         return indent;
          111 }
          112 
          113 Word**
          114 addword(Word **words, int *nwordp, char *s, int l, int indent, int bol)
          115 {
          116         Word *w;
          117 
          118         w = malloc(sizeof(Word)+l+1);
          119         memmove(w->text, s, l);
          120         w->text[l] = '\0';
          121         w->indent = indent;
          122         w->bol = bol;
          123         words = realloc(words, (*nwordp+1)*sizeof(Word*));
          124         words[(*nwordp)++] = w;
          125         return words;
          126 }
          127 
          128 Word**
          129 parseline(char *line, Word **words, int *nwordp)
          130 {
          131         int ind, l, bol;
          132 
          133         ind = indentof(&line);
          134         indent = ind;
          135         bol = 1;
          136         for(;;){
          137                 /* find next word */
          138                 while(*line==' ' || *line=='\t')
          139                         line++;
          140                 if(*line == '\0'){
          141                         if(bol)
          142                                 return addword(words, nwordp, "", 0, -1, bol);
          143                         break;
          144                 }
          145                 /* how long is this word? */
          146                 for(l=0; line[l]; l++)
          147                         if(line[l]==' ' || line[l]=='\t')
          148                                 break;
          149                 words = addword(words, nwordp, line, l, indent, bol);
          150                 bol = 0;
          151                 line += l;
          152         }
          153         return words;
          154 }
          155 
          156 void
          157 printindent(int w)
          158 {
          159         while(w >= maxtab){
          160                 Bputc(&bout, '\t');
          161                 w -= maxtab;
          162         }
          163         while(w > 0){
          164                 Bputc(&bout, ' ');
          165                 w--;
          166         }
          167 }
          168 
          169 void
          170 printwords(Word **w, int nw)
          171 {
          172         int i, j, n, col, nsp;
          173 
          174         /* one output line per loop */
          175         for(i=0; i<nw; ){
          176                 /* if it's a blank line, print it */
          177                 if(w[i]->indent == -1){
          178                         Bputc(&bout, '\n');
          179                         if(++i == nw)        /* out of words */
          180                                 break;
          181                 }
          182                 /* emit leading indent */
          183                 col = extraindent+w[i]->indent;
          184                 printindent(col);
          185                 /* emit words until overflow; always emit at least one word */
          186                 for(n=0;; n++){
          187                         Bprint(&bout, "%s", w[i]->text);
          188                         col += utflen(w[i]->text);
          189                         if(++i == nw)
          190                                 break;        /* out of words */
          191                         if(w[i]->indent != w[i-1]->indent)
          192                                 break;        /* indent change */
          193                         nsp = 1;
          194                         if(col+nsp+utflen(w[i]->text) > extraindent+length)
          195                                 break;        /* fold line */
          196                         if(!join && w[i]->bol)
          197                                 break;
          198                         for(j=0; j<nsp; j++)
          199                                 Bputc(&bout, ' ');        /* emit space; another word will follow */
          200                         col += nsp;
          201                 }
          202                 /* emit newline */
          203                 Bputc(&bout, '\n');
          204         }
          205 }
          206 
          207 void
          208 fmt(void)
          209 {
          210         char *s;
          211         int i, nw;
          212         Word **w;
          213 
          214         nw = 0;
          215         w = nil;
          216         while((s = Brdstr(&bin, '\n', 1)) != nil){
          217                 w = parseline(s, w, &nw);
          218                 free(s);
          219         }
          220         printwords(w, nw);
          221         for(i=0; i<nw; i++)
          222                 free(w[i]);
          223         free(w);
          224 }