📄 ms2html.c
字号:
#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 */voiddsnr(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);}voidds(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";}voidpushstr(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;voidpushsrc(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 */intgetrune(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; do { if(ssp < sstack) return -1; c = Bgetrune(&ssp->in); if(c >= 0){ r = c; break; } close(ssp->fd); ssp--; } while(r < 0); return r;}voidungetrune(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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -