X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/tidy/PPrint.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/tidy/PPrint.java new file mode 100644 index 0000000..435e606 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/tidy/PPrint.java @@ -0,0 +1,1845 @@ +/* + * @(#)PPrint.java 1.11 2000/08/16 + * + */ + +package net.sourceforge.phpdt.tidy; + +/** + * + * Pretty print parse tree + * + * (c) 1998-2000 (W3C) MIT, INRIA, Keio University + * See Tidy.java for the copyright notice. + * Derived from + * HTML Tidy Release 4 Aug 2000 + * + * @author Dave Raggett + * @author Andy Quick (translation to Java) + * @version 1.0, 1999/05/22 + * @version 1.0.1, 1999/05/29 + * @version 1.1, 1999/06/18 Java Bean + * @version 1.2, 1999/07/10 Tidy Release 7 Jul 1999 + * @version 1.3, 1999/07/30 Tidy Release 26 Jul 1999 + * @version 1.4, 1999/09/04 DOM support + * @version 1.5, 1999/10/23 Tidy Release 27 Sep 1999 + * @version 1.6, 1999/11/01 Tidy Release 22 Oct 1999 + * @version 1.7, 1999/12/06 Tidy Release 30 Nov 1999 + * @version 1.8, 2000/01/22 Tidy Release 13 Jan 2000 + * @version 1.9, 2000/06/03 Tidy Release 30 Apr 2000 + * @version 1.10, 2000/07/22 Tidy Release 8 Jul 2000 + * @version 1.11, 2000/08/16 Tidy Release 4 Aug 2000 + */ + +/* + 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 +*/ + +import java.io.FileOutputStream; +import java.io.File; + +import java.io.IOException; +import java.io.FileNotFoundException; + +public class PPrint { + + /* page transition effects */ + + public static final short EFFECT_BLEND = -1; + public static final short EFFECT_BOX_IN = 0; + public static final short EFFECT_BOX_OUT = 1; + public static final short EFFECT_CIRCLE_IN = 2; + public static final short EFFECT_CIRCLE_OUT = 3; + public static final short EFFECT_WIPE_UP = 4; + public static final short EFFECT_WIPE_DOWN = 5; + public static final short EFFECT_WIPE_RIGHT = 6; + public static final short EFFECT_WIPE_LEFT = 7; + public static final short EFFECT_VERT_BLINDS = 8; + public static final short EFFECT_HORZ_BLINDS = 9; + public static final short EFFECT_CHK_ACROSS = 10; + public static final short EFFECT_CHK_DOWN = 11; + public static final short EFFECT_RND_DISSOLVE = 12; + public static final short EFFECT_SPLIT_VIRT_IN = 13; + public static final short EFFECT_SPLIT_VIRT_OUT = 14; + public static final short EFFECT_SPLIT_HORZ_IN = 15; + public static final short EFFECT_SPLIT_HORZ_OUT = 16; + public static final short EFFECT_STRIPS_LEFT_DOWN = 17; + public static final short EFFECT_STRIPS_LEFT_UP = 18; + public static final short EFFECT_STRIPS_RIGHT_DOWN = 19; + public static final short EFFECT_STRIPS_RIGHT_UP = 20; + public static final short EFFECT_RND_BARS_HORZ = 21; + public static final short EFFECT_RND_BARS_VERT = 22; + public static final short EFFECT_RANDOM = 23; + + private static final short NORMAL = 0; + private static final short PREFORMATTED = 1; + private static final short COMMENT = 2; + private static final short ATTRIBVALUE = 4; + private static final short NOWRAP = 8; + private static final short CDATA = 16; + + private int[] linebuf = null; + private int lbufsize = 0; + private int linelen = 0; + private int wraphere = 0; + private boolean inAttVal = false; + private boolean InString = false; + + private int slide = 0; + private int count = 0; + private Node slidecontent = null; + + private Configuration configuration; + + public PPrint(Configuration configuration) + { + this.configuration = configuration; + } + + /* + 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 */ + public static int getUTF8(byte[] str, int start, MutableInteger ch) + { + int c, n, i, bytes; + + c = ((int)str[start]) & 0xFF; // Convert to unsigned. + + if ((c & 0xE0) == 0xC0) /* 110X XXXX two bytes */ + { + n = c & 31; + bytes = 2; + } + else if ((c & 0xF0) == 0xE0) /* 1110 XXXX three bytes */ + { + n = c & 15; + bytes = 3; + } + else if ((c & 0xF8) == 0xF0) /* 1111 0XXX four bytes */ + { + n = c & 7; + bytes = 4; + } + else if ((c & 0xFC) == 0xF8) /* 1111 10XX five bytes */ + { + n = c & 3; + bytes = 5; + } + else if ((c & 0xFE) == 0xFC) /* 1111 110X six bytes */ + + { + n = c & 1; + bytes = 6; + } + else /* 0XXX XXXX one byte */ + { + ch.value = c; + return 0; + } + + /* successor bytes should have the form 10XX XXXX */ + for (i = 1; i < bytes; ++i) + { + c = ((int)str[start + i]) & 0xFF; // Convert to unsigned. + n = (n << 6) | (c & 0x3F); + } + + ch.value = n; + return bytes - 1; + } + + /* store char c as UTF-8 encoded byte stream */ + public static int putUTF8(byte[] buf, int start, int c) + { + if (c < 128) + buf[start++] = (byte)c; + else if (c <= 0x7FF) + { + buf[start++] = (byte)(0xC0 | (c >> 6)); + buf[start++] = (byte)(0x80 | (c & 0x3F)); + } + else if (c <= 0xFFFF) + { + buf[start++] = (byte)(0xE0 | (c >> 12)); + buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F)); + buf[start++] = (byte)(0x80 | (c & 0x3F)); + } + else if (c <= 0x1FFFFF) + { + buf[start++] = (byte)(0xF0 | (c >> 18)); + buf[start++] = (byte)(0x80 | ((c >> 12) & 0x3F)); + buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F)); + buf[start++] = (byte)(0x80 | (c & 0x3F)); + } + else + { + buf[start++] = (byte)(0xF8 | (c >> 24)); + buf[start++] = (byte)(0x80 | ((c >> 18) & 0x3F)); + buf[start++] = (byte)(0x80 | ((c >> 12) & 0x3F)); + buf[start++] = (byte)(0x80 | ((c >> 6) & 0x3F)); + buf[start++] = (byte)(0x80 | (c & 0x3F)); + } + + return start; + } + + private void addC(int c, int index) + { + if (index + 1 >= lbufsize) + { + while (index + 1 >= lbufsize) + { + if (lbufsize == 0) + lbufsize = 256; + else + lbufsize = lbufsize * 2; + } + + int[] temp = new int[ lbufsize ]; + if (linebuf != null) + System.arraycopy(linebuf, 0, temp, 0, index); + linebuf = temp; + } + + linebuf[index] = c; + } + + private void wrapLine(Out fout, int indent) + { + int i, p, q; + + if (wraphere == 0) + return; + + for (i = 0; i < indent; ++i) + fout.outc((int)' '); + + for (i = 0; i < wraphere; ++i) + fout.outc(linebuf[i]); + + if (InString) + { + fout.outc((int)' '); + fout.outc((int)'\\'); + } + + fout.newline(); + + if (linelen > wraphere) + { + p = 0; + + if (linebuf[wraphere] == ' ') + ++wraphere; + + q = wraphere; + addC('\0', linelen); + + while (true) + { + linebuf[p] = linebuf[q]; + if (linebuf[q] == 0) break; + p++; + q++; + } + linelen -= wraphere; + } + else + linelen = 0; + + wraphere = 0; + } + + private void wrapAttrVal(Out fout, int indent, boolean inString) + { + int i, p, q; + + for (i = 0; i < indent; ++i) + fout.outc((int)' '); + + for (i = 0; i < wraphere; ++i) + fout.outc(linebuf[i]); + + fout.outc((int)' '); + + if (inString) + fout.outc((int)'\\'); + + fout.newline(); + + if (linelen > wraphere) + { + p = 0; + + if (linebuf[wraphere] == ' ') + ++wraphere; + + q = wraphere; + addC('\0', linelen); + + while (true) + { + linebuf[p] = linebuf[q]; + if (linebuf[q] == 0) break; + p++; + q++; + } + linelen -= wraphere; + } + else + linelen = 0; + + wraphere = 0; + } + + public void flushLine(Out fout, int indent) + { + int i; + + if (linelen > 0) + { + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + if (!inAttVal || this.configuration.IndentAttributes) + { + for (i = 0; i < indent; ++i) + fout.outc((int)' '); + } + + for (i = 0; i < linelen; ++i) + fout.outc(linebuf[i]); + } + + fout.newline(); + linelen = 0; + wraphere = 0; + inAttVal = false; + } + + public void condFlushLine(Out fout, int indent) + { + int i; + + if (linelen > 0) + { + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + if (!inAttVal || this.configuration.IndentAttributes) + { + for (i = 0; i < indent; ++i) + fout.outc((int)' '); + } + + for (i = 0; i < linelen; ++i) + fout.outc(linebuf[i]); + + fout.newline(); + linelen = 0; + wraphere = 0; + inAttVal = false; + } + } + + private void printChar(int c, short mode) + { + String entity; + + if (c == ' ' && !((mode & (PREFORMATTED | COMMENT | ATTRIBVALUE)) != 0)) + { + /* coerce a space character to a non-breaking space */ + if ((mode & NOWRAP) != 0) + { + /* by default XML doesn't define   */ + if (this.configuration.NumEntities || this.configuration.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) != 0) + { + addC(c, linelen++); + return; + } + + /* except in CDATA map < to < etc. */ + if (! ((mode & CDATA) != 0) ) + { + 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 == '&' && this.configuration.QuoteAmpersand) + { + addC('&', linelen++); + addC('a', linelen++); + addC('m', linelen++); + addC('p', linelen++); + addC(';', linelen++); + return; + } + + if (c == '"' && this.configuration.QuoteMarks) + { + addC('&', linelen++); + addC('q', linelen++); + addC('u', linelen++); + addC('o', linelen++); + addC('t', linelen++); + addC(';', linelen++); + return; + } + + if (c == '\'' && this.configuration.QuoteMarks) + { + addC('&', linelen++); + addC('#', linelen++); + addC('3', linelen++); + addC('9', linelen++); + addC(';', linelen++); + return; + } + + if (c == 160 && this.configuration.CharEncoding != Configuration.RAW) + { + if (this.configuration.QuoteNbsp) + { + addC('&', linelen++); + + if (this.configuration.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 (this.configuration.CharEncoding == Configuration.ISO2022 || + this.configuration.CharEncoding == Configuration.RAW) + { + addC(c, linelen++); + return; + } + + /* if preformatted text, map   to space */ + if (c == 160 && ((mode & PREFORMATTED) != 0)) + { + 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. My thanks to + Andrzej Novosiolov for his help with this code. + */ + + if (this.configuration.MakeClean) + { + if (c >= 0x2013 && c <= 0x201E) + { + switch (c) { + case 0x2013: + case 0x2014: + c = '-'; + break; + case 0x2018: + case 0x2019: + case 0x201A: + c = '\''; + break; + case 0x201C: + case 0x201D: + case 0x201E: + c = '"'; + break; + } + } + } + + /* don't map latin-1 chars to entities */ + if (this.configuration.CharEncoding == Configuration.LATIN1) + { + if (c > 255) /* multi byte chars */ + { + if (!this.configuration.NumEntities) + { + entity = EntityTable.getDefaultEntityTable().entityName((short)c); + if (entity != null) + entity = "&" + entity + ";"; + else + entity = "&#" + c + ";"; + } + else + entity = "&#" + c + ";"; + + for (int i = 0; i < entity.length(); i++) + addC((int)entity.charAt(i), linelen++); + + return; + } + + if (c > 126 && c < 160) + { + entity = "&#" + c + ";"; + + for (int i = 0; i < entity.length(); i++) + addC((int)entity.charAt(i), linelen++); + + return; + } + + addC(c, linelen++); + return; + } + + /* don't map utf8 chars to entities */ + if (this.configuration.CharEncoding == Configuration.UTF8) + { + addC(c, linelen++); + return; + } + + /* use numeric entities only for XML */ + if (this.configuration.XmlTags) + { + /* if ASCII use numeric entities for chars > 127 */ + if (c > 127 && this.configuration.CharEncoding == Configuration.ASCII) + { + entity = "&#" + c + ";"; + + for (int i = 0; i < entity.length(); i++) + addC((int)entity.charAt(i), linelen++); + + return; + } + + /* otherwise output char raw */ + addC(c, linelen++); + return; + } + + /* default treatment for ASCII */ + if (c > 126 || (c < ' ' && c != '\t')) + { + if (!this.configuration.NumEntities) + { + entity = EntityTable.getDefaultEntityTable().entityName((short)c); + if (entity != null) + entity = "&" + entity + ";"; + else + entity = "&#" + c + ";"; + } + else + entity = "&#" + c + ";"; + + for (int i = 0; i < entity.length(); i++) + addC((int)entity.charAt(i), 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. + */ + private void printText(Out fout, short mode, int indent, + byte[] textarray, int start, int end) + { + int i, c; + MutableInteger ci = new MutableInteger(); + + for (i = start; i < end; ++i) + { + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + c = ((int)textarray[i]) & 0xFF; // Convert to unsigned. + + /* look for UTF-8 multibyte character */ + if (c > 0x7F) + { + i += getUTF8(textarray, i, ci); + c = ci.value; + } + + if (c == '\n') + { + flushLine(fout, indent); + continue; + } + + printChar(c, mode); + } + } + + private void printString(Out fout, int indent, String str) + { + for (int i = 0; i < str.length(); i++ ) + addC((int)str.charAt(i), linelen++); + } + + private void printAttrValue(Out fout, int indent, String value, int delim, boolean wrappable) + { + int c; + MutableInteger ci = new MutableInteger(); + boolean wasinstring = false; + byte[] valueChars = null; + int i; + short mode = (wrappable ? (short)(NORMAL | ATTRIBVALUE) : + (short)(PREFORMATTED | ATTRIBVALUE)); + + if (value != null) + { + valueChars = Lexer.getBytes(value); + } + + /* look for ASP, Tango or PHP instructions for computed attribute value */ + if (valueChars != null && valueChars.length >= 5 && valueChars[0] == '<') + { + if (valueChars[1] == '%' || valueChars[1] == '@'|| + (new String(valueChars, 0, 5)).equals("= this.configuration.wraplen) + wrapLine(fout, indent); + + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; + else + condFlushLine(fout, indent); + } + + addC(delim, linelen++); + + if (value != null) + { + InString = false; + + i = 0; + while (i < valueChars.length) + { + c = ((int)valueChars[i]) & 0xFF; // Convert to unsigned. + + if (wrappable && c == ' ' && indent + linelen < this.configuration.wraplen) + { + wraphere = linelen; + wasinstring = InString; + } + + if (wrappable && wraphere > 0 && indent + linelen >= this.configuration.wraplen) + wrapAttrVal(fout, indent, wasinstring); + + if (c == delim) + { + String entity; + + entity = (c == '"' ? """ : "'"); + + for (int j = 0; j < entity.length(); j++ ) + addC(entity.charAt(j), linelen++); + + ++i; + continue; + } + else if (c == '"') + { + if (this.configuration.QuoteMarks) + { + addC('&', linelen++); + addC('q', linelen++); + addC('u', linelen++); + addC('o', linelen++); + addC('t', linelen++); + addC(';', linelen++); + } + else + addC('"', linelen++); + + if (delim == '\'') + InString = !InString; + + ++i; + continue; + } + else if (c == '\'') + { + if (this.configuration.QuoteMarks) + { + addC('&', linelen++); + addC('#', linelen++); + addC('3', linelen++); + addC('9', linelen++); + addC(';', linelen++); + } + else + addC('\'', linelen++); + + if (delim == '"') + InString = !InString; + + ++i; + continue; + } + + /* look for UTF-8 multibyte character */ + if (c > 0x7F) + { + i += getUTF8(valueChars, i, ci); + c = ci.value; + } + + ++i; + + if (c == '\n') + { + flushLine(fout, indent); + continue; + } + + printChar(c, mode); + } + } + + InString = false; + addC(delim, linelen++); + } + + private void printAttribute(Out fout, int indent, Node node, AttVal attr) + { + String name; + boolean wrappable = false; + + if (this.configuration.IndentAttributes) + { + flushLine(fout, indent); + indent += this.configuration.spaces; + } + + name = attr.attribute; + + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + if (!this.configuration.XmlTags && !this.configuration.XmlOut && attr.dict != null) + { + if (AttributeTable.getDefaultAttributeTable().isScript(name)) + wrappable = this.configuration.WrapScriptlets; + else if (!attr.dict.nowrap && this.configuration.WrapAttVals) + wrappable = true; + } + + if (indent + linelen < this.configuration.wraplen) + { + wraphere = linelen; + addC(' ', linelen++); + } + else + { + condFlushLine(fout, indent); + addC(' ', linelen++); + } + + for (int i = 0; i < name.length(); i++ ) + addC((int)Lexer.foldCase(name.charAt(i), + this.configuration.UpperCaseAttrs, + this.configuration.XmlTags), + linelen++); + + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + if (attr.value == null) + { + if (this.configuration.XmlTags || this.configuration.XmlOut) + printAttrValue(fout, indent, attr.attribute, attr.delim, true); + else if (!attr.isBoolAttribute() && !Node.isNewNode(node)) + printAttrValue(fout, indent, "", attr.delim, true); + else if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; + + } + else + printAttrValue(fout, indent, attr.value, attr.delim, wrappable); + } + + private void printAttrs(Out fout, int indent, + Node node, AttVal attr) + { + if (attr != null) + { + if (attr.next != null) + printAttrs(fout, indent, node, attr.next); + + if (attr.attribute != null) + printAttribute(fout, indent, node, attr); + else if (attr.asp != null) + { + addC(' ', linelen++); + printAsp(fout, indent, attr.asp); + } + else if (attr.php != null) + { + addC(' ', linelen++); + printPhp(fout, indent, attr.php); + } + } + + /* add xml:space attribute to pre and other elements */ + if (configuration.XmlOut && + configuration.XmlSpace && + ParserImpl.XMLPreserveWhiteSpace(node, configuration.tt) && + node.getAttrByName("xml:space") == null) + printString(fout, indent, " xml:space=\"preserve\""); + } + + /* + 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 + */ + private static boolean afterSpace(Node node) + { + Node prev; + int c; + + if (node == null || node.tag == null || !((node.tag.model & Dict.CM_INLINE) != 0)) + return true; + + prev = node.prev; + + if (prev != null) + { + if (prev.type == Node.TextNode && prev.end > prev.start) + { + c = ((int)prev.textarray[prev.end - 1]) & 0xFF; // Convert to unsigned. + + if (c == 160 || c == ' ' || c == '\n') + return true; + } + + return false; + } + + return afterSpace(node.parent); + } + + private void printTag(Lexer lexer, Out fout, short mode, int indent, Node node) + { + char c; + String p; + TagTable tt = this.configuration.tt; + + addC('<', linelen++); + + if (node.type == Node.EndTag) + addC('/', linelen++); + + p = node.element; + for (int i = 0; i < p.length(); i++ ) + addC((int)Lexer.foldCase(p.charAt(i), + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + + printAttrs(fout, indent, node, node.attributes); + + if ((this.configuration.XmlOut || lexer != null && lexer.isvoyager) && + (node.type == Node.StartEndTag || (node.tag.model & Dict.CM_EMPTY) != 0)) + { + addC(' ', linelen++); /* compatibility hack */ + addC('/', linelen++); + } + + addC('>', linelen++);; + + if (node.type != Node.StartEndTag && !((mode & PREFORMATTED) != 0)) + { + if (indent + linelen >= this.configuration.wraplen) + wrapLine(fout, indent); + + if (indent + linelen < this.configuration.wraplen) + { + /* + wrap after start tag if is
or if it's not + inline or it is an empty tag followed by + */ + if (afterSpace(node)) + { + if (!((mode & NOWRAP) != 0) && + (!((node.tag.model & Dict.CM_INLINE) != 0) || + (node.tag == tt.tagBr) || + (((node.tag.model & Dict.CM_EMPTY) != 0) && + node.next == null && + node.parent.tag == tt.tagA))) + { + wraphere = linelen; + } + } + } + else + condFlushLine(fout, indent); + } + } + + private void printEndTag(Out fout, short mode, int indent, Node node) + { + char c; + String p; + + /* + Netscape ignores SGML standard by not ignoring a + line break before or etc. To avoid rendering + this as an underlined space, I disable line wrapping + before inline end tags by the #if 0 ... #endif + */ +if (false) { + if (indent + linelen < this.configuration.wraplen && !((mode & NOWRAP) != 0)) + wraphere = linelen; +} + + addC('<', linelen++); + addC('/', linelen++); + + p = node.element; + for (int i = 0; i < p.length(); i++ ) + addC((int)Lexer.foldCase(p.charAt(i), + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + + addC('>', linelen++); + } + + private void printComment(Out fout, int indent, Node node) + { + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; + + addC('<', linelen++); + addC('!', linelen++); + addC('-', linelen++); + addC('-', linelen++); +if (false) { + if (linelen < this.configuration.wraplen) + wraphere = linelen; +} + printText(fout, COMMENT, indent, + node.textarray, node.start, node.end); +if (false) { + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; +} + // See Lexer.java: AQ 8Jul2000 + addC('-', linelen++); + addC('-', linelen++); + addC('>', linelen++); + + if (node.linebreak) + flushLine(fout, indent); + } + + private void printDocType(Out fout, int indent, Node node) + { + boolean q = this.configuration.QuoteMarks; + + this.configuration.QuoteMarks = false; + + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; + + condFlushLine(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 < this.configuration.wraplen) + wraphere = linelen; + + printText(fout, (short)0, indent, + node.textarray, node.start, node.end); + + if (linelen < this.configuration.wraplen) + wraphere = linelen; + + addC('>', linelen++); + this.configuration.QuoteMarks = q; + condFlushLine(fout, indent); + } + + private void printPI(Out fout, int indent, Node node) + { + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; + + addC('<', linelen++); + addC('?', linelen++); + + /* set CDATA to pass < and > unescaped */ + printText(fout, CDATA, indent, + node.textarray, node.start, node.end); + + if (node.textarray[node.end - 1] != (byte)'?') + addC('?', linelen++); + + addC('>', linelen++); + condFlushLine(fout, indent); + } + + /* note ASP and JSTE share <% ... %> syntax */ + private void printAsp(Out fout, int indent, Node node) + { + int savewraplen = this.configuration.wraplen; + + /* disable wrapping if so requested */ + + if (!this.configuration.WrapAsp || !this.configuration.WrapJste) + this.configuration.wraplen = 0xFFFFFF; /* a very large number */ +if (false) { //#if 0 + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; +} //#endif + + addC('<', linelen++); + addC('%', linelen++); + + printText(fout, (this.configuration.WrapAsp ? CDATA : COMMENT), indent, + node.textarray, node.start, node.end); + + addC('%', linelen++); + addC('>', linelen++); + /* condFlushLine(fout, indent); */ + this.configuration.wraplen = savewraplen; + } + + /* JSTE also supports <# ... #> syntax */ + private void printJste(Out fout, int indent, Node node) + { + int savewraplen = this.configuration.wraplen; + + /* disable wrapping if so requested */ + + if (!this.configuration.WrapJste) + this.configuration.wraplen = 0xFFFFFF; /* a very large number */ + + addC('<', linelen++); + addC('#', linelen++); + + printText(fout, (this.configuration.WrapJste ? CDATA : COMMENT), indent, + node.textarray, node.start, node.end); + + addC('#', linelen++); + addC('>', linelen++); + /* condFlushLine(fout, indent); */ + this.configuration.wraplen = savewraplen; + } + + /* PHP is based on XML processing instructions */ + private void printPhp(Out fout, int indent, Node node) + { + int savewraplen = this.configuration.wraplen; + + /* disable wrapping if so requested */ + + if (!this.configuration.WrapPhp) + this.configuration.wraplen = 0xFFFFFF; /* a very large number */ + +if (false) { //#if 0 + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; +} //#endif + addC('<', linelen++); + addC('?', linelen++); + + printText(fout, (this.configuration.WrapPhp ? CDATA : COMMENT), indent, + node.textarray, node.start, node.end); + + addC('?', linelen++); + addC('>', linelen++); + /* PCondFlushLine(fout, indent); */ + this.configuration.wraplen = savewraplen; + } + + private void printCDATA(Out fout, int indent, Node node) + { + int savewraplen = this.configuration.wraplen; + + condFlushLine(fout, indent); + + /* disable wrapping */ + + this.configuration.wraplen = 0xFFFFFF; /* a very large number */ + + addC('<', linelen++); + addC('!', linelen++); + addC('[', linelen++); + addC('C', linelen++); + addC('D', linelen++); + addC('A', linelen++); + addC('T', linelen++); + addC('A', linelen++); + addC('[', linelen++); + + printText(fout, COMMENT, indent, + node.textarray, node.start, node.end); + + addC(']', linelen++); + addC(']', linelen++); + addC('>', linelen++); + condFlushLine(fout, indent); + this.configuration.wraplen = savewraplen; + } + + private void printSection(Out fout, int indent, Node node) + { + int savewraplen = this.configuration.wraplen; + + /* disable wrapping if so requested */ + + if (!this.configuration.WrapSection) + this.configuration.wraplen = 0xFFFFFF; /* a very large number */ + +if (false) { //#if 0 + if (indent + linelen < this.configuration.wraplen) + wraphere = linelen; +} //#endif + addC('<', linelen++); + addC('!', linelen++); + addC('[', linelen++); + + printText(fout, (this.configuration.WrapSection ? CDATA : COMMENT), indent, + node.textarray, node.start, node.end); + + addC(']', linelen++); + addC('>', linelen++); + /* PCondFlushLine(fout, indent); */ + this.configuration.wraplen = savewraplen; + } + + private boolean shouldIndent(Node node) + { + TagTable tt = this.configuration.tt; + + if (!this.configuration.IndentContent) + return false; + + if (this.configuration.SmartIndent) + { + if (node.content != null && ((node.tag.model & Dict.CM_NO_INDENT) != 0)) + { + for (node = node.content; node != null; node = node.next) + if (node.tag != null && (node.tag.model & Dict.CM_BLOCK) != 0) + return true; + + return false; + } + + if ((node.tag.model & Dict.CM_HEADING) != 0) + return false; + + if (node.tag == tt.tagP) + return false; + + if (node.tag == tt.tagTitle) + return false; + } + + if ((node.tag.model & (Dict.CM_FIELD | Dict.CM_OBJECT)) != 0) + return true; + + if (node.tag == tt.tagMap) + return true; + + return !((node.tag.model & Dict.CM_INLINE) != 0); + } + + public void printTree(Out fout, short mode, int indent, + Lexer lexer, Node node) + { + Node content, last; + TagTable tt = this.configuration.tt; + + if (node == null) + return; + + if (node.type == Node.TextNode) + printText(fout, mode, indent, + node.textarray, node.start, node.end); + else if (node.type == Node.CommentTag) + { + printComment(fout, indent, node); + } + else if (node.type == Node.RootNode) + { + for (content = node.content; + content != null; + content = content.next) + printTree(fout, mode, indent, lexer, content); + } + else if (node.type == Node.DocTypeTag) + printDocType(fout, indent, node); + else if (node.type == Node.ProcInsTag) + printPI(fout, indent, node); + else if (node.type == Node.CDATATag) + printCDATA(fout, indent, node); + else if (node.type == Node.SectionTag) + printSection(fout, indent, node); + else if (node.type == Node.AspTag) + printAsp(fout, indent, node); + else if (node.type == Node.JsteTag) + printJste(fout, indent, node); + else if (node.type == Node.PhpTag) + printPhp(fout, indent, node); + else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag) + { + if (!((node.tag.model & Dict.CM_INLINE) != 0)) + condFlushLine(fout, indent); + + if (node.tag == tt.tagBr && node.prev != null && + node.prev.tag != tt.tagBr && this.configuration.BreakBeforeBR) + flushLine(fout, indent); + + if (this.configuration.MakeClean && node.tag == tt.tagWbr) + printString(fout, indent, " "); + else + printTag(lexer, fout, mode, indent, node); + + if (node.tag == tt.tagParam || node.tag == tt.tagArea) + condFlushLine(fout, indent); + else if (node.tag == tt.tagBr || node.tag == tt.tagHr) + flushLine(fout, indent); + } + else /* some kind of container element */ + { + if (node.tag != null && node.tag.parser == ParserImpl.getParsePre()) + { + condFlushLine(fout, indent); + + indent = 0; + condFlushLine(fout, indent); + printTag(lexer, fout, mode, indent, node); + flushLine(fout, indent); + + for (content = node.content; + content != null; + content = content.next) + printTree(fout, (short)(mode | PREFORMATTED | NOWRAP), indent, lexer, content); + + condFlushLine(fout, indent); + printEndTag(fout, mode, indent, node); + flushLine(fout, indent); + + if (this.configuration.IndentContent == false && node.next != null) + flushLine(fout, indent); + } + else if (node.tag == tt.tagStyle || node.tag == tt.tagScript) + { + condFlushLine(fout, indent); + + indent = 0; + condFlushLine(fout, indent); + printTag(lexer, fout, mode, indent, node); + flushLine(fout, indent); + + for (content = node.content; + content != null; + content = content.next) + printTree(fout, (short)(mode | PREFORMATTED | NOWRAP |CDATA), indent, lexer, content); + + condFlushLine(fout, indent); + printEndTag(fout, mode, indent, node); + flushLine(fout, indent); + + if (this.configuration.IndentContent == false && node.next != null) + flushLine(fout, indent); + } + else if ((node.tag.model & Dict.CM_INLINE) != 0) + { + if (this.configuration.MakeClean) + { + /* discards and tags */ + if (node.tag == tt.tagFont) + { + for (content = node.content; + content != null; + content = content.next) + printTree(fout, mode, indent, lexer, content); + return; + } + + /* replace ... by   or   etc. */ + if (node.tag == tt.tagNobr) + { + for (content = node.content; + content != null; + content = content.next) + printTree(fout, (short)(mode|NOWRAP), indent, lexer, content); + return; + } + } + + /* otherwise a normal inline element */ + + printTag(lexer, fout, mode, indent, node); + + /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */ + + if (shouldIndent(node)) + { + condFlushLine(fout, indent); + indent += this.configuration.spaces; + + for (content = node.content; + content != null; + content = content.next) + printTree(fout, mode, indent, lexer, content); + + condFlushLine(fout, indent); + indent -= this.configuration.spaces; + condFlushLine(fout, indent); + } + else + { + + for (content = node.content; + content != null; + content = content.next) + printTree(fout, mode, indent, lexer, content); + } + + printEndTag(fout, mode, indent, node); + } + else /* other tags */ + { + condFlushLine(fout, indent); + + if (this.configuration.SmartIndent && node.prev != null) + flushLine(fout, indent); + + if (this.configuration.HideEndTags == false || + !(node.tag != null && ((node.tag.model & Dict.CM_OMITST) != 0))) + { + printTag(lexer, fout, mode, indent, node); + + if (shouldIndent(node)) + condFlushLine(fout, indent); + else if ((node.tag.model & Dict.CM_HTML) != 0 || + node.tag == tt.tagNoframes || + ((node.tag.model & Dict.CM_HEAD) != 0 && + !(node.tag == tt.tagTitle))) + flushLine(fout, indent); + } + + if (node.tag == tt.tagBody && this.configuration.BurstSlides) + printSlide(fout, mode, (this.configuration.IndentContent ? indent+this.configuration.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 != null && !this.configuration.IndentContent && last.type == Node.TextNode && + content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0) + { + flushLine(fout, indent); + flushLine(fout, indent); + } + + printTree(fout, mode, + (shouldIndent(node) ? indent+this.configuration.spaces : indent), lexer, content); + + last = content; + } + } + + /* don't flush line for td and th */ + if (shouldIndent(node) || + (((node.tag.model & Dict.CM_HTML) != 0 || node.tag == tt.tagNoframes || + ((node.tag.model & Dict.CM_HEAD) != 0 && !(node.tag == tt.tagTitle))) + && this.configuration.HideEndTags == false)) + { + condFlushLine(fout, (this.configuration.IndentContent ? indent+this.configuration.spaces : indent)); + + if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0)) + { + printEndTag(fout, mode, indent, node); + flushLine(fout, indent); + } + } + else + { + if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0)) + printEndTag(fout, mode, indent, node); + + flushLine(fout, indent); + } + + if (this.configuration.IndentContent == false && + node.next != null && + this.configuration.HideEndTags == false && + (node.tag.model & (Dict.CM_BLOCK|Dict.CM_LIST|Dict.CM_DEFLIST|Dict.CM_TABLE)) != 0) + { + flushLine(fout, indent); + } + } + } + } + + public void printXMLTree(Out fout, short mode, int indent, + Lexer lexer, Node node) + { + TagTable tt = this.configuration.tt; + + if (node == null) + return; + + if (node.type == Node.TextNode) + { + printText(fout, mode, indent, + node.textarray, node.start, node.end); + } + else if (node.type == Node.CommentTag) + { + condFlushLine(fout, indent); + printComment(fout, 0, node); + condFlushLine(fout, 0); + } + else if (node.type == Node.RootNode) + { + Node content; + + for (content = node.content; + content != null; + content = content.next) + printXMLTree(fout, mode, indent, lexer, content); + } + else if (node.type == Node.DocTypeTag) + printDocType(fout, indent, node); + else if (node.type == Node.ProcInsTag) + printPI(fout, indent, node); + else if (node.type == Node.SectionTag) + printSection(fout, indent, node); + else if (node.type == Node.AspTag) + printAsp(fout, indent, node); + else if (node.type == Node.JsteTag) + printJste(fout, indent, node); + else if (node.type == Node.PhpTag) + printPhp(fout, indent, node); + else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag) + { + condFlushLine(fout, indent); + printTag(lexer, fout, mode, indent, node); + flushLine(fout, indent); + + if (node.next != null) + flushLine(fout, indent); + } + else /* some kind of container element */ + { + Node content; + boolean mixed = false; + int cindent; + + for (content = node.content; content != null; content = content.next) + { + if (content.type == Node.TextNode) + { + mixed = true; + break; + } + } + + condFlushLine(fout, indent); + + if (ParserImpl.XMLPreserveWhiteSpace(node, tt)) + { + indent = 0; + cindent = 0; + mixed = false; + } + else if (mixed) + cindent = indent; + else + cindent = indent + this.configuration.spaces; + + printTag(lexer, fout, mode, indent, node); + + if (!mixed) + flushLine(fout, indent); + + for (content = node.content; + content != null; + content = content.next) + printXMLTree(fout, mode, cindent, lexer, content); + + if (!mixed) + condFlushLine(fout, cindent); + printEndTag(fout, mode, indent, node); + condFlushLine(fout, indent); + + if (node.next != null) + flushLine(fout, indent); + } + } + + + /* split parse tree by h2 elements and output to separate files */ + + /* counts number of h2 children belonging to node */ + public int countSlides(Node node) + { + int n = 1; + TagTable tt = this.configuration.tt; + + for (node = node.content; node != null; node = node.next) + if (node.tag == tt.tagH2) + ++n; + + return n; + } + + /* + inserts a space gif called "dot.gif" to ensure + that the slide is at least n pixels high + */ + private void printVertSpacer(Out fout, int indent) + { + condFlushLine(fout, indent); + printString(fout, indent , + ""); + condFlushLine(fout, indent); + } + + private void printNavBar(Out fout, int indent) + { + String buf; + + condFlushLine(fout, indent); + printString(fout, indent , "
"); + + if (slide > 1) + { + buf = "previous | "; + printString(fout, indent , buf); + condFlushLine(fout, indent); + + if (slide < count) + printString(fout, indent , "start | "); + else + printString(fout, indent , "start"); + + condFlushLine(fout, indent); + } + + if (slide < count) + { + buf = "next"; + printString(fout, indent , buf); + } + + printString(fout, indent , "
"); + condFlushLine(fout, indent); + } + + /* + Called from printTree 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. + */ + public void printSlide(Out fout, short mode, int indent, Lexer lexer) + { + Node content, last; + TagTable tt = this.configuration.tt; + + /* insert div for onclick handler */ + String s; + s = "
"; + printString(fout, indent, s); + condFlushLine(fout, indent); + + /* first print the h2 element and navbar */ + if (slidecontent.tag == tt.tagH2) + { + printNavBar(fout, indent); + + /* now print an hr after h2 */ + + addC('<', linelen++); + + + addC((int)Lexer.foldCase('h', + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + addC((int)Lexer.foldCase('r', + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + + if (this.configuration.XmlOut == true) + printString(fout, indent , " />"); + else + addC('>', linelen++); + + + if (this.configuration.IndentContent == true) + condFlushLine(fout, indent); + + /* PrintVertSpacer(fout, indent); */ + + /*condFlushLine(fout, indent); */ + + /* print the h2 element */ + printTree(fout, mode, + (this.configuration.IndentContent ? indent+this.configuration.spaces : indent), lexer, slidecontent); + + slidecontent = slidecontent.next; + } + + /* now continue until we reach the next h2 */ + + last = null; + content = slidecontent; + + for (; content != null; content = content.next) + { + if (content.tag == tt.tagH2) + break; + + /* kludge for naked text before block level tag */ + if (last != null && !this.configuration.IndentContent && last.type == Node.TextNode && + content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0) + { + flushLine(fout, indent); + flushLine(fout, indent); + } + + printTree(fout, mode, + (this.configuration.IndentContent ? indent+this.configuration.spaces : indent), lexer, content); + + last = content; + } + + slidecontent = content; + + /* now print epilog */ + + condFlushLine(fout, indent); + + printString(fout, indent , "
"); + condFlushLine(fout, indent); + + addC('<', linelen++); + + + addC((int)Lexer.foldCase('h', + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + addC((int)Lexer.foldCase('r', + this.configuration.UpperCaseTags, + this.configuration.XmlTags), + linelen++); + + if (this.configuration.XmlOut == true) + printString(fout, indent , " />"); + else + addC('>', linelen++); + + + if (this.configuration.IndentContent == true) + condFlushLine(fout, indent); + + printNavBar(fout, indent); + + /* end tag for div */ + printString(fout, indent, "
"); + condFlushLine(fout, indent); + } + + + /* + Add meta element for page transition effect, this works on IE but not NS + */ + + public void addTransitionEffect(Lexer lexer, Node root, short effect, double duration) + { + Node head = root.findHEAD(lexer.configuration.tt); + String transition; + + if (0 <= effect && effect <= 23) + transition = "revealTrans(Duration=" + + (new Double(duration)).toString() + + ",Transition=" + effect + ")"; + else + transition = "blendTrans(Duration=" + + (new Double(duration)).toString() + ")"; + + if (head != null) + { + Node meta = lexer.inferredTag("meta"); + meta.addAttribute("http-equiv", "Page-Enter"); + meta.addAttribute("content", transition); + Node.insertNodeAtStart(head, meta); + } + } + + public void createSlides(Lexer lexer, Node root) + { + Node body; + String buf; + Out out = new OutImpl(); + + body = root.findBody(lexer.configuration.tt); + count = countSlides(body); + slidecontent = body.content; + addTransitionEffect(lexer, root, EFFECT_BLEND, 3.0); + + for (slide = 1; slide <= count; ++slide) + { + buf = "slide" + slide + ".html"; + out.state = StreamIn.FSM_ASCII; + out.encoding = this.configuration.CharEncoding; + + try + { + out.out = new FileOutputStream(buf); + printTree(out, (short)0, 0, lexer, root); + flushLine(out, 0); + out.out.close(); + } + catch (IOException e) + { + System.err.println(buf + e.toString() ); + } + } + + /* + delete superfluous slides by deleting slideN.html + for N = count+1, count+2, etc. until no such file + is found. + */ + + for (;;) + { + buf = "slide" + slide + "html"; + + if (!(new File(buf)).delete()) + break; + + ++slide; + } + } + +}