#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))#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 msflag = NO;int iflag = NO;int mac = MM;int disp = 0;int inmacro = NO;int intable = NO;int eqnflag = 0; #define MAX_ASCII 0X80#define CHARCLASS(c) ((c) >= MAX_ASCII ? EXTENDED : chars[(c)]) char chars[MAX_ASCII]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */ Rune line[4096];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);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); voidmain(int argc, char *av[]){ int i; char *f; argv = av; Binit(&bout, 1, OWRITE); ARGBEGIN{ case 'w': wordflag = 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; } if(dirstat(fname, &dir) >= 0 && ((dir.mode & CHDIR) || dir.type != 'M')) { fname[0] = '\0'; return; } /* * 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 [-nwpi] [-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; p++) if(i == LETTER) 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; com: 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; Lines 1–500 of 918. Load more
#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)) #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 msflag = NO; int iflag = NO; int mac = MM; int disp = 0; int inmacro = NO; int intable = NO; int eqnflag = 0; #define MAX_ASCII 0X80 #define CHARCLASS(c) ((c) >= MAX_ASCII ? EXTENDED : chars[(c)]) char chars[MAX_ASCII]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */ Rune line[4096]; 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); 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); void main(int argc, char *av[]) { int i; char *f; argv = av; Binit(&bout, 1, OWRITE); ARGBEGIN{ case 'w': wordflag = 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; } if(dirstat(fname, &dir) >= 0 && ((dir.mode & CHDIR) || dir.type != 'M')) { fname[0] = '\0'; return; } /* * 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 [-nwpi] [-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; p++) if(i == LETTER) 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; com: 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;