2
pprint.c -- pretty print parse tree
4
(c) 1998-2001 (W3C) MIT, INRIA, Keio University
5
See tidy.c for the copyright notice.
10
$Date: 2002/03/01 03:40:37 $
22
Block-level and unknown elements are printed on
23
new lines and their contents indented 2 spaces
25
Inline elements are printed inline.
27
Inline content is wrapped on spaces (except in
28
attribute values or preformatted text, after
29
start tags and before end tags
32
static void PPrintAsp(Out *fout, uint indent,
33
Lexer *lexer, Node *node);
34
static void PPrintJste(Out *fout, uint indent,
35
Lexer *lexer, Node *node);
36
static void PPrintPhp(Out *fout, uint indent,
37
Lexer *lexer, Node *node);
41
#define PREFORMATTED 1
47
extern int CharEncoding;
48
extern int inCharEncoding;
49
extern int outCharEncoding;
58
static int slide, count;
59
static Node *slidecontent;
61
#define AddAsciiString( s, llen )\
64
for (cp=s; *cp; ++cp)\
65
AddC( (uint) *cp, llen++ );\
68
#if SUPPORT_ASIAN_ENCODINGS
70
/* #431953 - start RJ Wraplen adjusted for smooth international ride */
71
uint CWrapLen(uint ind)
74
if ( !wstrcasecmp(Language, "zh") )
75
/* Chinese characters take two positions on a fixed-width screen */
76
/* It would be more accurate to keep a parallel linelen and wraphere
77
incremented by 2 for Chinese characters and 1 otherwise, but this
80
return (ind + (( wraplen - ind ) / 2)) ;
82
if ( !wstrcasecmp(Language, "ja") )
83
/* average Japanese text is 30% kanji */
84
return (ind + ((( wraplen - ind ) * 7) / 10)) ;
88
/* #431953 - end RJ */
92
/* return one less than the number of bytes used by the UTF-8 byte sequence */
93
/* str points to the UTF-8 byte sequence */
94
/* the Unicode char is returned in *ch */
95
uint GetUTF8(unsigned char *str, uint *ch)
103
if ((c & 0xE0) == 0xC0) /* 110X XXXX two bytes */
108
else if ((c & 0xF0) == 0xE0) /* 1110 XXXX three bytes */
113
else if ((c & 0xF8) == 0xF0) /* 1111 0XXX four bytes */
118
else if ((c & 0xFC) == 0xF8) /* 1111 10XX five bytes */
123
else if ((c & 0xFE) == 0xFC) /* 1111 110X six bytes */
129
else /* 0XXX XXXX one byte */
135
/* successor bytes should have the form 10XX XXXX */
136
for (i = 1; i < bytes; ++i)
139
n = (n << 6) | (c & 0x3F);
146
/* first byte "str[0]" is passed in separately from the */
147
/* rest of the UTF-8 byte sequence starting at "str[1]" */
148
err = DecodeUTF8BytesToChar(&n, str[0], (unsigned char *)&str[1], null, null, &bytes);
152
extern FILE* errout; /* debug */
154
tidy_out(errout, "pprint UTF-8 decoding error for U+%x : ", n); /* debug */
156
n = 0xFFFD; /* replacement char */
164
/* store char c as UTF-8 encoded byte stream */
165
char *PutUTF8(char *buf, uint c)
172
*buf++ = (0xC0 | (c >> 6));
173
*buf++ = (0x80 | (c & 0x3F));
175
else if (c <= 0xFFFF)
177
*buf++ = (0xE0 | (c >> 12));
178
*buf++ = (0x80 | ((c >> 6) & 0x3F));
179
*buf++ = (0x80 | (c & 0x3F));
181
else if (c <= 0x1FFFFF)
183
*buf++ = (0xF0 | (c >> 18));
184
*buf++ = (0x80 | ((c >> 12) & 0x3F));
185
*buf++ = (0x80 | ((c >> 6) & 0x3F));
186
*buf++ = (0x80 | (c & 0x3F));
190
*buf++ = (0xF8 | (c >> 24));
191
*buf++ = (0x80 | ((c >> 18) & 0x3F));
192
*buf++ = (0x80 | ((c >> 12) & 0x3F));
193
*buf++ = (0x80 | ((c >> 6) & 0x3F));
194
*buf++ = (0x80 | (c & 0x3F));
199
err = EncodeCharToUTF8Bytes(c, (unsigned char *)buf, null, null, &count);
203
extern FILE* errout; /* debug */
205
tidy_out(errout, "pprint UTF-8 encoding error for U+%x : ", c); /* debug */
207
/* replacement char 0xFFFD encoded as UTF-8 */
208
buf[0] = (char) 0xEF;
209
buf[1] = (char) 0xBF;
210
buf[2] = (char) 0xBD;
221
void FreePrintBuf(void)
230
static void AddC(uint c, uint index)
232
if (index + 1 >= lbufsize)
234
while (index + 1 >= lbufsize)
239
lbufsize = lbufsize * 2;
242
linebuf = (uint *)MemRealloc(linebuf, lbufsize*sizeof(uint));
245
linebuf[index] = (uint)c;
248
static void WrapLine(Out *fout, uint indent)
255
for (i = 0; i < indent; ++i)
258
for (i = 0; i < wraphere; ++i)
259
outc(linebuf[i], fout);
269
if (linelen > wraphere)
273
if (linebuf[wraphere] == ' ')
276
q = linebuf + wraphere;
279
p = linebuf; q = linebuf + wraphere; /* 433856 - fix by Terry Teague 23 Jun 00 */
281
while ((*p++ = *q++));
291
static void WrapAttrVal(Out *fout, uint indent, Bool inString)
295
for (i = 0; i < indent; ++i)
298
for (i = 0; i < wraphere; ++i)
299
outc(linebuf[i], fout);
308
if (linelen > wraphere)
312
if (linebuf[wraphere] == ' ')
315
q = linebuf + wraphere;
318
p = linebuf; q = linebuf + wraphere; /* 433856 - fix by Terry Teague 23 Jun 00 */
320
while ((*p++ = *q++));
330
void PFlushLine(Out *fout, uint indent)
336
if (indent + linelen >= wraplen)
337
WrapLine(fout, indent);
339
if (!InAttVal || IndentAttributes)
341
for (i = 0; i < indent; ++i)
345
for (i = 0; i < linelen; ++i)
346
outc(linebuf[i], fout);
350
linelen = wraphere = 0;
354
void PCondFlushLine(Out *fout, uint indent)
360
if (indent + linelen >= wraplen)
361
WrapLine(fout, indent);
363
if (!InAttVal || IndentAttributes)
365
for (i = 0; i < indent; ++i)
369
for (i = 0; i < linelen; ++i)
370
outc(linebuf[i], fout);
373
linelen = wraphere = 0;
378
static void PPrintChar(uint c, uint mode)
380
char *p, entity[128];
381
Bool breakable=no; /* #431953 - RJ */
383
if (c == ' ' && !(mode & (PREFORMATTED | COMMENT | ATTRIBVALUE | CDATA)))
385
/* coerce a space character to a non-breaking space */
388
/* by default XML doesn't define */
389
if (NumEntities || XmlTags)
391
AddC('&', linelen++);
392
AddC('#', linelen++);
393
AddC('1', linelen++);
394
AddC('6', linelen++);
395
AddC('0', linelen++);
396
AddC(';', linelen++);
398
else /* otherwise use named entity */
400
AddC('&', linelen++);
401
AddC('n', linelen++);
402
AddC('b', linelen++);
403
AddC('s', linelen++);
404
AddC('p', linelen++);
405
AddC(';', linelen++);
413
/* comment characters are passed raw */
414
if (mode & (COMMENT | CDATA))
420
/* except in CDATA map < to < etc. */
421
if (! (mode & CDATA) )
425
AddC('&', linelen++);
426
AddC('l', linelen++);
427
AddC('t', linelen++);
428
AddC(';', linelen++);
434
AddC('&', linelen++);
435
AddC('g', linelen++);
436
AddC('t', linelen++);
437
AddC(';', linelen++);
442
naked '&' chars can be left alone or
443
quoted as & The latter is required
444
for XML where naked '&' are illegal.
446
if (c == '&' && QuoteAmpersand)
448
AddC('&', linelen++);
449
AddC('a', linelen++);
450
AddC('m', linelen++);
451
AddC('p', linelen++);
452
AddC(';', linelen++);
456
if (c == '"' && QuoteMarks)
458
AddC('&', linelen++);
459
AddC('q', linelen++);
460
AddC('u', linelen++);
461
AddC('o', linelen++);
462
AddC('t', linelen++);
463
AddC(';', linelen++);
467
if (c == '\'' && QuoteMarks)
469
AddC('&', linelen++);
470
AddC('#', linelen++);
471
AddC('3', linelen++);
472
AddC('9', linelen++);
473
AddC(';', linelen++);
477
if (c == 160 && outCharEncoding != RAW)
480
AddC(' ', linelen++);
483
AddC('&', linelen++);
485
if (NumEntities || XmlTags)
487
AddC('#', linelen++);
488
AddC('1', linelen++);
489
AddC('6', linelen++);
490
AddC('0', linelen++);
494
AddC('n', linelen++);
495
AddC('b', linelen++);
496
AddC('s', linelen++);
497
AddC('p', linelen++);
500
AddC(';', linelen++);
509
#if SUPPORT_ASIAN_ENCODINGS
511
/* #431953 - start RJ */
512
/* Handle encoding-specific issues */
513
switch (outCharEncoding)
516
/* Chinese doesn't have spaces, so it needs other kinds of breaks */
517
/* This will also help documents using nice Unicode punctuation */
518
/* But we leave the ASCII range punctuation untouched */
520
/* Break after any punctuation or spaces characters */
521
if ((c >= 0x2000) && !(mode & PREFORMATTED))
523
if(((c >= 0x2000) && ( c<= 0x2006 ))
524
|| ((c >= 0x2008) && ( c<= 0x2010 ))
525
|| ((c >= 0x2011) && ( c<= 0x2046 ))
526
|| ((c >= 0x207D) && ( c<= 0x207E ))
527
|| ((c >= 0x208D) && ( c<= 0x208E ))
528
|| ((c >= 0x2329) && ( c<= 0x232A ))
529
|| ((c >= 0x3001) && ( c<= 0x3003 ))
530
|| ((c >= 0x3008) && ( c<= 0x3011 ))
531
|| ((c >= 0x3014) && ( c<= 0x301F ))
532
|| ((c >= 0xFD3E) && ( c<= 0xFD3F ))
533
|| ((c >= 0xFE30) && ( c<= 0xFE44 ))
534
|| ((c >= 0xFE49) && ( c<= 0xFE52 ))
535
|| ((c >= 0xFE54) && ( c<= 0xFE61 ))
536
|| ((c >= 0xFE6A) && ( c<= 0xFE6B ))
537
|| ((c >= 0xFF01) && ( c<= 0xFF03 ))
538
|| ((c >= 0xFF05) && ( c<= 0xFF0A ))
539
|| ((c >= 0xFF0C) && ( c<= 0xFF0F ))
540
|| ((c >= 0xFF1A) && ( c<= 0xFF1B ))
541
|| ((c >= 0xFF1F) && ( c<= 0xFF20 ))
542
|| ((c >= 0xFF3B) && ( c<= 0xFF3D ))
543
|| ((c >= 0xFF61) && ( c<= 0xFF65 )))
545
wraphere = linelen + 2; /* 2, because AddChar is not till later */
557
wraphere = linelen + 2;
560
/* but break before a left punctuation */
561
if (breakable == yes)
563
if (((c >= 0x201A) && (c <= 0x201C)) ||
564
((c >= 0x201E) && (c <= 0x201F)))
609
/* Allow linebreak at Chinese punctuation characters */
610
/* There are not many spaces in Chinese */
612
if (((c & 0xFF00) == 0xA100) & !(mode & PREFORMATTED))
615
/* opening brackets have odd codes: break before them */
616
if ((c > 0x5C) && (c < 0xAD) && ((c & 1) == 1))
622
case ISO2022: /* ISO 2022 characters are passed raw */
627
/* #431953 - end RJ */
631
/* otherwise ISO 2022 characters are passed raw */
632
if (outCharEncoding == ISO2022 || outCharEncoding == RAW)
640
/* if preformatted text, map to space */
641
if (c == 160 && (mode & PREFORMATTED))
643
AddC(' ', linelen++);
648
Filters from Word and PowerPoint often use smart
649
quotes resulting in character codes between 128
650
and 159. Unfortunately, the corresponding HTML 4.0
651
entities for these are not widely supported. The
652
following converts dashes and quotation marks to
653
the nearest ASCII equivalent. My thanks to
654
Andrzej Novosiolov for his help with this code.
657
if ( (MakeClean && AsciiChars) || MakeBare )
659
if (c >= 0x2013 && c <= 0x201E)
662
case 0x2013: /* en dash */
663
case 0x2014: /* em dash */
666
case 0x2018: /* left single quotation mark */
667
case 0x2019: /* right single quotation mark */
668
case 0x201A: /* single low-9 quotation mark */
671
case 0x201C: /* left double quotation mark */
672
case 0x201D: /* right double quotation mark */
673
case 0x201E: /* double low-9 quotation mark */
680
/* don't map latin-1 chars to entities */
681
if (outCharEncoding == LATIN1)
683
if (c > 255) /* multi byte chars */
685
if (!NumEntities && (p = EntityName(c)) != null)
686
sprintf(entity, "&%s;", p);
688
sprintf(entity, "&#%u;", c);
690
for (p = entity; *p; ++p)
696
if (c > 126 && c < 160)
698
sprintf(entity, "&#%d;", c);
700
for (p = entity; *p; ++p)
710
/* don't map UTF-8 chars to entities */
711
if (outCharEncoding == UTF8)
717
#if SUPPORT_UTF16_ENCODINGS
719
/* don't map UTF-16 chars to entities */
720
if (outCharEncoding == UTF16 || outCharEncoding == UTF16LE || outCharEncoding == UTF16BE)
728
/* use numeric entities only for XML */
731
/* if ASCII use numeric entities for chars > 127 */
732
if (c > 127 && outCharEncoding == ASCII)
734
sprintf(entity, "&#%u;", c);
736
for (p = entity; *p; ++p)
742
/* otherwise output char raw */
747
/* default treatment for ASCII */
748
if ((outCharEncoding == ASCII) && (c > 126 || (c < ' ' && c != '\t')))
750
if (!NumEntities && (p = EntityName(c)) != null)
751
sprintf(entity, "&%s;", p);
753
sprintf(entity, "&#%u;", c);
755
for (p = entity; *p; ++p)
765
The line buffer is uint not char so we can
766
hold Unicode values unencoded. The translation
767
to UTF-8 is deferred to the outc routine called
768
to flush the line buffer.
770
static void PPrintText(Out *fout, uint mode, uint indent,
771
Lexer *lexer, uint start, uint end)
775
for (i = start; i < end; ++i)
777
if (indent + linelen >= wraplen)
778
WrapLine(fout, indent);
780
c = (unsigned char)lexer->lexbuf[i];
782
/* look for UTF-8 multibyte character */
784
i += GetUTF8((unsigned char *)lexer->lexbuf + i, &c);
788
PFlushLine(fout, indent);
796
static void PPrintString(Out *fout, uint indent, char *str)
799
AddC(*str++, linelen++);
802
static void PPrintAttrValue(Out *fout, uint indent,
803
char *value, int delim, Bool wrappable)
806
Bool wasinstring = no;
808
int mode = (wrappable ? (NORMAL | ATTRIBVALUE) : (PREFORMATTED | ATTRIBVALUE));
810
/* look for ASP, Tango or PHP instructions for computed attribute value */
811
if (value && value[0] == '<')
813
if (value[1] == '%' || value[1] == '@'|| wstrncmp(value, "<?php", 5) == 0)
820
AddC('=', linelen++);
822
/* don't wrap after "=" for xml documents */
825
if (indent + linelen < wraplen)
828
if (indent + linelen >= wraplen)
829
WrapLine(fout, indent);
831
if (indent + linelen < wraplen)
834
PCondFlushLine(fout, indent);
837
AddC(delim, linelen++);
843
while (*value != '\0')
845
c = (unsigned char)*value;
847
if (wrappable && c == ' ' && indent + linelen < wraplen)
850
wasinstring = InString;
853
if (wrappable && wraphere > 0 && indent + linelen >= wraplen)
854
WrapAttrVal(fout, indent, wasinstring);
856
if (c == (uint)delim)
860
entity = (c == '"' ? """ : "'");
862
while (*entity != '\0')
863
AddC(*entity++, linelen++);
872
AddC('&', linelen++);
873
AddC('q', linelen++);
874
AddC('u', linelen++);
875
AddC('o', linelen++);
876
AddC('t', linelen++);
877
AddC(';', linelen++);
880
AddC('"', linelen++);
883
InString = (Bool)(!InString);
892
AddC('&', linelen++);
893
AddC('#', linelen++);
894
AddC('3', linelen++);
895
AddC('9', linelen++);
896
AddC(';', linelen++);
899
AddC('\'', linelen++);
902
InString = (Bool)(!InString);
908
/* look for UTF-8 multibyte character */
910
value += GetUTF8((unsigned char *)value, &c);
916
PFlushLine(fout, indent);
925
AddC(delim, linelen++);
928
static void PPrintAttribute(Out *fout, uint indent,
929
Node *node, AttVal *attr)
934
if (IndentAttributes)
936
PFlushLine(fout, indent);
940
name = attr->attribute;
942
if (indent + linelen >= wraplen)
943
WrapLine(fout, indent);
945
if (!XmlTags && !XmlOut && attr->dict)
948
wrappable = WrapScriptlets;
949
else if (!attr->dict->nowrap && WrapAttVals)
953
if (indent + linelen < wraplen)
956
AddC(' ', linelen++);
960
PCondFlushLine(fout, indent);
961
AddC(' ', linelen++);
964
while (*name != '\0')
965
AddC(FoldCase(*name++, UpperCaseAttrs), linelen++);
967
if (indent + linelen >= wraplen)
968
WrapLine(fout, indent);
970
if (attr->value == null)
972
if (XmlTags || XmlOut)
973
PPrintAttrValue(fout, indent,
974
IsBool(attr->attribute) ? attr->attribute : "",
976
else if (!IsBoolAttribute(attr) && !IsNewNode(node))
977
PPrintAttrValue(fout, indent, "", attr->delim, yes);
978
else if (indent + linelen < wraplen)
983
PPrintAttrValue(fout, indent, attr->value, attr->delim, wrappable);
986
static void PPrintAttrs(Out *fout, uint indent,
987
Lexer *lexer, Node *node, AttVal *attr)
989
Attribute *attribute;
994
PPrintAttrs(fout, indent, lexer, node, attr->next);
996
if (attr->attribute != null)
998
attribute = attr->dict;
1000
if (!DropPropAttrs ||
1001
!(attribute == null ||
1002
(attribute->versions & VERS_PROPRIETARY)))
1003
PPrintAttribute(fout, indent, node, attr);
1005
else if (attr->asp != null)
1007
AddC(' ', linelen++);
1008
PPrintAsp(fout, indent, lexer, attr->asp);
1010
else if (attr->php != null)
1012
AddC(' ', linelen++);
1013
PPrintPhp(fout, indent, lexer, attr->php);
1017
/* add xml:space attribute to pre and other elements */
1018
if (XmlOut == yes &&
1020
XMLPreserveWhiteSpace (node) &&
1021
!GetAttrByName(node, "xml:space"))
1022
PPrintString(fout, indent, " xml:space=\"preserve\"");
1026
Line can be wrapped immediately after inline start tag provided
1027
if follows a text node ending in a space, or it parent is an
1028
inline element that that rule applies to. This behaviour was
1029
reverse engineered from Netscape 3.0
1031
static Bool AfterSpace(Lexer *lexer, Node *node)
1036
if (!node || !node->tag || !(node->tag->model & CM_INLINE))
1043
if (prev->type == TextNode && prev->end > prev->start)
1045
c = (unsigned char)lexer->lexbuf[prev->end - 1];
1047
if (c == 160 || c == ' ' || c == '\n')
1054
return AfterSpace(lexer, node->parent);
1057
static void PPrintTag(Lexer *lexer, Out *fout,
1058
uint mode, uint indent, Node *node)
1062
AddC('<', linelen++);
1064
if (node->type == EndTag)
1065
AddC('/', linelen++);
1067
for (p = node->element; (c = *p); ++p)
1068
AddC(FoldCase(c, UpperCaseTags), linelen++);
1070
PPrintAttrs(fout, indent, lexer, node, node->attributes);
1072
if ( (XmlOut || xHTML) &&
1073
(node->type == StartEndTag || node->tag->model & CM_EMPTY))
1075
AddC(' ', linelen++); /* Space is NS compatibility hack <br /> */
1076
AddC('/', linelen++); /* Required end tag marker */
1079
AddC('>', linelen++);
1081
if ((node->type != StartEndTag || xHTML) && !(mode & PREFORMATTED))
1083
if (indent + linelen >= wraplen)
1084
WrapLine(fout, indent);
1086
if (indent + linelen < wraplen)
1089
wrap after start tag if is <br/> or if it's not
1090
inline or it is an empty tag followed by </a>
1092
if (AfterSpace(lexer, node))
1094
if (!(mode & NOWRAP) &&
1095
(!(node->tag->model & CM_INLINE) ||
1096
(node->tag == tag_br) ||
1097
((node->tag->model & CM_EMPTY) &&
1098
node->next == null &&
1099
node->parent->tag == tag_a)))
1106
PCondFlushLine(fout, indent);
1110
static void PPrintEndTag(Out *fout, uint mode, uint indent, Node *node)
1115
Netscape ignores SGML standard by not ignoring a
1116
line break before </A> or </U> etc. To avoid rendering
1117
this as an underlined space, I disable line wrapping
1118
before inline end tags by the #if 0 ... #endif
1121
if (indent + linelen < wraplen && !(mode & NOWRAP))
1125
AddC('<', linelen++);
1126
AddC('/', linelen++);
1128
for (p = node->element; (c = *p); ++p)
1129
AddC(FoldCase(c, UpperCaseTags), linelen++);
1131
AddC('>', linelen++);
1134
static void PPrintComment(Out *fout, uint indent,
1135
Lexer *lexer, Node *node)
1140
if (indent + linelen < wraplen)
1143
AddC('<', linelen++);
1144
AddC('!', linelen++);
1145
AddC('-', linelen++);
1146
AddC('-', linelen++);
1148
if (linelen < wraplen)
1151
PPrintText(fout, COMMENT, indent,
1152
lexer, node->start, node->end);
1154
if (indent + linelen < wraplen)
1156
AddC('-', linelen++);
1157
AddC('-', linelen++);
1159
AddC('>', linelen++);
1161
if (node->linebreak)
1162
PFlushLine(fout, indent);
1165
static void PPrintDocType(Out *fout, uint indent,
1166
Lexer *lexer, Node *node)
1168
uint i, c, mode = 0;
1169
Bool q = QuoteMarks;
1173
if (indent + linelen < wraplen)
1176
PCondFlushLine(fout, indent);
1178
AddC('<', linelen++);
1179
AddC('!', linelen++);
1180
AddC('D', linelen++);
1181
AddC('O', linelen++);
1182
AddC('C', linelen++);
1183
AddC('T', linelen++);
1184
AddC('Y', linelen++);
1185
AddC('P', linelen++);
1186
AddC('E', linelen++);
1187
AddC(' ', linelen++);
1189
if (indent + linelen < wraplen)
1192
for (i = node->start; i < node->end; ++i)
1194
if (indent + linelen >= wraplen)
1195
WrapLine(fout, indent);
1197
c = (unsigned char)lexer->lexbuf[i];
1200
if ( mode & CDATA ) {
1207
/* look for UTF-8 multibyte character */
1209
i += GetUTF8((unsigned char *)lexer->lexbuf + i, &c);
1213
PFlushLine(fout, indent);
1217
PPrintChar(c, mode);
1220
if (linelen < wraplen)
1223
AddC('>', linelen++);
1225
PCondFlushLine(fout, indent);
1228
static void PPrintPI(Out *fout, uint indent,
1229
Lexer *lexer, Node *node)
1231
if (indent + linelen < wraplen)
1234
AddC('<', linelen++);
1235
AddC('?', linelen++);
1237
/* set CDATA to pass < and > unescaped */
1238
PPrintText(fout, CDATA, indent,
1239
lexer, node->start, node->end);
1241
if (lexer->lexbuf[node->end - 1] != '?')
1242
AddC('?', linelen++);
1244
AddC('>', linelen++);
1246
PCondFlushLine(fout, indent);
1249
static void PPrintXmlDecl(Out *fout, uint indent,
1250
Lexer *lexer, Node *node)
1252
if (indent + linelen < wraplen)
1255
AddC('<', linelen++);
1256
AddC('?', linelen++);
1257
AddC('x', linelen++);
1258
AddC('m', linelen++);
1259
AddC('l', linelen++);
1261
PPrintAttrs(fout, indent, lexer, node, node->attributes);
1263
if (lexer->lexbuf[node->end - 1] != '?')
1264
AddC('?', linelen++);
1266
AddC('>', linelen++);
1268
PCondFlushLine(fout, indent);
1271
/* note ASP and JSTE share <% ... %> syntax */
1272
static void PPrintAsp(Out *fout, uint indent,
1273
Lexer *lexer, Node *node)
1275
int savewraplen = wraplen;
1277
/* disable wrapping if so requested */
1279
if (!WrapAsp || !WrapJste)
1280
wraplen = 0xFFFFFF; /* a very large number */
1283
if (indent + linelen < wraplen)
1286
AddC('<', linelen++);
1287
AddC('%', linelen++);
1289
PPrintText(fout, (WrapAsp ? CDATA : COMMENT), indent,
1290
lexer, node->start, node->end);
1292
AddC('%', linelen++);
1293
AddC('>', linelen++);
1294
/* PCondFlushLine(fout, indent); */
1295
wraplen = savewraplen;
1298
/* JSTE also supports <# ... #> syntax */
1299
static void PPrintJste(Out *fout, uint indent,
1300
Lexer *lexer, Node *node)
1302
int savewraplen = wraplen;
1304
/* disable wrapping if so requested */
1307
wraplen = 0xFFFFFF; /* a very large number */
1309
AddC('<', linelen++);
1310
AddC('#', linelen++);
1312
PPrintText(fout, (WrapJste ? CDATA : COMMENT), indent,
1313
lexer, node->start, node->end);
1315
AddC('#', linelen++);
1316
AddC('>', linelen++);
1317
/* PCondFlushLine(fout, indent); */
1318
wraplen = savewraplen;
1321
/* PHP is based on XML processing instructions */
1322
static void PPrintPhp(Out *fout, uint indent,
1323
Lexer *lexer, Node *node)
1325
int savewraplen = wraplen;
1327
/* disable wrapping if so requested */
1330
wraplen = 0xFFFFFF; /* a very large number */
1333
if (indent + linelen < wraplen)
1336
AddC('<', linelen++);
1337
AddC('?', linelen++);
1339
PPrintText(fout, (WrapPhp ? CDATA : COMMENT), indent,
1340
lexer, node->start, node->end);
1342
AddC('?', linelen++);
1343
AddC('>', linelen++);
1344
/* PCondFlushLine(fout, indent); */
1345
wraplen = savewraplen;
1348
static void PPrintCDATA(Out *fout, uint indent,
1349
Lexer *lexer, Node *node)
1351
int savewraplen = wraplen;
1356
PCondFlushLine(fout, indent);
1358
/* disable wrapping */
1360
wraplen = 0xFFFFFF; /* a very large number */
1362
AddC('<', linelen++);
1363
AddC('!', linelen++);
1364
AddC('[', linelen++);
1365
AddC('C', linelen++);
1366
AddC('D', linelen++);
1367
AddC('A', linelen++);
1368
AddC('T', linelen++);
1369
AddC('A', linelen++);
1370
AddC('[', linelen++);
1372
PPrintText(fout, COMMENT, indent,
1373
lexer, node->start, node->end);
1375
AddC(']', linelen++);
1376
AddC(']', linelen++);
1377
AddC('>', linelen++);
1378
PCondFlushLine(fout, indent);
1379
wraplen = savewraplen;
1382
static void PPrintSection(Out *fout, uint indent,
1383
Lexer *lexer, Node *node)
1385
int savewraplen = wraplen;
1387
/* disable wrapping if so requested */
1390
wraplen = 0xFFFFFF; /* a very large number */
1393
if (indent + linelen < wraplen)
1396
AddC('<', linelen++);
1397
AddC('!', linelen++);
1398
AddC('[', linelen++);
1400
PPrintText(fout, (WrapSection ? CDATA : COMMENT), indent,
1401
lexer, node->start, node->end);
1403
AddC(']', linelen++);
1404
AddC('>', linelen++);
1405
/* PCondFlushLine(fout, indent); */
1406
wraplen = savewraplen;
1412
** Print script and style elements. For XHTML, wrap the content as follows:
1432
static char* CDATA_START = "<![CDATA[";
1433
static char* CDATA_END = "]]>";
1434
static char* JS_COMMENT_START = "//";
1435
static char* JS_COMMENT_END = "";
1436
static char* VB_COMMENT_START = "\'";
1437
static char* VB_COMMENT_END = "";
1438
static char* CSS_COMMENT_START = "/*";
1439
static char* CSS_COMMENT_END = "*/";
1440
static char* DEFAULT_COMMENT_START = "";
1441
static char* DEFAULT_COMMENT_END = "";
1444
static Bool HasCDATA( Lexer* lexer, Node* node )
1446
/* Scan forward through the textarray. Since the characters we're
1447
** looking for are < 0x7f, we don't have to do any UTF-8 decoding.
1449
char* start = lexer->lexbuf + node->start;
1450
int len = node->end - node->start + 1;
1452
if ( node->type != TextNode )
1455
return wsubstrn( start, len, CDATA_START );
1460
static Bool StartsWithCDATA( Lexer* lexer, Node* node, char* commentStart )
1462
/* Scan forward through the textarray. Since the characters we're
1463
** looking for are < 0x7f, we don't have to do any UTF-8 decoding.
1465
int i = node->start, j, end = node->end;
1467
if ( node->type != TextNode )
1470
/* Skip whitespace. */
1471
while ( i < end && lexer->lexbuf[i] <= ' ' )
1474
/* Check for starting comment delimiter. */
1475
for ( j = 0; j < wstrlen(commentStart); ++j )
1477
if ( i >= end || lexer->lexbuf[i] != commentStart[j] )
1482
/* Skip whitespace. */
1483
while ( i < end && lexer->lexbuf[i] <= ' ' )
1486
/* Check for "<![CDATA[". */
1487
for ( j = 0; j < wstrlen(CDATA_START); ++j )
1489
if (i >= end || lexer->lexbuf[i] != CDATA_START[j])
1498
static Bool EndsWithCDATA( Lexer* lexer, Node* node,
1499
char* commentStart, char* commentEnd )
1501
/* Scan backward through the buff. Since the characters we're
1502
** looking for are < 0x7f, we don't have do any UTF-8 decoding. Note
1503
** that this is true even though we are scanning backwards because every
1504
** byte of a UTF-8 multibyte character is >= 0x80.
1507
int i = node->end - 1, j, start = node->start;
1509
if ( node->type != TextNode )
1512
/* Skip whitespace. */
1513
while ( i >= start && (lexer->lexbuf[i] & 0xff) <= ' ' )
1516
/* Check for ending comment delimiter. */
1517
for ( j = wstrlen(commentEnd) - 1; j >= 0; --j )
1519
if (i < start || lexer->lexbuf[i] != commentEnd[j])
1524
/* Skip whitespace. */
1525
while (i >= start && (lexer->lexbuf[i] & 0xff) <= ' ')
1528
/* Check for "]]>". */
1529
for (j = wstrlen(CDATA_END) - 1; j >= 0; j--)
1531
if (i < start || lexer->lexbuf[i] != CDATA_END[j])
1536
/* Skip whitespace. */
1537
while (i >= start && lexer->lexbuf[i] <= ' ')
1540
/* Check for starting comment delimiter. */
1541
for ( j = wstrlen(commentStart) - 1; j >= 0; --j )
1543
if ( i < start || lexer->lexbuf[i] != commentStart[j] )
1552
void PPrintScriptStyle( Out* fout, uint mode, uint indent,
1553
Lexer* lexer, Node* node )
1556
char* commentStart = DEFAULT_COMMENT_START;
1557
char* commentEnd = DEFAULT_COMMENT_END;
1560
PCondFlushLine(fout, indent);
1563
PPrintTag(lexer, fout, mode, indent, node);
1564
PFlushLine(fout, indent);
1566
if (xHTML && node->content != null)
1568
AttVal* type = GetAttrByName(node, "type");
1571
if (wstrcasecmp(type->value, "text/javascript") == 0)
1573
commentStart = JS_COMMENT_START;
1574
commentEnd = JS_COMMENT_END;
1576
else if (wstrcasecmp(type->value, "text/css") == 0)
1578
commentStart = CSS_COMMENT_START;
1579
commentEnd = CSS_COMMENT_END;
1581
else if (wstrcasecmp(type->value, "text/vbscript") == 0)
1583
commentStart = VB_COMMENT_START;
1584
commentEnd = VB_COMMENT_END;
1588
hasCData = HasCDATA( lexer, node->content );
1591
/* disable wrapping */
1592
uint savewraplen = wraplen;
1593
wraplen = 0xFFFFFF; /* a very large number */
1595
AddAsciiString( commentStart, linelen );
1596
AddAsciiString( CDATA_START, linelen );
1597
AddAsciiString( commentEnd, linelen );
1598
PCondFlushLine( fout, indent );
1600
/* restore wrapping */
1601
wraplen = savewraplen;
1605
for ( content = node->content;
1607
content = content->next )
1609
PPrintTree( fout, (mode | PREFORMATTED | NOWRAP |CDATA),
1610
indent, lexer, content );
1613
PCondFlushLine(fout, indent);
1615
if (xHTML && node->content != null)
1619
/* disable wrapping */
1620
uint savewraplen = wraplen;
1621
wraplen = 0xFFFFFF; /* a very large number */
1623
AddAsciiString( commentStart, linelen );
1624
AddAsciiString( CDATA_END, linelen );
1625
AddAsciiString( commentEnd, linelen );
1627
/* restore wrapping */
1628
wraplen = savewraplen;
1629
PCondFlushLine(fout, indent);
1633
PPrintEndTag(fout, mode, indent, node);
1634
PFlushLine(fout, indent);
1636
if (IndentContent == no && node->next != null)
1637
PFlushLine(fout, indent);
1642
static Bool ShouldIndent(Node *node)
1644
if (IndentContent == no)
1649
if (node->content && (node->tag->model & CM_NO_INDENT))
1651
for (node = node->content; node; node = node->next)
1652
if (node->tag && node->tag->model & CM_BLOCK)
1658
if (node->tag->model & CM_HEADING)
1661
if (node->tag == tag_p)
1664
if (node->tag == tag_title)
1668
if (node->tag->model & (CM_FIELD | CM_OBJECT))
1671
if (node->tag == tag_map)
1674
return (Bool)(!(node->tag->model & CM_INLINE));
1678
Feature request #434940 - fix by Dave Raggett/Ignacio Vazquez-Abrams 21 Jun 01
1679
print just the content of the body element.
1680
useful when you want to reuse material from
1683
-- Sebastiano Vigna <vigna@dsi.unimi.it>
1685
void PrintBody(Out *fout, Lexer *lexer, Node *root)
1687
Node *content, *body = FindBody(root);
1691
for (content = body->content;
1693
content = content->next)
1694
PPrintTree(fout, null, 0, lexer, content);
1698
void PPrintTree(Out *fout, uint mode, uint indent,
1699
Lexer *lexer, Node *node)
1701
Node *content, *last;
1706
if (node->type == TextNode ||
1707
(node->type == CDATATag && EscapeCdata))
1708
PPrintText(fout, mode, indent,
1709
lexer, node->start, node->end);
1710
else if (node->type == CommentTag)
1712
PPrintComment(fout, indent, lexer, node);
1714
else if (node->type == RootNode)
1716
for (content = node->content;
1718
content = content->next)
1719
PPrintTree(fout, mode, indent, lexer, content);
1721
else if (node->type == DocTypeTag)
1722
PPrintDocType(fout, indent, lexer, node);
1723
else if (node->type == ProcInsTag)
1724
PPrintPI(fout, indent, lexer, node);
1725
else if (node->type == XmlDecl)
1726
PPrintXmlDecl(fout, indent, lexer, node);
1727
else if (node->type == CDATATag)
1728
PPrintCDATA(fout, indent, lexer, node);
1729
else if (node->type == SectionTag)
1730
PPrintSection(fout, indent, lexer, node);
1731
else if (node->type == AspTag)
1732
PPrintAsp(fout, indent, lexer, node);
1733
else if (node->type == JsteTag)
1734
PPrintJste(fout, indent, lexer, node);
1735
else if (node->type == PhpTag)
1736
PPrintPhp(fout, indent, lexer, node);
1737
else if (node->tag->model & CM_EMPTY || (node->type == StartEndTag && !xHTML))
1739
if (!(node->tag->model & CM_INLINE))
1740
PCondFlushLine(fout, indent);
1742
if (node->tag == tag_br && node->prev && node->prev->tag != tag_br && BreakBeforeBR)
1743
PFlushLine(fout, indent);
1745
if (MakeClean && node->tag == tag_wbr)
1746
PPrintString(fout, indent, " ");
1748
PPrintTag(lexer, fout, mode, indent, node);
1750
if (node->tag == tag_param || node->tag == tag_area)
1751
PCondFlushLine(fout, indent);
1752
else if (node->tag == tag_br || node->tag == tag_hr)
1753
PFlushLine(fout, indent);
1755
else /* some kind of container element */
1757
if (node->tag && node->tag->parser == ParsePre)
1759
PCondFlushLine(fout, indent);
1762
PCondFlushLine(fout, indent);
1763
PPrintTag(lexer, fout, mode, indent, node);
1764
PFlushLine(fout, indent);
1766
for (content = node->content;
1768
content = content->next)
1769
PPrintTree(fout, (mode | PREFORMATTED | NOWRAP), indent, lexer, content);
1771
PCondFlushLine(fout, indent);
1772
PPrintEndTag(fout, mode, indent, node);
1773
PFlushLine(fout, indent);
1775
if (IndentContent == no && node->next != null)
1776
PFlushLine(fout, indent);
1778
else if (node->tag == tag_style || node->tag == tag_script)
1780
PPrintScriptStyle( fout, (mode | PREFORMATTED | NOWRAP |CDATA),
1781
indent, lexer, node );
1783
else if (node->tag->model & CM_INLINE)
1787
/* discards <font> and </font> tags */
1788
if (node->tag == tag_font)
1790
for (content = node->content;
1792
content = content->next)
1793
PPrintTree(fout, mode, indent, lexer, content);
1797
/* replace <nobr>...</nobr> by or   etc. */
1798
if (node->tag == tag_nobr)
1800
for (content = node->content;
1802
content = content->next)
1803
PPrintTree(fout, mode|NOWRAP, indent, lexer, content);
1808
/* otherwise a normal inline element */
1810
PPrintTag(lexer, fout, mode, indent, node);
1812
/* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */
1814
if (ShouldIndent(node))
1816
PCondFlushLine(fout, indent);
1819
for (content = node->content;
1821
content = content->next)
1822
PPrintTree(fout, mode, indent, lexer, content);
1824
PCondFlushLine(fout, indent);
1826
PCondFlushLine(fout, indent);
1831
for (content = node->content;
1833
content = content->next)
1834
PPrintTree(fout, mode, indent, lexer, content);
1837
PPrintEndTag(fout, mode, indent, node);
1839
else /* other tags */
1841
PCondFlushLine(fout, indent);
1843
if (SmartIndent && node->prev != null)
1844
PFlushLine(fout, indent);
1846
/* do not omit elements with attributes */
1847
if (HideEndTags == no ||
1848
!(node->tag && (node->tag->model & CM_OMITST)) ||
1849
node->attributes != null)
1851
PPrintTag(lexer, fout, mode, indent, node);
1853
if (ShouldIndent(node))
1854
PCondFlushLine(fout, indent);
1855
else if (node->tag->model & CM_HTML || node->tag == tag_noframes ||
1856
(node->tag->model & CM_HEAD && !(node->tag == tag_title)))
1857
PFlushLine(fout, indent);
1860
if (node->tag == tag_body && BurstSlides)
1861
PPrintSlide(fout, mode, (IndentContent ? indent+spaces : indent), lexer);
1866
for (content = node->content;
1867
content != null; content = content->next)
1869
/* kludge for naked text before block level tag */
1870
if (last && !IndentContent && last->type == TextNode &&
1871
content->tag && content->tag->model & CM_BLOCK)
1873
PFlushLine(fout, indent);
1874
PFlushLine(fout, indent);
1877
PPrintTree(fout, mode,
1878
(ShouldIndent(node) ? indent+spaces : indent), lexer, content);
1884
/* don't flush line for td and th */
1885
if (ShouldIndent(node) ||
1886
((node->tag->model & CM_HTML || node->tag == tag_noframes ||
1887
(node->tag->model & CM_HEAD && !(node->tag == tag_title)))
1888
&& HideEndTags == no))
1890
PCondFlushLine(fout, (IndentContent ? indent+spaces : indent));
1892
if (HideEndTags == no || !(node->tag->model & CM_OPT))
1894
PPrintEndTag(fout, mode, indent, node);
1895
PFlushLine(fout, indent);
1900
if (HideEndTags == no || !(node->tag->model & CM_OPT))
1901
PPrintEndTag(fout, mode, indent, node);
1903
PFlushLine(fout, indent);
1906
if (IndentContent == no &&
1907
node->next != null &&
1908
HideEndTags == no &&
1909
(node->tag->model & (CM_BLOCK|CM_LIST|CM_DEFLIST|CM_TABLE)))
1911
PFlushLine(fout, indent);
1917
void PPrintXMLTree(Out *fout, uint mode, uint indent,
1918
Lexer *lexer, Node *node)
1923
if (node->type == TextNode ||
1924
(node->type == CDATATag && EscapeCdata))
1926
PPrintText(fout, mode, indent,
1927
lexer, node->start, node->end);
1929
else if (node->type == CommentTag)
1931
PCondFlushLine(fout, indent);
1932
PPrintComment(fout, 0, lexer, node);
1933
PCondFlushLine(fout, 0);
1935
else if (node->type == RootNode)
1939
for (content = node->content;
1941
content = content->next)
1942
PPrintXMLTree(fout, mode, indent, lexer, content);
1944
else if (node->type == DocTypeTag)
1945
PPrintDocType(fout, indent, lexer, node);
1946
else if (node->type == ProcInsTag)
1947
PPrintPI(fout, indent, lexer, node);
1948
else if (node->type == XmlDecl)
1949
PPrintXmlDecl(fout, indent, lexer, node);
1950
else if (node->type == CDATATag)
1951
PPrintCDATA(fout, indent, lexer, node);
1952
else if (node->type == SectionTag)
1953
PPrintSection(fout, indent, lexer, node);
1954
else if (node->type == AspTag)
1955
PPrintAsp(fout, indent, lexer, node);
1956
else if (node->type == JsteTag)
1957
PPrintJste(fout, indent, lexer, node);
1958
else if (node->type == PhpTag)
1959
PPrintPhp(fout, indent, lexer, node);
1960
else if (node->tag->model & CM_EMPTY || (node->type == StartEndTag && !xHTML))
1962
PCondFlushLine(fout, indent);
1963
PPrintTag(lexer, fout, mode, indent, node);
1964
PFlushLine(fout, indent);
1967
PFlushLine(fout, indent);
1969
else /* some kind of container element */
1975
for (content = node->content; content; content = content->next)
1977
if (content->type == TextNode)
1984
PCondFlushLine(fout, indent);
1986
if (XMLPreserveWhiteSpace(node))
1995
cindent = indent + spaces;
1997
PPrintTag(lexer, fout, mode, indent, node);
2000
PFlushLine(fout, indent);
2002
for (content = node->content;
2004
content = content->next)
2005
PPrintXMLTree(fout, mode, cindent, lexer, content);
2008
PCondFlushLine(fout, cindent);
2010
PPrintEndTag(fout, mode, indent, node);
2011
PCondFlushLine(fout, indent);
2014
PFlushLine(fout, indent);
2018
/* split parse tree by h2 elements and output to separate files */
2020
/* counts number of h2 children (if any) belonging to node */
2021
int CountSlides(Node *node)
2023
int n = 1; /* assume minimum of 1 slide */
2025
/* #431716 - fix by Terry Teague 01 Jul 01 */
2026
if (node && node->content && node->content->tag == tag_h2)
2027
n--; /* "first" slide is empty, so ignore it */
2029
for (node = node->content; node; node = node->next)
2030
if (node->tag == tag_h2)
2037
inserts a space gif called "dot.gif" to ensure
2038
that the slide is at least n pixels high
2040
static void PrintVertSpacer(Out *fout, uint indent)
2042
PCondFlushLine(fout, indent);
2043
PPrintString(fout, indent ,
2044
"<img width=\"0\" height=\"0\" hspace=\"1\" src=\"dot.gif\" vspace=\"%d\" align=\"left\">");
2045
PCondFlushLine(fout, indent);
2048
static void PrintNavBar(Out *fout, uint indent)
2052
PCondFlushLine(fout, indent);
2053
PPrintString(fout, indent , "<center><small>");
2057
sprintf(buf, "<a href=\"slide%03d.html\">previous</a> | ", slide-1); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2058
PPrintString(fout, indent , buf);
2059
PCondFlushLine(fout, indent);
2062
PPrintString(fout, indent , "<a href=\"slide001.html\">start</a> | "); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2064
PPrintString(fout, indent , "<a href=\"slide001.html\">start</a>"); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2066
PCondFlushLine(fout, indent);
2071
sprintf(buf, "<a href=\"slide%03d.html\">next</a>", slide+1); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2072
PPrintString(fout, indent , buf);
2075
PPrintString(fout, indent , "</small></center>");
2076
PCondFlushLine(fout, indent);
2080
Called from PPrintTree to print the content of a slide from
2081
the node slidecontent. On return slidecontent points to the
2082
node starting the next slide or null. The variables slide
2083
and count are used to customise the navigation bar.
2085
void PPrintSlide(Out *fout, uint mode, uint indent, Lexer *lexer)
2087
Node *content, *last;
2090
/* insert div for onclick handler */
2091
sprintf(buf, "<div onclick=\"document.location='slide%03d.html'\">", /* #427666 - fix by Eric Rossen 02 Aug 00 */
2092
(slide < count ? slide + 1 : 1));
2093
PPrintString(fout, indent, buf);
2094
PCondFlushLine(fout, indent);
2096
/* first print the h2 element and navbar */
2097
if (slidecontent && slidecontent->tag == tag_h2) /* #431716 - fix by Terry Teague 01 Jul 01 */
2099
PrintNavBar(fout, indent);
2101
/* now print an hr after h2 */
2103
AddC('<', linelen++);
2106
AddC(FoldCase('h', UpperCaseTags), linelen++);
2107
AddC(FoldCase('r', UpperCaseTags), linelen++);
2110
PPrintString(fout, indent , " />");
2112
AddC('>', linelen++);
2115
if (IndentContent == yes)
2116
PCondFlushLine(fout, indent);
2118
/* PrintVertSpacer(fout, indent); */
2120
/*PCondFlushLine(fout, indent); */
2122
/* print the h2 element */
2123
PPrintTree(fout, mode,
2124
(IndentContent ? indent+spaces : indent), lexer, slidecontent);
2126
slidecontent = slidecontent->next;
2129
/* now continue until we reach the next h2 (or end) */
2132
content = slidecontent;
2134
for (; content != null; content = content->next)
2136
if (content->tag == tag_h2)
2139
/* kludge for naked text before block level tag */
2140
if (last && !IndentContent && last->type == TextNode &&
2141
content->tag && content->tag->model & CM_BLOCK)
2143
PFlushLine(fout, indent);
2144
PFlushLine(fout, indent);
2147
PPrintTree(fout, mode,
2148
(IndentContent ? indent+spaces : indent), lexer, content);
2153
slidecontent = content;
2155
/* now print epilog */
2157
PCondFlushLine(fout, indent);
2159
PPrintString(fout, indent , "<br clear=\"all\">");
2160
PCondFlushLine(fout, indent);
2162
AddC('<', linelen++);
2165
AddC(FoldCase('h', UpperCaseTags), linelen++);
2166
AddC(FoldCase('r', UpperCaseTags), linelen++);
2169
PPrintString(fout, indent , " />");
2171
AddC('>', linelen++);
2174
if (IndentContent == yes)
2175
PCondFlushLine(fout, indent);
2177
PrintNavBar(fout, indent);
2179
/* end tag for div */
2180
PPrintString(fout, indent, "</div>");
2181
PCondFlushLine(fout, indent);
2185
Add meta element for page transition effect, this works on IE but not NS
2188
void AddTransitionEffect(Lexer *lexer, Node *root, int effect, float duration)
2190
Node *head = FindHEAD(root);
2191
char transition[128];
2193
if (0 <= effect && effect <= 23)
2194
sprintf(transition, "revealTrans(Duration=%g,Transition=%d)", duration, effect);
2196
sprintf(transition, "blendTrans(Duration=%g)", duration);
2200
Node *meta = InferredTag(lexer, "meta");
2201
AddAttribute(meta, "http-equiv", "Page-Enter");
2202
AddAttribute(meta, "content", transition);
2203
InsertNodeAtStart(head, meta);
2207
void CreateSlides(Lexer *lexer, Node *root)
2214
body = FindBody(root);
2215
count = CountSlides(body);
2216
slidecontent = body->content;
2217
AddTransitionEffect(lexer, root, EFFECT_BLEND, 3.0);
2219
for (slide = 1; slide <= count; ++slide)
2221
sprintf(buf, "slide%03d.html", slide); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2222
out.state = FSM_ASCII;
2223
out.encoding = outCharEncoding;
2225
if ((fp = fopen(buf, "w")))
2228
PPrintTree(&out, null, 0, lexer, root);
2229
PFlushLine(&out, 0);
2235
delete superfluous slides by deleting slideN.html
2236
for N = count+1, count+2, etc. until no such file
2242
sprintf(buf, "slide%03d.html", slide); /* #427666 - fix by Eric Rossen 02 Aug 00 */
2244
if (unlink(buf) != 0)