978 lines · 14.7 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h> /* * Deroff command -- strip troff, eqn, and tbl sequences from * a file.  Has three flags argument, -w, to cause output one word per line * rather than in the original format. * -mm (or -ms) causes the corresponding macro's to be interpreted * so that just sentences are output * -ml  also gets rid of lists. * -i causes deroff to ignore .so and .nx commands. * Deroff follows .so and .nx commands, removes contents of macro * definitions, equations (both .EQ ... .EN and $...$), * Tbl command sequences, and Troff backslash vconstructions. *  * All input is through the C macro; the most recently read character is in c. */ /*#define	C	((c = Bgetrune(infile)) < 0?\			eof():\			((c == ldelim) && (filesp == files)?\				skeqn():\				(c == '\n'?\					(linect++,c):\						c))) #define	C1	((c = Bgetrune(infile)) == Beof?\			eof():\			(c == '\n'?\				(linect++,c):\				c))*/ /* lose those macros! */#define	C	fC()#define	C1	fC1() #define	SKIP	while(C != '\n') #define SKIP1	while(C1 != '\n')#define SKIP_TO_COM		SKIP;\				SKIP;\				pc=c;\				while(C != '.' || pc != '\n' || C > 'Z')\						pc=c #define YES		1#define NO		0#define MS		0#define MM		1#define ONE		1#define TWO		2 #define NOCHAR		-2#define	EXTENDED	-1		/* All runes above 0x7F */#define SPECIAL		0#define APOS		1#define PUNCT		2#define DIGIT		3#define LETTER		4  int	linect	= 0;int	wordflag= NO;int	underscoreflag = NO;int	msflag	= NO;int	iflag	= NO;int	mac	= MM;int	disp	= 0;int	inmacro	= NO;int	intable	= NO;int	eqnflag	= 0; #define	MAX_ASCII	0X80 char	chars[MAX_ASCII];	/* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */ Rune	line[30000];Rune*	lp; long	c;long	pc;int	ldelim	= NOCHAR;int	rdelim	= NOCHAR;  char**	argv; char	fname[50];Biobuf*	files[15];Biobuf**filesp;Biobuf*	infile;char*	devnull	= "/dev/null";Biobuf	*infile;Biobuf	bout; long	skeqn(void);Biobuf*	opn(char *p);int	eof(void);int	charclass(int);void	getfname(void);void	fatal(char *s, char *p);void	usage(void);void	work(void);void	putmac(Rune *rp, int vconst);void	regline(int macline, int vconst);void	putwords(void);void	comline(void);void	macro(void);void	eqn(void);void	tbl(void);void	stbl(void);void	sdis(char a1, char a2);void	sce(void);void	backsl(void);char*	copys(char *s);void	refer(int c1);void	inpic(void); intfC(void){	c = Bgetrune(infile);	if(c < 0)		return eof();	if(c == ldelim && filesp == files)		return skeqn();	if(c == '\n')		linect++;	return c;} intfC1(void){	c = Bgetrune(infile);	if(c == Beof)		return eof();	if(c == '\n')		linect++;	return c;} voidmain(int argc, char *av[]){	int i;	char *f; 	argv = av;	Binit(&bout, 1, OWRITE);	ARGBEGIN{	case 'w':		wordflag = YES;		break;	case '_':		wordflag = YES;		underscoreflag = YES;		break;	case 'm':		msflag = YES;		if(f = ARGF())			switch(*f)			{			case 'm':	mac = MM; break;			case 's':	mac = MS; break;			case 'l':	disp = 1; break;			default:	usage();			}		else			usage();		break;	case 'i':		iflag = YES;		break;	default:		usage();	}ARGEND	if(*argv)		infile = opn(*argv++);	else{		infile = malloc(sizeof(Biobuf));		Binit(infile, 0, OREAD);	}	files[0] = infile;	filesp = &files[0]; 	for(i='a'; i<='z' ; ++i)		chars[i] = LETTER;	for(i='A'; i<='Z'; ++i)		chars[i] = LETTER;	for(i='0'; i<='9'; ++i)		chars[i] = DIGIT;	chars['\''] = APOS;	chars['&'] = APOS;	chars['\b'] = APOS;	chars['.'] = PUNCT;	chars[','] = PUNCT;	chars[';'] = PUNCT;	chars['?'] = PUNCT;	chars[':'] = PUNCT;	work();} longskeqn(void){	while(C1 != rdelim)		if(c == '\\')			c = C1;		else if(c == '"')			while(C1 != '"')				if(c == '\\') 					C1;	if (msflag)		eqnflag = 1;	return(c = ' ');} Biobuf*opn(char *p){	Biobuf *fd; 	while ((fd = Bopen(p, OREAD)) == 0) {		if(msflag || p == devnull)			fatal("Cannot open file %s - quitting\n", p);		else {			fprint(2, "Deroff: Cannot open file %s - continuing\n", p);			p = devnull;		}	}	linect = 0;	return(fd);} inteof(void){	if(Bfildes(infile) != 0)		Bterm(infile);	if(filesp > files)		infile = *--filesp;	else	if(*argv)		infile = opn(*argv++);	else		exits(0);	return(C);} voidgetfname(void){	char *p;	Rune r;	Dir *dir;	struct chain	{ 		struct	chain*	nextp; 		char*	datap; 	} *q; 	static struct chain *namechain= 0; 	while(C == ' ')		;	for(p = fname; (r=c) != '\n' && r != ' ' && r != '\t' && r != '\\'; C)		p += runetochar(p, &r);	*p = '\0';	while(c != '\n')		C;	if(!strcmp(fname, "/sys/lib/tmac/tmac.cs")			|| !strcmp(fname, "/sys/lib/tmac/tmac.s")) {		fname[0] = '\0';		return;	}	dir = dirstat(fname);	if(dir!=nil && ((dir->mode & DMDIR) || dir->type != 'M')) {		free(dir);		fname[0] = '\0';		return;	}	free(dir);	/*	 * see if this name has already been used	 */ 	for(q = namechain; q; q = q->nextp)		if( !strcmp(fname, q->datap)) {			fname[0] = '\0';			return;		}	q = (struct chain*)malloc(sizeof(struct chain));	q->nextp = namechain;	q->datap = copys(fname);	namechain = q;} voidusage(void){	fprint(2,"usage: deroff [-nw_pi] [-m (m s l)] [file ...] \n");	exits("usage");} voidfatal(char *s, char *p){	fprint(2, "deroff: ");	fprint(2, s, p);	exits(s);} voidwork(void){ 	for(;;) {		eqnflag = 0;		if(C == '.'  ||  c == '\'')			comline();		else			regline(NO, TWO);	}} voidregline(int macline, int vconst){	line[0] = c;	lp = line;	for(;;) {		if(c == '\\') {			*lp = ' ';			backsl();			if(c == '%')	/* no blank for hyphenation char */				lp--;		}		if(c == '\n')			break;		if(intable && c=='T') {			*++lp = C;			if(c=='{' || c=='}') {				lp[-1] = ' ';				*lp = C;			}		} else {			if(msflag == 1 && eqnflag == 1) {				eqnflag = 0;				*++lp = 'x';			}			*++lp = C;		}	}	*lp = '\0';	if(lp != line) {		if(wordflag)			putwords();		else		if(macline)			putmac(line,vconst);		else			Bprint(&bout, "%S\n", line);	}} voidputmac(Rune *rp, int vconst){	Rune *t;	int found;	Rune last; 	found = 0;	last = 0;	while(*rp) {		while(*rp == ' ' || *rp == '\t')			Bputrune(&bout, *rp++);		for(t = rp; *t != ' ' && *t != '\t' && *t != '\0'; t++)			;		if(*rp == '\"')			rp++;		if(t > rp+vconst && charclass(*rp) == LETTER				&& charclass(rp[1]) == LETTER) {			while(rp < t)				if(*rp == '\"')					rp++;				else					Bputrune(&bout, *rp++);			last = t[-1];			found++;		} else		if(found && charclass(*rp) == PUNCT && rp[1] == '\0')			Bputrune(&bout, *rp++);		else {			last = t[-1];			rp = t;		}	}	Bputc(&bout, '\n');	if(msflag && charclass(last) == PUNCT)		Bprint(&bout, " %C\n", last);} /* * break into words for -w option */voidputwords(void){	Rune *p, *p1;	int i, nlet;  	for(p1 = line;;) {		/*		 * skip initial specials ampersands and apostrophes		 */		while((i = charclass(*p1)) != EXTENDED && i < DIGIT)			if(*p1++ == '\0')				return;		nlet = 0;		for(p = p1; (i = charclass(*p)) != SPECIAL || (underscoreflag && *p=='_'); p++)			if(i == LETTER || (underscoreflag && *p == '_'))				nlet++;		/*		 * MDM definition of word		 */		if(nlet > 1) {			/*			 * delete trailing ampersands and apostrophes			 */			while(*--p == '\'' || *p == '&'					   || charclass(*p) == PUNCT)				;			while(p1 <= p)				Bputrune(&bout, *p1++);			Bputc(&bout, '\n');		} else			p1 = p;	}} voidcomline(void){	long c1, c2; 	while(C==' ' || c=='\t')		;comx:	if((c1=c) == '\n')		return;	c2 = C;	if(c1=='.' && c2!='.')		inmacro = NO;	if(msflag && c1 == '['){		refer(c2);		return;	}	if(c2 == '\n')		return;	if(c1 == '\\' && c2 == '\"')		SKIP;	else	if (filesp==files && c1=='E' && c2=='Q')			eqn();	else	if(filesp==files && c1=='T' && (c2=='S' || c2=='C' || c2=='&')) {		if(msflag)			stbl(); 		else			tbl();	}	else	if(c1=='T' && c2=='E')		intable = NO;	else if (!inmacro &&			((c1 == 'd' && c2 == 'e') ||		   	 (c1 == 'i' && c2 == 'g') ||		   	 (c1 == 'a' && c2 == 'm')))				macro();	else	if(c1=='s' && c2=='o') {		if(iflag)			SKIP;		else {			getfname();			if(fname[0]) {

Lines 1–500 of 978.