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