plan9fox/sys/src/cmd/ms2html.c
2011-12-09 22:36:40 +01:00

2635 lines
40 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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', },
{ "&quot;", L'"', },
{ "&AElig;", L'Æ', },
{ "&Aacute;", L'Á', },
{ "&Acirc;", L'Â', },
{ "&Agrave;", L'À', },
{ "&Aring;", L'Å', },
{ "&Atilde;", L'Ã', },
{ "&Auml;", L'Ä', },
{ "&Ccedil;", L'Ç', },
{ "&ETH;", L'Ð', },
{ "&Eacute;", L'É', },
{ "&Ecirc;", L'Ê', },
{ "&Egrave;", L'È', },
{ "&Euml;", L'Ë', },
{ "&Iacute;", L'Í', },
{ "&Icirc;", L'Î', },
{ "&Igrave;", L'Ì', },
{ "&Iuml;", L'Ï', },
{ "&Ntilde;", L'Ñ', },
{ "&Oacute;", L'Ó', },
{ "&Ocirc;", L'Ô', },
{ "&Ograve;", L'Ò', },
{ "&Oslash;", L'Ø', },
{ "&Otilde;", L'Õ', },
{ "&Ouml;", L'Ö', },
{ "&THORN;", L'Þ', },
{ "&Uacute;", L'Ú', },
{ "&Ucirc;", L'Û', },
{ "&Ugrave;", L'Ù', },
{ "&Uuml;", L'Ü', },
{ "&Yacute;", L'Ý', },
{ "&aacute;", L'á', },
{ "&acirc;", L'â', },
{ "&aelig;", L'æ', },
{ "&agrave;", L'à', },
{ "&amp;", L'&', },
{ "&aring;", L'å', },
{ "&atilde;", L'ã', },
{ "&auml;", L'ä', },
{ "&ccedil;", L'ç', },
{ "&eacute;", L'é', },
{ "&ecirc;", L'ê', },
{ "&egrave;", L'è', },
{ "&eth;", L'ð', },
{ "&euml;", L'ë', },
{ "&gt;", L'>', },
{ "&iacute;", L'í', },
{ "&icirc;", L'î', },
{ "&igrave;", L'ì', },
{ "&iuml;", L'ï', },
{ "&lt;", L'<', },
{ "&ntilde;", L'ñ', },
{ "&oacute;", L'ó', },
{ "&ocirc;", L'ô', },
{ "&ograve;", L'ò', },
{ "&oslash;", L'ø', },
{ "&otilde;", L'õ', },
{ "&ouml;", L'ö', },
{ "&szlig;", L'ß', },
{ "&thorn;", L'þ', },
{ "&uacute;", L'ú', },
{ "&ucirc;", L'û', },
{ "&ugrave;", L'ù', },
{ "&uuml;", L'ü', },
{ "&yacute;", L'ý', },
{ "&yuml;", L'ÿ', },
{ "&#161;", L'¡', },
{ "&#162;", L'¢', },
{ "&#163;", L'£', },
{ "&#164;", L'¤', },
{ "&#165;", L'¥', },
{ "&#166;", L'¦', },
{ "&#167;", L'§', },
{ "&#168;", L'¨', },
{ "&#169;", L'©', },
{ "&#170;", L'ª', },
{ "&#171;", L'«', },
{ "&#172;", L'¬', },
{ "&#173;", L'­', },
{ "&#174;", L'®', },
{ "&#175;", L'¯', },
{ "&#176;", L'°', },
{ "&#177;", L'±', },
{ "&#178;", L'²', },
{ "&#179;", L'³', },
{ "&#180;", L'´', },
{ "&#181;", L'µ', },
{ "&#182;", L'', },
{ "&#183;", L'·', },
{ "&#184;", L'¸', },
{ "&#185;", L'¹', },
{ "&#186;", L'º', },
{ "&#187;", L'»', },
{ "&#188;", L'¼', },
{ "&#189;", L'½', },
{ "&#190;", L'¾', },
{ "&#191;", L'¿', },
{ "*", L'', },
{ "&#164;", L'', },
{ "&#186;", L'', },
{ "(tm)", L'', },
{"&#913;", L'Α',},
{"&#914;", L'Β',},
{"&#915;", L'Γ',},
{"&#916;", L'Δ',},
{"&#917;", L'Ε',},
{"&#918;", L'Ζ',},
{"&#919;", L'Η',},
{"&#920;", L'Θ',},
{"&#921;", L'Ι',},
{"&#922;", L'Κ',},
{"&#923;", L'Λ',},
{"&#924;", L'Μ',},
{"&#925;", L'Ν',},
{"&#926;", L'Ξ',},
{"&#927;", L'Ο',},
{"&#928;", L'Π',},
{"&#929;", L'Ρ',},
{"&#930;", L'΢',},
{"&#931;", L'Σ',},
{"&#932;", L'Τ',},
{"&#933;", L'Υ',},
{"&#934;", L'Φ',},
{"&#935;", L'Χ',},
{"&#936;", L'Ψ',},
{"&#937;", L'Ω',},
{"&#945;", L'α',},
{"&#946;", L'β',},
{"&#947;", L'γ',},
{"&#948;", L'δ',},
{"&#949;", L'ε',},
{"&#950;", L'ζ',},
{"&#951;", L'η',},
{"&#952;", L'θ',},
{"&#953;", L'ι',},
{"&#954;", L'κ',},
{"&#955;", L'λ',},
{"&#956;", L'μ',},
{"&#957;", L'ν',},
{"&#958;", L'ξ',},
{"&#959;", L'ο',},
{"&#960;", L'π',},
{"&#961;", L'ρ',},
{"&#962;", L'ς',},
{"&#963;", L'σ',},
{"&#964;", L'τ',},
{"&#965;", L'υ',},
{"&#966;", L'φ',},
{"&#967;", L'χ',},
{"&#968;", L'ψ',},
{"&#969;", L'ω',},
{ "<-", L'', },
{ "^", L'', },
{ "->", L'', },
{ "v", L'', },
{ "!=", L'', },
{ "<=", L'', },
{ "...", L'', },
{"&isin;", L'', },
{"&#8211;", L'', },
{"&#8212;", L'', },
{ "CYRILLIC XYZZY", L'й', },
{ "CYRILLIC XYZZY", L'ъ', },
{ "CYRILLIC Y", L'ь', },
{ "CYRILLIC YA", L'я', },
{ "CYRILLIC YA", L'ё', },
{ "&#191;", L'', },
{ nil, 0 },
};
typedef struct Troffspec Troffspec;
struct Troffspec
{
char *name;
char *value;
};
Troffspec tspec[] =
{
{ "A*", "&Aring;", },
{ "o\"", "&ouml;", },
{ "ff", "ff", },
{ "fi", "fi", },
{ "fl", "fl", },
{ "Fi", "ffi", },
{ "ru", "_", },
{ "em", "&#173;", },
{ "14", "&#188;", },
{ "12", "&#189;", },
{ "co", "&#169;", },
{ "de", "&#176;", },
{ "dg", "&#161;", },
{ "fm", "&#180;", },
{ "rg", "&#174;", },
{ "bu", "*", },
{ "sq", "&#164;", },
{ "hy", "-", },
{ "pl", "+", },
{ "mi", "-", },
{ "mu", "&#215;", },
{ "di", "&#247;", },
{ "eq", "=", },
{ "==", "==", },
{ ">=", ">=", },
{ "<=", "<=", },
{ "!=", "!=", },
{ "+-", "&#177;", },
{ "no", "&#172;", },
{ "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", "&Oslash;", },
{ "aa", "&#180;", },
{ "ga", "`", },
{ "ci", "O", },
{ "L1", "DEATHSTAR", },
{ "sc", "&#167;", },
{ "dd", "++", },
{ "lh", "<=", },
{ "rh", "=>", },
{ "lt", "(", },
{ "rt", ")", },
{ "lc", "|", },
{ "rc", "|", },
{ "lb", "(", },
{ "rb", ")", },
{ "lf", "|", },
{ "rf", "|", },
{ "lk", "|", },
{ "rk", "|", },
{ "bv", "|", },
{ "ts", "s", },
{ "br", "|", },
{ "or", "|", },
{ "ul", "_", },
{ "rn", " ", },
{ "**", "*", },
{ "tm", "&#153", },
{ 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 "&#191;";
/* 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 "&amp;";
case '<':
if(msp >= 0 || strsp >= 0)
return "<";
return "&#60;";
case '>':
if(msp >= 0 || strsp >= 0)
return ">";
return "&#62;";
}
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;
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>&#32;<br>\n");
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", "&#174;");
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>&#32;<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>&#32;");
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>&#32;<br>\n");
Bprint(&bout, "<HR>\n");
Bprint(&bout, "<br>&#32;<br>\n");
} else
for(; n > 0; n--)
Bprint(&bout, "<br>&#32;<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, &macros);
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>&#32;<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();
}