/* * 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. Load more
/* * 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); 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]) {