diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ms2html.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ms2html.c')
-rwxr-xr-x | sys/src/cmd/ms2html.c | 2639 |
1 files changed, 2639 insertions, 0 deletions
diff --git a/sys/src/cmd/ms2html.c b/sys/src/cmd/ms2html.c new file mode 100755 index 000000000..e6a6746b5 --- /dev/null +++ b/sys/src/cmd/ms2html.c @@ -0,0 +1,2639 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> + +enum +{ + SSIZE = 10, + + Maxnh= 8, /* highest NH level */ + HH= 4, /* heading level used for SH and NH */ + Maxmstack= 10, /* deepest macro/string nesting */ + Narg= 20, /* max args to a macro */ + Maxsstack= 5, /* deepest nesting of .so's */ + Nline= 1024, + Maxget= 10, + Maxif = 20, + Maxfsp = 100, + + /* list types */ + Lordered = 1, + Lunordered, + Ldef, + Lother, +}; + +char *delim = "$$"; +char *basename; +char *title; +int eqnmode; + +int quiet; +float indent; /* from .in */ +Biobuf bout; +int isup; +int isdown; +int debug; + +int nh[Maxnh]; +int ifwastrue[Maxif]; + +int list, listnum, example; +int hangingau, hangingdt, hanginghead, hangingcenter; +int indirective, paragraph, sol, titleseen, ignore_nl, weBref; +void dohangingcenter(void); + +typedef struct Goobie Goobie; +typedef struct Goobieif Goobieif; +struct Goobie +{ + char *name; + void (*f)(int, char**); +}; + +typedef void F(int, char**); +typedef void Fif(char*, char*); + +struct Goobieif +{ + char *name; + Fif *f; +}; + +/* if, ie */ +Fif g_as, g_ds, g_el, g_ie, g_if; +Goobieif gtabif[] = { + { "as", g_as }, + { "ds", g_ds }, + { "if", g_if }, + { "ie", g_ie }, + { "el", g_el }, + { nil, nil }, + }; + +/* pseudo ops */ +F g_notyet, g_ignore, g_hrule, g_startgif; + +/* ms macros */ +F g_AU, g_B, g_BI, g_CW, g_I, g_IP, g_LP, g_PP, g_SH, g_NH; +F g_P1, g_P2, g_TL, g_R, g_AB, g_AE, g_EQ, g_TS, g_TE, g_FS, g_FE; +F g_PY, g_IH, g_MH, g_HO, g_BX, g_QS, g_QE, g_RS, g_RE; + +/* pictures macro */ +F g_BP; + +/* real troff */ +F g_br, g_ft, g_sp, g_de, g_lf, g_so, g_rm, g_in; +F g_nr, g_ig, g_RT, g_BS, g_BE, g_LB, g_ta; + +/* macros to include ML in output */ +F g__H, g__T; + +Goobie gtab[] = +{ + { "_T", g__T, }, + { "_H", g__H, }, + { "1C", g_ignore, }, + { "2C", g_ignore, }, + { "AB", g_AB, }, + { "AE", g_AE, }, + { "AI", g_ignore, }, + { "AU", g_AU, }, + { "B", g_B, }, + { "B1", g_hrule, }, + { "B2", g_hrule, }, + { "BI", g_BI, }, + { "BP", g_BP, }, + { "BT", g_ignore, }, + { "BX", g_BX, }, + { "CW", g_CW, }, + { "CT", g_ignore, }, + { "DA", g_ignore, }, + { "DE", g_P2, }, + { "DS", g_P1, }, + { "EG", g_ignore, }, + { "EN", g_ignore, }, + { "EQ", g_startgif, }, + { "FE", g_FE, }, + { "FP", g_ignore, }, + { "FS", g_FS, }, + { "HO", g_HO, }, + { "I", g_I, }, + { "IH", g_IH, }, + { "IM", g_ignore, }, + { "IP", g_IP, }, + { "KE", g_ignore, }, + { "KF", g_ignore, }, + { "KS", g_ignore, }, + { "LG", g_ignore, }, + { "LP", g_LP, }, + { "LT", g_ignore, }, + { "MF", g_ignore, }, + { "MH", g_MH, }, + { "MR", g_ignore, }, + { "ND", g_ignore, }, + { "NH", g_NH, }, + { "NL", g_ignore, }, + { "P1", g_P1, }, + { "P2", g_P2, }, + { "PE", g_ignore, }, + { "PF", g_ignore, }, + { "PP", g_PP, }, + { "PS", g_startgif, }, + { "PY", g_PY, }, + { "QE", g_QE, }, + { "QP", g_QS, }, + { "QS", g_QS, }, + { "R", g_R, }, + { "RE", g_RE, }, + { "RP", g_ignore, }, + { "RS", g_RS, }, + { "SG", g_ignore, }, + { "SH", g_SH, }, + { "SM", g_ignore, }, + { "TA", g_ignore, }, + { "TE", g_ignore, }, + { "TH", g_TL, }, + { "TL", g_TL, }, + { "TM", g_ignore, }, + { "TR", g_ignore, }, + { "TS", g_startgif, }, + { "UL", g_I, }, + { "UX", g_ignore, }, + { "WH", g_ignore, }, + { "RT", g_RT, }, + + { "br", g_br, }, + { "ti", g_br, }, + { "nf", g_P1, }, + { "fi", g_P2, }, + { "ft", g_ft, }, + { "sp", g_sp, }, + { "rm", g_rm, }, + { "de", g_de, }, + { "am", g_de, }, + { "lf", g_lf, }, + { "so", g_so, }, + { "ps", g_ignore }, + { "vs", g_ignore }, + { "nr", g_nr }, + { "in", g_in }, + { "ne", g_ignore }, + { "ig", g_ig }, + { "BS", g_BS }, + { "BE", g_BE }, + { "LB", g_LB }, + { nil, nil }, +}; + +typedef struct Entity Entity; +struct Entity +{ + char *name; + int value; +}; + +Entity entity[] = +{ + { "&#SPACE;", L' ', }, + { "&#RS;", L'\n', }, + { "&#RE;", L'\r', }, + { """, L'"', }, + { "Æ", L'Æ', }, + { "Á", L'Á', }, + { "Â", L'Â', }, + { "À", L'À', }, + { "Å", L'Å', }, + { "Ã", L'Ã', }, + { "Ä", L'Ä', }, + { "Ç", L'Ç', }, + { "Ð", L'Ð', }, + { "É", L'É', }, + { "Ê", L'Ê', }, + { "È", L'È', }, + { "Ë", L'Ë', }, + { "Í", L'Í', }, + { "Î", L'Î', }, + { "Ì", L'Ì', }, + { "Ï", L'Ï', }, + { "Ñ", L'Ñ', }, + { "Ó", L'Ó', }, + { "Ô", L'Ô', }, + { "Ò", L'Ò', }, + { "Ø", L'Ø', }, + { "Õ", L'Õ', }, + { "Ö", L'Ö', }, + { "Þ", L'Þ', }, + { "Ú", L'Ú', }, + { "Û", L'Û', }, + { "Ù", L'Ù', }, + { "Ü", L'Ü', }, + { "Ý", L'Ý', }, + { "á", L'á', }, + { "â", L'â', }, + { "æ", L'æ', }, + { "à", L'à', }, + { "&", L'&', }, + { "å", L'å', }, + { "ã", L'ã', }, + { "ä", L'ä', }, + { "ç", L'ç', }, + { "é", L'é', }, + { "ê", L'ê', }, + { "è", L'è', }, + { "ð", L'ð', }, + { "ë", L'ë', }, + { ">", L'>', }, + { "í", L'í', }, + { "î", L'î', }, + { "ì", L'ì', }, + { "ï", L'ï', }, + { "<", L'<', }, + { "ñ", L'ñ', }, + { "ó", L'ó', }, + { "ô", L'ô', }, + { "ò", L'ò', }, + { "ø", L'ø', }, + { "õ", L'õ', }, + { "ö", L'ö', }, + { "ß", L'ß', }, + { "þ", L'þ', }, + { "ú", L'ú', }, + { "û", L'û', }, + { "ù", L'ù', }, + { "ü", L'ü', }, + { "ý", L'ý', }, + { "ÿ", L'ÿ', }, + { "¡", L'¡', }, + { "¢", L'¢', }, + { "£", L'£', }, + { "¤", L'¤', }, + { "¥", L'¥', }, + { "¦", L'¦', }, + { "§", L'§', }, + { "¨", L'¨', }, + { "©", L'©', }, + { "ª", L'ª', }, + { "«", L'«', }, + { "¬", L'¬', }, + { "­", L'', }, + { "®", L'®', }, + { "¯", L'¯', }, + { "°", L'°', }, + { "±", L'±', }, + { "²", L'²', }, + { "³", L'³', }, + { "´", L'´', }, + { "µ", L'µ', }, + { "¶", L'¶', }, + { "·", L'·', }, + { "¸", L'¸', }, + { "¹", L'¹', }, + { "º", L'º', }, + { "»", L'»', }, + { "¼", L'¼', }, + { "½", L'½', }, + { "¾", L'¾', }, + { "¿", L'¿', }, + + { "*", L'•', }, + { "¤", L'□', }, + { "º", L'◊', }, + { "(tm)", L'™', }, + {"Α", L'Α',}, + {"Β", L'Β',}, + {"Γ", L'Γ',}, + {"Δ", L'Δ',}, + {"Ε", L'Ε',}, + {"Ζ", L'Ζ',}, + {"Η", L'Η',}, + {"Θ", L'Θ',}, + {"Ι", L'Ι',}, + {"Κ", L'Κ',}, + {"Λ", L'Λ',}, + {"Μ", L'Μ',}, + {"Ν", L'Ν',}, + {"Ξ", L'Ξ',}, + {"Ο", L'Ο',}, + {"Π", L'Π',}, + {"Ρ", L'Ρ',}, + {"΢", L'',}, + {"Σ", L'Σ',}, + {"Τ", L'Τ',}, + {"Υ", L'Υ',}, + {"Φ", L'Φ',}, + {"Χ", L'Χ',}, + {"Ψ", L'Ψ',}, + {"Ω", L'Ω',}, + {"α", L'α',}, + {"β", L'β',}, + {"γ", L'γ',}, + {"δ", L'δ',}, + {"ε", L'ε',}, + {"ζ", L'ζ',}, + {"η", L'η',}, + {"θ", L'θ',}, + {"ι", L'ι',}, + {"κ", L'κ',}, + {"λ", L'λ',}, + {"μ", L'μ',}, + {"ν", L'ν',}, + {"ξ", L'ξ',}, + {"ο", L'ο',}, + {"π", L'π',}, + {"ρ", L'ρ',}, + {"ς", L'ς',}, + {"σ", L'σ',}, + {"τ", L'τ',}, + {"υ", L'υ',}, + {"φ", L'φ',}, + {"χ", L'χ',}, + {"ψ", L'ψ',}, + {"ω", L'ω',}, + + { "<-", L'←', }, + { "^", L'↑', }, + { "->", L'→', }, + { "v", L'↓', }, + { "!=", L'≠', }, + { "<=", L'≤', }, + { "...", L'⋯', }, + {"∈", L'∈', }, + + {"–", L'–', }, + {"—", L'—', }, + + { "CYRILLIC XYZZY", L'й', }, + { "CYRILLIC XYZZY", L'ъ', }, + { "CYRILLIC Y", L'ь', }, + { "CYRILLIC YA", L'я', }, + { "CYRILLIC YA", L'ё', }, + { "¿", L'ℱ', }, + + { nil, 0 }, +}; + +typedef struct Troffspec Troffspec; +struct Troffspec +{ + char *name; + char *value; +}; + +Troffspec tspec[] = +{ + { "A*", "Å", }, + { "o\"", "ö", }, + { "ff", "ff", }, + { "fi", "fi", }, + { "fl", "fl", }, + { "Fi", "ffi", }, + { "ru", "_", }, + { "em", "­", }, + { "14", "¼", }, + { "12", "½", }, + { "co", "©", }, + { "de", "°", }, + { "dg", "¡", }, + { "fm", "´", }, + { "rg", "®", }, + { "bu", "*", }, + { "sq", "¤", }, + { "hy", "-", }, + { "pl", "+", }, + { "mi", "-", }, + { "mu", "×", }, + { "di", "÷", }, + { "eq", "=", }, + { "==", "==", }, + { ">=", ">=", }, + { "<=", "<=", }, + { "!=", "!=", }, + { "+-", "±", }, + { "no", "¬", }, + { "sl", "/", }, + { "ap", "&", }, + { "~=", "~=", }, + { "pt", "oc", }, + { "gr", "GRAD", }, + { "->", "->", }, + { "<-", "<-", }, + { "ua", "^", }, + { "da", "v", }, + { "is", "Integral", }, + { "pd", "DIV", }, + { "if", "oo", }, + { "sr", "-/", }, + { "sb", "(~", }, + { "sp", "~)", }, + { "cu", "U", }, + { "ca", "(^)", }, + { "ib", "(=", }, + { "ip", "=)", }, + { "mo", "C", }, + { "es", "Ø", }, + { "aa", "´", }, + { "ga", "`", }, + { "ci", "O", }, + { "L1", "DEATHSTAR", }, + { "sc", "§", }, + { "dd", "++", }, + { "lh", "<=", }, + { "rh", "=>", }, + { "lt", "(", }, + { "rt", ")", }, + { "lc", "|", }, + { "rc", "|", }, + { "lb", "(", }, + { "rb", ")", }, + { "lf", "|", }, + { "rf", "|", }, + { "lk", "|", }, + { "rk", "|", }, + { "bv", "|", }, + { "ts", "s", }, + { "br", "|", }, + { "or", "|", }, + { "ul", "_", }, + { "rn", " ", }, + { "**", "*", }, + { "tm", "™", }, + { nil, nil, }, +}; + +typedef struct Font Font; +struct Font +{ + char *start; + char *end; +}; +Font bfont = { "<B>", "</B>" }; +Font ifont = { "<I>", "</I>" }; +Font bifont = { "<B><I>", "</I></B>" }; +Font cwfont = { "<TT>", "</TT>" }; +Font *fstack[Maxfsp]; +int fsp = -1; + +typedef struct String String; +struct String +{ + String *next; + char *name; + char *val; +}; +String *numregs, *strings; +char *strstack[Maxmstack]; +char *mustfree[Maxmstack]; +int strsp = -1; +int elsetop = -1; + +typedef struct Mstack Mstack; +struct Mstack +{ + char *ptr; + char *argv[Narg+1]; +}; +String *macros; +Mstack mstack[Maxmstack]; +int msp = -1; + +typedef struct Srcstack Srcstack; +struct Srcstack +{ + char filename[256]; + int fd; + int lno; + int rlno; + Biobuf in; +}; +Srcstack sstack[Maxsstack]; +Srcstack *ssp = &sstack[-1]; + +char token[128]; + +void closel(void); +void closefont(void); + +void* +emalloc(uint n) +{ + void *p; + + p = mallocz(n, 1); + if(p == nil){ + fprint(2, "ms2html: malloc failed: %r\n"); + exits("malloc"); + } + return p; +} + + +/* define a string variable */ +void +dsnr(char *name, char *val, String **l) +{ + String *s; + + for(s = *l; s != nil; s = *l){ + if(strcmp(s->name, name) == 0) + break; + l = &s->next; + } + if(s == nil){ + s = emalloc(sizeof(String)); + *l = s; + s->name = strdup(name); + } else + free(s->val); + s->val = strdup(val); +} + +void +ds(char *name, char *val) +{ + dsnr(name, val, &strings); +} + +/* look up a defined string */ +char* +getds(char *name) +{ + String *s; + + for(s = strings; s != nil; s = s->next) + if(strcmp(name, s->name) == 0) + break; + if(s != nil) + return s->val; + return ""; +} + +char * +getnr(char *name) +{ + String *s; + + for(s = numregs; s != nil; s = s->next) + if(strcmp(name, s->name) == 0) + break; + if(s != nil) + return s->val; + return "0"; +} + +void +pushstr(char *p) +{ + if(p == nil) + return; + if(strsp >= Maxmstack - 1) + return; + strstack[++strsp] = p; +} + + +/* lookup a defined macro */ +char* +getmacro(char *name) +{ + String *s; + + for(s = macros; s != nil; s = s->next) + if(strcmp(name, s->name) == 0) + return s->val; + return nil; +} + +enum +{ + Dstring, + Macro, + Input, +}; +int lastsrc; + +void +pushsrc(char *name) +{ + Dir *d; + int fd; + + if(ssp == &sstack[Maxsstack-1]){ + fprint(2, "ms2html: .so's too deep\n"); + return; + } + d = nil; + if(name == nil){ + d = dirfstat(0); + if(d == nil){ + fprint(2, "ms2html: can't stat %s: %r\n", name); + return; + } + name = d->name; + fd = 0; + } else { + fd = open(name, OREAD); + if(fd < 0){ + fprint(2, "ms2html: can't open %s: %r\n", name); + return; + } + } + ssp++; + ssp->fd = fd; + Binit(&ssp->in, fd, OREAD); + snprint(ssp->filename, sizeof(ssp->filename), "%s", name); + ssp->lno = ssp->rlno = 1; + free(d); +} + +/* get next logical byte. from stdin or a defined string */ +int +getrune(void) +{ + int i; + Rune r; + int c; + Mstack *m; + + while(strsp >= 0){ + i = chartorune(&r, strstack[strsp]); + if(r != 0){ + strstack[strsp] += i; + lastsrc = Dstring; + return r; + } + if (mustfree[strsp]) { + free(mustfree[strsp]); + mustfree[strsp] = nil; + } + strsp--; + } + while(msp >= 0){ + m = &mstack[msp]; + i = chartorune(&r, m->ptr); + if(r != 0){ + m->ptr += i; + lastsrc = Macro; + return r; + } + for(i = 0; m->argv[i] != nil; i++) + free(m->argv[i]); + msp--; + } + + lastsrc = Input; + for(;;) { + if(ssp < sstack) + return -1; + c = Bgetrune(&ssp->in); + if(c >= 0){ + r = c; + break; + } + close(ssp->fd); + ssp--; + } + + return r; +} + +void +ungetrune(void) +{ + switch(lastsrc){ + case Dstring: + if(strsp >= 0) + strstack[strsp]--; + break; + case Macro: + if(msp >= 0) + mstack[msp].ptr--; + break; + case Input: + if(ssp >= sstack) + Bungetrune(&ssp->in); + break; + } +} + +int vert; + +char* +changefont(Font *f) +{ + token[0] = 0; + if(fsp == Maxfsp) + return token; + if(fsp >= 0 && fstack[fsp]) + strcpy(token, fstack[fsp]->end); + if(f != nil) + strcat(token, f->start); + fstack[++fsp] = f; + return token; +} + +char* +changebackfont(void) +{ + token[0] = 0; + if(fsp >= 0){ + if(fstack[fsp]) + strcpy(token, fstack[fsp]->end); + fsp--; + } + if(fsp >= 0 && fstack[fsp]) + strcat(token, fstack[fsp]->start); + return token; +} + +char* +changesize(int amount) +{ + static int curamount; + static char buf[200]; + int i; + + buf[0] = 0; + if (curamount >= 0) + for (i = 0; i < curamount; i++) + strcat(buf, "</big>"); + else + for (i = 0; i < -curamount; i++) + strcat(buf, "</small>"); + curamount = 0; + if (amount >= 0) + for (i = 0; i < amount; i++) + strcat(buf, "<big>"); + else + for (i = 0; i < -amount; i++) + strcat(buf, "<small>"); + curamount = amount; + return buf; +} + +/* get next logical character. expand it with escapes */ +char* +getnext(void) +{ + int r; + Entity *e; + Troffspec *t; + Rune R; + char str[4]; + static char buf[8]; + + r = getrune(); + if(r < 0) + return nil; + if(r > 128 || r == '<' || r == '>'){ + for(e = entity; e->name; e++) + if(e->value == r) + return e->name; + sprint(buf, "&#%d;", r); + return buf; + } + + if (r == delim[eqnmode]){ + if (eqnmode == 0){ + eqnmode = 1; + return changefont(&ifont); + } + eqnmode = 0; + return changebackfont(); + } + switch(r){ + case '\\': + r = getrune(); + if(r < 0) + return nil; + switch(r){ + case ' ': + return " "; + + /* chars to ignore */ + case '&': + case '|': + case '%': + return ""; + + /* small space in troff, nothing in nroff */ + case '^': + return getnext(); + + /* ignore arg */ + case 'k': + getrune(); + return getnext(); + + /* comment */ + case '"': + while(getrune() != '\n') + ; + return "\n"; + /* ignore line */ + case '!': + while(getrune() != '\n') + ; + ungetrune(); + return getnext(); + + /* defined strings */ + case '*': + r = getrune(); + if(r == '('){ + str[0] = getrune(); + str[1] = getrune(); + str[2] = 0; + } else { + str[0] = r; + str[1] = 0; + } + pushstr(getds(str)); + return getnext(); + + /* macro args */ + case '$': + r = getrune(); + if(r < '1' || r > '9'){ + token[0] = '\\'; + token[1] = '$'; + token[2] = r; + token[3] = 0; + return token; + } + r -= '0'; + if(msp >= 0) + pushstr(mstack[msp].argv[r]); + return getnext(); + + /* special chars */ + case '(': + token[0] = getrune(); + token[1] = getrune(); + token[2] = 0; + for(t = tspec; t->name; t++) + if(strcmp(token, t->name) == 0) + return t->value; + return "¿"; + + /* ignore immediately following newline */ + case 'c': + r = getrune(); + if (r == '\n') { + sol = ignore_nl = 1; + if (indirective) + break; + } + else + ungetrune(); + return getnext(); + + /* escape backslash */ + case 'e': + return "\\"; + + /* font change */ + case 'f': + r = getrune(); + switch(r){ + case '(': + str[0] = getrune(); + str[1] = getrune(); + str[2] = 0; + token[0] = 0; + if(strcmp("BI", str) == 0) + return changefont(&bifont); + else if(strcmp("CW", str) == 0) + return changefont(&cwfont); + else + return changefont(nil); + case '3': + case 'B': + return changefont(&bfont); + case '2': + case 'I': + return changefont(&ifont); + case '4': + return changefont(&bifont); + case '5': + return changefont(&cwfont); + case 'P': + return changebackfont(); + case 'R': + default: + return changefont(nil); + } + + /* number register */ + case 'n': + r = getrune(); + if (r == '(') /*)*/ { + r = getrune(); + if (r < 0) + return nil; + str[0] = r; + r = getrune(); + if (r < 0) + return nil; + str[1] = r; + str[2] = 0; + } + else { + str[0] = r; + str[1] = 0; + } + pushstr(getnr(str)); + return getnext(); + + /* font size */ + case 's': + r = getrune(); + switch(r){ + case '0': + return changesize(0); + case '-': + r = getrune(); + if (!isdigit(r)) + return getnext(); + return changesize(-(r - '0')); + case '+': + r = getrune(); + if (!isdigit(r)) + return getnext(); + return changesize(r - '0'); + } + return getnext(); + /* vertical movement */ + case 'v': + r = getrune(); + if(r != '\''){ + ungetrune(); + return getnext(); + } + r = getrune(); + if(r != '-') + vert--; + else + vert++; + while(r != '\'' && r != '\n') + r = getrune(); + if(r != '\'') + ungetrune(); + + if(vert > 0) + return "^"; + return getnext(); + + + /* horizontal line */ + case 'l': + r = getrune(); + if(r != '\''){ + ungetrune(); + return "<HR>"; + } + while(getrune() != '\'') + ; + return "<HR>"; + + /* character height and slant */ + case 'S': + case 'H': + r = getrune(); + if(r != '\''){ + ungetrune(); + return "<HR>"; + } + while(getrune() != '\'') + ; + return getnext(); + + /* digit-width space */ + case '0': + return " "; + + /*for .if, .ie, .el */ + case '{': + return "\\{"; /*}*/ + case '}': + return ""; + /* up and down */ + case 'u': + if (isdown) { + isdown = 0; + return "</sub>"; + } + isup = 1; + return "<sup>"; + case 'd': + if (isup) { + isup = 0; + return "</sup>"; + } + isdown = 1; + return "<sub>"; + } + break; + case '&': + if(msp >= 0 || strsp >= 0) + return "&"; + return "&"; + case '<': + if(msp >= 0 || strsp >= 0) + return "<"; + return "<"; + case '>': + if(msp >= 0 || strsp >= 0) + return ">"; + return ">"; + } + if (r < Runeself) { + token[0] = r; + token[1] = 0; + } + else { + R = r; + token[runetochar(token,&R)] = 0; + } + return token; +} + +/* if arg0 is set, read up to (and expand) to the next whitespace, else to the end of line */ +char* +copyline(char *p, char *e, int arg0) +{ + int c; + Rune r; + char *p1; + + while((c = getrune()) == ' ' || c == '\t') + ; + for(indirective = 1; p < e; c = getrune()) { + if (c < 0) + goto done; + switch(c) { + case '\\': + break; + case '\n': + if (arg0) + ungetrune(); + goto done; + case ' ': + case '\t': + if (arg0) + goto done; + default: + r = c; + p += runetochar(p,&r); + continue; + } + ungetrune(); + p1 = getnext(); + if (p1 == nil) + goto done; + if (*p1 == '\n') { + if (arg0) + ungetrune(); + break; + } + while((*p = *p1++) && p < e) + p++; + } +done: + indirective = 0; + *p++ = 0; + return p; +} + +char* +copyarg(char *p, char *e, int *nullarg) +{ + int c, quoted, last; + Rune r; + + *nullarg = 0; + quoted = 0; + do{ + c = getrune(); + } while(c == ' ' || c == '\t'); + + if(c == '"'){ + quoted = 1; + *nullarg = 1; + c = getrune(); + } + + if(c == '\n') + goto done; + + last = 0; + for(; p < e; c = getrune()) { + if (c < 0) + break; + switch(c) { + case '\n': + ungetrune(); + goto done; + case '\\': + r = c; + p += runetochar(p,&r); + if(last == '\\') + r = 0; + break; + case ' ': + case '\t': + if(!quoted && last != '\\') + goto done; + r = c; + p += runetochar(p,&r); + break; + case '"': + if(quoted && last != '\\') + goto done; + r = c; + p += runetochar(p,&r); + break; + default: + r = c; + p += runetochar(p,&r); + break; + } + last = r; + } +done: + *p++ = 0; + return p; + +} + +int +parseargs(char *p, char *e, char **argv) +{ + int argc; + char *np; + int nullarg; + + indirective = 1; + *p++ = 0; + for(argc = 1; argc < Narg; argc++){ + np = copyarg(p, e, &nullarg); + if(nullarg==0 && np == p+1) + break; + argv[argc] = p; + p = np; + } + argv[argc] = nil; + indirective = 0; + + + return argc; +} + +void +dodirective(void) +{ + char *p, *e; + Goobie *g; + Goobieif *gif; + char line[Nline], *line1; + int i, argc; + char *argv[Narg]; + Mstack *m; + + /* read line, translate special bytes */ + e = line + sizeof(line) - UTFmax - 1; + line1 = copyline(line, e, 1); + if (!line[0]) + return; + argv[0] = line; + + /* first look through user defined macros */ + p = getmacro(argv[0]); + if(p != nil){ + if(msp == Maxmstack-1){ + fprint(2, "ms2html: macro stack overflow\n"); + return; + } + argc = parseargs(line1, e, argv); + m = &mstack[++msp]; + m->ptr = p; + memset(m->argv, 0, sizeof(m->argv)); + for(i = 0; i < argc; i++) + m->argv[i] = strdup(argv[i]); + return; + } + + /* check for .if or .ie */ + for(gif = gtabif; gif->name; gif++) + if(strcmp(gif->name, argv[0]) == 0){ + (*gif->f)(line1, e); + return; + } + + argc = parseargs(line1, e, argv); + + /* try standard ms macros */ + for(g = gtab; g->name; g++) + if(strcmp(g->name, argv[0]) == 0){ + (*g->f)(argc, argv); + return; + } + + if(debug) + fprint(2, "stdin %d(%s:%d): unknown directive %s\n", + ssp->lno, ssp->filename, ssp->rlno, line); +} + +void +printarg(char *a) +{ + char *e, *p; + + e = a + strlen(a); + pushstr(a); + while(strsp >= 0 && strstack[strsp] >= a && strstack[strsp] < e){ + p = getnext(); + if(p == nil) + return; + Bprint(&bout, "%s", p); + } +} + +void +printargs(int argc, char **argv) +{ + argc--; + argv++; + while(--argc > 0){ + printarg(*argv++); + Bprint(&bout, " "); + } + if(argc == 0) + printarg(*argv); +} + +void +dohangingdt(void) +{ + switch(hangingdt){ + case 3: + hangingdt--; + break; + case 2: + Bprint(&bout, "<dd>"); + hangingdt = 0; + break; + } + +} + +void +dohangingau(void) +{ + if(hangingau == 0) + return; + Bprint(&bout, "</I></DL>\n"); + hangingau = 0; +} + +void +dohanginghead(void) +{ + if(hanginghead == 0) + return; + Bprint(&bout, "</H%d>\n", hanginghead); + hanginghead = 0; +} + +/* + * convert a man page to html and output + */ +void +doconvert(void) +{ + char c, *p; + Tm *t; + + pushsrc(nil); + + sol = 1; + Bprint(&bout, "<html>\n"); + Bflush(&bout); + for(;;){ + p = getnext(); + if(p == nil) + break; + c = *p; + if(c == '.' && sol){ + dodirective(); + dohangingdt(); + ssp->lno++; + ssp->rlno++; + sol = 1; + } else if(c == '\n'){ + if (ignore_nl) + ignore_nl = 0; + else { + if(hangingau) + Bprint(&bout, "<br>\n"); + else + Bprint(&bout, "%s", p); + dohangingdt(); + } + ssp->lno++; + ssp->rlno++; + sol = 1; + } else{ + Bprint(&bout, "%s", p); + ignore_nl = sol = 0; + } + } + dohanginghead(); + dohangingdt(); + closel(); + if(fsp >= 0 && fstack[fsp]) + Bprint(&bout, "%s", fstack[fsp]->end); + Bprint(&bout, "<br> <br>\n"); + Bprint(&bout, "<A href=http://www.lucent.com/copyright.html>\n"); + t = localtime(time(nil)); + Bprint(&bout, "Copyright</A> © %d Alcatel-Lucent Inc. All rights reserved.\n", + t->year+1900); + Bprint(&bout, "</body></html>\n"); +} + +static void +usage(void) +{ + sysfatal("usage: ms2html [-q] [-b basename] [-d '$$'] [-t title]"); +} + +void +main(int argc, char **argv) +{ + quiet = 1; + ARGBEGIN { + case 't': + title = EARGF(usage()); + break; + case 'b': + basename = EARGF(usage()); + break; + case 'q': + quiet = 0; + break; + case 'd': + delim = EARGF(usage()); + break; + case '?': + default: + usage(); + } ARGEND; + + Binit(&bout, 1, OWRITE); + + ds("R", "®"); + + doconvert(); + exits(nil); +} + +void +g_notyet(int, char **argv) +{ + fprint(2, "ms2html: .%s not yet supported\n", argv[0]); +} + +void +g_ignore(int, char **argv) +{ + if(quiet) + return; + fprint(2, "ms2html: line %d: ignoring .%s\n", ssp->lno, argv[0]); +} + +void +g_PP(int, char**) +{ + dohanginghead(); + closel(); + closefont(); + Bprint(&bout, "<P>\n"); + paragraph = 1; +} + +void +g_LP(int, char**) +{ + dohanginghead(); + closel(); + closefont(); + Bprint(&bout, "<br> <br>\n"); +} + +/* close a list */ +void +closel(void) +{ + g_P2(1, nil); + dohangingau(); + if(paragraph){ + Bprint(&bout, "</P>\n"); + paragraph = 0; + } + switch(list){ + case Lordered: + Bprint(&bout, "</ol>\n"); + break; + case Lunordered: + Bprint(&bout, "</ul>\n"); + break; + case Lother: + case Ldef: + Bprint(&bout, "</dl>\n"); + break; + } + list = 0; + +} + + +void +g_IP(int argc, char **argv) +{ + switch(list){ + default: + closel(); + if(argc > 1){ + if(strcmp(argv[1], "1") == 0){ + list = Lordered; + listnum = 1; + Bprint(&bout, "<OL>\n"); + } else if(strcmp(argv[1], "\\(bu") == 0){ + list = Lunordered; + Bprint(&bout, "<UL>\n"); + } else { + list = Lother; + Bprint(&bout, "<DL COMPACT>\n"); + } + } else { + list = Lother; + Bprint(&bout, "<DL>\n"); + } + break; + case Lother: + case Lordered: + case Lunordered: + break; + } + + switch(list){ + case Lother: + Bprint(&bout, "<DT>"); + if(argc > 1) + printarg(argv[1]); + else + Bprint(&bout, "<DT> "); + Bprint(&bout, "<DD>\n"); + break; + case Lordered: + case Lunordered: + Bprint(&bout, "<LI>\n"); + break; + } +} + +/* + * .5i is one <DL><DT><DD> + */ +void +g_in(int argc, char **argv) +{ + float f; + int delta, x; + char *p; + + f = indent/0.5; + delta = f; + if(argc <= 1){ + indent = 0.0; + } else { + f = strtod(argv[1], &p); + switch(*p){ + case 'i': + break; + case 'c': + f = f / 2.54; + break; + case 'P': + f = f / 6; + break; + default: + case 'u': + case 'm': + f = f * (12 / 72); + break; + case 'n': + f = f * (6 / 72); + break; + case 'p': + f = f / 72.0; + break; + } + switch(argv[1][0]){ + case '+': + case '-': + indent += f; + break; + default: + indent = f; + break; + } + } + if(indent < 0.0) + indent = 0.0; + f = (indent/0.5); + x = f; + delta = x - delta; + while(delta < 0){ + Bprint(&bout, "</DL>\n"); + delta++; + } + while(delta > 0){ + Bprint(&bout, "<DL><DT><DD>\n"); + delta--; + } +} + +void +g_HP(int, char**) +{ + switch(list){ + default: + closel(); + list = Ldef; + hangingdt = 1; + Bprint(&bout, "<DL><DT>\n"); + break; + case Ldef: + if(hangingdt) + Bprint(&bout, "<DD>"); + Bprint(&bout, "<DT>"); + hangingdt = 1; + break; + } +} + +void +g_SH(int, char**) +{ + dohanginghead(); + dohangingcenter(); + closel(); + closefont(); + Bprint(&bout, "<H%d>", HH); + hanginghead = HH; +} + +void +g_NH(int argc, char **argv) +{ + int i, level; + + closel(); + closefont(); + + dohangingcenter(); + if(argc == 1) + level = 0; + else { + level = atoi(argv[1])-1; + if(level < 0 || level >= Maxnh) + level = Maxnh - 1; + } + nh[level]++; + + Bprint(&bout, "<H%d>", HH); + hanginghead = HH; + + Bprint(&bout, "%d", nh[0]); + for(i = 1; i <= level; i++) + Bprint(&bout, ".%d", nh[i]); + Bprint(&bout, " "); + + for(i = level+1; i < Maxnh; i++) + nh[i] = 0; +} + +void +g_TL(int, char**) +{ + char *p, *np; + char name[128]; + + closefont(); + + if(!titleseen){ + if(!title){ + /* get base part of filename */ + p = strrchr(ssp->filename, '/'); + if(p == nil) + p = ssp->filename; + else + p++; + strncpy(name, p, sizeof(name)); + name[sizeof(name)-1] = 0; + + /* dump any extensions */ + np = strchr(name, '.'); + if(np) + *np = 0; + title = p; + } + Bprint(&bout, "<title>\n"); + Bprint(&bout, "%s\n", title); + Bprint(&bout, "</title>\n"); + Bprint(&bout, "<body BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#330088\" ALINK=\"#FF0044\">\n"); + titleseen = 1; + } + + Bprint(&bout, "<center>"); + hangingcenter = 1; + Bprint(&bout, "<H%d>", 1); + hanginghead = 1; +} + +void +dohangingcenter(void) +{ + if(hangingcenter){ + Bprint(&bout, "</center>"); + hangingcenter = 1; + } +} + +void +g_AU(int, char**) +{ + closel(); + dohanginghead(); + Bprint(&bout, "<DL><DD><I>"); + hangingau = 1; +} + +void +pushfont(Font *f) +{ + if(fsp == Maxfsp) + return; + if(fsp >= 0 && fstack[fsp]) + Bprint(&bout, "%s", fstack[fsp]->end); + if(f != nil) + Bprint(&bout, "%s", f->start); + fstack[++fsp] = f; +} + +void +popfont(void) +{ + if(fsp >= 0){ + if(fstack[fsp]) + Bprint(&bout, "%s", fstack[fsp]->end); + fsp--; + } +} + +/* + * for 3 args print arg3 \fxarg1\fP arg2 + * for 2 args print arg1 \fxarg2\fP + * for 1 args print \fxarg1\fP + */ +void +font(Font *f, int argc, char **argv) +{ + if(argc == 1){ + pushfont(nil); + return; + } + if(argc > 3) + printarg(argv[3]); + pushfont(f); + printarg(argv[1]); + popfont(); + if(argc > 2) + printarg(argv[2]); + Bprint(&bout, "\n"); +} + +void +closefont(void) +{ + if(fsp >= 0 && fstack[fsp]) + Bprint(&bout, "%s", fstack[fsp]->end); + fsp = -1; +} + +void +g_B(int argc, char **argv) +{ + font(&bfont, argc, argv); +} + +void +g_R(int argc, char **argv) +{ + font(nil, argc, argv); +} + +void +g_BI(int argc, char **argv) +{ + font(&bifont, argc, argv); +} + +void +g_CW(int argc, char **argv) +{ + font(&cwfont, argc, argv); +} + +char* +lower(char *p) +{ + char *x; + + for(x = p; *x; x++) + if(*x >= 'A' && *x <= 'Z') + *x -= 'A' - 'a'; + return p; +} + +void +g_I(int argc, char **argv) +{ + int anchor; + char *p; + + anchor = 0; + if(argc > 2){ + p = argv[2]; + if(p[0] == '(') + if(p[1] >= '0' && p[1] <= '9') + if(p[2] == ')'){ + anchor = 1; + Bprint(&bout, "<A href=\"/magic/man2html/%c/%s\">", + p[1], lower(argv[1])); + } + } + font(&ifont, argc, argv); + if(anchor) + Bprint(&bout, "</A>"); +} + +void +g_br(int, char**) +{ + if(hangingdt){ + Bprint(&bout, "<dd>"); + hangingdt = 0; + }else + Bprint(&bout, "<br>\n"); +} + +void +g_P1(int, char**) +{ + if(example == 0){ + example = 1; + Bprint(&bout, "<DL><DT><DD><TT><PRE>\n"); + } +} + +void +g_P2(int, char**) +{ + if(example){ + example = 0; + Bprint(&bout, "</PRE></TT></DL>\n"); + } +} + +void +g_SM(int, char **argv) +{ + Bprint(&bout, "%s", argv[1]); +} + +void +g_ft(int argc, char **argv) +{ + if(argc < 2){ + pushfont(nil); + return; + } + + switch(argv[1][0]){ + case '3': + case 'B': + pushfont(&bfont); + break; + case '2': + case 'I': + pushfont(&ifont); + break; + case '4': + pushfont(&bifont); + break; + case '5': + pushfont(&cwfont); + break; + case 'P': + popfont(); + break; + case 'R': + default: + pushfont(nil); + break; + } +} + +void +g_sp(int argc, char **argv) +{ + int n; + + n = 1; + if(argc > 1){ + n = atoi(argv[1]); + if(n < 1) + n = 1; + if(argv[1][strlen(argv[1])-1] == 'i') + n *= 4; + } + if(n > 5){ + Bprint(&bout, "<br> <br>\n"); + Bprint(&bout, "<HR>\n"); + Bprint(&bout, "<br> <br>\n"); + } else + for(; n > 0; n--) + Bprint(&bout, "<br> <br>\n"); +} + + void +rm_loop(char *name, String **l) +{ + String *s; + for(s = *l; s != nil; s = *l){ + if(strcmp(name, s->name) == 0){ + *l = s->next; + free(s->name); + free(s->val); + free(s); + break; + } + l = &s->next; + } + } + +void +g_rm(int argc, char **argv) +{ + Goobie *g; + char *name; + int i; + + for(i = 1; i < argc; i++) { + name = argv[i]; + rm_loop(name, &strings); + rm_loop(name, ¯os); + for(g = gtab; g->name; g++) + if (strcmp(g->name, name) == 0) { + g->f = g_ignore; + break; + } + } + } + +void +g_AB(int, char**) +{ + closel(); + dohangingcenter(); + Bprint(&bout, "<center><H4>ABSTRACT</H4></center><DL><DD>\n"); +} + +void +g_AE(int, char**) +{ + Bprint(&bout, "</DL>\n"); +} + +void +g_FS(int, char **) +{ + char *argv[3]; + + argv[0] = "IP"; + argv[1] = nil; + argv[2] = nil; + g_IP(1, argv); + Bprint(&bout, "NOTE:<I> "); +} + +void +g_FE(int, char **) +{ + Bprint(&bout, "</I><DT> <DD>"); + closel(); + Bprint(&bout, "<br>\n"); +} + +void +g_de(int argc, char **argv) +{ + int r; + char *p, *cp; + String *m; + int len; + + if(argc < 2) + return; + + m = nil; + len = 0; + if(strcmp(argv[0], "am") == 0){ + for(m = macros; m != nil; m = m->next) + if(strcmp(argv[1], m->name) == 0){ + len = strlen(m->val); + break; + } + + if(m == nil){ + /* nothing to append to */ + for(;;){ + p = Brdline(&ssp->in, '\n'); + if(p == nil) + break; + p[Blinelen(&ssp->in)-1] = 0; + if(strcmp(p, "..") == 0) + break; + } + return; + } + } + + if(m == nil){ + m = emalloc(sizeof(*m)); + m->next = macros; + macros = m; + m->name = strdup(argv[1]); + m->val = nil; + len = 0; + } + + /* read up to a .. removing double backslashes */ + for(;;){ + p = Brdline(&ssp->in, '\n'); + if(p == nil) + break; + p[Blinelen(&ssp->in)-1] = 0; + if(strcmp(p, "..") == 0) + break; + m->val = realloc(m->val, len + Blinelen(&ssp->in)+1); + cp = m->val + len; + while(*p){ + r = *p++; + if(r == '\\' && *p == '\\') + p++; + *cp++ = r; + } + *cp++ = '\n'; + len = cp - m->val; + *cp = 0; + } +} + +void +g_hrule(int, char**) +{ + Bprint(&bout, "<HR>\n"); +} + +void +g_BX(int argc, char **argv) +{ + Bprint(&bout, "<HR>\n"); + printargs(argc, argv); + Bprint(&bout, "<HR>\n"); +} + +void +g_IH(int, char**) +{ + Bprint(&bout, "Bell Laboratories, Naperville, Illinois, 60540\n"); +} + +void +g_MH(int, char**) +{ + Bprint(&bout, "Bell Laboratories, Murray Hill, NJ, 07974\n"); +} + +void +g_PY(int, char**) +{ + Bprint(&bout, "Bell Laboratories, Piscataway, NJ, 08854\n"); +} + +void +g_HO(int, char**) +{ + Bprint(&bout, "Bell Laboratories, Holmdel, NJ, 07733\n"); +} + +void +g_QS(int, char**) +{ + Bprint(&bout, "<BLOCKQUOTE>\n"); +} + +void +g_QE(int, char**) +{ + Bprint(&bout, "</BLOCKQUOTE>\n"); +} + +void +g_RS(int, char**) +{ + Bprint(&bout, "<DL><DD>\n"); +} + +void +g_RE(int, char**) +{ + Bprint(&bout, "</DL>\n"); +} + +int gif; + +void +g_startgif(int, char **argv) +{ + int fd; + int pfd[2]; + char *e, *p; + char name[32]; + Dir *d; + + if(strcmp(argv[0], "EQ") == 0) + e = ".EN"; + else if(strcmp(argv[0], "TS") == 0) + e = ".TE"; + else if(strcmp(argv[0], "PS") == 0) + e = ".PE"; + else + return; + + if(basename) + p = basename; + else{ + p = strrchr(sstack[0].filename, '/'); + if(p != nil) + p++; + else + p = sstack[0].filename; + } + snprint(name, sizeof(name), "%s.%d.gif", p, gif++); + fd = create(name, OWRITE, 0664); + if(fd < 0){ + fprint(2, "ms2html: can't create %s: %r\n", name); + return; + } + + if(pipe(pfd) < 0){ + fprint(2, "ms2html: can't create pipe: %r\n"); + close(fd); + return; + } + switch(rfork(RFFDG|RFPROC)){ + case -1: + fprint(2, "ms2html: can't fork: %r\n"); + close(fd); + return; + case 0: + dup(fd, 1); + close(fd); + dup(pfd[0], 0); + close(pfd[0]); + close(pfd[1]); + execl("/bin/troff2gif", "troff2gif", nil); + fprint(2, "ms2html: couldn't exec troff2gif: %r\n"); + _exits(nil); + default: + close(fd); + close(pfd[0]); + fprint(pfd[1], ".ll 7i\n"); + /* fprint(pfd[1], ".EQ\ndelim %s\n.EN\n", delim); */ + /* fprint(pfd[1], ".%s\n", argv[0]); */ + for(;;){ + p = Brdline(&ssp->in, '\n'); + if(p == nil) + break; + ssp->lno++; + ssp->rlno++; + if(write(pfd[1], p, Blinelen(&ssp->in)) < 0) + break; + if(strncmp(p, e, 3) == 0) + break; + } + close(pfd[1]); + waitpid(); + d = dirstat(name); + if(d == nil) + break; + if(d->length == 0){ + remove(name); + free(d); + break; + } + free(d); + fprint(2, "ms2html: created auxiliary file %s\n", name); + Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); + break; + } +} + +void +g_lf(int argc, char **argv) +{ + if(argc > 2) + snprint(ssp->filename, sizeof(ssp->filename), argv[2]); + if(argc > 1) + ssp->rlno = atoi(argv[1]); +} + +void +g_so(int argc, char **argv) +{ + ssp->lno++; + ssp->rlno++; + if(argc > 1) + pushsrc(argv[1]); +} + + +void +g_BP(int argc, char **argv) +{ + int fd; + char *p, *ext; + char name[32]; + Dir *d; + + if(argc < 2) + return; + + p = strrchr(argv[1], '/'); + if(p != nil) + p++; + else + p = argv[1]; + + + ext = strrchr(p, '.'); + if(ext){ + if(strcmp(ext, ".jpeg") == 0 + || strcmp(ext, ".gif") == 0){ + Bprint(&bout, "<br><img src=\"%s\"><br>\n", argv[1]); + return; + } + } + + + snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); + fd = create(name, OWRITE, 0664); + if(fd < 0){ + fprint(2, "ms2html: can't create %s: %r\n", name); + return; + } + + switch(rfork(RFFDG|RFPROC)){ + case -1: + fprint(2, "ms2html: can't fork: %r\n"); + close(fd); + return; + case 0: + dup(fd, 1); + close(fd); + execl("/bin/ps2gif", "ps2gif", argv[1], nil); + fprint(2, "ms2html: couldn't exec ps2gif: %r\n"); + _exits(nil); + default: + close(fd); + waitpid(); + d = dirstat(name); + if(d == nil) + break; + if(d->length == 0){ + remove(name); + free(d); + break; + } + free(d); + fprint(2, "ms2html: created auxiliary file %s\n", name); + Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); + break; + } +} + +/* insert straight HTML into output */ +void +g__H(int argc, char **argv) +{ + int i; + + for(i = 1; i < argc; i++) + Bprint(&bout, "%s ", argv[i]); + Bprint(&bout, "\n"); +} + +/* HTML page title */ +void +g__T(int argc, char **argv) +{ + if(titleseen) + return; + + Bprint(&bout, "<title>\n"); + printargs(argc, argv); + Bprint(&bout, "</title></head><body>\n"); + titleseen = 1; +} + +void +g_nr(int argc, char **argv) +{ + char *val; + + if (argc > 1) { + if (argc == 2) + val = "0"; + else + val = argv[2]; + dsnr(argv[1], val, &numregs); + } +} + +void +zerodivide(void) +{ + fprint(2, "stdin %d(%s:%d): division by 0\n", + ssp->lno, ssp->filename, ssp->rlno); +} + +int +numval(char **pline, int recur) +{ + char *p; + int neg, x, y; + + x = neg = 0; + p = *pline; + while(*p == '-') { + neg = 1 - neg; + p++; + } + if (*p == '(') { + p++; + x = numval(&p, 1); + if (*p != ')') + goto done; + p++; + } + else while(*p >= '0' && *p <= '9') + x = 10*x + *p++ - '0'; + if (neg) + x = -x; + if (recur) + for(;;) { + switch(*p++) { + case '+': + x += numval(&p, 0); + continue; + case '-': + x -= numval(&p, 0); + continue; + case '*': + x *= numval(&p, 0); + continue; + case '/': + y = numval(&p, 0); + if (y == 0) { + zerodivide(); + x = 0; + goto done; + } + x /= y; + continue; + case '<': + if (*p == '=') { + p++; + x = x <= numval(&p, 0); + continue; + } + x = x < numval(&p, 0); + continue; + case '>': + if (*p == '=') { + p++; + x = x >= numval(&p, 0); + continue; + } + x = x > numval(&p, 0); + continue; + case '=': + if (*p == '=') + p++; + x = x == numval(&p, 0); + continue; + case '&': + x &= numval(&p, 0); + continue; + case ':': + x |= numval(&p, 0); + continue; + case '%': + y = numval(&p, 0); + if (!y) { + zerodivide(); + goto done; + } + x %= y; + continue; + } + --p; + break; + } + done: + *pline = p; + return x; +} + +int +iftest(char *p, char **bp) +{ + char *p1; + int c, neg, rv; + + rv = neg = 0; + if (*p == '!') { + neg = 1; + p++; + } + c = *p; + if (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '('/*)*/) { + if (numval(&p,1) >= 1) + rv = 1; + goto done; + } + switch(c) { + case 't': + case 'o': + rv = 1; + case 'n': + case 'e': + p++; + goto done; + } + for(p1 = ++p; *p != c; p++) + if (!*p) + goto done; + for(p++;;) { + if (*p != *p1++) { + while(*p && *p++ != c); + goto done; + } + if (*p++ == c) + break; + } + rv = 1; + done: + if (neg) + rv = 1 - rv; + while(*p == ' ' || *p == '\t') + p++; + *bp = p; + return rv; +} + +void +scanline(char *p, char *e, int wantnl) +{ + int c; + Rune r; + + while((c = getrune()) == ' ' || c == '\t') ; + while(p < e) { + if (c < 0) + break; + if (c < Runeself) { + if (c == '\n') { + if (wantnl) + *p++ = c; + break; + } + *p++ = c; + } + else { + r = c; + p += runetochar(p, &r); + } + c = getrune(); + } + *p = 0; +} + +void +pushbody(char *line) +{ + char *b; + + if (line[0] == '\\' && line[1] == '{' /*}*/ ) + line += 2; + if (strsp < Maxmstack - 1) { + pushstr(b = strdup(line)); + mustfree[strsp] = b; + } +} + +void +skipbody(char *line) +{ + int c, n; + + if (line[0] != '\\' || line[1] != '{' /*}*/ ) + return; + for(n = 1;;) { + while((c = getrune()) != '\\') + if (c < 0) + return; + c = getrune(); + if (c == '{') + n++; + else if ((c == '}' && (c = getrune()) == '\n' && !--n) + || c < 0) + return; + } +} + +int +ifstart(char *line, char *e, char **bp) +{ + int it; + char *b; + + b = copyline(line, e, 1); + ungetrune(); + b[-1] = getrune(); + scanline(b, e, 1); + it = iftest(line, bp); + return it; +} + +void +g_ie(char *line, char *e) +{ + char *b; + + if (elsetop >= Maxif-1) { + fprint(2, "ms2html: .ie's too deep\n"); + return; + } + if (ifwastrue[++elsetop] = ifstart(line, e, &b)) + pushbody(b); + else + skipbody(b); +} + +void +g_if(char *line, char *e) +{ + char *b; + + if (ifstart(line, e, &b)) + pushbody(b); + else + skipbody(b); +} + +void +g_el(char *line, char *e) +{ + if (elsetop < 0) + return; + scanline(line, e, 1); + if (ifwastrue[elsetop--]) + skipbody(line); + else + pushbody(line); +} + +void +g_ig(int argc, char **argv) +{ + char *p, *s; + + s = ".."; + if (argc > 1) + s = argv[1]; + for(;;) { + p = Brdline(&ssp->in, '\n'); + if(p == nil) + break; + p[Blinelen(&ssp->in)-1] = 0; + if(strcmp(p, s) == 0) + break; + } +} + +void +g_ds(char *line, char *e) +{ + char *b; + + b = copyline(line, e, 1); + if (b > line) { + copyline(b, e, 0); + if (*b == '"') + b++; + ds(line, b); + } +} + +void +g_as(char *line, char *e) +{ + String *s; + char *b; + + b = copyline(line, e, 1); + if (b == line) + return; + copyline(b, e, 0); + if (*b == '"') + b++; + for(s = strings; s != nil; s = s->next) + if(strcmp(line, s->name) == 0) + break; + + if(s == nil){ + ds(line, b); + return; + } + + s->val = realloc(s->val, strlen(s->val) + strlen(b) + 1); + strcat(s->val, b); +} + +void +g_BS(int argc, char **argv) +{ + int i; + + if (argc > 1 && !weBref) { + Bprint(&bout, "<a href=\"%s\"", argv[1]); + for(i = 2; i < argc; i++) + Bprint(&bout, " %s", argv[i]); + Bprint(&bout, ">"); + weBref = 1; + } +} + +void +g_BE(int, char**) +{ + if (weBref) { + Bprint(&bout, "</a>"); + weBref = 0; + } +} + +void +g_LB(int argc, char **argv) +{ + if (argc > 1) { + if (weBref) + g_BE(0,nil); + Bprint(&bout, "<a name=\"%s\"></a>", argv[1]); + } +} + +void +g_RT(int, char**) +{ + g_BE(0,nil); + dohanginghead(); + closel(); + closefont(); +} |