2635 lines
40 KiB
C
2635 lines
40 KiB
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 */
|
||
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;
|
||
|
||
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, "</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();
|
||
}
|