240 lines · 3.7 KB · C
RawDownload
#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{	Word	*next; 	int	indent;	int	length;	char	bol;	char	text[];}; void	fmt(void); voidusage(void){	fprint(2, "usage: %s [-j] [-i indent] [-l length] [file...]\n", argv0);	exits("usage");} voidmain(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);} intindentof(char *s){	int ind; 	ind = 0;	for(; *s != '\0'; s++)		switch(*s){		default:			return ind;		case ' ':			ind++;			break;		case '\t':			ind += maxtab;			ind -= ind%maxtab;			break;		} 	/* plain white space doesn't change the indent */	return indent;} Word*newword(char *s, int n, int ind, int bol){	Word *w; 	w = malloc(sizeof(Word) + n+1);	w->next = nil;	w->indent = ind;	w->bol = bol;	memmove(w->text, s, n);	w->text[n] = 0;	w->length = utflen(w->text);	return w;} Word*getword(void){	static Word *head, *tail;	char *line, *s;	Word *w;		w = head;	if(w != nil){		head = w->next;		return w;	}	line = Brdstr(&bin, '\n', 1);	if(line == nil)		return nil;	tail = nil;	indent = indentof(line);	for(;;){		while(*line == ' ' || *line == '\t')			line++;		if(*line == '\0'){			if(head == nil)				return newword("", 0, -1, 1);			break;		}		/* how long is this word? */		for(s=line++; *line != '\0'; line++)			if(*line==' ' || *line=='\t')				break;		w = newword(s, line-s, indent, head==nil);		if(head == nil)			head = w;		else			tail->next = w;		tail = w;	}	w = head;	head = w->next;	return w;} voidprintindent(int w){	while(w >= maxtab){		Bputc(&bout, '\t');		w -= maxtab;	}	while(w > 0){		Bputc(&bout, ' ');		w--;	}} /* give extra space if word ends with period, etc. */intnspaceafter(char *s){	int n; 	n = strlen(s);	if(n < 2)		return 1;	if(isupper(s[0]) && n < 4)		return 1;	if(strchr(".!?", s[n-1]) != nil)		return 2;	return 1;} voidfmt(void){	Word *w, *o;	int col, nsp; 	w = getword();	while(w != nil){		if(w->indent == -1){			Bputc(&bout, '\n');			free(w);			w = getword();			if(w == nil)				break;		}		col = w->indent;		printindent(extraindent+col);		/* emit words until overflow; always emit at least one word */		for(;;){			Bprint(&bout, "%s", w->text);			col += w->length;			o = w;			w = getword();			if(w == nil)				break;			if(w->indent != o->indent)				break;	/* indent change */			nsp = nspaceafter(o->text);			if(col+nsp+w->length > length)				break;	/* fold line */			if(!join && w->bol)				break;			while(--nsp >= 0){				Bputc(&bout, ' ');	/* emit space; another word will follow */				col++;			}			free(o);		}		free(o);		Bputc(&bout, '\n');	}}