0001: // Copyright (c) 2001, 2004, 2006 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.text;
0005:
0006: import java.io.*;
0007: import gnu.mapping.ThreadLocation;
0008: import gnu.lists.LList;
0009:
0010: /** A pretty printer.
0011: *
0012: * This code is transcribed from pprint.lisp in Steel Bank Common Lisp,
0013: * which is again based on the code in CMU Common Lisp.
0014: */
0015:
0016: public class PrettyWriter extends java.io.Writer {
0017: protected Writer out;
0018:
0019: public PrettyWriter(java.io.Writer out) {
0020: this .out = out;
0021: prettyPrintingMode = 1;
0022: }
0023:
0024: public PrettyWriter(java.io.Writer out, int lineLength) {
0025: this .out = out;
0026: this .lineLength = lineLength;
0027: prettyPrintingMode = lineLength > 1 ? 1 : 0;
0028: }
0029:
0030: public PrettyWriter(java.io.Writer out, boolean prettyPrintingMode) {
0031: this .out = out;
0032: this .prettyPrintingMode = prettyPrintingMode ? 1 : 0;
0033: }
0034:
0035: /** Line length we should format to. */
0036: int lineLength = 80;
0037: int miserWidth = 40;
0038:
0039: public static ThreadLocation lineLengthLoc = new ThreadLocation(
0040: "line-length");
0041: public static ThreadLocation miserWidthLoc = new ThreadLocation(
0042: "miser-width");
0043: public static ThreadLocation indentLoc = new ThreadLocation(
0044: "indent");
0045:
0046: /** The current pretty-printing mode.
0047: * See setPrettyPrintingMode for valid values. */
0048: int prettyPrintingMode;
0049:
0050: /** Control pretty-printing mode.
0051: * @param mode the value 0 disables pretty-printing;
0052: * the value 1 enables ecplicit pretty-printing;
0053: * the value 2 enables pretty-printing with auto-fill, which means that
0054: * spaces are treated like enqueing NEWLINE_SPACE (essentiall a 'fill').
0055: */
0056: public void setPrettyPrintingMode(int mode) {
0057: prettyPrintingMode = mode;
0058: }
0059:
0060: /** Return pretty-printing mode.
0061: * @return 0, 1, 2, as described for {@link #setPrettyPrintingMode(int)}.
0062: */
0063: public int getPrettyPrintingMode() {
0064: return prettyPrintingMode;
0065: }
0066:
0067: /** Is pretty printing enabled? */
0068: public boolean isPrettyPrinting() {
0069: return prettyPrintingMode > 0;
0070: }
0071:
0072: /** Turn pretty printing on or off.
0073: * Equivalent to {@code setPrettyPrintingMode(mode?1:0)}.
0074: */
0075: public void setPrettyPrinting(boolean mode) {
0076: prettyPrintingMode = mode ? 0 : 1;
0077: }
0078:
0079: public static int initialBufferSize = 126;
0080:
0081: /** Holds all the text that has been output but not yet printed. */
0082: public/* FIXME */char[] buffer = new char[initialBufferSize];
0083:
0084: /** The index into BUFFER where more text should be put. */
0085: public/* FIXME */int bufferFillPointer;
0086:
0087: /** Total amount of stuff that has been shifted out of the buffer.
0088: * Whenever we output stuff from the buffer, we shift the remaining noise
0089: * over. This makes it difficult to keep references to locations in
0090: * the buffer. */
0091: int bufferOffset;
0092:
0093: /** The column the first character in the buffer will appear in.
0094: * Normally zero, but if we end up with a very long line with no breaks in it
0095: * we might have to output part of it. Then this will no longer be zero.
0096: * Ditto after emitting a prompt. */
0097: int bufferStartColumn;
0098:
0099: /** The line number we are currently on. Used for *print-lines* abrevs and
0100: * to tell when sections have been split across multiple lines. */
0101: int lineNumber;
0102:
0103: // There are three different units for measuring character positions:
0104: // COLUMN - offset (in characters) from the start of the current line.
0105: // INDEX - index into the output buffer.
0106: // POSN - some position in the stream of characters cycling through
0107: // the output buffer.
0108:
0109: private int indexPosn(int index) {
0110: return index + bufferOffset;
0111: }
0112:
0113: private int posnIndex(int posn) {
0114: return posn - bufferOffset;
0115: }
0116:
0117: private int posnColumn(int posn) {
0118: return indexColumn(posnIndex(posn));
0119: }
0120:
0121: /** Stack of logical blocks in effect at the buffer start.
0122: * I.e. blocks for which {@code reallyStartLogicalBlock} has been called.
0123: * Each block uses {@code LOGICAL_BLOCK_LENGTH} {@code int} in this array. */
0124: int[] blocks = new int[10 * LOGICAL_BLOCK_LENGTH];
0125: /** Number of {@code int}s used by each block in the {@code blocks} array. */
0126: static final private int LOGICAL_BLOCK_LENGTH = 6;
0127: static final private int BLOCK_START_COLUMN = -1;
0128: static final private int BLOCK_SECTION_COLUMN = -2;
0129: static final private int BLOCK_PER_LINE_PREFIX_END = -3;
0130: static final private int BLOCK_PREFIX_LENGTH = -4;
0131: static final private int BLOCK_SUFFIX_LENGTH = -5;
0132: static final private int BLOCK_SECTION_START_LINE = -6;
0133: /** The "stack pointer" in the {@code blocks} array. */
0134: int blockDepth = LOGICAL_BLOCK_LENGTH;
0135:
0136: /** Buffer holding the per-line prefix active at the buffer start.
0137: * Indentation is included in this. The length of this is stored
0138: * in the logical block stack. */
0139: char[] prefix = new char[initialBufferSize];
0140:
0141: /** Buffer holding the total remaining suffix active at the buffer start.
0142: * The characters are right-justified in the buffer to make it easier
0143: * to output the buffer. The length is stored in the logical block stack. */
0144: char[] suffix = new char[initialBufferSize];
0145:
0146: static final int QUEUE_INIT_ALLOC_SIZE = 300; // FIXME
0147:
0148: /** A queue of pending operations.
0149: * This is primarily stored in the circular buffer queueInts. There
0150: * are different kinds of operation types, and each operation can
0151: * require a variable number of elements in the buffer, depending on
0152: * the operation type. Given an operation at 'index', the type
0153: * operation type code is 'getQueueType(index)' (one of the
0154: * QITEM_XXX_TYPE macros below), and the number of elements in the
0155: * buffer is 'getQueueSize(index)' (one of the QITEM_XXX_SIZE values
0156: * below). You can think of the various QITEM_XXX_TYPEs as
0157: * "sub-classes" of queued operations, but instead of creating
0158: * actual Java objects, we allocate the objects' fields in the
0159: * queueInts and QueueStrings arrays, to avoid expensive object
0160: * allocation. The special QITEM_NOP_TYPE is a used as a marker for
0161: * when there isn't enough space in the rest of buffer, so we have
0162: * to wrap around to the start. The other QITEM_XXX macros are the
0163: * offsets of the various "fields" relative to the start index. */
0164: int[] queueInts = new int[QUEUE_INIT_ALLOC_SIZE];
0165:
0166: /** For simplicity, queueStrings is the same size as queueInts. */
0167: String[] queueStrings = new String[QUEUE_INIT_ALLOC_SIZE];
0168: /** Index in queueInts and queueStrings of oldest enqueued operation. */
0169: int queueTail;
0170: /** Number of elements (in queueInts and queueStrings) in use. */
0171: int queueSize;
0172: /** If >= 0, index (into queueInts) of current unclosed begin-block node.
0173: * This is a head of a linked linked of queued BLOCK_START for which
0174: * we haven't seen the matching BLOCK_END */
0175: int currentBlock = -1;
0176: /** Number of startLogicalBlock - number of endLogicalBlock. */
0177: public int pendingBlocksCount;
0178:
0179: /** The first it QITEM contains it type code and size.
0180: * The type code is one of the QITEM_XXX_TYPE values below.
0181: * The size is the corresponding QITEM_XXX_SIZE value below,
0182: * except for the case of QITEM_NOP_TYPE (which is used as a filler). */
0183: static final int QITEM_TYPE_AND_SIZE = 0;
0184:
0185: private int getQueueType(int index) {
0186: return queueInts[index] & 0xFF;
0187: }
0188:
0189: private int getQueueSize(int index) {
0190: return queueInts[index] >> 16;
0191: }
0192:
0193: /** Relative offset of POSN field of a QITEM> */
0194: static final int QITEM_POSN = 1;
0195: /** Size of "base part" of a QITEM. */
0196: static final int QITEM_BASE_SIZE = 2;
0197:
0198: /** A dummy queue item used at the high end of the queue buffer
0199: * when there isn't enough space for the needed queue item. */
0200: static final int QITEM_NOP_TYPE = 0;
0201:
0202: /** "Abstract" type for beginning of section.
0203: * A section is from a block-start to a newline, from a newline to
0204: * the next newline (in the same block?), or from a newline to
0205: * the block end (?). */
0206: /*static final int QITEM_SECTION_START_TYPE = 1;*/
0207: static final int QITEM_SECTION_START_SIZE = QITEM_BASE_SIZE + 2;
0208: static final int QITEM_SECTION_START_DEPTH = QITEM_BASE_SIZE;
0209: static final int QITEM_SECTION_START_SECTION_END = QITEM_BASE_SIZE + 1;
0210:
0211: /** A newline queue item. */
0212: static final int QITEM_NEWLINE_TYPE = 2;
0213: static final int QITEM_NEWLINE_SIZE = QITEM_SECTION_START_SIZE + 1;
0214: static final int QITEM_NEWLINE_KIND = QITEM_SECTION_START_SIZE;
0215: public static final int NEWLINE_LINEAR = 'N';
0216: public static final int NEWLINE_LITERAL = 'L';
0217: public static final int NEWLINE_FILL = 'F';
0218: /** A non-nested ' ' gets an implicit NEWLINE_SPACE.
0219: * This is treated similarly to NEWLINE_FILL, but not quite. */
0220: public static final int NEWLINE_SPACE = 'S';
0221: public static final int NEWLINE_MISER = 'M';
0222: public static final int NEWLINE_MANDATORY = 'R'; // "required"
0223:
0224: static final int QITEM_INDENTATION_TYPE = 3;
0225: static final int QITEM_INDENTATION_SIZE = QITEM_BASE_SIZE + 2;
0226: static final int QITEM_INDENTATION_KIND = QITEM_BASE_SIZE;
0227: static final char QITEM_INDENTATION_BLOCK = 'B';
0228: static final char QITEM_INDENTATION_CURRENT = 'C';
0229: static final int QITEM_INDENTATION_AMOUNT = QITEM_BASE_SIZE + 1;
0230:
0231: /** A "block-start" queue item. */
0232: static final int QITEM_BLOCK_START_TYPE = 4;
0233: static final int QITEM_BLOCK_START_SIZE = QITEM_SECTION_START_SIZE + 3;
0234: /** If the QITEM_BLOCK_START_BLOCK_END < 0, it points to
0235: * the previous (outer) un-closed block-start.
0236: * If QITEM_BLOCK_START_BLOCK_END > 0, it points to the
0237: * corresponding block-end node.
0238: * In both cases the pointers are relative to the current BLOCK_START. */
0239: static final int QITEM_BLOCK_START_BLOCK_END = QITEM_SECTION_START_SIZE;
0240: static final int QITEM_BLOCK_START_PREFIX = QITEM_SECTION_START_SIZE + 1;
0241: static final int QITEM_BLOCK_START_SUFFIX = QITEM_SECTION_START_SIZE + 2;
0242:
0243: static final int QITEM_BLOCK_END_TYPE = 5;
0244: static final int QITEM_BLOCK_END_SIZE = QITEM_BASE_SIZE;
0245:
0246: static final int QITEM_TAB_TYPE = 6;
0247: static final int QITEM_TAB_SIZE = QITEM_BASE_SIZE + 3;
0248: static final int QITEM_TAB_FLAGS = QITEM_BASE_SIZE;
0249: static final int QITEM_TAB_IS_SECTION = 1;
0250: static final int QITEM_TAB_IS_RELATIVE = 2;
0251: static final int QITEM_TAB_COLNUM = QITEM_BASE_SIZE + 1;
0252: static final int QITEM_TAB_COLINC = QITEM_BASE_SIZE + 2;
0253:
0254: private int getSectionColumn() {
0255: return blocks[blockDepth + BLOCK_SECTION_COLUMN];
0256: }
0257:
0258: private int getStartColumn() {
0259: return blocks[blockDepth + BLOCK_START_COLUMN];
0260: }
0261:
0262: private int getPerLinePrefixEnd() {
0263: return blocks[blockDepth + BLOCK_PER_LINE_PREFIX_END];
0264: }
0265:
0266: private int getPrefixLength() {
0267: return blocks[blockDepth + BLOCK_PREFIX_LENGTH];
0268: }
0269:
0270: private int getSuffixLength() {
0271: return blocks[blockDepth + BLOCK_SUFFIX_LENGTH];
0272: }
0273:
0274: private int getSectionStartLine() {
0275: return blocks[blockDepth + BLOCK_SECTION_START_LINE];
0276: }
0277:
0278: boolean wordEndSeen;
0279:
0280: /** Note the end of a "word". See {@link #writeWordStart}. */
0281: public void writeWordEnd() {
0282: wordEndSeen = true;
0283: }
0284:
0285: /** Maybe write a word-separating space.
0286: * Specifically, write a space if the previous output
0287: * was {@link #writeWordEnd}. Otherwise, do nothing.
0288: */
0289: public void writeWordStart() {
0290: if (wordEndSeen)
0291: write(' ');
0292: wordEndSeen = false;
0293: }
0294:
0295: public void clearWordEnd() {
0296: wordEndSeen = false;
0297: }
0298:
0299: public void write(int ch) {
0300: wordEndSeen = false;
0301: //log("{WRITE-ch: "+((char)ch)+"}");
0302: if (ch == '\n' && prettyPrintingMode > 0)
0303: enqueueNewline(NEWLINE_LITERAL);
0304: else {
0305: ensureSpaceInBuffer(1);
0306: int fillPointer = bufferFillPointer;
0307: buffer[fillPointer] = (char) ch;
0308: bufferFillPointer = 1 + fillPointer;
0309: if (ch == ' ' && prettyPrintingMode > 1 && currentBlock < 0)
0310: enqueueNewline(NEWLINE_SPACE);
0311: }
0312: }
0313:
0314: public void write(String str) {
0315: write(str, 0, str.length());
0316: }
0317:
0318: public void write(String str, int start, int count) {
0319: wordEndSeen = false;
0320: //log("{WRITE-str: "+str.substring(start, start+count)+"}");
0321: while (count > 0) {
0322: int cnt = count;
0323: // May allocate for space than we need (if the buffer gets fluhed). FIXME
0324: int available = ensureSpaceInBuffer(count);
0325: if (cnt > available)
0326: cnt = available;
0327: int fillPointer = bufferFillPointer;
0328: count -= cnt;
0329: while (--cnt >= 0) {
0330: char ch = str.charAt(start++);
0331: if (ch == '\n' && prettyPrintingMode > 0) {
0332: bufferFillPointer = fillPointer;
0333: enqueueNewline(NEWLINE_LITERAL);
0334: fillPointer = bufferFillPointer;
0335: } else {
0336: buffer[fillPointer++] = (char) ch;
0337: if (ch == ' ' && prettyPrintingMode > 1
0338: && currentBlock < 0) {
0339: bufferFillPointer = fillPointer;
0340: enqueueNewline(NEWLINE_SPACE);
0341: fillPointer = bufferFillPointer;
0342: }
0343: }
0344: }
0345: bufferFillPointer = fillPointer;
0346: }
0347: }
0348:
0349: public void write(char[] str) {
0350: write(str, 0, str.length);
0351: }
0352:
0353: public void write(char[] str, int start, int count) {
0354: wordEndSeen = false;
0355: //log("{WRITE: "+new String(str, start, count)+"}");
0356: int end = start + count;
0357: retry: while (count > 0) {
0358: // Look for newline. Should be merged with following loop. FIXME.
0359: for (int i = start; i < end; i++) {
0360: char c;
0361: if (prettyPrintingMode > 0
0362: && ((c = str[i]) == '\n' || (c == ' ' && currentBlock < 0))) {
0363: write(str, start, i - start); // Recurse
0364: write(c);
0365: start = i + 1;
0366: count = end - start;
0367: continue retry;
0368: }
0369: }
0370:
0371: for (;;) {
0372: int available = ensureSpaceInBuffer(count);
0373: int cnt = available < count ? available : count;
0374: int fillPointer = bufferFillPointer;
0375: int newFillPtr = fillPointer + cnt;
0376: for (int i = fillPointer; i < newFillPtr; i++)
0377: buffer[i] = str[start++];
0378: bufferFillPointer = newFillPtr;
0379: count -= cnt;
0380: if (count == 0)
0381: break;
0382: }
0383: }
0384: }
0385:
0386: private void pushLogicalBlock(int column, int perLineEnd,
0387: int prefixLength, int suffixLength, int sectionStartLine) {
0388: int newLength = blockDepth + LOGICAL_BLOCK_LENGTH;
0389: if (newLength >= blocks.length) {
0390: int[] newBlocks = new int[2 * blocks.length];
0391: System.arraycopy(blocks, 0, newBlocks, 0, blockDepth);
0392: blocks = newBlocks;
0393: }
0394: blockDepth = newLength;
0395: blocks[blockDepth + BLOCK_START_COLUMN] = column;
0396: blocks[blockDepth + BLOCK_SECTION_COLUMN] = column;
0397: blocks[blockDepth + BLOCK_PER_LINE_PREFIX_END] = perLineEnd;
0398: blocks[blockDepth + BLOCK_PREFIX_LENGTH] = prefixLength;
0399: blocks[blockDepth + BLOCK_SUFFIX_LENGTH] = suffixLength;
0400: blocks[blockDepth + BLOCK_SECTION_START_LINE] = sectionStartLine;
0401: }
0402:
0403: void reallyStartLogicalBlock(int column, String prefix,
0404: String suffix) {
0405: int perLineEnd = getPerLinePrefixEnd();
0406: int prefixLength = getPrefixLength();
0407: int suffixLength = getSuffixLength();
0408: pushLogicalBlock(column, perLineEnd, prefixLength,
0409: suffixLength, lineNumber);
0410: setIndentation(column);
0411: if (prefix != null) {
0412: blocks[blockDepth + BLOCK_PER_LINE_PREFIX_END] = column;
0413: int plen = prefix.length();
0414: prefix.getChars(0, plen, this .suffix, column - plen);
0415: }
0416: if (suffix != null) {
0417: // Prepend the new suffix in front of the old suffix in this.suffix.
0418: // The suffix is stored at the "right" (high-index) end of
0419: // this.suffix to make it easier to prepend new suffixes.
0420: char[] totalSuffix = this .suffix;
0421: int totalSuffixLen = totalSuffix.length;
0422: int additional = suffix.length();
0423: int newSuffixLen = suffixLength + additional;
0424: if (newSuffixLen > totalSuffixLen) {
0425: int newTotalSuffixLen = enoughSpace(totalSuffixLen,
0426: additional);
0427: this .suffix = new char[newTotalSuffixLen];
0428: System.arraycopy(totalSuffix, totalSuffixLen
0429: - suffixLength, this .suffix, newTotalSuffixLen
0430: - suffixLength, suffixLength);
0431: totalSuffixLen = newTotalSuffixLen;
0432: }
0433: suffix.getChars(0, additional, totalSuffix, totalSuffixLen
0434: - newSuffixLen);
0435: blocks[blockDepth + BLOCK_SUFFIX_LENGTH] = newSuffixLen;
0436: }
0437:
0438: }
0439:
0440: int enqueueTab(int flags, int colnum, int colinc) // DONE
0441: {
0442: int addr = enqueue(QITEM_TAB_TYPE, QITEM_TAB_SIZE);
0443: queueInts[addr + QITEM_TAB_FLAGS] = flags;
0444: queueInts[addr + QITEM_TAB_COLNUM] = colnum;
0445: queueInts[addr + QITEM_TAB_COLINC] = colinc;
0446: return addr;
0447: }
0448:
0449: /** Calculate how much space to allocate for a buffer.
0450: * @param current the current size of the buffer
0451: * @param want how much more space is needed
0452: */
0453: private static int enoughSpace(int current, int want) {
0454: int doubled = 2 * current;
0455: int enough = current + ((5 * want) >> 2);
0456: return doubled > enough ? doubled : enough;
0457: }
0458:
0459: public void setIndentation(int column) {
0460: char[] prefix = this .prefix;
0461: int prefixLen = prefix.length;
0462: int current = getPrefixLength();
0463: int minimum = getPerLinePrefixEnd();
0464: if (minimum > column)
0465: column = minimum;
0466: if (column > prefixLen) {
0467: prefix = new char[enoughSpace(prefixLen, column - prefixLen)];
0468: System.arraycopy(this .prefix, 0, prefix, 0, current);
0469: this .prefix = prefix;
0470: }
0471: if (column > current) {
0472: for (int i = current; i < column; i++)
0473: prefix[i] = ' ';
0474: }
0475: blocks[blockDepth + BLOCK_PREFIX_LENGTH] = column;
0476: }
0477:
0478: void reallyEndLogicalBlock() {
0479: int oldIndent = getPrefixLength();
0480: blockDepth -= LOGICAL_BLOCK_LENGTH; // Pop
0481: int newIndent = getPrefixLength();
0482: if (newIndent > oldIndent) {
0483: for (int i = oldIndent; i < newIndent; i++)
0484: prefix[i] = ' ';
0485: }
0486: }
0487:
0488: public int enqueue(int kind, int size) {
0489: int oldLength = queueInts.length;
0490: int endAvail = oldLength - queueTail - queueSize;
0491: if (endAvail > 0 && size > endAvail)
0492: enqueue(QITEM_NOP_TYPE, endAvail);
0493: if (queueSize + size > oldLength) {
0494: int newLength = enoughSpace(oldLength, size);
0495: int[] newInts = new int[newLength];
0496: String[] newStrings = new String[newLength];
0497: int queueHead = queueTail + queueSize - oldLength;
0498: if (queueHead > 0) { // Wraps around.
0499: System.arraycopy(queueInts, 0, newInts, 0, queueHead);
0500: System.arraycopy(queueStrings, 0, newStrings, 0,
0501: queueHead);
0502: }
0503: int part1Len = oldLength - queueTail;
0504: int deltaLength = newLength - oldLength;
0505: System.arraycopy(queueInts, queueTail, newInts, queueTail
0506: + deltaLength, part1Len);
0507: System.arraycopy(queueStrings, queueTail, newStrings,
0508: queueTail + deltaLength, part1Len);
0509: queueInts = newInts;
0510: queueStrings = newStrings;
0511: if (currentBlock >= queueTail)
0512: currentBlock += deltaLength;
0513: queueTail += deltaLength;
0514: }
0515: int addr = queueTail + queueSize;
0516: if (addr >= queueInts.length)
0517: addr -= queueInts.length;
0518: queueInts[addr + QITEM_TYPE_AND_SIZE] = kind | (size << 16);
0519: if (size > 1)
0520: queueInts[addr + QITEM_POSN] = indexPosn(bufferFillPointer);
0521: //log("enqueue "+itemKindString(kind)+" size:"+size+" at:"+queueSize+enqueueExtraLog); enqueueExtraLog = "";
0522: queueSize += size;
0523: return addr;
0524: }
0525:
0526: public void enqueueNewline(int kind) {
0527: wordEndSeen = false;
0528: int depth = pendingBlocksCount;
0529: //enqueueExtraLog = " kind:"+(char) kind;
0530: int newline = enqueue(QITEM_NEWLINE_TYPE, QITEM_NEWLINE_SIZE);
0531: queueInts[newline + QITEM_NEWLINE_KIND] = kind;
0532: queueInts[newline + QITEM_SECTION_START_DEPTH] = pendingBlocksCount;
0533: queueInts[newline + QITEM_SECTION_START_SECTION_END] = 0;
0534: int entry = queueTail;
0535: int todo = queueSize;
0536: while (todo > 0) {
0537: if (entry == queueInts.length)
0538: entry = 0;
0539: if (entry == newline)
0540: break;
0541: int type = getQueueType(entry);
0542: if ((type == QITEM_NEWLINE_TYPE || type == QITEM_BLOCK_START_TYPE)
0543: && queueInts[entry
0544: + QITEM_SECTION_START_SECTION_END] == 0
0545: && depth <= queueInts[entry
0546: + QITEM_SECTION_START_DEPTH]) {
0547: int delta = newline - entry;
0548: if (delta < 0)
0549: delta += queueInts.length;
0550: queueInts[entry + QITEM_SECTION_START_SECTION_END] = delta;
0551: }
0552: int size = getQueueSize(entry);
0553: todo -= size;
0554: entry += size;
0555: }
0556: maybeOutput(kind == NEWLINE_LITERAL
0557: || kind == NEWLINE_MANDATORY, false);
0558: }
0559:
0560: public final void writeBreak(int kind) {
0561: if (prettyPrintingMode > 0)
0562: enqueueNewline(kind);
0563: }
0564:
0565: public int enqueueIndent(char kind, int amount) {
0566: //enqueueExtraLog = " kind:"+kind+" amount:"+amount;
0567: int result = enqueue(QITEM_INDENTATION_TYPE,
0568: QITEM_INDENTATION_SIZE);
0569: queueInts[result + QITEM_INDENTATION_KIND] = kind;
0570: queueInts[result + QITEM_INDENTATION_AMOUNT] = amount;
0571: return result;
0572: }
0573:
0574: public void addIndentation(int amount, boolean current) {
0575: if (prettyPrintingMode > 0)
0576: enqueueIndent((current ? QITEM_INDENTATION_CURRENT
0577: : QITEM_INDENTATION_BLOCK), amount);
0578: }
0579:
0580: public void startLogicalBlock(String prefix, boolean perLine,
0581: String suffix) {
0582: // If the queue is empty, it is a good time to check if line-length etc
0583: // have been changed.
0584: if (queueSize == 0 && bufferFillPointer == 0) {
0585: Object llen = lineLengthLoc.get(null);
0586: if (llen == null)
0587: lineLength = 80;
0588: else
0589: lineLength = Integer.parseInt(llen.toString());
0590:
0591: Object mwidth = miserWidthLoc.get(null);
0592: if (mwidth == null || mwidth == Boolean.FALSE
0593: // For Common Lisp nil. Should we use Language.isTrue() FIXME.
0594: || mwidth == LList.Empty)
0595: miserWidth = -1;
0596: else
0597: miserWidth = Integer.parseInt(mwidth.toString());
0598:
0599: Object indent = indentLoc.get(null);
0600: // if (indent == null || indent ...
0601: }
0602: if (prefix != null)
0603: write(prefix);
0604: if (prettyPrintingMode == 0)
0605: return;
0606: int start = enqueue(QITEM_BLOCK_START_TYPE,
0607: QITEM_BLOCK_START_SIZE);
0608: queueInts[start + QITEM_SECTION_START_DEPTH] = pendingBlocksCount;
0609: queueStrings[start + QITEM_BLOCK_START_PREFIX] = perLine ? prefix
0610: : null;
0611: queueStrings[start + QITEM_BLOCK_START_SUFFIX] = suffix;
0612: pendingBlocksCount++;
0613: int outerBlock = currentBlock;
0614: if (outerBlock < 0)
0615: outerBlock = 0;
0616: else {
0617: outerBlock -= start;
0618: if (outerBlock > 0)
0619: outerBlock -= queueInts.length;
0620: }
0621: queueInts[start + QITEM_BLOCK_START_BLOCK_END] = outerBlock;
0622: queueInts[start + QITEM_SECTION_START_SECTION_END] = 0;
0623: currentBlock = start;
0624: }
0625:
0626: public void endLogicalBlock() {
0627: int end = enqueue(QITEM_BLOCK_END_TYPE, QITEM_BLOCK_END_SIZE);
0628: pendingBlocksCount--;
0629: if (currentBlock < 0) {
0630: // reallyStartLogicalBlock has been called for the matching
0631: // BEGIN_BLOCK, so it is no longer in the queue. Instead it is in
0632: // the 'blocks' stack.
0633: int suffixLength = blocks[blockDepth + BLOCK_SUFFIX_LENGTH];
0634: int suffixPreviousLength = blocks[blockDepth
0635: - LOGICAL_BLOCK_LENGTH + BLOCK_SUFFIX_LENGTH];
0636: if (suffixLength > suffixPreviousLength)
0637: write(this .suffix, this .suffix.length - suffixLength,
0638: suffixLength - suffixPreviousLength);
0639: currentBlock = -1;
0640: return;
0641: }
0642: int start = currentBlock;
0643: int outerBlock = queueInts[start + QITEM_BLOCK_START_BLOCK_END];
0644: if (outerBlock == 0)
0645: currentBlock = -1;
0646: else {
0647: int qtailFromStart = queueTail - start;
0648: if (qtailFromStart > 0)
0649: qtailFromStart -= queueInts.length;
0650: if (outerBlock < qtailFromStart) {
0651: // reallyStartLogicalBlock has been called for the outer block,
0652: // so there is no currentBlock.
0653: currentBlock = -1;
0654: } else {
0655: // Make currentBlock absolute instead of relative.
0656: outerBlock += start;
0657: if (outerBlock < 0)
0658: outerBlock += queueInts.length;
0659: currentBlock = outerBlock;
0660: }
0661: }
0662: String suffix = queueStrings[start + QITEM_BLOCK_START_SUFFIX];
0663: if (suffix != null)
0664: write(suffix);
0665: int endFromStart = end - start;
0666: if (endFromStart < 0) // wrap-around.
0667: endFromStart += queueInts.length;
0668: queueInts[start + QITEM_BLOCK_START_BLOCK_END] = endFromStart;
0669: //log("endLogicalBlock end:"+end+" start:"+start+" rel:"+endFromStart);
0670: }
0671:
0672: public void endLogicalBlock(String suffix) {
0673: if (prettyPrintingMode > 0)
0674: endLogicalBlock();
0675: else if (suffix != null)
0676: write(suffix);
0677: }
0678:
0679: // Tab support
0680:
0681: int computeTabSize(int tab, int sectionStart, int column) // DONE
0682: {
0683: int flags = queueInts[tab + QITEM_TAB_FLAGS];
0684: boolean isSection = (flags & QITEM_TAB_IS_SECTION) != 0;
0685: boolean isRelative = (flags & QITEM_TAB_IS_RELATIVE) != 0;
0686: int origin = isSection ? sectionStart : 0;
0687: int colnum = queueInts[tab + QITEM_TAB_COLNUM];
0688: int colinc = queueInts[tab + QITEM_TAB_COLINC];
0689: if (isRelative) {
0690: if (colinc > 1) {
0691: int newposn = column + colnum;
0692: int rem = newposn % colinc;
0693: if (rem != 0)
0694: colnum += colinc = rem;
0695: }
0696: return colnum;
0697: } else if (column <= colnum + origin)
0698: return column + origin - column;
0699: else
0700: return colinc - (column - origin) % colinc;
0701: }
0702:
0703: int indexColumn(int index) {
0704: int column = bufferStartColumn;
0705: int sectionStart = getSectionColumn();
0706: int endPosn = indexPosn(index);
0707: int op = queueTail;
0708: int todo = queueSize;
0709: while (todo > 0) {
0710: // If at end of queueInts, skip.
0711: if (op >= queueInts.length)
0712: op = 0;
0713: int type = getQueueType(op);
0714: if (type != QITEM_NOP_TYPE) {
0715: int posn = queueInts[op + QITEM_POSN];
0716: if (posn >= endPosn)
0717: break;
0718: if (type == QITEM_TAB_TYPE)
0719: column += computeTabSize(op, sectionStart, column
0720: + posnIndex(posn));
0721: else if (type == QITEM_NEWLINE_TYPE
0722: || type == QITEM_BLOCK_START_TYPE)
0723: sectionStart = column
0724: + posnIndex(queueInts[op + QITEM_POSN]);
0725: }
0726: int size = getQueueSize(op);
0727: todo -= size;
0728: op += size;
0729: }
0730: return column + index;
0731: }
0732:
0733: void expandTabs(int through) {
0734: int numInsertions = 0;
0735: int additional = 0;
0736: int column = bufferStartColumn;
0737: int sectionStart = getSectionColumn();
0738: int op = queueTail;
0739: int todo = queueSize;
0740: int blocksUsed = LOGICAL_BLOCK_LENGTH * pendingBlocksCount;
0741: while (todo > 0) {
0742: if (op == queueInts.length)
0743: op = 0;
0744: if (op == through)
0745: break;
0746: int type = getQueueType(op);
0747: if (type == QITEM_TAB_TYPE) {
0748: int index = posnIndex(queueInts[op + QITEM_POSN]);
0749: int tabsize = computeTabSize(op, sectionStart, column
0750: + index);
0751: if (tabsize != 0) {
0752: // We use the blocks array for a temporary tab buffer.
0753: if (blocksUsed + 2 * numInsertions + 1 >= blocks.length) {
0754: int[] newBlocks = new int[2 * blocks.length];
0755: System.arraycopy(blocks, 0, newBlocks, 0,
0756: blocks.length);
0757: blocks = newBlocks;
0758: }
0759: blocks[blocksUsed + 2 * numInsertions] = index;
0760: blocks[blocksUsed + 2 * numInsertions + 1] = tabsize;
0761: numInsertions++;
0762: additional += tabsize;
0763: column += tabsize;
0764: }
0765: } else if (op == QITEM_NEWLINE_TYPE
0766: || op == QITEM_BLOCK_START_TYPE) {
0767: sectionStart = column
0768: + posnIndex(queueInts[op + QITEM_POSN]);
0769: }
0770: int size = getQueueSize(op);
0771: todo -= size;
0772: op += size;
0773: }
0774: if (numInsertions > 0) {
0775: int fillPtr = bufferFillPointer;
0776: int newFillPtr = fillPtr + additional;
0777: char[] buffer = this .buffer;
0778: char[] newBuffer = buffer;
0779: int length = buffer.length;
0780: int end = fillPtr;
0781: if (newFillPtr > length) {
0782: int newLength = enoughSpace(fillPtr, additional);
0783: newBuffer = new char[newLength];
0784: this .buffer = newBuffer;
0785: }
0786: bufferFillPointer = newFillPtr;
0787: bufferOffset -= additional;
0788: for (int i = numInsertions; --i >= 0;) {
0789: int srcpos = blocks[blocksUsed + 2 * i];
0790: int amount = blocks[blocksUsed + 2 * i + 1];
0791: int dstpos = srcpos + additional;
0792: System.arraycopy(buffer, srcpos, newBuffer, dstpos, end
0793: - srcpos);
0794: for (int j = dstpos - amount; j < dstpos; j++)
0795: newBuffer[j] = ' ';
0796: additional -= amount;
0797: end = srcpos;
0798: }
0799: if (newBuffer != buffer)
0800: System.arraycopy(buffer, 0, newBuffer, 0, end);
0801: }
0802: }
0803:
0804: // stuff to do the actual outputting
0805:
0806: int ensureSpaceInBuffer(int want) {
0807: char[] buffer = this .buffer;
0808: int length = buffer.length;
0809: int fillPtr = bufferFillPointer;
0810: int available = length - fillPtr;
0811: if (available > 0)
0812: return available;
0813: else if (prettyPrintingMode > 0 && fillPtr > lineLength) {
0814: if (!maybeOutput(false, false))
0815: outputPartialLine();
0816: return ensureSpaceInBuffer(want);
0817: } else {
0818: int newLength = enoughSpace(length, want);
0819: char[] newBuffer = new char[newLength];
0820: this .buffer = newBuffer;
0821: for (int i = fillPtr; --i >= 0;)
0822: newBuffer[i] = buffer[i];
0823: return newLength - fillPtr;
0824: }
0825: }
0826:
0827: boolean maybeOutput(boolean forceNewlines, boolean flushing) {
0828: boolean outputAnything = false;
0829: //log("maybeOutput("+forceNewlines+"):"); dumpQueue();
0830: loop: while (queueSize > 0) {
0831: if (queueTail >= queueInts.length)
0832: queueTail = 0;
0833: int next = queueTail;
0834: int type = getQueueType(next);
0835: switch (type) {
0836: case QITEM_NEWLINE_TYPE:
0837: boolean cond;
0838: int fits = -1;
0839: switch (queueInts[next + QITEM_NEWLINE_KIND]) {
0840: default: // LINEAR, LITERAL, or MANDATORY:
0841: cond = true;
0842: break;
0843: case NEWLINE_MISER:
0844: cond = isMisering();
0845: break;
0846: case NEWLINE_FILL:
0847: if (isMisering()
0848: || (lineNumber > getSectionStartLine())) {
0849: cond = true;
0850: break;
0851: }
0852: /// ... fall through to ...
0853: case NEWLINE_SPACE:
0854: int end = queueInts[next
0855: + QITEM_SECTION_START_SECTION_END];
0856: if (end == 0)
0857: end = -1;
0858: else { // convert relative->absolute.
0859: end = next + end;
0860: if (end >= queueInts.length)
0861: end -= queueInts.length;
0862: }
0863: fits = fitsOnLine(end, forceNewlines);
0864: if (fits > 0)
0865: cond = false;
0866: else if (fits < 0 || flushing)
0867: cond = true;
0868: else
0869: break loop;
0870: break;
0871: }
0872: if (cond) {
0873: outputAnything = true;
0874: try {
0875: if (flushing && fits == 0)
0876: outputPartialLine();
0877: else
0878: outputLine(next);
0879: } catch (IOException ex) {
0880: throw new RuntimeException(ex.toString());
0881: }
0882: }
0883: break;
0884: case QITEM_INDENTATION_TYPE:
0885: if (!isMisering()) {
0886: int kind = queueInts[next + QITEM_INDENTATION_KIND];
0887: int indent = queueInts[next
0888: + QITEM_INDENTATION_AMOUNT];
0889: if (kind == QITEM_INDENTATION_BLOCK)
0890: indent += getStartColumn();
0891: else
0892: indent += posnColumn(queueInts[next
0893: + QITEM_POSN]);
0894: //log("setIndent from "+next+": "+queueInts[next+QITEM_INDENTATION_AMOUNT]+" column:"+indent);
0895: setIndentation(indent);
0896: }
0897: break;
0898: case QITEM_BLOCK_START_TYPE:
0899: int start = next;
0900: int end = queueInts[next
0901: + QITEM_SECTION_START_SECTION_END];
0902: // Convert relative offset to absolute index:
0903: end = end > 0 ? (end + next) % queueInts.length : -1;
0904: fits = fitsOnLine(end, forceNewlines);
0905: //log("block-start @"+next+" end:"+end+" force:"+forceNewlines+" fits:"+fits);
0906: if (fits > 0) {
0907: // Just nuke the whole logical block and make it look
0908: // like one nice long literal.
0909: int endr = queueInts[next
0910: + QITEM_BLOCK_START_BLOCK_END];
0911: // make absolute:
0912: next = (endr + next) % queueInts.length;
0913: expandTabs(next);
0914: queueTail = next;
0915: queueSize -= endr;
0916: //log("remove block -> next:"+next+" endr:"+endr+" qSize:"+queueSize);
0917: } else if (fits < 0 || flushing) {
0918: String prefix = queueStrings[next
0919: + QITEM_BLOCK_START_PREFIX];
0920: String suffix = queueStrings[next
0921: + QITEM_BLOCK_START_SUFFIX];
0922: //log("reallyStartLogicalBlock: "+blockDepth+" at:"+next);
0923: reallyStartLogicalBlock(posnColumn(queueInts[next
0924: + QITEM_POSN]), prefix, suffix);
0925: } else
0926: // Don't know.
0927: break loop;
0928: if (currentBlock == start)
0929: currentBlock = -1;
0930: break;
0931: case QITEM_BLOCK_END_TYPE:
0932: //log("reallyEndLogicalBlock: "+blockDepth+" at:"+next);
0933: reallyEndLogicalBlock();
0934: break;
0935: case QITEM_TAB_TYPE:
0936: expandTabs(next);
0937: break;
0938: }
0939: int size = getQueueSize(queueTail);
0940: queueSize -= size;
0941: //log("maybeWrite size: "+size+" ->"+queueSize);
0942: queueTail = next + size;
0943: }
0944: return outputAnything;
0945: }
0946:
0947: protected int getMiserWidth() // DONE
0948: {
0949: // CommonLisp: Use *print-miser-width*.
0950: return miserWidth;
0951: }
0952:
0953: boolean isMisering() // DONE
0954: {
0955: int mwidth = getMiserWidth();
0956: return (mwidth > 0 && lineLength - getStartColumn() <= mwidth);
0957: }
0958:
0959: int getMaxLines() {
0960: // Should be value of CommonLisp *print-lines*.
0961: return -1;
0962: }
0963:
0964: boolean printReadably() {
0965: // Should be value of CommonLisp *print-readably*.
0966: return true;
0967: }
0968:
0969: /** Return 1 if true; -1 if false; 0 if don't know. */
0970: int fitsOnLine(int sectionEnd, boolean forceNewlines) // DONE
0971: {
0972: int available = lineLength;
0973: if (!printReadably() && getMaxLines() == lineNumber) {
0974: available -= 3; // For the " ..".
0975: available -= getSuffixLength();
0976: }
0977: if (sectionEnd >= 0)
0978: return posnColumn(queueInts[sectionEnd + QITEM_POSN]) <= available ? 1
0979: : -1;
0980: if (forceNewlines)
0981: return -1;
0982: if (indexColumn(bufferFillPointer) > available)
0983: return -1;
0984: return 0; // don't know.
0985: }
0986:
0987: public void lineAbbreviationHappened() {
0988: // Hook.
0989: }
0990:
0991: /** Output a new line.
0992: * @param newline index of a newline queue item
0993: */
0994: void outputLine(int newline) throws IOException {
0995: char[] buffer = this .buffer;
0996: int kind = queueInts[newline + QITEM_NEWLINE_KIND];
0997: boolean isLiteral = kind == NEWLINE_LITERAL;
0998: int amountToConsume = posnIndex(queueInts[newline + QITEM_POSN]);
0999: int amountToPrint;
1000: if (isLiteral)
1001: amountToPrint = amountToConsume;
1002: else {
1003: // Skip trailing spaces.
1004: for (int i = amountToConsume;;) {
1005: if (--i < 0) {
1006: amountToPrint = 0;
1007: break;
1008: }
1009: if (buffer[i] != ' ') {
1010: amountToPrint = i + 1;
1011: break;
1012: }
1013: }
1014: }
1015: out.write(buffer, 0, amountToPrint);
1016: int lineNumber = this .lineNumber;
1017: //log("outputLine#"+lineNumber+": \""+new String(buffer, 0, amountToPrint)+"\" curBlock:"+currentBlock);
1018: lineNumber++;
1019: if (!printReadably()) {
1020: int maxLines = getMaxLines();
1021: if (maxLines > 0 && lineNumber >= maxLines) {
1022: out.write(" ..");
1023: int suffixLength = getSuffixLength();
1024: if (suffixLength != 0) {
1025: char[] suffix = this .suffix;
1026: int len = suffix.length;
1027: out.write(suffix, len - suffixLength, suffixLength);
1028: }
1029: // (throw 'line-limit-abbreviation-happened t))
1030: lineAbbreviationHappened();
1031: }
1032: }
1033: this .lineNumber = lineNumber;
1034: out.write('\n');
1035: bufferStartColumn = 0;
1036: int fillPtr = bufferFillPointer;
1037: int prefixLen = isLiteral ? getPerLinePrefixEnd()
1038: : getPrefixLength();
1039: int shift = amountToConsume - prefixLen;
1040: int newFillPtr = fillPtr - shift;
1041: char[] newBuffer = buffer;
1042: int bufferLength = buffer.length;
1043: if (newFillPtr > bufferLength) {
1044: newBuffer = new char[enoughSpace(bufferLength, newFillPtr
1045: - bufferLength)];
1046: this .buffer = newBuffer;
1047: }
1048: System.arraycopy(buffer, amountToConsume, newBuffer, prefixLen,
1049: fillPtr - amountToConsume);
1050: System.arraycopy(prefix, 0, newBuffer, 0, prefixLen);
1051: bufferFillPointer = newFillPtr;
1052: bufferOffset += shift;
1053: if (!isLiteral) {
1054: blocks[blockDepth + BLOCK_SECTION_COLUMN] = prefixLen;
1055: blocks[blockDepth + BLOCK_SECTION_START_LINE] = lineNumber;
1056: }
1057: }
1058:
1059: void outputPartialLine() {
1060: //log("outputPartialLine");
1061: int tail = queueTail;
1062: while (queueSize > 0 && getQueueType(tail) == QITEM_NOP_TYPE) {
1063: int size = getQueueSize(tail);
1064: queueSize -= size;
1065: tail += size;
1066: if (tail == queueInts.length)
1067: tail = 0;
1068: queueTail = tail;
1069: }
1070: int fillPtr = bufferFillPointer;
1071: int count = queueSize > 0 ? posnIndex(queueInts[tail
1072: + QITEM_POSN]) : fillPtr;
1073: int newFillPtr = fillPtr - count;
1074: if (count <= 0)
1075: throw new Error(
1076: "outputPartialLine called when nothing can be output.");
1077: try {
1078: out.write(buffer, 0, count);
1079: //log("outputPartial: \""+new String(buffer, 0, count)+'\"');
1080: } catch (IOException ex) {
1081: throw new RuntimeException(ex.toString());
1082: }
1083: bufferStartColumn += count;
1084: System.arraycopy(buffer, count, buffer, 0, newFillPtr);
1085: bufferFillPointer = newFillPtr;
1086: bufferOffset += count;
1087: }
1088:
1089: public void forcePrettyOutput() throws IOException {
1090: maybeOutput(false, true);
1091: if (bufferFillPointer > 0)
1092: outputPartialLine();
1093: expandTabs(-1);
1094: bufferStartColumn = getColumnNumber();
1095: out.write(buffer, 0, bufferFillPointer);
1096: bufferFillPointer = 0;
1097: queueSize = 0;
1098: }
1099:
1100: public void flush() {
1101: if (out == null)
1102: return;
1103: try {
1104: forcePrettyOutput();
1105: out.flush();
1106: } catch (IOException ex) {
1107: throw new RuntimeException(ex.toString());
1108: }
1109: }
1110:
1111: public void close() throws IOException {
1112: if (out != null) {
1113: forcePrettyOutput();
1114: out.close();
1115: out = null;
1116: }
1117: buffer = null;
1118: }
1119:
1120: /** Not meaningful if {@code prettyPrintingMode > 0}. */
1121: public int getColumnNumber() {
1122: int i = bufferFillPointer;
1123: for (;;) {
1124: if (--i < 0)
1125: return bufferStartColumn + bufferFillPointer;
1126: char ch = buffer[i];
1127: if (ch == '\n' || ch == '\r')
1128: return bufferFillPointer - (i + 1);
1129: }
1130: }
1131:
1132: public void setColumnNumber(int column) {
1133: bufferStartColumn += column - getColumnNumber();
1134: }
1135:
1136: public void clearBuffer() {
1137: bufferStartColumn = 0;
1138: bufferFillPointer = 0;
1139: lineNumber = 0;
1140: bufferOffset = 0;
1141: blockDepth = LOGICAL_BLOCK_LENGTH;
1142: queueTail = 0;
1143: queueSize = 0;
1144: pendingBlocksCount = 0;
1145: }
1146:
1147: /*
1148: public static PrintWriter log;
1149: static {
1150: try { log = new PrintWriter(new FileOutputStream("/tmp/pplog")); }
1151: catch (Throwable ex) { ex.printStackTrace(); }
1152: }
1153: void log(String str)
1154: {
1155: log.println(str);
1156: log.flush();
1157: }
1158: void dumpQueue()
1159: {
1160: log.println("Queue tail:"+queueTail+" size:"+queueSize
1161: +" length:"+queueInts.length+" startCol:"+bufferStartColumn);
1162: dumpQueue(queueTail, queueSize, log);
1163: }
1164:
1165: void dumpQueue(int start, int todo, PrintWriter out)
1166: {
1167: int bufIndex = 0;
1168: while (todo > 0)
1169: {
1170: if (start == queueInts.length)
1171: start = 0;
1172: if (start < 0 || start >= queueInts.length)
1173: {
1174: out.print('@'); out.print(start); out.print(": ");
1175: out.print("out of bounds - queueInts length is ");
1176: out.println(queueInts.length);
1177: break;
1178: }
1179: int type = getQueueType(start);
1180: int size = getQueueSize(start);
1181: if (type != QITEM_NOP_TYPE)
1182: {
1183: int newIndex = posnIndex(queueInts[start+QITEM_POSN]);
1184: int count = newIndex - bufIndex;
1185: if (count > 0)
1186: {
1187: out.print(count); out.print(" chars: \"");
1188: out.write(buffer, bufIndex, count);
1189: out.println('\"');
1190: bufIndex = newIndex;
1191: }
1192: }
1193: out.print('@'); out.print(start); out.print(": ");
1194: out.print("type:"); out.print(type);
1195: switch (type)
1196: {
1197: case QITEM_NEWLINE_TYPE:
1198: out.print("(newline)"); break;
1199: case QITEM_INDENTATION_TYPE:
1200: out.print("(indentation)"); break;
1201: case QITEM_BLOCK_START_TYPE:
1202: out.print("(block-start)"); break;
1203: case QITEM_BLOCK_END_TYPE:
1204: out.print("(block-end)"); break;
1205: case QITEM_TAB_TYPE: out.print("(tab)");
1206: break;
1207: case QITEM_NOP_TYPE:
1208: out.print("(nop)"); break;
1209: }
1210: out.print(" size:"); out.print(size);
1211: out.print("; @"); out.print(start+QITEM_POSN);
1212: if (type != QITEM_NOP_TYPE)
1213: {
1214: out.print(": posn:");
1215: int posn = queueInts[start+QITEM_POSN];
1216: out.print(posn);
1217: out.print(" index:");
1218: out.println(posnIndex(posn));
1219: }
1220: if (type == QITEM_NEWLINE_TYPE
1221: || type == QITEM_BLOCK_START_TYPE)
1222:
1223: {
1224: out.print('@'); out.print(start+QITEM_SECTION_START_DEPTH);
1225: out.print(": - depth:");
1226: out.print(queueInts[start+QITEM_SECTION_START_DEPTH]);
1227: out.print("; @");
1228: out.print(start+QITEM_SECTION_START_SECTION_END);
1229: out.print(": section-end:");
1230: out.println(queueInts[start+QITEM_SECTION_START_SECTION_END]);
1231: }
1232: switch (type)
1233: {
1234: case QITEM_BLOCK_START_TYPE:
1235: printQueueWord(start, QITEM_BLOCK_START_BLOCK_END, "block-end", out);
1236: printQueueStringWord(start, QITEM_BLOCK_START_PREFIX, "prefix", out);
1237: printQueueStringWord(start, QITEM_BLOCK_START_SUFFIX, "suffix", out);
1238: break;
1239: case QITEM_NEWLINE_TYPE:
1240: out.print('@');
1241: out.print(start+QITEM_NEWLINE_KIND);
1242: out.print(": - kind: ");
1243: int kind = queueInts[start+QITEM_NEWLINE_KIND];
1244: String skind = "???";
1245: switch (kind)
1246: {
1247: case NEWLINE_LINEAR: skind = "linear"; break;
1248: case NEWLINE_LITERAL: skind = "literal"; break;
1249: case NEWLINE_FILL: skind = "fill"; break;
1250: case NEWLINE_SPACE: skind = "space"; break;
1251: case NEWLINE_MISER: skind = "miser"; break;
1252: case NEWLINE_MANDATORY: skind = "mandatory"; break;
1253: }
1254: out.print(kind);
1255: out.print('(');
1256: out.print(skind);
1257: out.println(')');
1258: break;
1259: case QITEM_INDENTATION_TYPE:
1260: printQueueWord(start, QITEM_INDENTATION_KIND, "kind", out);
1261: printQueueWord(start, QITEM_INDENTATION_AMOUNT, "amount", out);
1262: break;
1263: default:
1264: for (int i = 2; i < size; i++)
1265: printQueueWord(start, i, "word#"+i, out);
1266: }
1267: todo -= size;
1268: start += size;
1269: }
1270: int count = bufferFillPointer - bufIndex;
1271: if (count > 0)
1272: {
1273: out.print(count); out.print(" chars: \"");
1274: out.write(buffer, bufIndex, count);
1275: out.println('\"');
1276: }
1277: }
1278:
1279: private void printQueueWord(int start, int offset,
1280: String fname, PrintWriter out)
1281: {
1282: out.print('@');
1283: out.print(start+offset);
1284: out.print(": - ");
1285: out.print(fname);
1286: out.print(": ");
1287: out.println(queueInts[start+offset]);
1288: }
1289:
1290: private void printQueueStringWord(int start, int offset,
1291: String fname, PrintWriter out)
1292: {
1293: out.print('@');
1294: out.print(start+offset);
1295: out.print(": - ");
1296: out.print(fname);
1297: out.print(": ");
1298: String str = queueStrings[start+offset];
1299: if (str == null)
1300: out.println("null");
1301: else
1302: {
1303: out.print('\"');
1304: out.print(str);
1305: out.print('\"');
1306: out.print(" length: ");
1307: out.println(str.length());
1308: }
1309: }
1310:
1311: void check (String where)
1312: {
1313: String msg = null;
1314: if (currentBlock != -1
1315: && ! (currentBlock < queueInts.length
1316: && currentBlock >= queueTail
1317: ? currentBlock < queueTail + queueSize
1318: : currentBlock < queueTail + queueSize - queueInts.length))
1319: msg = ("currentBlock ("+currentBlock
1320: +") >= queue length ("+queueInts.length+")");
1321: if (msg != null)
1322: {
1323: if (where != null)
1324: msg = "in "+where+": "+msg;
1325: log.println(msg);
1326: dumpQueue();
1327: log.flush();
1328: throw new Error(msg);
1329: }
1330: }
1331:
1332: String itemKindString (int kind)
1333: {
1334: switch (kind)
1335: {
1336: case QITEM_NOP_TYPE: return "nop";
1337: case QITEM_NEWLINE_TYPE: return "newline";
1338: case QITEM_INDENTATION_TYPE: return "indentation";
1339: case QITEM_BLOCK_START_TYPE: return "block-start";
1340: case QITEM_BLOCK_END_TYPE: return "block-end";
1341: case QITEM_TAB_TYPE: return "tab";
1342: default: return "("+kind+" - unknown)";
1343: }
1344: }
1345: String enqueueExtraLog = "";
1346: */
1347: }
|