|  | #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); | 
|  |  | 
|  | int | 
|  | fC(void) | 
|  | { | 
|  | c = Bgetrune(infile); | 
|  | if(c < 0) | 
|  | return eof(); | 
|  | if(c == ldelim && filesp == files) | 
|  | return skeqn(); | 
|  | if(c == '\n') | 
|  | linect++; | 
|  | return c; | 
|  | } | 
|  |  | 
|  | int | 
|  | fC1(void) | 
|  | { | 
|  | c = Bgetrune(infile); | 
|  | if(c == Beof) | 
|  | return eof(); | 
|  | if(c == '\n') | 
|  | linect++; | 
|  | return c; | 
|  | } | 
|  |  | 
|  | void | 
|  | main(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(); | 
|  | } | 
|  |  | 
|  | long | 
|  | skeqn(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); | 
|  | } | 
|  |  | 
|  | int | 
|  | eof(void) | 
|  | { | 
|  | if(Bfildes(infile) != 0) | 
|  | Bterm(infile); | 
|  | if(filesp > files) | 
|  | infile = *--filesp; | 
|  | else | 
|  | if(*argv) | 
|  | infile = opn(*argv++); | 
|  | else | 
|  | exits(0); | 
|  | return(C); | 
|  | } | 
|  |  | 
|  | void | 
|  | getfname(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; | 
|  | } | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2,"usage: deroff [-nw_pi] [-m (m s l)] [file ...] \n"); | 
|  | exits("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | fatal(char *s, char *p) | 
|  | { | 
|  | fprint(2, "deroff: "); | 
|  | fprint(2, s, p); | 
|  | exits(s); | 
|  | } | 
|  |  | 
|  | void | 
|  | work(void) | 
|  | { | 
|  |  | 
|  | for(;;) { | 
|  | eqnflag = 0; | 
|  | if(C == '.'  ||  c == '\'') | 
|  | comline(); | 
|  | else | 
|  | regline(NO, TWO); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | regline(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); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | putmac(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 | 
|  | */ | 
|  | void | 
|  | putwords(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; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | comline(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]) { | 
|  | if(infile = opn(fname)) | 
|  | *++filesp = infile; | 
|  | else infile = *filesp; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | if(c1=='n' && c2=='x') | 
|  | if(iflag) | 
|  | SKIP; | 
|  | else { | 
|  | getfname(); | 
|  | if(fname[0] == '\0') | 
|  | exits(0); | 
|  | if(Bfildes(infile) != 0) | 
|  | Bterm(infile); | 
|  | infile = *filesp = opn(fname); | 
|  | } | 
|  | else | 
|  | if(c1 == 't' && c2 == 'm') | 
|  | SKIP; | 
|  | else | 
|  | if(c1=='h' && c2=='w') | 
|  | SKIP; | 
|  | else | 
|  | if(msflag && c1 == 'T' && c2 == 'L') { | 
|  | SKIP_TO_COM; | 
|  | goto comx; | 
|  | } | 
|  | else | 
|  | if(msflag && c1=='N' && c2 == 'R') | 
|  | SKIP; | 
|  | else | 
|  | if(msflag && c1 == 'A' && (c2 == 'U' || c2 == 'I')){ | 
|  | if(mac==MM)SKIP; | 
|  | else { | 
|  | SKIP_TO_COM; | 
|  | goto comx; | 
|  | } | 
|  | } else | 
|  | if(msflag && c1=='F' && c2=='S') { | 
|  | SKIP_TO_COM; | 
|  | goto comx; | 
|  | } | 
|  | else | 
|  | if(msflag && (c1=='S' || c1=='N') && c2=='H') { | 
|  | SKIP_TO_COM; | 
|  | goto comx; | 
|  | } else | 
|  | if(c1 == 'U' && c2 == 'X') { | 
|  | if(wordflag) | 
|  | Bprint(&bout, "UNIX\n"); | 
|  | else | 
|  | Bprint(&bout, "UNIX "); | 
|  | } else | 
|  | if(msflag && c1=='O' && c2=='K') { | 
|  | SKIP_TO_COM; | 
|  | goto comx; | 
|  | } else | 
|  | if(msflag && c1=='N' && c2=='D') | 
|  | SKIP; | 
|  | else | 
|  | if(msflag && mac==MM && c1=='H' && (c2==' '||c2=='U')) | 
|  | SKIP; | 
|  | else | 
|  | if(msflag && mac==MM && c2=='L') { | 
|  | if(disp || c1=='R') | 
|  | sdis('L', 'E'); | 
|  | else { | 
|  | SKIP; | 
|  | Bprint(&bout, " ."); | 
|  | } | 
|  | } else | 
|  | if(!msflag && c1=='P' && c2=='S') { | 
|  | inpic(); | 
|  | } else | 
|  | if(msflag && (c1=='D' || c1=='N' || c1=='K'|| c1=='P') && c2=='S') { | 
|  | sdis(c1, 'E'); | 
|  | } else | 
|  | if(msflag && (c1 == 'K' && c2 == 'F')) { | 
|  | sdis(c1,'E'); | 
|  | } else | 
|  | if(msflag && c1=='n' && c2=='f') | 
|  | sdis('f','i'); | 
|  | else | 
|  | if(msflag && c1=='c' && c2=='e') | 
|  | sce(); | 
|  | else { | 
|  | if(c1=='.' && c2=='.') { | 
|  | if(msflag) { | 
|  | SKIP; | 
|  | return; | 
|  | } | 
|  | while(C == '.') | 
|  | ; | 
|  | } | 
|  | inmacro++; | 
|  | if(c1 <= 'Z' && msflag) | 
|  | regline(YES,ONE); | 
|  | else { | 
|  | if(wordflag) | 
|  | C; | 
|  | regline(YES,TWO); | 
|  | } | 
|  | inmacro--; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | macro(void) | 
|  | { | 
|  | if(msflag) { | 
|  | do { | 
|  | SKIP1; | 
|  | } while(C1 != '.' || C1 != '.' || C1 == '.'); | 
|  | if(c != '\n') | 
|  | SKIP; | 
|  | return; | 
|  | } | 
|  | SKIP; | 
|  | inmacro = YES; | 
|  | } | 
|  |  | 
|  | void | 
|  | sdis(char a1, char a2) | 
|  | { | 
|  | int c1, c2; | 
|  | int eqnf; | 
|  | int lct; | 
|  |  | 
|  | if(a1 == 'P'){ | 
|  | while(C1 == ' ') | 
|  | ; | 
|  | if(c == '<') { | 
|  | SKIP1; | 
|  | return; | 
|  | } | 
|  | } | 
|  | lct = 0; | 
|  | eqnf = 1; | 
|  | if(c != '\n') | 
|  | SKIP1; | 
|  | for(;;) { | 
|  | while(C1 != '.') | 
|  | if(c == '\n') | 
|  | continue; | 
|  | else | 
|  | SKIP1; | 
|  | if((c1=C1) == '\n') | 
|  | continue; | 
|  | if((c2=C1) == '\n') { | 
|  | if(a1 == 'f' && (c1 == 'P' || c1 == 'H')) | 
|  | return; | 
|  | continue; | 
|  | } | 
|  | if(c1==a1 && c2 == a2) { | 
|  | SKIP1; | 
|  | if(lct != 0){ | 
|  | lct--; | 
|  | continue; | 
|  | } | 
|  | if(eqnf) | 
|  | Bprint(&bout, " ."); | 
|  | Bputc(&bout, '\n'); | 
|  | return; | 
|  | } else | 
|  | if(a1 == 'L' && c2 == 'L') { | 
|  | lct++; | 
|  | SKIP1; | 
|  | } else | 
|  | if(a1 == 'D' && c1 == 'E' && c2 == 'Q') { | 
|  | eqn(); | 
|  | eqnf = 0; | 
|  | } else | 
|  | if(a1 == 'f') { | 
|  | if((mac == MS && c2 == 'P') || | 
|  | (mac == MM && c1 == 'H' && c2 == 'U')){ | 
|  | SKIP1; | 
|  | return; | 
|  | } | 
|  | SKIP1; | 
|  | } | 
|  | else | 
|  | SKIP1; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | tbl(void) | 
|  | { | 
|  | while(C != '.') | 
|  | ; | 
|  | SKIP; | 
|  | intable = YES; | 
|  | } | 
|  |  | 
|  | void | 
|  | stbl(void) | 
|  | { | 
|  | while(C != '.') | 
|  | ; | 
|  | SKIP_TO_COM; | 
|  | if(c != 'T' || C != 'E') { | 
|  | SKIP; | 
|  | pc = c; | 
|  | while(C != '.' || pc != '\n' || C != 'T' || C != 'E') | 
|  | pc = c; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | eqn(void) | 
|  | { | 
|  | long c1, c2; | 
|  | int dflg; | 
|  | char last; | 
|  |  | 
|  | last = 0; | 
|  | dflg = 1; | 
|  | SKIP; | 
|  |  | 
|  | for(;;) { | 
|  | if(C1 == '.'  || c == '\'') { | 
|  | while(C1==' ' || c=='\t') | 
|  | ; | 
|  | if(c=='E' && C1=='N') { | 
|  | SKIP; | 
|  | if(msflag && dflg) { | 
|  | Bputc(&bout, 'x'); | 
|  | Bputc(&bout, ' '); | 
|  | if(last) { | 
|  | Bputc(&bout, last); | 
|  | Bputc(&bout, '\n'); | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  | } else | 
|  | if(c == 'd') { | 
|  | if(C1=='e' && C1=='l') | 
|  | if(C1=='i' && C1=='m') { | 
|  | while(C1 == ' ') | 
|  | ; | 
|  | if((c1=c)=='\n' || (c2=C1)=='\n' || | 
|  | (c1=='o' && c2=='f' && C1=='f')) { | 
|  | ldelim = NOCHAR; | 
|  | rdelim = NOCHAR; | 
|  | } else { | 
|  | ldelim = c1; | 
|  | rdelim = c2; | 
|  | } | 
|  | } | 
|  | dflg = 0; | 
|  | } | 
|  | if(c != '\n') | 
|  | while(C1 != '\n') { | 
|  | if(chars[c] == PUNCT) | 
|  | last = c; | 
|  | else | 
|  | if(c != ' ') | 
|  | last = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * skip over a complete backslash vconstruction | 
|  | */ | 
|  | void | 
|  | backsl(void) | 
|  | { | 
|  | int bdelim; | 
|  |  | 
|  | sw: | 
|  | switch(C1) | 
|  | { | 
|  | case '"': | 
|  | SKIP1; | 
|  | return; | 
|  |  | 
|  | case 's': | 
|  | if(C1 == '\\') | 
|  | backsl(); | 
|  | else { | 
|  | while(C1>='0' && c<='9') | 
|  | ; | 
|  | Bungetrune(infile); | 
|  | c = '0'; | 
|  | } | 
|  | lp--; | 
|  | return; | 
|  |  | 
|  | case 'f': | 
|  | case 'n': | 
|  | case '*': | 
|  | if(C1 != '(') | 
|  | return; | 
|  |  | 
|  | case '(': | 
|  | if(msflag) { | 
|  | if(C == 'e') { | 
|  | if(C1 == 'm') { | 
|  | *lp = '-'; | 
|  | return; | 
|  | } | 
|  | } else | 
|  | if(c != '\n') | 
|  | C1; | 
|  | return; | 
|  | } | 
|  | if(C1 != '\n') | 
|  | C1; | 
|  | return; | 
|  |  | 
|  | case '$': | 
|  | C1;	/* discard argument number */ | 
|  | return; | 
|  |  | 
|  | case 'b': | 
|  | case 'x': | 
|  | case 'v': | 
|  | case 'h': | 
|  | case 'w': | 
|  | case 'o': | 
|  | case 'l': | 
|  | case 'L': | 
|  | if((bdelim=C1) == '\n') | 
|  | return; | 
|  | while(C1!='\n' && c!=bdelim) | 
|  | if(c == '\\') | 
|  | backsl(); | 
|  | return; | 
|  |  | 
|  | case '\\': | 
|  | if(inmacro) | 
|  | goto sw; | 
|  | default: | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | char* | 
|  | copys(char *s) | 
|  | { | 
|  | char *t, *t0; | 
|  |  | 
|  | if((t0 = t = malloc((strlen(s)+1))) == 0) | 
|  | fatal("Cannot allocate memory", (char*)0); | 
|  | while(*t++ = *s++) | 
|  | ; | 
|  | return(t0); | 
|  | } | 
|  |  | 
|  | void | 
|  | sce(void) | 
|  | { | 
|  | int n = 1; | 
|  |  | 
|  | while (C != '\n' && !('0' <= c && c <= '9')) | 
|  | ; | 
|  | if (c != '\n') { | 
|  | for (n = c-'0';'0' <= C && c <= '9';) | 
|  | n = n*10 + c-'0'; | 
|  | } | 
|  | while(n) { | 
|  | if(C == '.') { | 
|  | if(C == 'c') { | 
|  | if(C == 'e') { | 
|  | while(C == ' ') | 
|  | ; | 
|  | if(c == '0') { | 
|  | SKIP; | 
|  | break; | 
|  | } else | 
|  | SKIP; | 
|  | } else | 
|  | SKIP; | 
|  | } else | 
|  | if(c == 'P' || C == 'P') { | 
|  | if(c != '\n') | 
|  | SKIP; | 
|  | break; | 
|  | } else | 
|  | if(c != '\n') | 
|  | SKIP; | 
|  | } else { | 
|  | SKIP; | 
|  | n--; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | refer(int c1) | 
|  | { | 
|  | int c2; | 
|  |  | 
|  | if(c1 != '\n') | 
|  | SKIP; | 
|  | c2 = 0; | 
|  | for(;;) { | 
|  | if(C != '.') | 
|  | SKIP; | 
|  | else { | 
|  | if(C != ']') | 
|  | SKIP; | 
|  | else { | 
|  | while(C != '\n') | 
|  | c2 = c; | 
|  | if(charclass(c2) == PUNCT) | 
|  | Bprint(&bout, " %C",c2); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | inpic(void) | 
|  | { | 
|  | int c1; | 
|  | Rune *p1; | 
|  |  | 
|  | /*	SKIP1;*/ | 
|  | while(C1 != '\n') | 
|  | if(c == '<'){ | 
|  | SKIP1; | 
|  | return; | 
|  | } | 
|  | p1 = line; | 
|  | c = '\n'; | 
|  | for(;;) { | 
|  | c1 = c; | 
|  | if(C1 == '.' && c1 == '\n') { | 
|  | if(C1 != 'P' || C1 != 'E') { | 
|  | if(c != '\n'){ | 
|  | SKIP1; | 
|  | c = '\n'; | 
|  | } | 
|  | continue; | 
|  | } | 
|  | SKIP1; | 
|  | return; | 
|  | } else | 
|  | if(c == '\"') { | 
|  | while(C1 != '\"') { | 
|  | if(c == '\\') { | 
|  | if(C1 == '\"') | 
|  | continue; | 
|  | Bungetrune(infile); | 
|  | backsl(); | 
|  | } else | 
|  | *p1++ = c; | 
|  | } | 
|  | *p1++ = ' '; | 
|  | } else | 
|  | if(c == '\n' && p1 != line) { | 
|  | *p1 = '\0'; | 
|  | if(wordflag) | 
|  | putwords(); | 
|  | else | 
|  | Bprint(&bout, "%S\n\n", line); | 
|  | p1 = line; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | charclass(int c) | 
|  | { | 
|  | if(c < MAX_ASCII) | 
|  | return chars[c]; | 
|  | switch(c){ | 
|  | case 0x2013: case 0x2014:	/* en dash, em dash */ | 
|  | return SPECIAL; | 
|  | } | 
|  | return EXTENDED; | 
|  | } |