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 void fmt(Biobuf*); 11 void outchar(Rune); 12 void addrune(Rune); 13 void outword(void); 14 void puncttest(void); 15 void flush(void); 16 17 int join=1; /* can input lines be joined? */ 18 int indent=0; /* how many spaces to indent */ 19 int length=70; /* how many columns per output line */ 20 Biobuf bin; 21 Biobuf bout; 22 23 void 24 main(int argc, char **argv) 25 { 26 int i, f; 27 ARGBEGIN{ 28 case 'i': 29 indent = atoi(ARGF()); 30 break; 31 case 'j': 32 join = 0; 33 break; 34 case 'w': 35 case 'l': 36 length = atoi(ARGF()); 37 break; 38 default: 39 fprint(2, "Usage: %s [-j] [-i indent] [-l length] [file ...]\n", 40 argv0); 41 exits("usage"); 42 }ARGEND 43 if(length<=indent){ 44 fprint(2, "%s: line length<=indentation\n", argv0); 45 exits("length"); 46 } 47 Binit(&bout, 1, OWRITE); 48 if(argc<=0){ 49 Binit(&bin, 0, OREAD); 50 fmt(&bin); 51 }else{ 52 for(i=0; i<argc; i++){ 53 f=open(argv[i], OREAD); 54 if(f<0) 55 perror(argv[i]); 56 else{ 57 Binit(&bin, f, OREAD); 58 fmt(&bin); 59 Bterm(&bin); 60 if(i!=argc-1) 61 Bputc(&bout, '\n'); 62 } 63 } 64 } 65 exits(0); 66 } 67 void 68 fmt(Biobuf *f) 69 { 70 long c; 71 72 while((c = Bgetrune(f)) >= 0) 73 outchar((Rune) c); 74 flush(); 75 } 76 77 #define TAB 8 78 #define NWORD (TAB*32) 79 80 Rune word[NWORD+1]; 81 Rune *wp=word; 82 int col=0; /* output column number */ 83 int bol=1; /* at beginning of output line? */ 84 int punct=0; /* last character out was punctuation? */ 85 int newline=1; /* last char read was newline(1) or init space(2) */ 86 87 void 88 outchar(Rune c){ 89 switch(c){ 90 case '\0': 91 break; 92 case '\n': 93 switch(newline){ 94 case 0: 95 if(join) 96 outword(); 97 else 98 flush(); 99 break; 100 case 1: 101 flush(); 102 case 2: 103 Bputc(&bout, '\n'); 104 wp=word; 105 } 106 newline=1; 107 break; 108 case ' ': 109 case '\t': 110 switch(newline) { 111 case 0: 112 outword(); 113 break; 114 case 1: 115 flush(); 116 newline=2; 117 case 2: 118 do { 119 addrune(L' '); 120 } while(c=='\t' && (wp-word)%TAB); 121 } 122 break; 123 default: 124 addrune(c); 125 newline=0; 126 } 127 } 128 129 void 130 addrune(Rune c) 131 { 132 if(wp==&word[NWORD]) { 133 if(utfrune(" \t",wp[-1])) 134 wp=word; 135 outword(); 136 } 137 *wp++=c; 138 } 139 140 void 141 outword(void) 142 { 143 int i; 144 145 if(wp==word) 146 return; 147 if(wp-word+col+(bol?0:punct?2:1)>length){ 148 Bputc(&bout, '\n'); 149 col=0; 150 bol=1; 151 } 152 if(col==0){ 153 for(i=0;i+8<=indent;i+=8) 154 Bputc(&bout, '\t'); 155 while(i++<indent) 156 Bputc(&bout, ' '); 157 col=indent; 158 } 159 if(bol) 160 bol=0; 161 else{ 162 if(punct){ 163 Bputc(&bout, ' '); 164 col++; 165 } 166 Bputc(&bout, ' '); 167 col++; 168 } 169 puncttest(); 170 for (i = 0; word+i < wp; i++) 171 Bputrune(&bout, word[i]); 172 col+=i; 173 wp=word; 174 } 175 /* is the word followed by major punctuation, .?:! */ 176 /* disregard short things followed by periods; they are probably 177 initials or titles like Mrs. and Dr. */ 178 void 179 puncttest(void) 180 { 181 Rune *rp; 182 183 punct = 0; 184 for(rp=wp; --rp>=word; ) { 185 switch(*rp) { 186 case ')': case '\'': case '"': 187 continue; 188 case '.': 189 if(isupper(*word)&&rp-word<=3) 190 return; 191 case '?': case '!': /*case ':':*/ 192 punct = 1; 193 default: 194 return; 195 } 196 } 197 } 198 void 199 flush(void){ 200 outword(); 201 if(col!=0){ 202 Bputc(&bout, '\n'); 203 col=0; 204 bol=1; 205 } 206 } 207