/*
* a Char is >= 32 bits. low 16 bits are the rune. higher are attributes.
* must be able to hold a pointer.
*/
enum
{
Italic = 16,
Bold,
CW,
Indent1,
Indent2,
Indent3,
Heading = 25,
Anchor = 26, /* must be last */
};
void
emit(Rune r)
{
emitchar(r | attr);
/*
* Close man page references early, so that
* .IR proof (1),
* doesn't make the comma part of the link.
*/
if(r == ')')
attr &= ~(1<<Anchor);
}
/* 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]);
if(nnest >= nelem(nest))
sysfatal("nesting too deep");
nest[nnest++] = j;
}
}
attr = a;
}
void
flush(void)
{
int i;
Char c, a;
nanchors = 0;
for(i=0; i<nchars; i++){
c = chars[i];
if(c == Estring){
/* next word is string to print */
iputs(&bout, (char*)chars[++i]);
continue;
}
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);
iputrune(&bout, c & 0xFFFF);
}
}
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(" ");
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;
}
}
}