home *** CD-ROM | disk | FTP | other *** search
- /*
- pprint.c -- pretty print parse tree (c) 1998 (W3C) MIT, INRIA, Keio University
- See tidy.c for the copyright notice.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "platform.h"
- #include "html.h"
-
- /*
- Block-level and unknown elements are printed on
- new lines and their contents indented 2 spaces
-
- Inline elements are printed inline.
-
- Inline content is wrapped on spaces (except in
- attribute values or preformatted text, after
- start tags and before end tags
- */
-
- #define NORMAL 0
- #define PREFORMATTED 1
- #define COMMENT 2
- #define ATTRIBVALUE 4
- #define NOWRAP 8
- #define CDATA 16
-
- extern int CharEncoding;
-
- static uint *linebuf;
- static uint lbufsize;
- static uint linelen;
- static uint wraphere;
- static Bool InAttVal;
- static Bool InString;
-
- static int slide, count;
- static Node *slidecontent;
-
- int foo; /* debug */
-
- /*
- 1010 A
- 1011 B
- 1100 C
- 1101 D
- 1110 E
- 1111 F
- */
-
- /* return one less that the number of bytes used by UTF-8 char */
- /* str points to 1st byte, *ch initialized to 1st byte */
- uint GetUTF8(unsigned char *str, uint *ch)
- {
- uint c, n, i, count;
-
- c = str[0];
-
- if ((c & 0xE0) == 0xC0) /* 110X XXXX two bytes */
- {
- n = c & 31;
- count = 1;
- }
- else if ((c & 0xF0) == 0xE0) /* 1110 XXXX three bytes */
- {
- n = c & 15;
- count = 2;
- }
- else if ((c & 0xF8) == 0xF0) /* 1111 0XXX four bytes */
- {
- n = c & 7;
- count = 3;
- }
- else if ((c & 0xFC) == 0xF8) /* 1111 10XX five bytes */
- {
- n = c & 3;
- count = 4;
- }
- else if ((c & 0xFE) == 0xFC) /* 1111 110X six bytes */
-
- {
- n = c & 1;
- count = 5;
- }
- else /* 0XXX XXXX one byte */
- {
- *ch = c;
- return 0;
- }
-
- /* successor bytes should have the form 10XX XXXX */
- for (i = 1; i <= count; ++i)
- {
- c = str[i];
- n = (n << 6) | (c & 0x3F);
- }
-
- *ch = n;
- return count;
- }
-
- void FreePrintBuf(void)
- {
- if (linebuf)
- MemFree(linebuf);
- }
-
- void AddC(uint c, uint index)
- {
- if (index + 1 >= lbufsize)
- {
- while (index + 1 >= lbufsize)
- {
- if (lbufsize == 0)
- lbufsize = 256;
- else
- lbufsize = lbufsize * 2;
- }
-
- linebuf = (uint *)MemRealloc(linebuf, lbufsize*sizeof(uint));
- }
-
- linebuf[index] = (uint)c;
- }
-
- void WrapLine(Out *fout, uint indent)
- {
- uint i, *p, *q;
-
- if (wraphere == 0)
- return;
-
- for (i = 0; i < indent; ++i)
- outc(' ', fout);
-
- for (i = 0; i < wraphere; ++i)
- outc(linebuf[i], fout);
-
- if (InString)
- {
- outc(' ', fout);
- outc('\\', fout);
- }
-
- outc('\n', fout);
-
- if (linelen > wraphere)
- {
- p = linebuf;
-
- if (linebuf[wraphere] == ' ')
- ++wraphere;
-
- q = linebuf + wraphere;
- AddC('\0', linelen);
-
- while (*p++ = *q++);
- linelen -= wraphere;
- }
- else
- linelen = 0;
-
- wraphere = 0;
- }
-
- void WrapAttrVal(Out *fout, uint indent, Bool inString)
- {
- uint i, *p, *q;
-
- for (i = 0; i < indent; ++i)
- outc(' ', fout);
-
- for (i = 0; i < wraphere; ++i)
- outc(linebuf[i], fout);
-
- outc(' ', fout);
-
- if (inString)
- outc('\\', fout);
-
- outc('\n', fout);
-
- if (linelen > wraphere)
- {
- p = linebuf;
-
- if (linebuf[wraphere] == ' ')
- ++wraphere;
-
- q = linebuf + wraphere;
- AddC('\0', linelen);
-
- while ((*p++ = *q++));
- linelen -= wraphere;
- }
- else
- linelen = 0;
-
- wraphere = 0;
- }
-
- void PFlushLine(Out *fout, uint indent)
- {
- uint i;
-
- if (linelen > 0)
- {
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (!InAttVal || IndentAttributes)
- {
- for (i = 0; i < indent; ++i)
- outc(' ', fout);
- }
-
- for (i = 0; i < linelen; ++i)
- outc(linebuf[i], fout);
- }
-
- outc('\n', fout);
- linelen = wraphere = 0;
- InAttVal = no;
- }
-
- void PCondFlushLine(Out *fout, uint indent)
- {
- uint i;
-
- if (linelen > 0)
- {
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (!InAttVal || IndentAttributes)
- {
- for (i = 0; i < indent; ++i)
- outc(' ', fout);
- }
-
- for (i = 0; i < linelen; ++i)
- outc(linebuf[i], fout);
-
- outc('\n', fout);
- linelen = wraphere = 0;
- InAttVal = no;
- }
- }
-
- void PPrintChar(uint c, uint mode)
- {
- char *p, entity[128];
-
- if (c == ' ' && !(mode & (PREFORMATTED | COMMENT | ATTRIBVALUE)))
- {
- /* coerce a space character to a non-breaking space */
- if (mode & NOWRAP)
- {
- /* by default XML doesn't define */
- if (NumEntities || XmlTags)
- {
- AddC('&', linelen++);
- AddC('#', linelen++);
- AddC('1', linelen++);
- AddC('6', linelen++);
- AddC('0', linelen++);
- AddC(';', linelen++);
- }
- else /* otherwise use named entity */
- {
- AddC('&', linelen++);
- AddC('n', linelen++);
- AddC('b', linelen++);
- AddC('s', linelen++);
- AddC('p', linelen++);
- AddC(';', linelen++);
- }
- return;
- }
- else
- wraphere = linelen;
- }
-
- /* comment characters are passed raw */
- if (mode & COMMENT)
- {
- AddC(c, linelen++);
- return;
- }
-
- /* except in CDATA map < to < etc. */
- if (! (mode & CDATA) )
- {
- if (c == '<')
- {
- AddC('&', linelen++);
- AddC('l', linelen++);
- AddC('t', linelen++);
- AddC(';', linelen++);
- return;
- }
-
- if (c == '>')
- {
- AddC('&', linelen++);
- AddC('g', linelen++);
- AddC('t', linelen++);
- AddC(';', linelen++);
- return;
- }
-
- /*
- naked '&' chars can be left alone or
- quoted as & The latter is required
- for XML where naked '&' are illegal.
- */
- if (c == '&' && QuoteAmpersand)
- {
- AddC('&', linelen++);
- AddC('a', linelen++);
- AddC('m', linelen++);
- AddC('p', linelen++);
- AddC(';', linelen++);
- return;
- }
-
- if (c == '"' && QuoteMarks)
- {
- AddC('&', linelen++);
- AddC('q', linelen++);
- AddC('u', linelen++);
- AddC('o', linelen++);
- AddC('t', linelen++);
- AddC(';', linelen++);
- return;
- }
-
- if (c == '\'' && QuoteMarks)
- {
- AddC('&', linelen++);
- AddC('#', linelen++);
- AddC('3', linelen++);
- AddC('9', linelen++);
- AddC(';', linelen++);
- return;
- }
-
- if (c == 160)
- {
- if (QuoteNbsp)
- {
- AddC('&', linelen++);
-
- if (NumEntities)
- {
- AddC('#', linelen++);
- AddC('1', linelen++);
- AddC('6', linelen++);
- AddC('0', linelen++);
- }
- else
- {
- AddC('n', linelen++);
- AddC('b', linelen++);
- AddC('s', linelen++);
- AddC('p', linelen++);
- }
-
- AddC(';', linelen++);
- }
- else
- AddC(c, linelen++);
-
- return;
- }
- }
-
- /* otherwise ISO 2022 characters are passed raw */
- if (CharEncoding == ISO2022 || CharEncoding == RAW)
- {
- AddC(c, linelen++);
- return;
- }
-
- /* if preformatted text, map to space */
- if (c == 160 && (mode & PREFORMATTED))
- {
- AddC(' ', linelen++);
- return;
- }
-
- /*
- Filters from Word and PowerPoint often use smart
- quotes resulting in character codes between 128
- and 159. Unfortunately, the corresponding HTML 4.0
- entities for these are not widely supported. The
- following converts dashes and quotation marks to
- the nearest ASCII equivalent.
- */
-
- if (MakeClean)
- {
- if (c > 126 && c < 160)
- {
- if (c == 8211)
- c = '-'; /* en dash */
- else if (c == 8212)
- c = '-'; /* em dash */
- else if (c == 8216)
- c = '\''; /* single left quotation mark */
- else if (c == 8217)
- c = '\''; /* single right quotation mark */
- else if (c == 8220)
- c = '"'; /* double left quotation mark */
- else if (c == 8221)
- c = '"'; /* double right quotation mark */
- }
- }
-
- /* don't map latin-1 chars to entities */
- if (CharEncoding == LATIN1)
- {
- if (c > 255) /* multi byte chars */
- {
- if (!NumEntities && (p = EntityName(c)) != null)
- sprintf(entity, "&%s;", p);
- else
- sprintf(entity, "%u;", c);
-
- for (p = entity; *p; ++p)
- AddC(*p, linelen++);
-
- return;
- }
-
- if (c > 126 && c < 160)
- {
- sprintf(entity, "%d;", c);
-
- for (p = entity; *p; ++p)
- AddC(*p, linelen++);
-
- return;
- }
-
- AddC(c, linelen++);
- return;
- }
-
- /* don't map utf8 chars to entities */
- if (CharEncoding == UTF8)
- {
- AddC(c, linelen++);
- return;
- }
-
- /* use numeric entities only for XML */
- if (XmlTags)
- {
- /* if ASCII use numeric entities for chars > 127 */
- if (c > 127 && CharEncoding == ASCII)
- {
- sprintf(entity, "%u;", c);
-
- for (p = entity; *p; ++p)
- AddC(*p, linelen++);
-
- return;
- }
-
- /* otherwise output char raw */
- AddC(c, linelen++);
- return;
- }
-
- /* default treatment for ASCII */
- if (c > 126 || (c < ' ' && c != '\t'))
- {
- if (!NumEntities && (p = EntityName(c)) != null)
- sprintf(entity, "&%s;", p);
- else
- sprintf(entity, "%u;", c);
-
- for (p = entity; *p; ++p)
- AddC(*p, linelen++);
-
- return;
- }
-
- AddC(c, linelen++);
- }
-
- /*
- The line buffer is uint not char so we can
- hold Unicode values unencoded. The translation
- to UTF-8 is deferred to the outc routine called
- to flush the line buffer.
- */
- void PPrintText(Out *fout, uint mode, uint indent,
- Lexer *lexer, uint start, uint end)
- {
- uint i, c;
-
- for (i = start; i < end; ++i)
- {
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- c = (unsigned char)lexer->lexbuf[i];
-
- /* look for UTF-8 multibyte character */
- if (c > 0x7F)
- i += GetUTF8((unsigned char *)lexer->lexbuf + i, &c);
-
- if (c == '\n')
- {
- PFlushLine(fout, indent);
- continue;
- }
-
- PPrintChar(c, mode);
- }
- }
-
- void PPrintString(Out *fout, uint indent, char *str)
- {
- while (*str != '\0')
- AddC(*str++, linelen++);
- }
-
- void PPrintAttrValue(Out *fout, uint indent, char *value, int delim, Bool wrappable)
- {
- uint c;
- Bool wasinstring = no;
-
- if (delim == null)
- delim = '"';
-
- AddC('=', linelen++);
-
- if (indent + linelen < wraplen)
- wraphere = linelen;
-
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (indent + linelen < wraplen)
- wraphere = linelen;
- else
- PCondFlushLine(fout, indent);
-
- AddC(delim, linelen++);
-
- if (value)
- {
- InString = no;
-
- while (*value != '\0')
- {
- c = (unsigned char)*value;
-
- if (wrappable && c == ' ' && indent + linelen < wraplen)
- {
- wraphere = linelen;
- wasinstring = InString;
- }
-
- if (wrappable && wraphere > 0 && indent + linelen >= wraplen)
- WrapAttrVal(fout, indent, wasinstring);
-
- if (c == (uint)delim)
- {
- char *entity;
-
- entity = (c == '"' ? """ : "'");
-
- while (*entity != '\0')
- AddC(*entity++, linelen++);
-
- ++value;
- continue;
- }
- else if (c == '"')
- {
- if (QuoteMarks)
- {
- AddC('&', linelen++);
- AddC('q', linelen++);
- AddC('u', linelen++);
- AddC('o', linelen++);
- AddC('t', linelen++);
- AddC(';', linelen++);
- }
- else
- AddC('"', linelen++);
-
- if (delim == '\'')
- InString = (Bool)(!InString);
-
- ++value;
- continue;
- }
- else if (c == '\'')
- {
- if (QuoteMarks)
- {
- AddC('&', linelen++);
- AddC('#', linelen++);
- AddC('3', linelen++);
- AddC('9', linelen++);
- AddC(';', linelen++);
- }
- else
- AddC('\'', linelen++);
-
- if (delim == '"')
- InString = (Bool)(!InString);
-
- ++value;
- continue;
- }
-
- /* look for UTF-8 multibyte character */
- if (c > 0x7F)
- value += GetUTF8((unsigned char *)value, &c);
-
- ++value;
-
- if (c == '\n')
- {
- PFlushLine(fout, indent);
- continue;
- }
-
- PPrintChar(c, (wrappable ? (NORMAL | ATTRIBVALUE) : (PREFORMATTED | ATTRIBVALUE)));
- }
- }
-
- InString = no;
- AddC(delim, linelen++);
- }
-
- void PPrintAttribute(Out *fout, uint indent, AttVal *attr)
- {
- char *name;
- Bool wrappable = yes;
-
- if (IndentAttributes)
- {
- PFlushLine(fout, indent);
- indent += spaces;
- }
-
- name = attr->attribute;
-
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (!XmlTags && !XmlOut && attr->dict)
- {
- if (attr->dict->nowrap)
- wrappable = no;
- else if (IsScript(name))
- wrappable = WrapScriptlets;
- }
-
- if (indent + linelen < wraplen)
- {
- wraphere = linelen;
- AddC(' ', linelen++);
- }
- else
- PCondFlushLine(fout, indent);
-
- while (*name != '\0')
- AddC(FoldCase(*name++, UpperCaseAttrs), linelen++);
-
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (attr->value == null)
- {
- if (XmlTags || XmlOut)
- PPrintAttrValue(fout, indent, attr->attribute, attr->delim, yes);
- else if (!IsBoolAttribute(attr))
- PPrintAttrValue(fout, indent, "", attr->delim, yes);
- else if (indent + linelen < wraplen)
- wraphere = linelen;
-
- }
- else
- PPrintAttrValue(fout, indent, attr->value, attr->delim, wrappable);
- }
-
- void PPrintAttrs(Out *fout, uint indent, Lexer *lexer, AttVal *attr)
- {
- if (attr)
- {
- if (attr->next)
- PPrintAttrs(fout, indent, lexer, attr->next);
-
- if (attr->attribute != null)
- PPrintAttribute(fout, indent, attr);
- else if (attr->asp != null)
- {
- AddC(' ', linelen++);
- PPrintAsp(fout, indent, lexer, attr->asp);
- }
- }
- }
-
- /*
- Line can be wrapped immediately after inline start tag provided
- if follows a text node ending in a space, or it parent is an
- inline element that that rule applies to. This behaviour was
- reverse engineered from Netscape 3.0
- */
- Bool AfterSpace(Lexer *lexer, Node *node)
- {
- Node *prev;
- uint c;
-
- if (!node || !node->tag || !(node->tag->model & CM_INLINE))
- return yes;
-
- prev = node->prev;
-
- if (prev)
- {
- if (prev->type == TextNode && prev->end > prev->start)
- {
- c = (unsigned char)lexer->lexbuf[prev->end - 1];
-
- if (c == 160 || c == ' ' || c == '\n')
- return yes;
- }
-
- return no;
- }
-
- return AfterSpace(lexer, node->parent);
- }
-
- void PPrintTag(Lexer *lexer, Out *fout, uint mode, uint indent, Node *node)
- {
- char c, *p;
-
- AddC('<', linelen++);
-
- if (node->type == EndTag)
- AddC('/', linelen++);
-
- for (p = node->element; (c = *p); ++p)
- AddC(FoldCase(c, UpperCaseTags), linelen++);
-
- PPrintAttrs(fout, indent, lexer, node->attributes);
-
- if ((XmlOut == yes || lexer->isvoyager) &&
- (node->type == StartEndTag || node->tag->model & CM_EMPTY ))
- {
- AddC(' ', linelen++); /* compatibility hack */
- AddC('/', linelen++);
- }
-
- AddC('>', linelen++);;
-
- if (node->type != StartEndTag && !(mode & PREFORMATTED))
- {
- if (indent + linelen >= wraplen)
- WrapLine(fout, indent);
-
- if (indent + linelen < wraplen)
- {
- /*
- avoid wrapping after inline start tag unless
- it or its parent follows a space and its not
- an empty tag (e.g. IMG) followed by </a>
- */
- if (AfterSpace(lexer, node))
- {
- if (!(mode & NOWRAP) &&
- !((node->tag->model & CM_EMPTY) &&
- node->next == null &&
- node->parent->tag == tag_a))
- {
- wraphere = linelen;
- }
- }
- }
- else
- PCondFlushLine(fout, indent);
- }
- }
-
- void PPrintEndTag(Out *fout, uint mode, uint indent, Node *node)
- {
- char c, *p;
-
- /*
- Netscape ignores SGML standard by not ignoring a
- line break before </A> or </U> etc. To avoid rendering
- this as an underlined space, I disable line wrapping
- before inline end tags by the #if 0 ... #endif
- */
- #if 0
- if (indent + linelen < wraplen && !(mode & NOWRAP))
- wraphere = linelen;
- #endif
-
- AddC('<', linelen++);
- AddC('/', linelen++);
-
- for (p = node->element; (c = *p); ++p)
- AddC(FoldCase(c, UpperCaseTags), linelen++);
-
- AddC('>', linelen++);
- }
-
- void PPrintComment(Out *fout, uint indent,
- Lexer *lexer, Node *node)
- {
- if (indent + linelen < wraplen)
- wraphere = linelen;
-
- AddC('<', linelen++);
- AddC('!', linelen++);
- AddC('-', linelen++);
- AddC('-', linelen++);
- #if 0
- if (linelen < wraplen)
- wraphere = linelen;
- #endif
- PPrintText(fout, COMMENT, indent,
- lexer, node->start, node->end);
- #if 0
- if (indent + linelen < wraplen)
- wraphere = linelen;
- #endif
- AddC('-', linelen++);
- AddC('-', linelen++);
- AddC('>', linelen++);
- }
-
- void PPrintDocType(Out *fout, uint indent,
- Lexer *lexer, Node *node)
- {
- if (indent + linelen < wraplen)
- wraphere = linelen;
-
- PCondFlushLine(fout, indent);
-
- AddC('<', linelen++);
- AddC('!', linelen++);
- AddC('D', linelen++);
- AddC('O', linelen++);
- AddC('C', linelen++);
- AddC('T', linelen++);
- AddC('Y', linelen++);
- AddC('P', linelen++);
- AddC('E', linelen++);
- AddC(' ', linelen++);
-
- if (indent + linelen < wraplen)
- wraphere = linelen;
-
- PPrintText(fout, null, indent,
- lexer, node->start, node->end);
-
- if (linelen < wraplen)
- wraphere = linelen;
-
- AddC('>', linelen++);
- PCondFlushLine(fout, indent);
- }
-
- void PPrintPI(Out *fout, uint indent,
- Lexer *lexer, Node *node)
- {
- if (indent + linelen < wraplen)
- wraphere = linelen;
-
- AddC('<', linelen++);
- AddC('?', linelen++);
-
- /* set CDATA to pass < and > unescaped */
- PPrintText(fout, CDATA, indent,
- lexer, node->start, node->end);
-
- if (lexer->lexbuf[node->end - 1] != '?')
- AddC('?', linelen++);
-
- AddC('>', linelen++);
- /* PCondFlushLine(fout, indent); */
- }
-
- void PPrintAsp(Out *fout, uint indent,
- Lexer *lexer, Node *node)
- {
- int savewraplen = wraplen;
-
- /* disable wrapping if so requested */
-
- if (!WrapAsp)
- wraplen = 0xFFFFFF; /* a very large number */
- #if 0
- if (indent + linelen < wraplen)
- wraphere = linelen;
- #endif
- AddC('<', linelen++);
- AddC('%', linelen++);
-
- PPrintText(fout, null, indent,
- lexer, node->start, node->end);
-
- AddC('%', linelen++);
- AddC('>', linelen++);
- /* PCondFlushLine(fout, indent); */
- wraplen = savewraplen;
- }
-
- Bool ShouldIndent(Node *node)
- {
- if (IndentContent == no)
- return no;
-
- if (node->tag->model & CM_NEW)
- foo = 1;
-
- if (SmartIndent)
- {
- if (node->content && (node->tag->model & CM_NO_INDENT))
- {
- for (node = node->content; node; node = node->next)
- if (node->tag && node->tag->model & CM_BLOCK)
- return yes;
-
- return no;
- }
-
- if (node->tag->model & CM_HEADING)
- return no;
-
- if (node->tag == tag_p)
- return no;
- }
-
- if (node->tag->model & (CM_FIELD | CM_OBJECT))
- return yes;
-
- if (node->tag == tag_map)
- return yes;
-
- return (Bool)(!(node->tag->model & CM_INLINE));
- }
-
- void PPrintTree(Out *fout, uint mode, uint indent,
- Lexer *lexer, Node *node)
- {
- Node *content, *last;
-
- if (node == null)
- return;
-
- if (node->type == TextNode)
- PPrintText(fout, mode, indent,
- lexer, node->start, node->end);
- else if (node->type == CommentTag)
- {
- PPrintComment(fout, indent, lexer, node);
- }
- else if (node->type == RootNode)
- {
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode, indent, lexer, content);
- }
- else if (node->type == DocTypeTag)
- PPrintDocType(fout, indent, lexer, node);
- else if (node->type == ProcInsTag)
- PPrintPI(fout, indent, lexer, node);
- else if (node->type == AspTag)
- PPrintAsp(fout, indent, lexer, node);
- else if (node->tag->model & CM_EMPTY || node->type == StartEndTag)
- {
- if (!(node->tag->model & CM_INLINE))
- PCondFlushLine(fout, indent);
-
- if (node->tag == tag_br && node->prev && node->prev->tag != tag_br && BreakBeforeBR)
- PFlushLine(fout, indent);
-
- if (MakeClean && node->tag == tag_wbr)
- PPrintString(fout, indent, " ");
- else
- PPrintTag(lexer, fout, mode, indent, node);
-
- if (node->tag == tag_param || node->tag == tag_area)
- PCondFlushLine(fout, indent);
- else if (node->tag == tag_br || node->tag == tag_hr)
- PFlushLine(fout, indent);
- }
- else /* some kind of container element */
- {
- if (node->tag == tag_pre)
- {
- PCondFlushLine(fout, indent);
-
- indent = 0;
- PCondFlushLine(fout, indent);
- PPrintTag(lexer, fout, mode, indent, node);
- PFlushLine(fout, indent);
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, (mode | PREFORMATTED | NOWRAP), indent, lexer, content);
-
- PCondFlushLine(fout, indent);
- PPrintEndTag(fout, mode, indent, node);
- PFlushLine(fout, indent);
-
- if (IndentContent == no && node->next != null)
- PFlushLine(fout, indent);
- }
- else if (node->tag == tag_style || node->tag == tag_script)
- {
- PCondFlushLine(fout, indent);
-
- indent = 0;
- PCondFlushLine(fout, indent);
- PPrintTag(lexer, fout, mode, indent, node);
- PFlushLine(fout, indent);
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, (mode | PREFORMATTED | NOWRAP |CDATA), indent, lexer, content);
-
- PCondFlushLine(fout, indent);
- PPrintEndTag(fout, mode, indent, node);
- PFlushLine(fout, indent);
-
- if (IndentContent == no && node->next != null)
- PFlushLine(fout, indent);
- }
- else if (node->tag->model & CM_INLINE)
- {
- if (MakeClean)
- {
- /* discards <font> and </font> tags */
- if (node->tag == tag_font)
- {
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode, indent, lexer, content);
- return;
- }
-
- /* replace <nobr>...</nobr> by or etc. */
- if (node->tag == tag_nobr)
- {
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode|NOWRAP, indent, lexer, content);
- return;
- }
- }
-
- /* otherwise a normal inline element */
-
- PPrintTag(lexer, fout, mode, indent, node);
-
- /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */
-
- if (ShouldIndent(node))
- {
- PCondFlushLine(fout, indent);
- indent += spaces;
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode, indent, lexer, content);
-
- PCondFlushLine(fout, indent);
- indent -= spaces;
- PCondFlushLine(fout, indent);
- }
- else
- {
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode, indent, lexer, content);
- }
-
- PPrintEndTag(fout, mode, indent, node);
- }
- else /* other tags */
- {
- if (MakeClean && node->tag == tag_center)
- {
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintTree(fout, mode, indent, lexer, content);
- return;
- }
-
- PCondFlushLine(fout, indent);
-
- if (SmartIndent && node->prev != null)
- PFlushLine(fout, indent);
-
- PPrintTag(lexer, fout, mode, indent, node);
-
- if (ShouldIndent(node))
- PCondFlushLine(fout, indent);
- else if (node->tag->model & CM_HTML || node->tag == tag_noframes ||
- (node->tag->model & CM_HEAD && !(node->tag == tag_title)))
- PFlushLine(fout, indent);
-
- if (node->tag == tag_body && BurstSlides)
- PPrintSlide(fout, mode, (IndentContent ? indent+spaces : indent), lexer);
- else
- {
- last = null;
-
- for (content = node->content;
- content != null; content = content->next)
- {
- /* kludge for naked text before block level tag */
- if (last && !IndentContent && last->type == TextNode &&
- content->tag && content->tag->model & CM_BLOCK)
- {
- PFlushLine(fout, indent);
- PFlushLine(fout, indent);
- }
-
- PPrintTree(fout, mode,
- (ShouldIndent(node) ? indent+spaces : indent), lexer, content);
-
- last = content;
- }
- }
-
- /* don't flush line for td and th */
- if (ShouldIndent(node) ||
- ((node->tag->model & CM_HTML || node->tag == tag_noframes ||
- (node->tag->model & CM_HEAD && !(node->tag == tag_title)))
- && HideEndTags == no))
- {
- PCondFlushLine(fout, (IndentContent ? indent+spaces : indent));
-
- if (HideEndTags == no || !(node->tag->model & CM_OPT))
- {
- PPrintEndTag(fout, mode, indent, node);
- PFlushLine(fout, indent);
- }
- }
- else
- {
- if (HideEndTags == no || !(node->tag->model & CM_OPT))
- PPrintEndTag(fout, mode, indent, node);
-
- PFlushLine(fout, indent);
- }
-
- if (IndentContent == no &&
- node->next != null &&
- node->tag->model & (CM_BLOCK|CM_LIST|CM_DEFLIST|CM_TABLE))
- {
- PFlushLine(fout, indent);
- }
- }
- }
- }
-
- void PPrintXMLTree(Out *fout, uint mode, uint indent,
- Lexer *lexer, Node *node)
- {
- if (node == null)
- return;
-
- if (node->type == TextNode)
- {
- PPrintText(fout, mode, indent,
- lexer, node->start, node->end);
- }
- else if (node->type == CommentTag)
- {
- PPrintComment(fout, indent, lexer, node);
- }
- else if (node->type == RootNode)
- {
- Node *content;
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintXMLTree(fout, mode, indent, lexer, content);
- }
- else if (node->type == DocTypeTag)
- PPrintDocType(fout, indent, lexer, node);
- else if (node->type == ProcInsTag)
- PPrintPI(fout, indent, lexer, node);
- else if (node->type == AspTag)
- PPrintAsp(fout, indent, lexer, node);
- else if (node->tag->model & CM_EMPTY || node->type == StartEndTag)
- {
- PCondFlushLine(fout, indent);
- PPrintTag(lexer, fout, mode, indent, node);
- PFlushLine(fout, indent);
- }
- else /* some kind of container element */
- {
- Node *content;
- int cindent;
-
- PCondFlushLine(fout, indent);
-
- if (XMLPreserveWhiteSpace(node))
- {
- indent = 0;
- cindent = 0;
- }
- else
- cindent = indent + spaces;
-
- PPrintTag(lexer, fout, mode, indent, node);
- PFlushLine(fout, indent);
-
- for (content = node->content;
- content != null;
- content = content->next)
- PPrintXMLTree(fout, mode, cindent, lexer, content);
-
- PCondFlushLine(fout, cindent);
- PPrintEndTag(fout, mode, indent, node);
- PCondFlushLine(fout, indent);
- }
- }
-
- Node *FindBody(Node *root)
- {
- Node *node;
-
- node = root->content;
-
- while (node && node->tag != tag_html)
- node = node->next;
-
- if (node == null)
- return null;
-
- node = node->content;
-
- while (node && node->tag != tag_body)
- node = node->next;
-
- return node;
- }
-
- /* split parse tree by h2 elements and output to separate files */
-
- /* counts number of h2 children belonging to node */
- /* ??? somehow misses last slide ??? */
- int CountSlides(Node *node)
- {
- int count = 1;
-
- for (node = node->content; node; node = node->next)
- if (node->tag == tag_h2)
- ++count;
-
- return count;
- }
-
- /*
- inserts a space gif called "dot.gif" to ensure
- that the slide is at least n pixels high
- */
- void PrintVertSpacer(Out *fout, uint indent)
- {
- PCondFlushLine(fout, indent);
- PPrintString(fout, indent ,
- "<img width=\"0\" height=\"0\" hspace=\"1\" src=\"dot.gif\" vspace=\"%d\" align=\"left\">");
- PCondFlushLine(fout, indent);
- }
-
- void PrintNavBar(Out *fout, uint indent)
- {
- char buf[128];
-
- PCondFlushLine(fout, indent);
- PPrintString(fout, indent , "<center><small>");
-
- if (slide > 1)
- {
- sprintf(buf, "<a href=\"slide%d.html\">previous</a> | ", slide-1);
- PPrintString(fout, indent , buf);
- PCondFlushLine(fout, indent);
-
- if (slide < count)
- PPrintString(fout, indent , "<a href=\"slide1.html\">start</a> | ");
- else
- PPrintString(fout, indent , "<a href=\"slide1.html\">start</a>");
-
- PCondFlushLine(fout, indent);
- }
-
- if (slide < count)
- {
- sprintf(buf, "<a href=\"slide%d.html\">next</a>", slide+1);
- PPrintString(fout, indent , buf);
- }
-
- PPrintString(fout, indent , "</small></center>");
- PCondFlushLine(fout, indent);
- }
-
- /*
- Called from PPrintTree to print the content of a slide from
- the node slidecontent. On return slidecontent points to the
- node starting the next slide or null. The variables slide
- and count are used to customise the navigation bar.
- */
- void PPrintSlide(Out *fout, uint mode, uint indent, Lexer *lexer)
- {
- Node *content, *last;
-
- /* first print the h2 element and navbar */
- if (slidecontent->tag == tag_h2)
- {
- PrintNavBar(fout, indent);
-
- /* now print an hr after h2 */
-
- AddC('<', linelen++);
-
-
- AddC(FoldCase('h', UpperCaseTags), linelen++);
- AddC(FoldCase('r', UpperCaseTags), linelen++);
-
- if (XmlOut == yes)
- PPrintString(fout, indent , " />");
- else
- AddC('>', linelen++);
-
-
- if (IndentContent == yes)
- PCondFlushLine(fout, indent);
-
- /* PrintVertSpacer(fout, indent); */
-
- /*PCondFlushLine(fout, indent); */
-
- /* print the h2 element */
- PPrintTree(fout, mode,
- (IndentContent ? indent+spaces : indent), lexer, slidecontent);
-
- slidecontent = slidecontent->next;
- }
-
- /* now continue until we reach the next h2 or hr tag */
-
- last = null;
- content = slidecontent;
-
- for (; content != null; content = content->next)
- {
- if (content->tag == tag_h2 || content->tag == tag_hr)
- break;
-
- /* kludge for naked text before block level tag */
- if (last && !IndentContent && last->type == TextNode &&
- content->tag && content->tag->model & CM_BLOCK)
- {
- PFlushLine(fout, indent);
- PFlushLine(fout, indent);
- }
-
- PPrintTree(fout, mode,
- (IndentContent ? indent+spaces : indent), lexer, content);
-
- last = content;
- }
-
- slidecontent = content;
-
- /* now print epilog */
-
- PCondFlushLine(fout, indent);
-
- PPrintString(fout, indent , "<br clear=\"all\">");
- PCondFlushLine(fout, indent);
-
- AddC('<', linelen++);
-
-
- AddC(FoldCase('h', UpperCaseTags), linelen++);
- AddC(FoldCase('r', UpperCaseTags), linelen++);
-
- if (XmlOut == yes)
- PPrintString(fout, indent , " />");
- else
- AddC('>', linelen++);
-
-
- if (IndentContent == yes)
- PCondFlushLine(fout, indent);
-
- PrintNavBar(fout, indent);
- }
-
-
- void CreateSlides(Lexer *lexer, Node *root)
- {
- Node *body;
- char buf[128];
- Out out;
- FILE *fp;
-
- body = FindBody(root);
- count = CountSlides(body);
- slidecontent = body->content;
-
- for (slide = 1; slide <= count; ++slide)
- {
- sprintf(buf, "slide%d.html", slide);
- out.state = FSM_ASCII;
- out.encoding = CharEncoding;
-
- if ((fp = fopen(buf, "w")))
- {
- out.fp = fp;
- PPrintTree(&out, null, 0, lexer, root);
- PFlushLine(&out, 0);
- fclose(fp);
- }
- }
-
- /*
- delete superfluous slides by deleting slideN.html
- for N = count+1, count+2, etc. until no such file
- is found.
- */
-
- for (;;)
- {
- sprintf(buf, "slide%d.html", slide);
-
- if (unlink(buf) != 0)
- break;
-
- ++slide;
- }
- }
-