doesn't work across etc. */
SwallowAttributes();
emph |= EMPH_STRIKE;
break;
case TAG_ADDED: /* doesn't work across
etc! */
SwallowAttributes();
emph |= EMPH_HIGHLIGHT;
if (preformatted)
{
if (font == IDX_BFIXEDFONT)
font = IDX_BIFIXEDFONT;
else
font = IDX_IFIXEDFONT;
}
else
{
if (font == IDX_BNORMALFONT)
font = IDX_BINORMALFONT;
else
font = IDX_INORMALFONT;
}
break;
case TAG_TEXTAREA: /* a short term bodge */
ParseTextAreaAttrs(&type, &name, &nlen, &value, &vlen, &rows, &cols, &flags);
if (form == NULL)
form = DefaultForm();
field = GetField(form, type, Here+1, name, nlen, value, vlen, rows, cols, flags|font);
PrintInputField(frames, field);
Here += field->width + 2;
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_INPUT:
ParseInputAttrs(&type, &name, &nlen, &value, &vlen, &size, &flags);
if (form == NULL)
form = DefaultForm();
field = GetField(form, type, Here+1, name, nlen, value, vlen, 1, size, flags|font);
PrintInputField(frames, field);
Here += field->width+2;
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_SELECT:
ParseSelect(0, frames, font);
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_OPTION:
ParseSelect(1, frames, font);
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_BR:
SwallowAttributes();
if (align == ALIGN_LEFT)
delta = 0;
else if (align == ALIGN_CENTER)
delta = (right - Here - LineWidth) / 2;
else if (align == ALIGN_RIGHT)
delta = right - Here - LineWidth;
Here = left;
EndOfLine(delta);
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_FIG:
ParseImageAttrs(&href, &hreflen, &align, &ismap);
start_figure = GetImage(href, hreflen);
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
case TAG_IMG:
p = bufptr - 4;
ParseImageAttrs(&href, &hreflen, &align, &ismap);
image = GetImage(href, hreflen);
width = image->width;
height = image->height;
if (ismap | (emph & EMPH_ANCHOR))
{
width += 8;
height += 8;
}
else
p = NULL;
if (image)
{
if (align == ALIGN_BOTTOM)
{
delta = height - DESCENT(font);
PrintImage(frames, delta, p, image->pixmap, width, height);
delta += 2;
if (delta > above)
above = delta;
}
else if (align == ALIGN_MIDDLE)
{
if (height > ASCENT(font) + DESCENT(font))
delta = (height + ASCENT(font) - DESCENT(font))/2;
else
delta = (height + ASCENT(font))/2;
PrintImage(frames, delta, p, image->pixmap, width, height);
delta += 2;
if (delta > above)
above = delta;
delta = 2 + height - delta;
if (delta> below)
below = delta;
}
else /* ALIGN_TOP */
{
delta = ASCENT(font);
PrintImage(frames, delta, p, image->pixmap, width, height);
delta = 2 + height - delta;
if (delta > below)
below = delta;
}
Here += width;
}
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
return;
default:
SwallowAttributes();
break;
}
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
if (ThisToken == TAG_Q)
{
PrintSeqText(frames, IDX_NORMALFONT, "\253"); /* open quote char */
Here += XTextWidth(Fonts[IDX_NORMALFONT], "\253", 1);
}
for (;;)
{
GetToken();
if (Token == ThisToken && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (TokenClass != EN_TEXT)
{
error |= ERR_EMPH;
UnGetToken();
break;
}
if (Token == WHITESPACE)
{
if (preformatted)
{
if (TokenValue == '\n')
FlushLine(BREAK, frames, align, emph, font, left, right);
else
{
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
}
continue;
}
while (GetToken() == WHITESPACE);
UnGetToken();
if (Here == left && LineLen == 0)
{
StartOfLine = StartOfWord = bufptr;
continue;
}
/* check that we have a word */
if ((WordLen = LineLen - WordStart) > 0)
WrapIfNeeded(frames, align, emph, font, left, right);
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
WordStart = LineLen;
StartOfWord = bufptr;
continue;
}
if (IsTag(Token))
{
FlushLine(NOBREAK, frames, align, emph, font, left, right);
ParseEmph(frames, align, emph, font, left, right);
continue;
}
/* must be PCDATA */
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = TokenValue;
}
LineBuf[LineLen] = '\0';
FlushLine(NOBREAK, frames, align, emph, font, left, right);
if (ThisToken == TAG_Q)
{
PrintSeqText(frames, IDX_NORMALFONT, "\273"); /* close quote char */
Here += XTextWidth(Fonts[IDX_NORMALFONT], "\273", 1);
}
if (ThisToken == TAG_MARGIN)
{
if (align == ALIGN_LEFT)
delta = 0;
else if (align == ALIGN_CENTER)
delta = (right - Here - LineWidth) / 2;
else if (align == ALIGN_RIGHT)
delta = right - Here - LineWidth;
EndOfLine(delta);
Here = left - indent;
PixOffset += LineSpacing[font];
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
}
}
void ParseHeader(Frame **frames, int align, int left, int right)
{
int HeaderTag, WordLen, emph, font;
ParseParaAttrs(&align);
if (EndTag)
return;
HeaderTag = Token;
Here = left;
switch (HeaderTag)
{
case TAG_H1:
font = IDX_H1FONT;
break;
case TAG_H2:
font = IDX_H2FONT;
break;
case TAG_H3:
case TAG_H4:
font = IDX_H3FONT;
break;
default:
font = IDX_H4FONT;
break;
}
emph = EMPH_NORMAL;
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
for (;;)
{
GetToken();
if (Token == HeaderTag && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (TokenClass != EN_TEXT)
{
error |= ERR_HEADER;
UnGetToken();
break;
}
if (Token == WHITESPACE)
{
while (GetToken() == WHITESPACE);
UnGetToken();
if (Here == left && LineLen == 0)
{
StartOfLine = StartOfWord = bufptr;
continue;
}
/* check that we have a word */
if ((WordLen = LineLen - WordStart) > 0)
WrapIfNeeded(frames, align, emph, font, left, right);
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
WordStart = LineLen;
StartOfWord = bufptr;
continue;
}
if (IsTag(Token))
{
if (EndTag)
{
SwallowAttributes();
continue;
}
FlushLine(NOBREAK, frames, align, emph, font, left, right);
ParseEmph(frames, align, emph, font, left, right);
continue;
}
/* must be PCDATA */
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = TokenValue;
}
LineBuf[LineLen] = '\0';
FlushLine(BREAK, frames, align, emph, font, left, right);
PixOffset += LineSpacing[font]/2;
}
void ParsePara(int implied, Frame **frames, int align, int font, int left, int right)
{
int WordLen, emph;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
ParseParaAttrs(&align);
if (Here < left)
Here = left;
emph = EMPH_NORMAL;
/* skip leading white space - subsequently contigous
white space is compressed to a single space */
while (GetToken() == WHITESPACE);
UnGetToken();
above = below = 0;
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
for (;;)
{
GetToken();
if (Token == TAG_P && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (TokenClass != EN_TEXT)
{
UnGetToken();
break;
}
if (Token == WHITESPACE)
{
while (GetToken() == WHITESPACE);
UnGetToken();
if (Here == left && LineLen == 0)
{
StartOfLine = StartOfWord = bufptr;
continue;
}
/* check that we have a word */
if ((WordLen = LineLen - WordStart) > 0)
WrapIfNeeded(frames, align, emph, font, left, right);
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
WordStart = LineLen;
StartOfWord = bufptr;
continue;
}
if (IsTag(Token))
{
if (EndTag)
{
SwallowAttributes();
continue;
}
FlushLine(NOBREAK, frames, align, emph, font, left, right);
ParseEmph(frames, align, emph, font, left, right);
continue;
}
/* must be PCDATA */
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = TokenValue;
}
LineBuf[LineLen] = '\0';
FlushLine(BREAK, frames, align, emph, font, left, right);
PixOffset += LineSpacing[font]/3;
}
void ItemNumber(char *buf, int depth, int n)
{
int w, ones, tens, hundreds, thousands;
char *p, *q;
w = depth % 3;
if (w == 0)
sprintf(buf, "%d.", n);
else if (w == 1)
{
thousands = n/1000;
n = n % 1000;
hundreds = n/100;
n = n % 100;
tens = n/10;
ones = n % 10;
p = buf;
while (thousands-- > 0)
*p++ = 'm';
if (hundreds)
{
q = Hundreds[hundreds-1];
while (*p++ = *q++);
--p;
}
if (tens)
{
q = Tens[tens-1];
while (*p++ = *q++);
--p;
}
if (ones)
{
q = Ones[ones-1];
while (*p++ = *q++);
--p;
}
*p++ = ')';
*p = '\0';
}
else
sprintf(buf, "%c)", 'a' + (n-1)%26);
}
/* advance declaration due for nested lists */
void ParseUL(int implied, Frame **frames, int depth, int align, int left, int right);
void ParseOL(int implied, Frame **frames, int depth, int align, int left, int right);
void ParseDL(int implied, Frame **frames, int left, int align, int right);
void ParseLI(int implied, Frame **frames, int depth, int seq, int align, int left, int right)
{
int indent, w;
long y;
char buf[16];
if (EndTag)
{
SwallowAttributes();
return;
}
indent = XTextWidth(Fonts[IDX_NORMALFONT], "mmm", 3);
y = PixOffset;
if (!implied)
SwallowAttributes();
Here = left + indent/3;
if (seq > 0)
{
ItemNumber(buf, depth++, seq);
PrintSeqText(frames, IDX_NORMALFONT, buf);
w = XTextWidth(Fonts[IDX_NORMALFONT], buf, strlen(buf));
if (w + indent/3 > indent - 4)
indent = 4 + w + indent/3;
}
else
PrintBullet(frames, depth++, IDX_NORMALFONT);
if ((w = left + indent) > list_indent) /* for tables */
list_indent = w;
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_LI && EndTag)
{
SwallowAttributes();
break;
}
if (Token == TAG_UL)
{
UnGetToken();
if (EndTag)
break;
ParseUL(0, frames, depth, align, left + indent, right);
continue;
}
if (Token == TAG_OL)
{
UnGetToken();
if (EndTag)
break;
ParseOL(0, frames, depth, align, left + indent, right);
continue;
}
if (Token == TAG_DL)
{
UnGetToken();
if (EndTag)
break;
ParseDL(0, frames, align, left + indent, right);
continue;
}
if (Token == TAG_DT || Token == TAG_DD)
{
UnGetToken();
ParseDL(1, frames, align, left + indent, right);
continue;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_P)
{
ParsePara(0, frames, align, IDX_NORMALFONT, left + indent, right);
continue;
}
if (Token == TAG_HR)
{
SwallowAttributes();
if (EndTag)
continue;
PrintRule(frames, left + indent, right);
EndOfLine(0);
continue;
}
if (TokenClass == EN_TEXT)
{
UnGetToken();
ParsePara(1, frames, align, IDX_NORMALFONT, left + indent, right);
continue;
}
/* unexpected tag so terminate element */
UnGetToken();
break;
}
/* kludge to cope with an
element with no content */
if (y == PixOffset)
PixOffset += (4 * LineSpacing[IDX_NORMALFONT])/3;
}
void ParseUL(int implied, Frame **frames, int depth, int align, int left, int right)
{
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_UL && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_LI)
{
ParseLI(0, frames, depth, 0, align, left, right);
continue;
}
if (Token == TAG_P || Token == TAG_HR || TokenClass == EN_TEXT)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseLI(1, frames, depth, 0, align, left, right);
continue;
}
if (Token == TAG_UL || Token == TAG_OL ||
Token == TAG_DL || Token == TAG_DT || Token == TAG_DD)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseLI(1, frames, depth, 0, align, left, right);
continue;
}
/* unexpected tag so terminate element */
error |= ERR_UL;
UnGetToken();
break;
}
Here = left;
}
void ParseOL(int implied, Frame **frames, int depth, int align, int left, int right)
{
int seq;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
seq = 0;
for (;;)
{
++seq;
while (GetToken() == WHITESPACE);
if (Token == TAG_OL && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_LI)
{
ParseLI(0, frames, depth, seq, align, left, right);
continue;
}
if (Token == TAG_P || Token == TAG_HR || TokenClass == EN_TEXT)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseLI(1, frames, depth, seq, align, left, right);
continue;
}
if (Token == TAG_UL || Token == TAG_OL ||
Token == TAG_DL || Token == TAG_DT || Token == TAG_DD)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseLI(1, frames, depth, seq, align, left, right);
continue;
}
/* unexpected tag so terminate element */
error |= ERR_OL;
UnGetToken();
break;
}
Here = left;
}
void ParseDT(int implied, Frame **frames, int align, int left, int right)
{
int WordLen, emph, font;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
Here = left;
emph = EMPH_NORMAL;
font = IDX_BNORMALFONT;
/* skip leading white space - subsequently contigous
white space is compressed to a single space */
while (GetToken() == WHITESPACE);
UnGetToken();
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
for (;;)
{
GetToken();
if (Token == TAG_DT && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (TokenClass != EN_TEXT)
{
UnGetToken();
break;
}
if (Token == WHITESPACE)
{
while (GetToken() == WHITESPACE);
UnGetToken();
/* check that we have a word */
if ((WordLen = LineLen - WordStart) > 0)
WrapIfNeeded(frames, align, emph, font, left, right);
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
WordStart = LineLen;
StartOfWord = bufptr;
continue;
}
if (IsTag(Token))
{
if (EndTag)
{
SwallowAttributes();
continue;
}
FlushLine(NOBREAK, frames, align, emph, font, left, right);
ParseEmph(frames, align, emph, font, left, right);
continue;
}
/* must be PCDATA */
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = TokenValue;
}
LineBuf[LineLen] = '\0';
FlushLine(NOBREAK, frames, align, emph, font, left, right);
Here += 5;
}
void ParseDD(int implied, Frame **frames, int align, int left, int right)
{
int delta;
long y;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
y = PixOffset;
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_DD && EndTag)
{
SwallowAttributes();
break;
}
if (Token == TAG_DL && EndTag)
{
UnGetToken();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_UL)
{
ParseUL(0, frames, 0, align, left, right);
continue;
}
if (Token == TAG_OL)
{
ParseOL(0, frames, 0, align, left, right);
continue;
}
if (Token == TAG_LI)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseUL(1, frames, 0, align, left, right);
continue;
}
if (Token == TAG_DL)
{
if (PixOffset == y) /* force a line break */
{
if (align == ALIGN_LEFT)
delta = 0;
else if (align == ALIGN_CENTER)
delta = (right - Here - LineWidth) / 2;
else if (align == ALIGN_RIGHT)
delta = right - Here - LineWidth;
Here = left;
EndOfLine(delta);
}
ParseDL(0, frames, align, left, right);
Here = left;
continue;
}
if (Token == TAG_HR)
{
SwallowAttributes();
if (EndTag)
continue;
PrintRule(frames, left, right);
EndOfLine(0);
continue;
}
if (Token == TAG_P)
{
ParsePara(0, frames, align, IDX_NORMALFONT, left, right);
continue;
}
if (TokenClass == EN_TEXT || Token == ENTITY)
{
UnGetToken();
ParsePara(1, frames, align, IDX_NORMALFONT, left, right);
continue;
}
/* unexpected tag so terminate element */
if (Token != TAG_DT)
error |= ERR_DL;
UnGetToken();
break;
}
/* kludge to cope with an element with no content */
if (y == PixOffset)
{
PixOffset += LineSpacing[IDX_NORMALFONT]/3;
EndOfLine(0);
}
}
void ParseDL(int implied, Frame **frames, int align, int left, int right)
{
int indent, LastToken, delta;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
LastToken = TAG_DL;
indent = XTextWidth(Fonts[IDX_NORMALFONT], "mm", 2);
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_DL && EndTag)
{
SwallowAttributes();
if (LastToken == TAG_DT)
{
if (align == ALIGN_LEFT)
delta = 0;
else if (align == ALIGN_CENTER)
delta = (right - Here - LineWidth) / 2;
else if (align == ALIGN_RIGHT)
delta = right - Here - LineWidth;
EndOfLine(delta);
}
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_DT )
{
if (EndTag)
{
SwallowAttributes();
continue;
}
if (LastToken == TAG_DT)
{
if (align == ALIGN_LEFT)
delta = 0;
else if (align == ALIGN_CENTER)
delta = (right - Here - LineWidth) / 2;
else if (align == ALIGN_RIGHT)
delta = right - Here - LineWidth;
EndOfLine(delta);
}
ParseDT(0, frames, align, left, right);
LastToken = TAG_DT;
continue;
}
if (Token == TAG_DD )
{
if (EndTag)
{
SwallowAttributes();
continue;
}
if (LastToken != TAG_DT)
error |= ERR_DL;
ParseDD(0, frames, align, left + indent, right);
LastToken = TAG_DD;
continue;
}
if (Token == TAG_P || Token == TAG_HR || TokenClass == EN_TEXT ||
Token == TAG_UL || Token == TAG_LI || Token == TAG_OL || Token == TAG_DL)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
error |= ERR_DL;
UnGetToken();
ParseDD(1, frames, align, left + indent, right);
LastToken = TAG_DD;
continue;
}
/* unexpected tag so terminate element */
error |= ERR_DL;
UnGetToken();
break;
}
Here = left;
}
void ParseBlock(int implied, Frame **frames, int tag, int align, int font, int left, int right)
{
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
Here = left;
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == tag && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_P)
{
ParsePara(0, frames, align, font, left, right);
continue;
}
if (TokenClass == EN_TEXT)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParsePara(1, frames, align, font, left, right);
continue;
}
/* unexpected tag so terminate element */
error |= ERR_BLOCK;
UnGetToken();
break;
}
}
void ParsePRE(int implied, Frame **frames, int left, int right)
{
int WordLen, ch, n, emph, font;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
Here = left;
preformatted = 1;
emph = EMPH_NORMAL;
font = IDX_FIXEDFONT;
ch = CHWIDTH(font);
StartOfLine = StartOfWord = bufptr;
LineLen = LineWidth = WordStart = 0;
for (;;)
{
GetToken();
if (Token == TAG_PRE && EndTag)
{
SwallowAttributes();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (TokenClass != EN_TEXT)
{
error |= ERR_PRE;
UnGetToken();
break;
}
if (Token == WHITESPACE && TokenValue == '\n')
{
FlushLine(BREAK, frames, ALIGN_LEFT, emph, font, left, right);
continue;
}
if (IsTag(Token))
{
if (EndTag)
{
SwallowAttributes();
continue;
}
FlushLine(NOBREAK, frames, ALIGN_LEFT, emph, font, left, right);
ParseEmph(frames, ALIGN_LEFT, emph, font, left, right);
continue;
}
/* must be PCDATA */
#if 0 /* CopyLine can't work out how many spaces to use! */
if (TokenValue == '\t')
{
n = LineLen + (Here - left)/ch;
n = 8 - n % 8;
while (n-- > 0 && LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = ' ';
continue;
}
#endif
if (LineLen < LBUFSIZE - 1)
LineBuf[LineLen++] = TokenValue;
}
LineBuf[LineLen] = '\0';
FlushLine(BREAK, frames, ALIGN_LEFT, emph, font, left, right);
preformatted = 0;
}
/* tag is TAG_TH or TAG_TD, col is column number starting from 1 upwards, returns cell height */
long ParseTableCell(int implied, Frame **frames, int row, Frame **cells,
int border, ColumnWidth *widths, int *pcol, int tag, int left, int right)
{
int align, nowrap, col, rowspan, colspan, m, prev_width, font;
long cellTop, cellHeight;
Frame *frame, *newframes;
if (EndTag)
{
SwallowAttributes();
return;
}
newframes = NULL;
col = *pcol;
align = ALIGN_CENTER;
nowrap = 0;
prev_width = html_width;
html_width = 0;
list_indent = min_width = max_width = 0;
rowspan = colspan = 1;
if (!implied)
ParseCellAttrs(&rowspan, &colspan, &align, &nowrap);
*pcol += colspan;
if (!prepass)
{
font = (tag == TAG_TH ? IDX_H3FONT : IDX_NORMALFONT);
cellTop = PixOffset;
left = widths[col].left;
right = widths[col + colspan - 1].right;
frame = BeginFrame(frames, 0, border, left-3, right+4);
frame->lastrow = row + rowspan - 1;
/* try to make TH and TD baselines match for first line */
if (tag == TAG_TH)
PixOffset += ASCENT(IDX_NORMALFONT) - ASCENT(IDX_H3FONT);
PixOffset += LineSpacing[IDX_NORMALFONT]/3;
}
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_DD && EndTag)
{
SwallowAttributes();
break;
}
if (Token == TAG_DL && EndTag)
{
UnGetToken();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_UL)
{
ParseUL(0, &newframes, 0, align, left, right);
continue;
}
if (Token == TAG_OL)
{
ParseOL(0, &newframes, 0, align, left, right);
continue;
}
if (Token == TAG_LI)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParseUL(1, &newframes, 0, align, left, right);
continue;
}
if (Token == TAG_DL)
{
ParseDL(0, &newframes, align, left, right);
Here = left;
continue;
}
if (Token == TAG_HR)
{
SwallowAttributes();
if (EndTag)
continue;
PrintRule(&newframes, left, right);
EndOfLine(0);
continue;
}
if (Token == TAG_P)
{
ParsePara(0, &newframes, align, (tag == TAG_TH ? IDX_H3FONT : IDX_NORMALFONT), left, right);
continue;
}
if (TokenClass == EN_HEADER)
{
UnGetToken();
ParseHeader(&newframes, align, left, right);
continue;
}
if (TokenClass == EN_TEXT || Token == ENTITY)
{
UnGetToken();
ParsePara(1, &newframes, align, (tag == TAG_TH ? IDX_H3FONT : IDX_NORMALFONT), left, right);
continue;
}
/* unexpected tag so terminate element */
UnGetToken();
break;
}
if (col > COLS(widths)) /* update table column count */
COLS(widths) = col;
m = MAXCOLS(widths);
if (col + colspan - 1 > m) /* double array size as needed */
{
while (col + colspan - 1> m)
m = m << 1;
widths = (ColumnWidth *)realloc(widths, (m + 1) * sizeof(ColumnWidth));
MAXCOLS(widths) = m;
while (m >= col) /* zero widths for newly allocated elements */
{
widths[m].min = 0;
widths[m].max = 0;
widths[m].rows = 0;
--m;
}
}
if (html_width > left)
max_width = html_width - left;
if (prev_width > html_width)
html_width = prev_width;
min_width += list_indent;
if (nowrap && max_width > min_width)
min_width = max_width;
if (colspan > 1) /* apportion widths evenly */
{
min_width = min_width/colspan;
max_width = max_width/colspan;
for (m = 0; m < colspan; ++m)
{
if (min_width > widths[col + m].min)
widths[col + m].min = min_width;
if (max_width > widths[col + m].max)
widths[col + m].max = max_width;
}
}
else
{
if (min_width > widths[col].min)
widths[col].min = min_width;
if (max_width > widths[col].max)
widths[col].max = max_width;
}
widths[col].rows = rowspan - 1;
if (!prepass)
{
cellHeight = (PixOffset - cellTop)/rowspan;
frame->height = cellHeight; /* for debug only */
widths[col].min = cellHeight;
FlushFrames(1, &newframes); /* any nested frames */
frame->length = paintlen - frame->info - FRAMESTLEN;
PrintFrameLength(frame);
InsertCell(cells, frame);
return cellHeight;
}
return 0;
}
void DummyCell(Frame **frames, int row, Frame **cells,
int border, ColumnWidth *widths, int col)
{
int left, right;
Frame *frame;
left = widths[col].left;
right = widths[COLS(widths)].right;
frame = BeginFrame(frames, 0, border, left-3, right+4);
frame->lastrow = row;
frame->length = paintlen - frame->info - FRAMESTLEN;
PrintFrameLength(frame);
InsertCell(cells, frame);
}
void ParseTableRow(int implied, Frame **frames, int row,
Frame **cells, int border, ColumnWidth *widths, int left, int right)
{
int cols = 1;
long rowTop, rowHeight, cellHeight;
char *row_bufptr;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
SwallowAttributes();
Here = left;
rowTop = PixOffset;
rowHeight = 0;
for (;;)
{
PixOffset = rowTop;
/* if this cell spans more than one row */
if (widths[cols].rows > 0)
{
widths[cols].rows -= 1; /* decrement span count */
if (!prepass) /* does spanned cell effect rowBottom? */
{
if (widths[cols].min > rowHeight)
rowHeight = widths[cols].min;
}
++cols;
continue;
}
while (GetToken() == WHITESPACE);
if (Token == TAG_TR && EndTag)
{
if (EndTag)
{
SwallowAttributes();
break;
}
UnGetToken();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_TH)
{
cellHeight = ParseTableCell(0, frames, row, cells, border, widths, &cols, TAG_TH, left, right);
if (cellHeight > rowHeight)
rowHeight = cellHeight;
continue;
}
if (Token == TAG_TD)
{
cellHeight = ParseTableCell(0, frames, row, cells, border, widths, &cols, TAG_TD, left, right);
if (cellHeight > rowHeight)
rowHeight = cellHeight;
continue;
}
if (Token == TAG_TABLE)
{
UnGetToken();
break;
}
if (TokenClass == EN_LIST || TokenClass == EN_TEXT ||
TokenClass == EN_HEADER || TokenClass == EN_BLOCK)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
cellHeight = ParseTableCell(1, frames, row, cells, border, widths, &cols, TAG_TD, left, right);
if (cellHeight > rowHeight)
rowHeight = cellHeight;
continue;
}
/* unexpected tag so terminate element */
UnGetToken();
break;
}
if (!prepass && cols <= COLS(widths))
DummyCell(frames, row, cells, border, widths, cols);
PixOffset = rowTop + rowHeight;
if (!prepass)
FlushCells(frames, row, cells); /* calls EndFrame() for cells ending this row */
}
void ParseTable(int implied, Frame **frames, int left, int right)
{
int row, cols, border, i, w, W, x, min, max, spare, prev_width;
long table_offset;
char *table_bufptr;
Frame *cells;
ColumnWidth *widths;
if (EndTag)
{
SwallowAttributes();
return;
}
if (!implied)
ParseTableAttrs(&border);
prev_width = html_width;
Here = left;
widths = (ColumnWidth *)malloc((NCOLS + 1) * sizeof(ColumnWidth));
COLS(widths) = 0; /* current number of columns */
MAXCOLS(widths) = NCOLS; /* space currently allocated */
widths[0].rows = 0;
for (i = NCOLS; i > 0; --i) /* zero widths for allocated elements */
{
widths[i].min = 0;
widths[i].max = 0;
widths[i].rows = 0;
}
prepass = 1;
table_bufptr = bufptr; /* note parse position for second pass */
table_offset = PixOffset;
draw_table:
row = 0;
cells = NULL;
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_TABLE && EndTag)
{
if (EndTag)
{
SwallowAttributes();
break;
}
UnGetToken();
break;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_TR)
{
++row;
ParseTableRow(0, frames, row, &cells, border, widths, left, right);
continue;
}
if (TokenClass == EN_LIST || TokenClass == EN_TEXT || TokenClass == EN_TABLE ||
TokenClass == EN_HEADER || TokenClass == EN_BLOCK)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
++row;
ParseTableRow(1, frames, row, &cells, border, widths, left, right);
continue;
}
/* unexpected tag so terminate element */
UnGetToken();
break;
}
if (prepass) /* assign actual column widths */
{
for (i = 1, min = 3, max = 3, W = 0; i <= COLS(widths); ++i)
{
min += 7 + widths[i].min;
max += 7 + widths[i].max;
W += widths[i].max - widths[i].min;
}
/* if max fits in window then use max widths */
if (max <= right - left)
{
x = left + (right - left - max)/2;
for (i = 1; i <= COLS(widths); ++i)
{
widths[i].left = x + 3;
x += 7 + widths[i].max;
widths[i].right = x - 4;
}
}
else if (min < right - left)
{
x = left;
spare = right - left - min;
for (i = 1; i <= COLS(widths); ++i)
{
w = widths[i].max - widths[i].min;
widths[i].left = x + 3;
x += 7 + widths[i].min + (spare * w)/W;
widths[i].right = x - 4;
}
}
else /* assign minimum column widths */
{
x = left;
for (i = 1; i <= COLS(widths); ++i)
{
widths[i].left = x + 3;
x += 7 + widths[i].min;
widths[i].right = x - 4;
}
}
/* and do second pass to draw table */
bufptr = table_bufptr;
PixOffset = table_offset;
prepass = 0;
goto draw_table;
}
free(widths); /* free column widths */
Here = left;
PixOffset += LineSpacing[IDX_H1FONT]/2;
/* restore previous value of html_width as needed */
w = left + max;
html_width = (w < prev_width ? prev_width : w);
}
void ParseBody(int implied, Frame **frames, int left, int right)
{
int indent, margin;
if (EndTag)
{
SwallowAttributes();
return;
}
indent = margin = XTextWidth(Fonts[IDX_NORMALFONT], "mmm", 2);
if (!implied)
SwallowAttributes();
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == TAG_BODY && EndTag)
{
SwallowAttributes();
break;
}
if (IsTag(Token) && TokenClass == EN_HEADER)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
if (Token == TAG_H1 || Token == TAG_H2)
ParseHeader(frames, ALIGN_LEFT, left, right);
else
ParseHeader(frames, ALIGN_LEFT, left+(margin/2), right);
continue;
}
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
if (Token == TAG_UL)
{
ParseUL(0, frames, 0, ALIGN_LEFT, left+margin, right);
continue;
}
if (Token == TAG_OL)
{
ParseOL(0, frames, 0, ALIGN_LEFT, left+margin, right);
continue;
}
if (Token == TAG_LI)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
error |= ERR_LI;
UnGetToken();
ParseUL(1, frames, 0, ALIGN_LEFT, left+margin, right);
continue;
}
if (Token == TAG_DL)
{
ParseDL(0, frames, ALIGN_LEFT, left+margin, right);
continue;
}
if (TokenClass == EN_TABLE)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
error |= ERR_TABLE;
UnGetToken();
ParseTable(1, frames, left, right);
continue;
}
if (Token == TAG_TABLE)
{
ParseTable(0, frames, left, right);
continue;
}
if (Token == TAG_DT || Token == TAG_DD)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
error = ERR_DL;
UnGetToken();
ParseDL(1, frames, ALIGN_LEFT, left+margin, right);
continue;
}
if (Token == TAG_HR)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
SwallowAttributes();
PrintRule(frames, left, right);
EndOfLine(0);
continue;
}
if (Token == TAG_PRE)
{
ParsePRE(0, frames, left+margin, right);
continue;
}
if (Token == TAG_P)
{
ParsePara(0, frames, ALIGN_LEFT, IDX_NORMALFONT, left+margin, right);
continue;
}
if (TokenClass == EN_TEXT || Token == ENTITY)
{
if (EndTag)
{
SwallowAttributes();
continue;
}
UnGetToken();
ParsePara(1, frames, ALIGN_LEFT, IDX_NORMALFONT, left+margin, right);
continue;
}
if (Token == TAG_ADDRESS)
{
ParseBlock(0, frames, Token, ALIGN_RIGHT, IDX_H3FONT, left+margin+indent, right-indent);
Here = left;
continue;
}
if (Token == TAG_ABSTRACT)
{
ParseBlock(0, frames, Token, ALIGN_LEFT, IDX_BINORMALFONT, left+margin+indent, right-indent);
Here = left;
continue;
}
if (Token == TAG_QUOTE)
{
ParseBlock(0, frames, Token, ALIGN_LEFT, IDX_INORMALFONT, left+indent+indent, right-indent);
Here = left;
continue;
}
if (Token == ENDDATA)
{
UnGetToken();
break;
}
if (Token == TAG_BODY || TokenClass == EN_SETUP)
{
error |= ERR_SETUP;
SwallowAttributes();
continue;
}
}
}
long ParseHTML(int *width)
{
int c, WordLen;
Byte *p;
Frame *frames;
PixOffset = 0;
LastBufPtr = bufptr = buffer+hdrlen;
error = prepass = preformatted = 0;
paintlen = 0;
IsIndex = 0;
start_figure = figure = 0;
html_width = WinWidth;
font = paintStartLine = -1;
frames = NULL;
form = NULL;
if (paintbufsize == 0)
{
paintbufsize = 8192;
paint = (Byte *)malloc(paintbufsize);
}
/* Reserve space for background's begin frame object
which is needed to simply display and scrolling routines */
MakeRoom(FRAMESTLEN);
for (;;)
{
while (GetToken() == WHITESPACE);
if (Token == UNKNOWN)
{
SwallowAttributes();
continue;
}
break;
}
if (Token == TAG_HEAD)
ParseSetUp(0, &frames);
else
{
UnGetToken();
ParseSetUp(1, &frames);
}
while (GetToken() == WHITESPACE);
if (Token == TAG_BODY)
ParseBody(0, &frames, MININDENT, MAXMARGIN);
else
{
UnGetToken();
ParseBody(1, &frames, MININDENT, MAXMARGIN);
}
FlushFrames(1, &frames); /* flush remaining end of frames */
*width = html_width;
/* initialise background frame */
background.next = NULL;
background.child = NULL;
background.top = paint + FRAMESTLEN;
background.offset = 0;
background.indent = 0;
background.height = PixOffset;
background.width = html_width;
background.info = 0;
background.length = paintlen - FRAMESTLEN;
background.style = 0;
background.border = 0;
/* and fill in begin frame object at start of paint buffer */
p = paint;
*p++ = BEGIN_FRAME;
PushValue(p, background.offset & 0xFFFF);
PushValue(p, (background.offset >> 16) & 0xFFFF);
PushValue(p, background.indent);
PushValue(p, background.width);
PushValue(p, background.height);
*p++ = background.style;
*p++ = background.border;
PushValue(p, background.length);
TopObject = paint; /* obsolete */
return PixOffset;
}