more small changes

This commit is contained in:
rsc 2005-01-13 04:50:11 +00:00
parent c8b6342d3c
commit 357621cd82
3 changed files with 1049 additions and 0 deletions

195
src/cmd/troff2html/chars.h Normal file
View file

@ -0,0 +1,195 @@
/* sorted by unicode value */
Htmlchar htmlchars[] =
{
{ "\"", """ },
{ "&", "&" },
{ "<", "&lt;" },
{ ">", "&gt;" },
{ "¡", "&iexcl;" },
{ "¢", "&cent;" },
{ "£", "&pound;" },
{ "¤", "&curren;" },
{ "¥", "&yen;" },
{ "¦", "&brvbar;" },
{ "§", "&sect;" },
{ "¨", "&uml;" },
{ "©", "&copy;" },
{ "ª", "&ordf;" },
{ "«", "&laquo;" },
{ "¬", "&not;" },
{ "­", "&ndash;" },
{ "®", "&reg;" },
{ "¯", "&macr;" },
{ "°", "&deg;" },
{ "±", "&plusmn;" },
{ "²", "&sup2;" },
{ "³", "&sup3;" },
{ "´", "&acute;" },
{ "µ", "&micro;" },
{ "", "&para;" },
{ "·", "&middot;" },
{ "¸", "&cedil;" },
{ "¹", "&sup1;" },
{ "º", "&ordm;" },
{ "»", "&raquo;" },
{ "¼", "&frac14;" },
{ "½", "&frac12;" },
{ "¾", "&frac34;" },
{ "¿", "&iquest;" },
{ "À", "&Agrave;" },
{ "Á", "&Aacute;" },
{ "Â", "&Acirc;" },
{ "Ã", "&Atilde;" },
{ "Ä", "&Auml;" },
{ "Å", "&Aring;" },
{ "Æ", "&AElig;" },
{ "Ç", "&Ccedil;" },
{ "È", "&Egrave;" },
{ "É", "&Eacute;" },
{ "Ê", "&Ecirc;" },
{ "Ë", "&Euml;" },
{ "Ì", "&Igrave;" },
{ "Í", "&Iacute;" },
{ "Î", "&Icirc;" },
{ "Ï", "&Iuml;" },
{ "Ð", "&ETH;" },
{ "Ñ", "&Ntilde;" },
{ "Ò", "&Ograve;" },
{ "Ó", "&Oacute;" },
{ "Ô", "&Ocirc;" },
{ "Õ", "&Otilde;" },
{ "Ö", "&Ouml;" },
{ "×", "x" },
{ "Ø", "&Oslash;" },
{ "Ù", "&Ugrave;" },
{ "Ú", "&Uacute;" },
{ "Û", "&Ucirc;" },
{ "Ü", "&Uuml;" },
{ "Ý", "&Yacute;" },
{ "Þ", "&THORN;" },
{ "ß", "&szlig;" },
{ "à", "&agrave;" },
{ "á", "&aacute;" },
{ "â", "&acirc;" },
{ "ã", "&atilde;" },
{ "ä", "&auml;" },
{ "å", "&aring;" },
{ "æ", "&aelig;" },
{ "ç", "&ccedil;" },
{ "è", "&egrave;" },
{ "é", "&eacute;" },
{ "ê", "&ecirc;" },
{ "ë", "&euml;" },
{ "ì", "&igrave;" },
{ "í", "&iacute;" },
{ "î", "&icirc;" },
{ "ï", "&iuml;" },
{ "ð", "&eth;" },
{ "ñ", "&ntilde;" },
{ "ò", "&ograve;" },
{ "ó", "&oacute;" },
{ "ô", "&ocirc;" },
{ "õ", "&otilde;" },
{ "ö", "&ouml;" },
{ "ø", "&oslash;" },
{ "ù", "&ugrave;" },
{ "ú", "&uacute;" },
{ "û", "&ucirc;" },
{ "ü", "&uuml;" },
{ "ý", "&yacute;" },
{ "þ", "&thorn;" },
{ "ÿ", "&yuml;" },
{ "", "*" },
{ "", "(tm)" },
{ "", "&larr;" },
{ "", "&uarr;" },
{ "", "&rarr;" },
{ "", "&darr;" },
{ "", "!=" },
{ "", "&le;" },
/* { "□", "&#164;" },
{ "", "&#186;" }, */
};
/* unsorted */
Troffchar troffchars[] =
{
{ "A*", "&Aring;", },
{ "o\"", "&ouml;", },
{ "ff", "ff", },
{ "fi", "fi", },
{ "fl", "fl", },
{ "Fi", "ffi", },
{ "ru", "_", },
{ "em", "--", },
{ "en", "-", },
{ "\\-", "&ndash;", },
{ "14", "&#188;", },
{ "12", "&#189;", },
{ "co", "&#169;", },
{ "de", "&#176;", },
{ "dg", "&#161;", },
{ "fm", "&#180;", },
{ "rg", "&#174;", },
{ "bu", "*", },
{ "sq", "&#164;", },
{ "hy", "&ndash;", },
{ "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", " ", },
{ "**", "*", },
{ nil, nil, },
};

View file

@ -0,0 +1,8 @@
<$PLAN9/src/mkhdr
TARG=troff2html
HFILES=chars.h
OFILES=troff2html.$O\
<$PLAN9/src/mkone

View file

@ -0,0 +1,846 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
enum{
Nfont = 11,
Wid = 20, /* tmac.anhtml sets page width to 20" so we can recognize .nf text */
};
typedef ulong Char;
typedef struct Troffchar Troffchar;
typedef struct Htmlchar Htmlchar;
typedef struct Font Font;
typedef struct HTMLfont HTMLfont;
/* a Char is 32 bits. low 16 bits are the rune. higher are attributes */
enum
{
Italic = 16,
Bold,
CW,
Indent1,
Indent2,
Indent3,
Heading = 25,
Anchor = 26, /* must be last */
};
enum /* magic emissions */
{
Estring = 0,
Epp = 1<<16,
};
int attrorder[] = { Indent1, Indent2, Indent3, Heading, Anchor, Italic, Bold, CW };
int nest[10];
int nnest;
struct Troffchar
{
char *name;
char *value;
};
struct Htmlchar
{
char *utf;
char *name;
int value;
};
#include "chars.h"
struct Font{
char *name;
HTMLfont *htmlfont;
};
struct HTMLfont{
char *name;
char *htmlname;
int bit;
};
/* R must be first; it's the default representation for fonts we don't recognize */
HTMLfont htmlfonts[] =
{
"R", nil, 0,
"LucidaSans", nil, 0,
"I", "i", Italic,
"LucidaSansI", "i", Italic,
"CW", "tt", CW,
"LucidaCW", "tt", CW,
nil, nil,
};
#define TABLE "<table border=0 cellpadding=0 cellspacing=0>"
char*
onattr[8*sizeof(ulong)] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
"<i>", /* italic */
"<b>", /* bold */
"<tt><font size=+1>", /* cw */
"<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent1 */
"<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent2 */
"<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent3 */
0,
0,
0,
"<p><font size=+1><b>", /* heading 25 */
"<unused>", /* anchor 26 */
};
char*
offattr[8*sizeof(ulong)] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
"</i>", /* italic */
"</b>", /* bold */
"</font></tt>", /* cw */
"<-/table>", /* indent1 */
"<-/table>", /* indent2 */
"<-/table>", /* indent3 */
0,
0,
0,
"</b></font>", /* heading 25 */
"</a>", /* anchor 26 */
};
Font *font[Nfont];
Biobuf bout;
int debug = 0;
/* troff state */
int page = 1;
int ft = 1;
int vp = 0;
int hp = 0;
int ps = 1;
int res = 720;
int didP = 0;
int atnewline = 1;
int prevlineH = 0;
ulong attr = 0; /* or'ed into each Char */
Char *chars;
int nchars;
int nalloc;
char** anchors; /* allocated in order */
int nanchors;
char *pagename;
char *section;
char *filename;
int cno;
char buf[8192];
char *title = "Plan 9 man page";
void process(Biobuf*, char*);
void mountfont(int, char*);
void switchfont(int);
void header(char*);
void flush(void);
void trailer(void);
void*
emalloc(ulong n)
{
void *p;
p = malloc(n);
if(p == nil)
sysfatal("malloc failed: %r");
return p;
}
void*
erealloc(void *p, ulong n)
{
p = realloc(p, n);
if(p == nil)
sysfatal("realloc failed: %r");
return p;
}
char*
estrdup(char *s)
{
char *t;
t = strdup(s);
if(t == nil)
sysfatal("strdup failed: %r");
return t;
}
void
usage(void)
{
fprint(2, "usage: troff2html [-d] [-t title] [file ...]\n");
exits("usage");
}
int
hccmp(const void *va, const void *vb)
{
Htmlchar *a, *b;
a = (Htmlchar*)va;
b = (Htmlchar*)vb;
return a->value - b->value;
}
void
main(int argc, char *argv[])
{
int i;
Biobuf in, *inp;
Rune r;
for(i=0; i<nelem(htmlchars); i++){
chartorune(&r, htmlchars[i].utf);
htmlchars[i].value = r;
}
qsort(htmlchars, nelem(htmlchars), sizeof(htmlchars[0]), hccmp);
ARGBEGIN{
case 't':
title = ARGF();
if(title == nil)
usage();
break;
case 'd':
debug++;
break;
default:
usage();
}ARGEND
Binit(&bout, 1, OWRITE);
if(argc == 0){
Binit(&in, 0, OREAD);
process(&in, "<stdin>");
}else{
for(i=0; i<argc; i++){
inp = Bopen(argv[i], OREAD);
if(inp == nil)
sysfatal("can't open %s: %r", argv[i]);
process(inp, argv[i]);
Bterm(inp);
}
}
header(title);
flush();
trailer();
exits(nil);
}
void
emitul(ulong ul, int special)
{
ulong a, c;
if(nalloc == nchars){
nalloc += 10000;
chars = realloc(chars, nalloc*sizeof(chars[0]));
if(chars == nil)
sysfatal("malloc failed: %r");
}
if(!special){
a = ul&~0xFFFF;
c = ul&0xFFFF;
/*
* Attr-specific transformations.
*/
if((a&(1<<CW)) && c=='-')
c = 0x2212;
if(!(a&(1<<CW))){
if(c == '`')
c = 0x2018;
if(c == '\'')
c = 0x2019;
}
ul = a|c;
/*
* Turn single quotes into double quotes.
*/
if(nchars > 0){
if(c == 0x2018 && (chars[nchars-1]&0xFFFF) == 0x2018
&& a==(chars[nchars-1]&~0xFFFF)){
chars[nchars-1] = (ul&~0xFFFF) | 0x201C;
return;
}
if(c == 0x2019 && (chars[nchars-1]&0xFFFF) == 0x2019
&& a==(chars[nchars-1]&~0xFFFF)){
chars[nchars-1] = (ul&~0xFFFF) | 0x201D;
return;
}
}
}
chars[nchars++] = ul;
}
void
emit(Rune r)
{
emitul(r | attr, 0);
/*
* Close man page references early, so that
* .IR proof (1),
* doesn't make the comma part of the link.
*/
if(r == ')')
attr &= ~(1<<Anchor);
}
void
emitstr(char *s)
{
emitul(Estring | attr, 0);
emitul((ulong)s, 1);
}
int indentlevel;
int linelen;
void
iputrune(Biobuf *b, Rune r)
{
int i;
if(linelen++ > 60 && r == ' ')
r = '\n';
if(r >= 0x80)
Bprint(b, "&#%d;", r);
else
Bputrune(b, r);
if(r == '\n'){
for(i=0; i<indentlevel; i++)
Bprint(b, " ");
linelen = 0;
}
}
void
iputs(Biobuf *b, char *s)
{
if(s[0]=='<' && s[1]=='+'){
iputrune(b, '\n');
Bprint(b, "<%s", s+2);
indentlevel++;
iputrune(b, '\n');
}else if(s[0]=='<' && s[1]=='-'){
indentlevel--;
iputrune(b, '\n');
Bprint(b, "<%s", s+2);
iputrune(b, '\n');
}else
Bprint(b, "%s", s);
}
void
setattr(ulong a)
{
int on, off, i, j;
on = a & ~attr;
off = attr & ~a;
/* walk up the nest stack until we reach something we need to turn off. */
for(i=0; i<nnest; i++)
if(off&(1<<nest[i]))
break;
/* turn off everything above that */
for(j=nnest-1; j>=i; j--)
iputs(&bout, offattr[nest[j]]);
/* turn on everything we just turned off but didn't want to */
for(j=i; j<nnest; j++)
if(a&(1<<nest[j]))
iputs(&bout, onattr[nest[j]]);
else
nest[j] = 0;
/* shift the zeros (turned off things) up */
for(i=j=0; i<nnest; i++)
if(nest[i] != 0)
nest[j++] = nest[i];
nnest = j;
/* now turn on the new attributes */
for(i=0; i<nelem(attrorder); i++){
j = attrorder[i];
if(on&(1<<j)){
if(j == Anchor)
onattr[j] = anchors[nanchors++];
iputs(&bout, onattr[j]);
nest[nnest++] = j;
}
}
attr = a;
}
void
flush(void)
{
int i;
ulong c, a;
nanchors = 0;
for(i=0; i<nchars; i++){
c = chars[i];
if(c == Epp){
iputrune(&bout, '\n');
iputs(&bout, TABLE "<tr height=5><td></table>");
iputrune(&bout, '\n');
continue;
}
a = c & ~0xFFFF;
c &= 0xFFFF;
/*
* If we're going to something off after a space,
* let's just turn it off before.
*/
if(c==' ' && i<nchars-1 && (chars[i+1]&0xFFFF) >= 32)
a ^= a & ~chars[i+1];
setattr(a);
if(c == Estring){
/* next word is string to print */
iputs(&bout, (char*)chars[++i]);
continue;
}
iputrune(&bout, c & 0xFFFF);
}
}
void
header(char *s)
{
Bprint(&bout, "<head>\n");
Bprint(&bout, "<title>%s</title>\n", s);
Bprint(&bout, "<meta content=\"text/html; charset=utf-8\" http-equiv=Content-Type>\n");
Bprint(&bout, "</head>\n");
Bprint(&bout, "<body bgcolor=#ffffff>\n");
Bprint(&bout, "<table>\n");
Bprint(&bout, "<tr height=10><td>\n");
Bprint(&bout, "<tr><td width=10><td>\n");
if(pagename && section){
Bprint(&bout, "<tr><td width=20><td><b>%s(%s)</b><td align=right><b>%s(%s)</b>\n",
pagename, section, pagename, section);
}
Bprint(&bout, "<tr><td width=10><td colspan=2>\n");
}
void
trailer(void)
{
Bprint(&bout, "<td width=20>\n");
Bprint(&bout, "<tr height=20><td>\n");
Bprint(&bout, "</table>\n");
#ifdef LUCENT
{
Tm *t;
t = localtime(time(nil));
Bprint(&bout, TABLE "<tr height=20><td></table>\n");
Bprint(&bout, "<font size=-1><a href=\"http://www.lucent.com/copyright.html\">\n");
Bprint(&bout, "Portions Copyright</A> &#169; %d Lucent Technologies. All rights reserved.</font>\n", t->year+1900);
}
#endif
Bprint(&bout, "<!-- TRAILER -->\n");
Bprint(&bout, "</body></html>\n");
}
int
getc(Biobuf *b)
{
cno++;
return Bgetrune(b);
}
void
ungetc(Biobuf *b)
{
cno--;
Bungetrune(b);
}
char*
getline(Biobuf *b)
{
int i, c;
for(i=0; i<sizeof buf; i++){
c = getc(b);
if(c == Beof)
return nil;
buf[i] = c;
if(c == '\n'){
buf[i] = '\0';
break;
}
}
return buf;
}
int
getnum(Biobuf *b)
{
int i, c;
i = 0;
for(;;){
c = getc(b);
if(c<'0' || '9'<c){
ungetc(b);
break;
}
i = i*10 + (c-'0');
}
return i;
}
char*
getstr(Biobuf *b)
{
int i, c;
for(i=0; i<sizeof buf; i++){
/* must get bytes not runes */
cno++;
c = Bgetc(b);
if(c == Beof)
return nil;
buf[i] = c;
if(c == '\n' || c==' ' || c=='\t'){
ungetc(b);
buf[i] = '\0';
break;
}
}
return buf;
}
int
setnum(Biobuf *b, char *name, int min, int max)
{
int i;
i = getnum(b);
if(debug > 2)
fprint(2, "set %s = %d\n", name, i);
if(min<=i && i<max)
return i;
sysfatal("value of %s is %d; min %d max %d at %s:#%d", name, i, min, max, filename, cno);
return i;
}
void
xcmd(Biobuf *b)
{
char *p, *fld[16], buf[1024];
int i, nfld;
p = getline(b);
if(p == nil)
sysfatal("xcmd error: %r");
if(debug)
fprint(2, "x command '%s'\n", p);
nfld = tokenize(p, fld, nelem(fld));
if(nfld == 0)
return;
switch(fld[0][0]){
case 'f':
/* mount font */
if(nfld != 3)
break;
i = atoi(fld[1]);
if(i<0 || Nfont<=i)
sysfatal("font %d out of range at %s:#%d", i, filename, cno);
mountfont(i, fld[2]);
return;
case 'i':
/* init */
return;
case 'r':
if(nfld<2 || atoi(fld[1])!=res)
sysfatal("typesetter has unexpected resolution %s", fld[1]? fld[1] : "<unspecified>");
return;
case 's':
/* stop */
return;
case 't':
/* trailer */
return;
case 'T':
if(nfld!=2 || strcmp(fld[1], "utf")!=0)
sysfatal("output for unknown typesetter type %s", fld[1]);
return;
case 'X':
if(nfld<3 || strcmp(fld[1], "html")!=0)
break;
/* is it a man reference of the form cp(1)? */
/* X manref start/end cp (1) */
if(nfld==6 && strcmp(fld[2], "manref")==0){
/* was the right macro; is it the right form? */
if(strlen(fld[5])>=3 &&
fld[5][0]=='(' && fld[5][2]==')' &&
'0'<=fld[5][1] && fld[5][1]<='9'){
if(strcmp(fld[3], "start") == 0){
/* set anchor attribute and remember string */
attr |= (1<<Anchor);
snprint(buf, sizeof buf,
"<a href=\"/magic/man2html/%c/%s\">",
fld[5][1], fld[4]);
nanchors++;
anchors = erealloc(anchors, nanchors*sizeof(char*));
anchors[nanchors-1] = estrdup(buf);
}else if(strcmp(fld[3], "end") == 0)
attr &= ~(1<<Anchor);
}
}else if(strcmp(fld[2], "manPP") == 0){
didP = 1;
emitul(Epp, 1);
}else if(nfld>=5 && strcmp(fld[2], "manhead") == 0){
pagename = strdup(fld[3]);
section = strdup(fld[4]);
}else if(nfld<4 || strcmp(fld[2], "manref")!=0){
if(nfld>2 && strcmp(fld[2], "<P>")==0){ /* avoid triggering extra <br> */
didP = 1;
/* clear all font attributes before paragraph */
emitul(' ' | (attr & ~(0xFFFF|((1<<Italic)|(1<<Bold)|(1<<CW)))), 0);
emitstr("<P>");
/* next emittec char will turn font attributes back on */
}else if(nfld>2 && strcmp(fld[2], "<H4>")==0)
attr |= (1<<Heading);
else if(nfld>2 && strcmp(fld[2], "</H4>")==0)
attr &= ~(1<<Heading);
else if(debug)
fprint(2, "unknown in-line html %s... at %s:%#d\n",
fld[2], filename, cno);
}
return;
}
if(debug)
fprint(2, "unknown or badly formatted x command %s\n", fld[0]);
}
int
lookup(int c, Htmlchar tab[], int ntab)
{
int low, high, mid;
low = 0;
high = ntab - 1;
while(low <= high){
mid = (low+high)/2;
if(c < tab[mid].value)
high = mid - 1;
else if(c > tab[mid].value)
low = mid + 1;
else
return mid;
}
return -1; /* no match */
}
void
emithtmlchar(int r)
{
int i;
i = lookup(r, htmlchars, nelem(htmlchars));
if(i >= 0)
emitstr(htmlchars[i].name);
else
emit(r);
}
char*
troffchar(char *s)
{
int i;
for(i=0; troffchars[i].name!=nil; i++)
if(strcmp(s, troffchars[i].name) == 0)
return troffchars[i].value;
return "??";
}
void
indent(void)
{
int nind;
didP = 0;
if(atnewline){
if(hp != prevlineH){
prevlineH = hp;
/* these most peculiar numbers appear in the troff -man output */
nind = ((prevlineH-1*res)+323)/324;
attr &= ~((1<<Indent1)|(1<<Indent2)|(1<<Indent3));
if(nind >= 1)
attr |= (1<<Indent1);
if(nind >= 2)
attr |= (1<<Indent2);
if(nind >= 3)
attr |= (1<<Indent3);
}
atnewline = 0;
}
}
void
process(Biobuf *b, char *name)
{
int c, r, v, i;
char *p;
cno = 0;
prevlineH = res;
filename = name;
for(;;){
c = getc(b);
switch(c){
case Beof:
/* go to ground state */
attr = 0;
emit('\n');
return;
case '\n':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
v = c-'0';
c = getc(b);
if(c<'0' || '9'<c)
sysfatal("illegal character motion at %s:#%d", filename, cno);
v = v*10 + (c-'0');
hp += v;
/* fall through to character case */
case 'c':
indent();
r = getc(b);
emithtmlchar(r);
break;
case 'D':
/* draw line; ignore */
do
c = getc(b);
while(c!='\n' && c!= Beof);
break;
case 'f':
v = setnum(b, "font", 0, Nfont);
switchfont(v);
break;
case 'h':
v = setnum(b, "hpos", -20000, 20000);
/* generate spaces if motion is large and within a line */
if(!atnewline && v>2*72)
for(i=0; i<v; i+=72)
emitstr("&nbsp;");
hp += v;
break;
case 'n':
setnum(b, "n1", -10000, 10000);
//Bprint(&bout, " N1=%d", v);
getc(b); /* space separates */
setnum(b, "n2", -10000, 10000);
atnewline = 1;
if(!didP && hp < (Wid-1)*res) /* if line is less than 19" long, probably need a line break */
emitstr("<br>");
emit('\n');
break;
case 'p':
page = setnum(b, "ps", -10000, 10000);
break;
case 's':
ps = setnum(b, "ps", 1, 1000);
break;
case 'v':
vp += setnum(b, "vpos", -10000, 10000);
/* BUG: ignore motion */
break;
case 'x':
xcmd(b);
break;
case 'w':
emit(' ');
break;
case 'C':
indent();
p = getstr(b);
emitstr(troffchar(p));
break;
case 'H':
hp = setnum(b, "hpos", 0, 20000);
//Bprint(&bout, " H=%d ", hp);
break;
case 'V':
vp = setnum(b, "vpos", 0, 10000);
break;
default:
fprint(2, "dhtml: unknown directive %c(0x%.2ux) at %s:#%d\n", c, c, filename, cno);
return;
}
}
}
HTMLfont*
htmlfont(char *name)
{
int i;
for(i=0; htmlfonts[i].name!=nil; i++)
if(strcmp(name, htmlfonts[i].name) == 0)
return &htmlfonts[i];
return &htmlfonts[0];
}
void
mountfont(int pos, char *name)
{
if(debug)
fprint(2, "mount font %s on %d\n", name, pos);
if(font[pos] != nil){
free(font[pos]->name);
free(font[pos]);
}
font[pos] = emalloc(sizeof(Font));
font[pos]->name = estrdup(name);
font[pos]->htmlfont = htmlfont(name);
}
void
switchfont(int pos)
{
HTMLfont *hf;
if(debug)
fprint(2, "font change from %d (%s) to %d (%s)\n", ft, font[ft]->name, pos, font[pos]->name);
if(pos == ft)
return;
hf = font[ft]->htmlfont;
if(hf->bit != 0)
attr &= ~(1<<hf->bit);
ft = pos;
hf = font[ft]->htmlfont;
if(hf->bit != 0)
attr |= (1<<hf->bit);
}