fmt.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 }