Source Code Cross Referenced for PrettyWriter.java in  » Scripting » Kawa » gnu » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » Kawa » gnu.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.