| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include <ctype.h> |
| |
| /* |
| * block up paragraphs, possibly with indentation |
| */ |
| |
| int extraindent = 0; /* how many spaces to indent all lines */ |
| int indent = 0; /* current value of indent, before extra indent */ |
| int length = 70; /* how many columns per output line */ |
| int join = 1; /* can lines be joined? */ |
| int maxtab = 8; |
| Biobuf bin; |
| Biobuf bout; |
| |
| typedef struct Word Word; |
| struct Word{ |
| int bol; |
| int indent; |
| char text[1]; |
| }; |
| |
| void fmt(void); |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: %s [-j] [-i indent] [-l length] [file...]\n", argv0); |
| exits("usage"); |
| } |
| |
| void |
| main(int argc, char **argv) |
| { |
| int i, f; |
| char *s, *err; |
| |
| ARGBEGIN{ |
| case 'i': |
| extraindent = atoi(EARGF(usage())); |
| break; |
| case 'j': |
| join = 0; |
| break; |
| case 'w': |
| case 'l': |
| length = atoi(EARGF(usage())); |
| break; |
| default: |
| usage(); |
| }ARGEND |
| |
| if(length <= indent){ |
| fprint(2, "%s: line length<=indentation\n", argv0); |
| exits("length"); |
| } |
| |
| s=getenv("tabstop"); |
| if(s!=nil && atoi(s)>0) |
| maxtab=atoi(s); |
| err = nil; |
| Binit(&bout, 1, OWRITE); |
| if(argc <= 0){ |
| Binit(&bin, 0, OREAD); |
| fmt(); |
| }else{ |
| for(i=0; i<argc; i++){ |
| f = open(argv[i], OREAD); |
| if(f < 0){ |
| fprint(2, "%s: can't open %s: %r\n", argv0, argv[i]); |
| err = "open"; |
| }else{ |
| Binit(&bin, f, OREAD); |
| fmt(); |
| Bterm(&bin); |
| if(i != argc-1) |
| Bputc(&bout, '\n'); |
| } |
| } |
| } |
| exits(err); |
| } |
| |
| int |
| indentof(char **linep) |
| { |
| int i, ind; |
| char *line; |
| |
| ind = 0; |
| line = *linep; |
| for(i=0; line[i]; i++) |
| switch(line[i]){ |
| default: |
| *linep = line; |
| return ind; |
| case ' ': |
| ind++; |
| break; |
| case '\t': |
| ind += maxtab; |
| ind -= ind%maxtab; |
| break; |
| } |
| |
| /* plain white space doesn't change the indent */ |
| *linep = ""; |
| return indent; |
| } |
| |
| Word** |
| addword(Word **words, int *nwordp, char *s, int l, int indent, int bol) |
| { |
| Word *w; |
| |
| w = malloc(sizeof(Word)+l+1); |
| memmove(w->text, s, l); |
| w->text[l] = '\0'; |
| w->indent = indent; |
| w->bol = bol; |
| words = realloc(words, (*nwordp+1)*sizeof(Word*)); |
| words[(*nwordp)++] = w; |
| return words; |
| } |
| |
| Word** |
| parseline(char *line, Word **words, int *nwordp) |
| { |
| int ind, l, bol; |
| |
| ind = indentof(&line); |
| indent = ind; |
| bol = 1; |
| for(;;){ |
| /* find next word */ |
| while(*line==' ' || *line=='\t') |
| line++; |
| if(*line == '\0'){ |
| if(bol) |
| return addword(words, nwordp, "", 0, -1, bol); |
| break; |
| } |
| /* how long is this word? */ |
| for(l=0; line[l]; l++) |
| if(line[l]==' ' || line[l]=='\t') |
| break; |
| words = addword(words, nwordp, line, l, indent, bol); |
| bol = 0; |
| line += l; |
| } |
| return words; |
| } |
| |
| void |
| printindent(int w) |
| { |
| while(w >= maxtab){ |
| Bputc(&bout, '\t'); |
| w -= maxtab; |
| } |
| while(w > 0){ |
| Bputc(&bout, ' '); |
| w--; |
| } |
| } |
| |
| void |
| printwords(Word **w, int nw) |
| { |
| int i, j, n, col, nsp; |
| |
| /* one output line per loop */ |
| for(i=0; i<nw; ){ |
| /* if it's a blank line, print it */ |
| if(w[i]->indent == -1){ |
| Bputc(&bout, '\n'); |
| if(++i == nw) /* out of words */ |
| break; |
| } |
| /* emit leading indent */ |
| col = extraindent+w[i]->indent; |
| printindent(col); |
| /* emit words until overflow; always emit at least one word */ |
| for(n=0;; n++){ |
| Bprint(&bout, "%s", w[i]->text); |
| col += utflen(w[i]->text); |
| if(++i == nw) |
| break; /* out of words */ |
| if(w[i]->indent != w[i-1]->indent) |
| break; /* indent change */ |
| nsp = 1; |
| if(col+nsp+utflen(w[i]->text) > extraindent+length) |
| break; /* fold line */ |
| if(!join && w[i]->bol) |
| break; |
| for(j=0; j<nsp; j++) |
| Bputc(&bout, ' '); /* emit space; another word will follow */ |
| col += nsp; |
| } |
| /* emit newline */ |
| Bputc(&bout, '\n'); |
| } |
| } |
| |
| void |
| fmt(void) |
| { |
| char *s; |
| int i, nw; |
| Word **w; |
| |
| nw = 0; |
| w = nil; |
| while((s = Brdstr(&bin, '\n', 1)) != nil){ |
| w = parseline(s, w, &nw); |
| free(s); |
| } |
| printwords(w, nw); |
| for(i=0; i<nw; i++) |
| free(w[i]); |
| free(w); |
| } |