netscape-revival
sun-java/classsrc/sun/tools/javadoc/MIFPrintStream.java
/*
* @(#)MIFPrintStream.java 1.4 95/12/07 Frank Yellin
*
* Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
package sun.tools.javadoc;
import java.util.*;
import java.io.*;
import sun.tools.java.*;
public class MIFPrintStream {
PrintStream out;
public final static int STATE_OUTER = 0;
public final static int STATE_PARAGRAPH = 1;
public final static int STATE_LINE = 2;
public final static int STATE_STRING = 3;
public final static char hardReturnChar = (char)0x09;
public final static char hardSpaceChar = (char)0x11;
public final static int MIF_VERSION = 5;
int state;
Vector pendingMarks = null;
int currentStringLength = 0; // characters in current string
static Date today = new Date();
public MIFPrintStream(OutputStream out) {
this(new PrintStream(out));
}
public MIFPrintStream(PrintStream out) {
this.out = out;
out.println("<MIFFile " + MIF_VERSION + ".00>");
out.println("<Comment Generated by javadoc on " + today + ">");
include("DocTemplate.mif");
out.println("<TextFlow <TFTag `A'> <TFAutoConnect Yes> <TextRectID 7>");
state = STATE_OUTER;
}
public MIFPrintStream println(Object x) {
out.println(x.toString());
return this;
}
public MIFPrintStream newParagraph(String name) {
topLevel();
out.println("<Para");
out.println(" <PgfTag `" + name + "'>");
state = STATE_PARAGRAPH;
return this;
}
public MIFPrintStream newParaLine() {
inParagraph();
out.println(" <ParaLine");
state = STATE_LINE;
return this;
}
public MIFPrintStream newString(String tag) {
inParaLine();
out.print(" <" + tag + " `");
state = STATE_STRING;
currentStringLength = 0;
return this;
}
public MIFPrintStream topLevel() {
if (state > STATE_OUTER) {
inParagraph();
out.println("> # end paragraph");
}
state = STATE_OUTER;
return this;
}
public MIFPrintStream inParagraph() {
if (state < STATE_PARAGRAPH)
throw new RuntimeException("Bad call to inParagraph");
else if (state > STATE_PARAGRAPH) {
inParaLine();
out.println(" >");
state = STATE_PARAGRAPH;
}
return this;
}
public MIFPrintStream inParaLine() {
if (state < STATE_LINE)
return newParaLine();
else if (state > STATE_LINE) {
inString();
out.println("'>");
state = STATE_LINE;
}
return this;
}
public MIFPrintStream inString() {
if (state < STATE_STRING)
return newString("String");
return this;
}
public MIFPrintStream indent(double first, double left, double right) {
inParagraph();
out.println(" <PgfFIndent " + first + "in>");
out.println(" <PgfLIndent " + left + "in>");
out.println(" <PgfRIndent " + right + "in>");
return this;
}
MIFPrintStream skip(int pts) {
inParagraph();
out.println(" <PgfSpBefore " + pts + "pt>");
return this;
}
MIFPrintStream bold(Object x) {
inParaLine();
out.println(" <Font <FTag `'> <FWeight `Bold'> >");
literal(x);
inParaLine();
out.println(" <Font <FTag `'> >");
return this;
}
MIFPrintStream italic(Object x) {
inParaLine();
out.println(" <Font <FTag `'> <FAngle `Italic'> >");
literal(x);
inParaLine();
out.println(" <Font <FTag `'> >");
return this;
}
MIFPrintStream tty(Object x) {
inParaLine();
out.println(" <Font <FTag `'> <FFamily `Courier'> >");
literal(x);
inParaLine();
out.println(" <Font <FTag `'> >");
return this;
}
MIFPrintStream charTag(String tag, Object x) {
inParaLine();
out.println(" <Font <FTag `" + tag + "'> >");
literal(x);
inParaLine();
out.println(" <Font <FTag `'> >");
return this;
}
public MIFPrintStream literal(Object o) {
String string = o.toString();
int length = string.length();
for (int i = 0; i < length; i++)
literal(string.charAt(i));
return this;
}
public MIFPrintStream literal(char ch) {
inString();
currentStringLength++;
switch(ch) {
default:
if (ch >= ' ' && ch < 0x80) {
out.print(ch);
} else {
currentStringLength += 4;
out.print("\\x" +
Character.forDigit((ch >> 4) & 0xF, 16) +
Character.forDigit(ch & 0xF, 16) + ' ');
}
break;
case '\'':
out.print("\\q"); currentStringLength++; break;
case '`':
out.print("\\Q"); currentStringLength++; break;
case '>':
out.print("\\>"); currentStringLength++; break;
case '\\':
out.print("\\\\"); currentStringLength++; break;
case '\t':
out.print("\\t"); currentStringLength++; break;
case ' ':
out.print(' '); // normal
if (currentStringLength >= 55) // break long lines
inParaLine();
break;
case '\n': // hard return
out.print("\\n");
inParagraph();
break;
}
return this;
}
final static int MarkerHF1 = 0;
final static int MarkerHF2 = 1;
final static int MarkerIndex = 2;
final static int MarkerComment = 3;
final static int MarkerSubject = 4;
final static int MarkerAuthor = 5;
final static int MarkerGlossary = 6;
final static int MarkerEquation = 7;
final static int MarkerHypertext = 8;
final static int MarkerXRef = 9;
final static int MarkerCondText = 10;
private void markInternal(int mtype, Object text) {
if (state == STATE_OUTER) {
if (pendingMarks == null)
pendingMarks = new Vector();
pendingMarks.addElement(new Integer(mtype));
pendingMarks.addElement(text);
} else {
inParaLine();
out.println(" <Marker <MType " + mtype + "> <MText `" +
text + "'> >");
}
}
public MIFPrintStream mark(int mtype, Object text) {
markInternal(mtype, literalText(text.toString(), false));
return this;
}
public MIFPrintStream markReference(Object text) {
markInternal(MarkerXRef, literalText(text.toString(), false));
return this;
}
public MIFPrintStream index(Object text, String sort) {
markInternal(MarkerIndex,
literalText(text.toString(), true) + '[' +
literalText(sort.toString(), true) + ']');
return this;
}
public MIFPrintStream index(Object text) {
markInternal(MarkerIndex, literalText(text.toString(), true));
return this;
}
private String literalText(String text, boolean forIndex) {
int length = text.length();
StringBuffer result = new StringBuffer();
for (int i = 0; i < length; i++) {
char ch = text.charAt(i);
switch (ch) {
default:
if (ch >= ' ' && ch < 0x80) {
result.append(ch);
} else {
result.append("\\x" +
Character.forDigit((ch >> 4) & 0xF, 16) +
Character.forDigit(ch & 0xF, 16) + ' ');
}
break;
case '\'':
result.append("\\q"); break;
case '`':
result.append("\\Q"); break;
case '>':
result.append("\\>"); break;
case '\\':
result.append("\\\\"); break;
case '[': case ']':
if (forIndex)
result.append("\\\\");
result.append(ch);
break;
}
}
return result.toString();
}
public MIFPrintStream emitPendingMarks() {
if (pendingMarks != null) {
for (int i = 0; i < pendingMarks.size(); i += 2) {
int mtype = ((Number)(pendingMarks.elementAt(i))).intValue();
String text = (String)(pendingMarks.elementAt(i + 1));
mark(mtype, text);
}
}
pendingMarks = null;
return this;
}
public MIFPrintStream XRef(String type, String text, String source) {
String ttext = literalText(text, false);
String ref = (source == null) ? "" : literalText("<c>" + source, false);
inParaLine();
out.println(" <XRef <XRefName `" + type + "'>");
out.println(" <XRefSrcText `" + ttext + "'>");
out.println(" <XRefSrcFile `" + ref + "'>");
out.println(" > #XRef");
out.println(" <String `page\\x11 XX\u0015XX'>"); // default
out.println(" <XRefEnd>");
return this;
}
public MIFPrintStream close() {
topLevel();
out.println("> #end TextFlow");
out.println("# end of MIF");
out.close();
return null;
}
static final int BOLD = 1;
static final int ITALIC = 2;
static final int UNDERLINE = 4;
static final int SMALLCAPS = 8;
static final int TTY = 16;
boolean isFormatted, lastSpace;
int currentFont, desiredFont;
String currentType;
MIFPrintStream html(String type, String text) {
int[] fontStack = new int[30];
int fontStackHeight = 0;
newParagraph(type);
currentFont = desiredFont = 0;
isFormatted = false;
lastSpace = true;
currentType = type;
for (int i = 0; i < text.length(); i++) {
boolean seenSpace = false, seenHTML = false;
char ch = text.charAt(i);
String html = null;
switch(ch) {
default:
htmlLiteral((char)ch);
break;
case '&':
if (text.startsWith("gt;", i + 1)) {
htmlLiteral('>'); i += 3; break;
} else if (text.startsWith("lt;", i + 1)) {
htmlLiteral('<'); i += 3; break;
} else if (text.startsWith("amp;", i + 1)) {
htmlLiteral('&'); i += 4; break;
} else if (text.startsWith("quot;", i + 1)) {
htmlLiteral('"'); i += 5; break;
} else if (text.startsWith("reg;", i + 1)) {
htmlLiteral('\u00a8'); i += 4; break;
} else if (text.startsWith("copy;", i + 1)) {
htmlLiteral('\u00a9'); i += 5; break;
} else {
htmlLiteral('&'); break;
}
case '<': {
int j = text.indexOf('>', i + 1);
if (j <= i + 1) {
htmlLiteral('<');
break;
}
html = text.substring(i + 1, j); // html code sequence
char first = html.charAt(0);
if (first != '/' && Character.digit(first, 36) == -1) {
htmlLiteral('<');
html = null;
break;
}
i = j; // point at the >
break;
}
case '\t': case ' ': case '\n':
if (isFormatted) {
htmlLiteral(ch == ' ' ? hardSpaceChar : ch);
} else if (!lastSpace) {
htmlLiteral(' ');
}
break;
}
if (html == null)
continue;
if (html.equalsIgnoreCase("tt")||html.equalsIgnoreCase("code")) {
fontStack[fontStackHeight++] = currentFont;
desiredFont = currentFont | TTY;
} else if (html.equalsIgnoreCase("cite") ||
html.equalsIgnoreCase("em") ||
html.equalsIgnoreCase("i")) {
fontStack[++fontStackHeight] = currentFont;
desiredFont = currentFont | ITALIC;
} else if (html.equalsIgnoreCase("b")) {
fontStack[fontStackHeight++] = currentFont;
desiredFont = currentFont | BOLD;
} else if (html.equalsIgnoreCase("strong")) {
fontStack[fontStackHeight++] = currentFont;
desiredFont = currentFont | BOLD | SMALLCAPS;
} else if (html.equalsIgnoreCase("/tt") ||
html.equalsIgnoreCase("/code") ||
html.equalsIgnoreCase("/cite") ||
html.equalsIgnoreCase("/em") ||
html.equalsIgnoreCase("/i") ||
html.equalsIgnoreCase("/b") ||
html.equalsIgnoreCase("/strong")) {
if (fontStackHeight == 0) {
System.out.println("Font stack underflow");
desiredFont = 0;
} else {
desiredFont = fontStack[--fontStackHeight];
}
} else if (html.equalsIgnoreCase("pre")) {
topLevel();
fontStack[++fontStackHeight] = currentFont;
topLevel();
desiredFont = currentFont | TTY;
isFormatted = true;
} else if (html.equalsIgnoreCase("/pre")) {
topLevel();
desiredFont = fontStack[--fontStackHeight];
isFormatted = false;
} else if (html.equalsIgnoreCase("p") ||
html.equalsIgnoreCase("par")) {
topLevel();
} else if (html.startsWith("a ") ||
html.startsWith("A ") ||
html.equalsIgnoreCase("/a")) {
// donothing for anchors
} else if (html.indexOf("@") > 0 && html.indexOf(' ') == -1) {
// probably an internet address
htmlLiteral('<');
i -= html.length(); // point back at skipped text
} else {
System.out.println("Unknown html <" + html + ">");
}
} // end of for loop
return this;
}
private void htmlLiteral(char ch) {
if (state < STATE_PARAGRAPH) {
newParagraph(currentType);
out.println(" <PgfSpBefore 6pt>");
currentFont = 0;
lastSpace = true;
}
if (currentFont != desiredFont) {
inParagraph();
out.println(" <Font <FTag `'> >");
out.print(" <Font ");
if ((desiredFont & ITALIC) != 0)
out.print("<FAngle Italic> ");
if ((desiredFont & BOLD) != 0)
out.print("<FBold Yes> ");
if ((desiredFont & UNDERLINE) != 0)
out.print("<FUnderlining FSingle> ");
if ((desiredFont & SMALLCAPS) != 0)
out.print("<FCase FSmallCaps> ");
if ((desiredFont & TTY) != 0)
out.print("<FFamily Courier> ");
out.println(">");
currentFont = desiredFont;
}
literal(ch);
lastSpace = (ch <= ' ');
}
public static void main(String argv[]) {
MIFPrintStream x = new MIFPrintStream(System.out);
x.html("Body", "<b>hello </b>");
x.close();
}
private void include(String filename) {
if (MIF_VERSION >= 5) {
out.println("include(" + filename + ")");
} else {
try {
FileInputStream f = new FileInputStream(filename);
BufferedInputStream b = new BufferedInputStream(f);
byte buffer[] = new byte[1024];
for (;;) {
int i = b.read(buffer);
if (i < 0) break;
out.write(buffer, 0, i);
}
} catch (Exception e) {
}
}
}
}