#include "a.h" enum{ MAXREQ = 100, MAXRAW = 40, MAXESC = 60, MAXLINE = 1024, MAXIF = 20, MAXARG = 10,}; typedef struct Esc Esc;typedef struct Req Req;typedef struct Raw Raw; /* escape sequence handler, like for \c */struct Esc{ Rune r; int (*f)(void); int mode;}; /* raw request handler, like for .ie */struct Raw{ Rune *name; void (*f)(Rune*);}; /* regular request handler, like for .ft */struct Req{ int argc; Rune *name; void (*f)(int, Rune**);}; int dot = '.';int tick = '\'';int backslash = '\\'; int inputmode;Req req[MAXREQ];int nreq;Raw raw[MAXRAW];int nraw;Esc esc[MAXESC];int nesc;int iftrue[MAXIF];int niftrue; int isoutput;int linepos; voidaddraw(Rune *name, void (*f)(Rune*)){ Raw *r; if(nraw >= nelem(raw)){ fprint(2, "too many raw requets\n"); return; } r = &raw[nraw++]; r->name = erunestrdup(name); r->f = f;} voiddelraw(Rune *name){ int i; for(i=0; i<nraw; i++){ if(runestrcmp(raw[i].name, name) == 0){ if(i != --nraw){ free(raw[i].name); raw[i] = raw[nraw]; } return; } }} voidrenraw(Rune *from, Rune *to){ int i; delraw(to); for(i=0; i<nraw; i++) if(runestrcmp(raw[i].name, from) == 0){ free(raw[i].name); raw[i].name = erunestrdup(to); return; }} voidaddreq(Rune *s, void (*f)(int, Rune**), int argc){ Req *r; if(nreq >= nelem(req)){ fprint(2, "too many requests\n"); return; } r = &req[nreq++]; r->name = erunestrdup(s); r->f = f; r->argc = argc;} voiddelreq(Rune *name){ int i; for(i=0; i<nreq; i++){ if(runestrcmp(req[i].name, name) == 0){ if(i != --nreq){ free(req[i].name); req[i] = req[nreq]; } return; } }} voidrenreq(Rune *from, Rune *to){ int i; delreq(to); for(i=0; i<nreq; i++) if(runestrcmp(req[i].name, from) == 0){ free(req[i].name); req[i].name = erunestrdup(to); return; }} voidaddesc(Rune r, int (*f)(void), int mode){ Esc *e; if(nesc >= nelem(esc)){ fprint(2, "too many escapes\n"); return; } e = &esc[nesc++]; e->r = r; e->f = f; e->mode = mode;} /* * Get the next logical character in the input stream. */intgetnext(void){ int i, r; next: r = getrune(); if(r < 0) return -1; if(r == Uformatted){ br(); assert(!isoutput); while((r = getrune()) >= 0 && r != Uunformatted){ if(r == Uformatted) continue; outrune(r); } goto next; } if(r == Uunformatted) goto next; if(r == backslash){ r = getrune(); if(r < 0) return -1; for(i=0; i<nesc; i++){ if(r == esc[i].r && (inputmode&esc[i].mode)==inputmode){ if(esc[i].f == e_warn) warn("ignoring %C%C", backslash, r); r = esc[i].f(); if(r <= 0) goto next; return r; } } if(inputmode&(ArgMode|CopyMode)){ ungetrune(r); r = backslash; } } return r;} voidungetnext(Rune r){ /* * really we want to undo the getrunes that led us here, * since the call after ungetnext might be getrune! */ ungetrune(r);} int_readx(Rune *p, int n, int nmode, int line){ int c, omode; Rune *e; while((c = getrune()) == ' ' || c == '\t') ; ungetrune(c); omode = inputmode; inputmode = nmode; e = p+n-1; for(c=getnext(); p<e; c=getnext()){ if(c < 0) break; if(!line && (c == ' ' || c == '\t')) break; if(c == '\n'){ if(!line) ungetnext(c); break; } *p++ = c; } inputmode = omode; *p = 0; if(c < 0) return -1; return 0;} /* * Get the next argument from the current line. */Rune*copyarg(void){ static Rune buf[MaxLine]; int c; Rune *r; if(_readx(buf, sizeof buf, ArgMode, 0) < 0) return nil; r = runestrstr(buf, L("\\\"")); if(r){ *r = 0; while((c = getrune()) >= 0 && c != '\n') ; ungetrune('\n'); } r = erunestrdup(buf); return r;} /* * Read the current line in given mode. Newline not kept. * Uses different buffer from copyarg! */Rune*readline(int m){ static Rune buf[MaxLine]; Rune *r; if(_readx(buf, sizeof buf, m, 1) < 0) return nil; r = erunestrdup(buf); return r;} /* * Given the argument line (already read in copy+arg mode), * parse into arguments. Note that \" has been left in place * during copy+arg mode parsing, so comments still need to be stripped. */intparseargs(Rune *p, Rune **argv){ int argc; Rune *w; for(argc=0; argc<MAXARG; argc++){ while(*p == ' ' || *p == '\t') p++; if(*p == 0) break; argv[argc] = p; if(*p == '"'){ /* quoted argument */ if(*(p+1) == '"'){ /* empty argument */ *p = 0; p += 2; }else{ /* parse quoted string */ w = p++; for(; *p; p++){ if(*p == '"' && *(p+1) == '"') *w++ = '"'; else if(*p == '"'){ p++; break; }else *w++ = *p; } *w = 0; } }else{ /* unquoted argument - need to watch out for \" comment */ for(; *p; p++){ if(*p == ' ' || *p == '\t'){ *p++ = 0; break; } if(*p == '\\' && *(p+1) == '"'){ *p = 0; if(p != argv[argc]) argc++; return argc; } } } } return argc;} /* * Process a dot line. The dot has been read. */voiddotline(int dot){ int argc, i; Rune *a, *argv[1+MAXARG]; /* * Read request/macro name */ a = copyarg(); if(a == nil || a[0] == 0){ free(a); getrune(); /* \n */ return; } argv[0] = a; /* * Check for .if, .ie, and others with special parsing. */ for(i=0; i<nraw; i++){ if(runestrcmp(raw[i].name, a) == 0){ raw[i].f(raw[i].name); free(a); return; } } /* * Read rest of line in copy mode, invoke regular request. */ a = readline(ArgMode); if(a == nil){ free(argv[0]); return; } argc = 1+parseargs(a, argv+1); for(i=0; i<nreq; i++){ if(runestrcmp(req[i].name, argv[0]) == 0){ if(req[i].argc != -1){ if(argc < 1+req[i].argc){ warn("not enough arguments for %C%S", dot, req[i].name); free(argv[0]); free(a); return; } if(argc > 1+req[i].argc) warn("too many arguments for %C%S", dot, req[i].name); } req[i].f(argc, argv); free(argv[0]); free(a); return; } } /* * Invoke user-defined macros. */ runmacro(dot, argc, argv); free(argv[0]); free(a);} /* * newlines are magical in various ways. */int bol;voidnewline(void){ int n; if(bol) sp(eval(L("1v"))); bol = 1; if((n=getnr(L(".ce"))) > 0){ nr(L(".ce"), n-1); br(); } if(getnr(L(".fi")) == 0) br(); outrune('\n');} voidstartoutput(void){ char *align; double ps, vs, lm, rm, ti; Rune buf[200]; if(isoutput) return; isoutput = 1; if(getnr(L(".paragraph")) == 0) return; nr(L(".ns"), 0); isoutput = 1; ps = getnr(L(".s")); if(ps <= 1) ps = 10; ps /= 72.0; USED(ps); vs = getnr(L(".v"))*getnr(L(".ls")) * 1.0/UPI; vs /= (10.0/72.0); /* ps */ if(vs == 0) vs = 1.2; lm = (getnr(L(".o"))+getnr(L(".i"))) * 1.0/UPI; ti = getnr(L(".ti")) * 1.0/UPI; nr(L(".ti"), 0); rm = 8.0 - getnr(L(".l"))*1.0/UPI - getnr(L(".o"))*1.0/UPI; if(rm < 0) rm = 0; switch(getnr(L(".j"))){ default: case 0: align = "left"; break; case 1: align = "justify"; break; case 3: align = "center"; break; case 5: align = "right"; break; } if(getnr(L(".ce"))) align = "center"; if(!getnr(L(".margin"))) runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; text-indent: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n", vs, ti, align); else runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; margin-left: %.2fin; text-indent: %.2fin; margin-right: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n", vs, lm, ti, rm, align); outhtml(buf);}voidbr(void){ if(!isoutput) return; isoutput = 0; nr(L(".dv"), 0); dv(0); hideihtml();Lines 1–500 of 750. Load more
#include "a.h" enum { MAXREQ = 100, MAXRAW = 40, MAXESC = 60, MAXLINE = 1024, MAXIF = 20, MAXARG = 10, }; typedef struct Esc Esc; typedef struct Req Req; typedef struct Raw Raw; /* escape sequence handler, like for \c */ struct Esc { Rune r; int (*f)(void); int mode; }; /* raw request handler, like for .ie */ struct Raw { Rune *name; void (*f)(Rune*); }; /* regular request handler, like for .ft */ struct Req { int argc; Rune *name; void (*f)(int, Rune**); }; int dot = '.'; int tick = '\''; int backslash = '\\'; int inputmode; Req req[MAXREQ]; int nreq; Raw raw[MAXRAW]; int nraw; Esc esc[MAXESC]; int nesc; int iftrue[MAXIF]; int niftrue; int isoutput; int linepos; void addraw(Rune *name, void (*f)(Rune*)) { Raw *r; if(nraw >= nelem(raw)){ fprint(2, "too many raw requets\n"); return; } r = &raw[nraw++]; r->name = erunestrdup(name); r->f = f; } void delraw(Rune *name) { int i; for(i=0; i<nraw; i++){ if(runestrcmp(raw[i].name, name) == 0){ if(i != --nraw){ free(raw[i].name); raw[i] = raw[nraw]; } return; } } } void renraw(Rune *from, Rune *to) { int i; delraw(to); for(i=0; i<nraw; i++) if(runestrcmp(raw[i].name, from) == 0){ free(raw[i].name); raw[i].name = erunestrdup(to); return; } } void addreq(Rune *s, void (*f)(int, Rune**), int argc) { Req *r; if(nreq >= nelem(req)){ fprint(2, "too many requests\n"); return; } r = &req[nreq++]; r->name = erunestrdup(s); r->f = f; r->argc = argc; } void delreq(Rune *name) { int i; for(i=0; i<nreq; i++){ if(runestrcmp(req[i].name, name) == 0){ if(i != --nreq){ free(req[i].name); req[i] = req[nreq]; } return; } } } void renreq(Rune *from, Rune *to) { int i; delreq(to); for(i=0; i<nreq; i++) if(runestrcmp(req[i].name, from) == 0){ free(req[i].name); req[i].name = erunestrdup(to); return; } } void addesc(Rune r, int (*f)(void), int mode) { Esc *e; if(nesc >= nelem(esc)){ fprint(2, "too many escapes\n"); return; } e = &esc[nesc++]; e->r = r; e->f = f; e->mode = mode; } /* * Get the next logical character in the input stream. */ int getnext(void) { int i, r; next: r = getrune(); if(r < 0) return -1; if(r == Uformatted){ br(); assert(!isoutput); while((r = getrune()) >= 0 && r != Uunformatted){ if(r == Uformatted) continue; outrune(r); } goto next; } if(r == Uunformatted) goto next; if(r == backslash){ r = getrune(); if(r < 0) return -1; for(i=0; i<nesc; i++){ if(r == esc[i].r && (inputmode&esc[i].mode)==inputmode){ if(esc[i].f == e_warn) warn("ignoring %C%C", backslash, r); r = esc[i].f(); if(r <= 0) goto next; return r; } } if(inputmode&(ArgMode|CopyMode)){ ungetrune(r); r = backslash; } } return r; } void ungetnext(Rune r) { /* * really we want to undo the getrunes that led us here, * since the call after ungetnext might be getrune! */ ungetrune(r); } int _readx(Rune *p, int n, int nmode, int line) { int c, omode; Rune *e; while((c = getrune()) == ' ' || c == '\t') ; ungetrune(c); omode = inputmode; inputmode = nmode; e = p+n-1; for(c=getnext(); p<e; c=getnext()){ if(c < 0) break; if(!line && (c == ' ' || c == '\t')) break; if(c == '\n'){ if(!line) ungetnext(c); break; } *p++ = c; } inputmode = omode; *p = 0; if(c < 0) return -1; return 0; } /* * Get the next argument from the current line. */ Rune* copyarg(void) { static Rune buf[MaxLine]; int c; Rune *r; if(_readx(buf, sizeof buf, ArgMode, 0) < 0) return nil; r = runestrstr(buf, L("\\\"")); if(r){ *r = 0; while((c = getrune()) >= 0 && c != '\n') ; ungetrune('\n'); } r = erunestrdup(buf); return r; } /* * Read the current line in given mode. Newline not kept. * Uses different buffer from copyarg! */ Rune* readline(int m) { static Rune buf[MaxLine]; Rune *r; if(_readx(buf, sizeof buf, m, 1) < 0) return nil; r = erunestrdup(buf); return r; } /* * Given the argument line (already read in copy+arg mode), * parse into arguments. Note that \" has been left in place * during copy+arg mode parsing, so comments still need to be stripped. */ int parseargs(Rune *p, Rune **argv) { int argc; Rune *w; for(argc=0; argc<MAXARG; argc++){ while(*p == ' ' || *p == '\t') p++; if(*p == 0) break; argv[argc] = p; if(*p == '"'){ /* quoted argument */ if(*(p+1) == '"'){ /* empty argument */ *p = 0; p += 2; }else{ /* parse quoted string */ w = p++; for(; *p; p++){ if(*p == '"' && *(p+1) == '"') *w++ = '"'; else if(*p == '"'){ p++; break; }else *w++ = *p; } *w = 0; } }else{ /* unquoted argument - need to watch out for \" comment */ for(; *p; p++){ if(*p == ' ' || *p == '\t'){ *p++ = 0; break; } if(*p == '\\' && *(p+1) == '"'){ *p = 0; if(p != argv[argc]) argc++; return argc; } } } } return argc; } /* * Process a dot line. The dot has been read. */ void dotline(int dot) { int argc, i; Rune *a, *argv[1+MAXARG]; /* * Read request/macro name */ a = copyarg(); if(a == nil || a[0] == 0){ free(a); getrune(); /* \n */ return; } argv[0] = a; /* * Check for .if, .ie, and others with special parsing. */ for(i=0; i<nraw; i++){ if(runestrcmp(raw[i].name, a) == 0){ raw[i].f(raw[i].name); free(a); return; } } /* * Read rest of line in copy mode, invoke regular request. */ a = readline(ArgMode); if(a == nil){ free(argv[0]); return; } argc = 1+parseargs(a, argv+1); for(i=0; i<nreq; i++){ if(runestrcmp(req[i].name, argv[0]) == 0){ if(req[i].argc != -1){ if(argc < 1+req[i].argc){ warn("not enough arguments for %C%S", dot, req[i].name); free(argv[0]); free(a); return; } if(argc > 1+req[i].argc) warn("too many arguments for %C%S", dot, req[i].name); } req[i].f(argc, argv); free(argv[0]); free(a); return; } } /* * Invoke user-defined macros. */ runmacro(dot, argc, argv); free(argv[0]); free(a); } /* * newlines are magical in various ways. */ int bol; void newline(void) { int n; if(bol) sp(eval(L("1v"))); bol = 1; if((n=getnr(L(".ce"))) > 0){ nr(L(".ce"), n-1); br(); } if(getnr(L(".fi")) == 0) br(); outrune('\n'); } void startoutput(void) { char *align; double ps, vs, lm, rm, ti; Rune buf[200]; if(isoutput) return; isoutput = 1; if(getnr(L(".paragraph")) == 0) return; nr(L(".ns"), 0); isoutput = 1; ps = getnr(L(".s")); if(ps <= 1) ps = 10; ps /= 72.0; USED(ps); vs = getnr(L(".v"))*getnr(L(".ls")) * 1.0/UPI; vs /= (10.0/72.0); /* ps */ if(vs == 0) vs = 1.2; lm = (getnr(L(".o"))+getnr(L(".i"))) * 1.0/UPI; ti = getnr(L(".ti")) * 1.0/UPI; nr(L(".ti"), 0); rm = 8.0 - getnr(L(".l"))*1.0/UPI - getnr(L(".o"))*1.0/UPI; if(rm < 0) rm = 0; switch(getnr(L(".j"))){ default: case 0: align = "left"; break; case 1: align = "justify"; break; case 3: align = "center"; break; case 5: align = "right"; break; } if(getnr(L(".ce"))) align = "center"; if(!getnr(L(".margin"))) runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; text-indent: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n", vs, ti, align); else runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; margin-left: %.2fin; text-indent: %.2fin; margin-right: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n", vs, lm, ti, rm, align); outhtml(buf); } void br(void) { if(!isoutput) return; isoutput = 0; nr(L(".dv"), 0); dv(0); hideihtml();