xref: /plan9-contrib/sys/src/cmd/fmt.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <ctype.h>
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  * block up paragraphs, possibly with indentation
83e12c5d1SDavid du Colombier  */
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier void	fmt(Biobuf*);
113e12c5d1SDavid du Colombier void	outchar(Rune);
123e12c5d1SDavid du Colombier void	addrune(Rune);
133e12c5d1SDavid du Colombier void	outword(void);
143e12c5d1SDavid du Colombier void	puncttest(void);
153e12c5d1SDavid du Colombier void	flush(void);
163e12c5d1SDavid du Colombier 
173e12c5d1SDavid du Colombier int join=1;		/* can input lines be joined? */
183e12c5d1SDavid du Colombier int indent=0;		/* how many spaces to indent */
193e12c5d1SDavid du Colombier int length=70;		/* how many columns per output line */
203e12c5d1SDavid du Colombier Biobuf bin;
213e12c5d1SDavid du Colombier Biobuf bout;
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier void
243e12c5d1SDavid du Colombier main(int argc, char **argv)
253e12c5d1SDavid du Colombier {
263e12c5d1SDavid du Colombier 	int i, f;
273e12c5d1SDavid du Colombier 	ARGBEGIN{
283e12c5d1SDavid du Colombier 	case 'i':
293e12c5d1SDavid du Colombier 		indent = atoi(ARGF());
303e12c5d1SDavid du Colombier 		break;
313e12c5d1SDavid du Colombier 	case 'j':
323e12c5d1SDavid du Colombier 		join = 0;
333e12c5d1SDavid du Colombier 		break;
343e12c5d1SDavid du Colombier 	case 'w':
353e12c5d1SDavid du Colombier 	case 'l':
363e12c5d1SDavid du Colombier 		length = atoi(ARGF());
373e12c5d1SDavid du Colombier 		break;
383e12c5d1SDavid du Colombier 	default:
393e12c5d1SDavid du Colombier 		fprint(2, "Usage: %s [-j] [-i indent] [-l length] [file ...]\n",
403e12c5d1SDavid du Colombier 				argv0);
413e12c5d1SDavid du Colombier 		exits("usage");
423e12c5d1SDavid du Colombier 	}ARGEND
433e12c5d1SDavid du Colombier 	if(length<=indent){
443e12c5d1SDavid du Colombier 		fprint(2, "%s: line length<=indentation\n", argv0);
453e12c5d1SDavid du Colombier 		exits("length");
463e12c5d1SDavid du Colombier 	}
473e12c5d1SDavid du Colombier 	Binit(&bout, 1, OWRITE);
483e12c5d1SDavid du Colombier 	if(argc<=0){
493e12c5d1SDavid du Colombier 		Binit(&bin, 0, OREAD);
503e12c5d1SDavid du Colombier 		fmt(&bin);
513e12c5d1SDavid du Colombier 	}else{
523e12c5d1SDavid du Colombier 		for(i=0; i<argc; i++){
533e12c5d1SDavid du Colombier 			f=open(argv[i], OREAD);
543e12c5d1SDavid du Colombier 			if(f<0)
553e12c5d1SDavid du Colombier 				perror(argv[i]);
563e12c5d1SDavid du Colombier 			else{
573e12c5d1SDavid du Colombier 				Binit(&bin, f, OREAD);
583e12c5d1SDavid du Colombier 				fmt(&bin);
59*219b2ee8SDavid du Colombier 				Bterm(&bin);
603e12c5d1SDavid du Colombier 				if(i!=argc-1)
613e12c5d1SDavid du Colombier 					Bputc(&bout, '\n');
623e12c5d1SDavid du Colombier 			}
633e12c5d1SDavid du Colombier 		}
643e12c5d1SDavid du Colombier 	}
653e12c5d1SDavid du Colombier 	exits(0);
663e12c5d1SDavid du Colombier }
673e12c5d1SDavid du Colombier void
683e12c5d1SDavid du Colombier fmt(Biobuf *f)
693e12c5d1SDavid du Colombier {
703e12c5d1SDavid du Colombier 	long c;
713e12c5d1SDavid du Colombier 
723e12c5d1SDavid du Colombier 	while((c = Bgetrune(f)) >= 0)
733e12c5d1SDavid du Colombier 		outchar((Rune) c);
743e12c5d1SDavid du Colombier 	flush();
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier #define TAB 8
783e12c5d1SDavid du Colombier #define	NWORD	(TAB*32)
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier Rune word[NWORD+1];
813e12c5d1SDavid du Colombier Rune *wp=word;
823e12c5d1SDavid du Colombier int col=0;	/* output column number */
833e12c5d1SDavid du Colombier int bol=1;	/* at beginning of output line? */
843e12c5d1SDavid du Colombier int punct=0;	/* last character out was punctuation? */
853e12c5d1SDavid du Colombier int newline=1;	/* last char read was newline(1) or init space(2) */
863e12c5d1SDavid du Colombier 
873e12c5d1SDavid du Colombier void
883e12c5d1SDavid du Colombier outchar(Rune c){
893e12c5d1SDavid du Colombier 	switch(c){
903e12c5d1SDavid du Colombier 	case '\0':
913e12c5d1SDavid du Colombier 		break;
923e12c5d1SDavid du Colombier 	case '\n':
933e12c5d1SDavid du Colombier 		switch(newline){
943e12c5d1SDavid du Colombier 		case 0:
953e12c5d1SDavid du Colombier 			if(join)
963e12c5d1SDavid du Colombier 				outword();
973e12c5d1SDavid du Colombier 			else
983e12c5d1SDavid du Colombier 				flush();
993e12c5d1SDavid du Colombier 			break;
1003e12c5d1SDavid du Colombier 		case 1:
1013e12c5d1SDavid du Colombier 			flush();
1023e12c5d1SDavid du Colombier 		case 2:
1033e12c5d1SDavid du Colombier 			Bputc(&bout, '\n');
1043e12c5d1SDavid du Colombier 			wp=word;
1053e12c5d1SDavid du Colombier 		}
1063e12c5d1SDavid du Colombier 		newline=1;
1073e12c5d1SDavid du Colombier 		break;
1083e12c5d1SDavid du Colombier 	case ' ':
1093e12c5d1SDavid du Colombier 	case '\t':
1103e12c5d1SDavid du Colombier 		switch(newline) {
1113e12c5d1SDavid du Colombier 		case 0:
1123e12c5d1SDavid du Colombier 			outword();
1133e12c5d1SDavid du Colombier 			break;
1143e12c5d1SDavid du Colombier 		case 1:
1153e12c5d1SDavid du Colombier 			flush();
1163e12c5d1SDavid du Colombier 			newline=2;
1173e12c5d1SDavid du Colombier 		case 2:
1183e12c5d1SDavid du Colombier 			do {
1193e12c5d1SDavid du Colombier 				addrune(L' ');
1203e12c5d1SDavid du Colombier 			} while(c=='\t' && (wp-word)%TAB);
1213e12c5d1SDavid du Colombier 		}
1223e12c5d1SDavid du Colombier 		break;
1233e12c5d1SDavid du Colombier 	default:
1243e12c5d1SDavid du Colombier 		addrune(c);
1253e12c5d1SDavid du Colombier 		newline=0;
1263e12c5d1SDavid du Colombier 	}
1273e12c5d1SDavid du Colombier }
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier void
1303e12c5d1SDavid du Colombier addrune(Rune c)
1313e12c5d1SDavid du Colombier {
1323e12c5d1SDavid du Colombier 	if(wp==&word[NWORD]) {
1333e12c5d1SDavid du Colombier 		if(utfrune(" \t",wp[-1]))
1343e12c5d1SDavid du Colombier 			wp=word;
1353e12c5d1SDavid du Colombier 		outword();
1363e12c5d1SDavid du Colombier 	}
1373e12c5d1SDavid du Colombier 	*wp++=c;
1383e12c5d1SDavid du Colombier }
1393e12c5d1SDavid du Colombier 
1403e12c5d1SDavid du Colombier void
1413e12c5d1SDavid du Colombier outword(void)
1423e12c5d1SDavid du Colombier {
1433e12c5d1SDavid du Colombier 	int i;
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	if(wp==word)
1463e12c5d1SDavid du Colombier 		return;
1473e12c5d1SDavid du Colombier 	if(wp-word+col+(bol?0:punct?2:1)>length){
1483e12c5d1SDavid du Colombier 		Bputc(&bout, '\n');
1493e12c5d1SDavid du Colombier 		col=0;
1503e12c5d1SDavid du Colombier 		bol=1;
1513e12c5d1SDavid du Colombier 	}
1523e12c5d1SDavid du Colombier 	if(col==0){
1533e12c5d1SDavid du Colombier 		for(i=0;i+8<=indent;i+=8)
1543e12c5d1SDavid du Colombier 			Bputc(&bout, '\t');
1553e12c5d1SDavid du Colombier 		while(i++<indent)
1563e12c5d1SDavid du Colombier 			Bputc(&bout, ' ');
1573e12c5d1SDavid du Colombier 		col=indent;
1583e12c5d1SDavid du Colombier 	}
1593e12c5d1SDavid du Colombier 	if(bol)
1603e12c5d1SDavid du Colombier 		bol=0;
1613e12c5d1SDavid du Colombier 	else{
1623e12c5d1SDavid du Colombier 		if(punct){
1633e12c5d1SDavid du Colombier 			Bputc(&bout, ' ');
1643e12c5d1SDavid du Colombier 			col++;
1653e12c5d1SDavid du Colombier 		}
1663e12c5d1SDavid du Colombier 		Bputc(&bout, ' ');
1673e12c5d1SDavid du Colombier 		col++;
1683e12c5d1SDavid du Colombier 	}
1693e12c5d1SDavid du Colombier 	puncttest();
1703e12c5d1SDavid du Colombier 	for (i = 0; word+i < wp; i++)
1713e12c5d1SDavid du Colombier 		Bputrune(&bout, word[i]);
1723e12c5d1SDavid du Colombier 	col+=i;
1733e12c5d1SDavid du Colombier 	wp=word;
1743e12c5d1SDavid du Colombier }
1753e12c5d1SDavid du Colombier /* is the word followed by major punctuation, .?:! */
1763e12c5d1SDavid du Colombier /* disregard short things followed by periods; they are probably
1773e12c5d1SDavid du Colombier    initials or titles like Mrs. and Dr. */
1783e12c5d1SDavid du Colombier void
1793e12c5d1SDavid du Colombier puncttest(void)
1803e12c5d1SDavid du Colombier {
1813e12c5d1SDavid du Colombier 	Rune *rp;
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	punct = 0;
1843e12c5d1SDavid du Colombier 	for(rp=wp; --rp>=word; ) {
1853e12c5d1SDavid du Colombier 		switch(*rp) {
1863e12c5d1SDavid du Colombier 		case ')': case '\'': case '"':
1873e12c5d1SDavid du Colombier 			continue;
1883e12c5d1SDavid du Colombier 		case '.':
1893e12c5d1SDavid du Colombier 			if(isupper(*word)&&rp-word<=3)
1903e12c5d1SDavid du Colombier 				return;
191*219b2ee8SDavid du Colombier 		case '?': case '!': /*case ':':*/
1923e12c5d1SDavid du Colombier 			punct = 1;
1933e12c5d1SDavid du Colombier 		default:
1943e12c5d1SDavid du Colombier 			return;
1953e12c5d1SDavid du Colombier 		}
1963e12c5d1SDavid du Colombier 	}
1973e12c5d1SDavid du Colombier }
1983e12c5d1SDavid du Colombier void
1993e12c5d1SDavid du Colombier flush(void){
2003e12c5d1SDavid du Colombier 	outword();
2013e12c5d1SDavid du Colombier 	if(col!=0){
2023e12c5d1SDavid du Colombier 		Bputc(&bout, '\n');
2033e12c5d1SDavid du Colombier 		col=0;
2043e12c5d1SDavid du Colombier 		bol=1;
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier }
207