KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > text > PrettyWriter


1 // Copyright (c) 2001, 2004, 2006 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.text;
5 import java.io.*;
6 import gnu.mapping.ThreadLocation;
7 import gnu.lists.LList;
8
9 /** A pretty printer.
10  *
11  * This code is transcribed from pprint.lisp in Steel Bank Common Lisp,
12  * which is again based on the code in CMU Common Lisp.
13  */

14
15 public class PrettyWriter extends java.io.Writer JavaDoc
16 {
17   protected Writer out;
18
19   public PrettyWriter(java.io.Writer JavaDoc out)
20   {
21     this.out = out;
22     prettyPrintingMode = 1;
23   }
24
25   public PrettyWriter(java.io.Writer JavaDoc out, int lineLength)
26   {
27     this.out = out;
28     this.lineLength = lineLength;
29     prettyPrintingMode = lineLength > 1 ? 1 : 0;
30   }
31
32   public PrettyWriter(java.io.Writer JavaDoc out, boolean prettyPrintingMode)
33   {
34     this.out = out;
35     this.prettyPrintingMode = prettyPrintingMode ? 1 : 0;
36   }
37
38   /** Line length we should format to. */
39   int lineLength = 80;
40   int miserWidth = 40;
41
42   public static ThreadLocation lineLengthLoc
43     = new ThreadLocation("line-length");
44   public static ThreadLocation miserWidthLoc
45     = new ThreadLocation("miser-width");
46   public static ThreadLocation indentLoc
47     = new ThreadLocation("indent");
48
49   /** The current pretty-printing mode.
50    * See setPrettyPrintingMode for valid values. */

51   int prettyPrintingMode;
52
53   /** Control pretty-printing mode.
54    * @param mode the value 0 disables pretty-printing;
55    * the value 1 enables ecplicit pretty-printing;
56    * the value 2 enables pretty-printing with auto-fill, which means that
57    * spaces are treated like enqueing NEWLINE_SPACE (essentiall a 'fill').
58    */

59   public void setPrettyPrintingMode (int mode)
60   { prettyPrintingMode = mode; }
61
62   /** Return pretty-printing mode.
63    * @return 0, 1, 2, as described for {@link #setPrettyPrintingMode(int)}.
64    */

65   public int getPrettyPrintingMode () { return prettyPrintingMode; }
66
67   /** Is pretty printing enabled? */
68   public boolean isPrettyPrinting () { return prettyPrintingMode > 0; }
69
70   /** Turn pretty printing on or off.
71    * Equivalent to {@code setPrettyPrintingMode(mode?1:0)}.
72    */

73   public void setPrettyPrinting (boolean mode)
74   {
75     prettyPrintingMode = mode ? 0 : 1;
76   }
77
78   public static int initialBufferSize = 126;
79
80   /** Holds all the text that has been output but not yet printed. */
81   public /* FIXME */ char[] buffer = new char[initialBufferSize];
82
83   /** The index into BUFFER where more text should be put. */
84   public /* FIXME */ int bufferFillPointer;
85
86   /** Total amount of stuff that has been shifted out of the buffer.
87    * Whenever we output stuff from the buffer, we shift the remaining noise
88    * over. This makes it difficult to keep references to locations in
89    * the buffer. */

90   int bufferOffset;
91
92   /** The column the first character in the buffer will appear in.
93    * Normally zero, but if we end up with a very long line with no breaks in it
94    * we might have to output part of it. Then this will no longer be zero.
95    * Ditto after emitting a prompt. */

96   int bufferStartColumn;
97   
98   /** The line number we are currently on. Used for *print-lines* abrevs and
99    * to tell when sections have been split across multiple lines. */

100   int lineNumber;
101
102   // There are three different units for measuring character positions:
103
// COLUMN - offset (in characters) from the start of the current line.
104
// INDEX - index into the output buffer.
105
// POSN - some position in the stream of characters cycling through
106
// the output buffer.
107

108   private int indexPosn (int index)
109   {
110     return index + bufferOffset;
111   }
112
113   private int posnIndex (int posn)
114   {
115     return posn - bufferOffset;
116   }
117
118   private int posnColumn (int posn)
119   {
120     return indexColumn(posnIndex(posn));
121   }
122
123   /** Stack of logical blocks in effect at the buffer start.
124    * I.e. blocks for which {@code reallyStartLogicalBlock} has been called.
125    * Each block uses {@code LOGICAL_BLOCK_LENGTH} {@code int} in this array. */

126   int[] blocks = new int[10 * LOGICAL_BLOCK_LENGTH];
127   /** Number of {@code int}s used by each block in the {@code blocks} array. */
128   static final private int LOGICAL_BLOCK_LENGTH = 6;
129   static final private int BLOCK_START_COLUMN = -1;
130   static final private int BLOCK_SECTION_COLUMN = -2;
131   static final private int BLOCK_PER_LINE_PREFIX_END = -3;
132   static final private int BLOCK_PREFIX_LENGTH = -4;
133   static final private int BLOCK_SUFFIX_LENGTH = -5;
134   static final private int BLOCK_SECTION_START_LINE = -6;
135   /** The "stack pointer" in the {@code blocks} array. */
136   int blockDepth = LOGICAL_BLOCK_LENGTH;
137
138   /** Buffer holding the per-line prefix active at the buffer start.
139    * Indentation is included in this. The length of this is stored
140    * in the logical block stack. */

141   char[] prefix = new char[initialBufferSize];
142
143   /** Buffer holding the total remaining suffix active at the buffer start.
144    * The characters are right-justified in the buffer to make it easier
145    * to output the buffer. The length is stored in the logical block stack. */

146   char[] suffix = new char[initialBufferSize];
147
148   static final int QUEUE_INIT_ALLOC_SIZE = 300; // FIXME
149

150   /** A queue of pending operations.
151    * This is primarily stored in the circular buffer queueInts. There
152    * are different kinds of operation types, and each operation can
153    * require a variable number of elements in the buffer, depending on
154    * the operation type. Given an operation at 'index', the type
155    * operation type code is 'getQueueType(index)' (one of the
156    * QITEM_XXX_TYPE macros below), and the number of elements in the
157    * buffer is 'getQueueSize(index)' (one of the QITEM_XXX_SIZE values
158    * below). You can think of the various QITEM_XXX_TYPEs as
159    * "sub-classes" of queued operations, but instead of creating
160    * actual Java objects, we allocate the objects' fields in the
161    * queueInts and QueueStrings arrays, to avoid expensive object
162    * allocation. The special QITEM_NOP_TYPE is a used as a marker for
163    * when there isn't enough space in the rest of buffer, so we have
164    * to wrap around to the start. The other QITEM_XXX macros are the
165    * offsets of the various "fields" relative to the start index. */

166   int[] queueInts = new int[QUEUE_INIT_ALLOC_SIZE];
167
168   /** For simplicity, queueStrings is the same size as queueInts. */
169   String JavaDoc[] queueStrings = new String JavaDoc[QUEUE_INIT_ALLOC_SIZE];
170   /** Index in queueInts and queueStrings of oldest enqueued operation. */
171   int queueTail;
172   /** Number of elements (in queueInts and queueStrings) in use. */
173   int queueSize;
174   /** If >= 0, index (into queueInts) of current unclosed begin-block node.
175    * This is a head of a linked linked of queued BLOCK_START for which
176    * we haven't seen the matching BLOCK_END */

177   int currentBlock = -1;
178   /** Number of startLogicalBlock - number of endLogicalBlock. */
179   public int pendingBlocksCount;
180
181   /** The first it QITEM contains it type code and size.
182    * The type code is one of the QITEM_XXX_TYPE values below.
183    * The size is the corresponding QITEM_XXX_SIZE value below,
184    * except for the case of QITEM_NOP_TYPE (which is used as a filler). */

185   static final int QITEM_TYPE_AND_SIZE = 0;
186   private int getQueueType(int index) { return queueInts[index] & 0xFF; }
187   private int getQueueSize(int index) { return queueInts[index] >> 16; }
188   /** Relative offset of POSN field of a QITEM> */
189   static final int QITEM_POSN = 1;
190   /** Size of "base part" of a QITEM. */
191   static final int QITEM_BASE_SIZE = 2;
192
193   /** A dummy queue item used at the high end of the queue buffer
194    * when there isn't enough space for the needed queue item. */

195   static final int QITEM_NOP_TYPE = 0;
196
197   /** "Abstract" type for beginning of section.
198    * A section is from a block-start to a newline, from a newline to
199    * the next newline (in the same block?), or from a newline to
200    * the block end (?). */

201   /*static final int QITEM_SECTION_START_TYPE = 1;*/
202   static final int QITEM_SECTION_START_SIZE = QITEM_BASE_SIZE + 2;
203   static final int QITEM_SECTION_START_DEPTH = QITEM_BASE_SIZE;
204   static final int QITEM_SECTION_START_SECTION_END = QITEM_BASE_SIZE + 1;
205
206   /** A newline queue item. */
207   static final int QITEM_NEWLINE_TYPE = 2;
208   static final int QITEM_NEWLINE_SIZE = QITEM_SECTION_START_SIZE + 1;
209   static final int QITEM_NEWLINE_KIND = QITEM_SECTION_START_SIZE;
210   public static final int NEWLINE_LINEAR = 'N';
211   public static final int NEWLINE_LITERAL = 'L';
212   public static final int NEWLINE_FILL = 'F';
213   /** A non-nested ' ' gets an implicit NEWLINE_SPACE.
214    * This is treated similarly to NEWLINE_FILL, but not quite. */

215   public static final int NEWLINE_SPACE = 'S';
216   public static final int NEWLINE_MISER = 'M';
217   public static final int NEWLINE_MANDATORY = 'R'; // "required"
218

219   static final int QITEM_INDENTATION_TYPE = 3;
220   static final int QITEM_INDENTATION_SIZE = QITEM_BASE_SIZE + 2;
221   static final int QITEM_INDENTATION_KIND = QITEM_BASE_SIZE;
222   static final char QITEM_INDENTATION_BLOCK = 'B';
223   static final char QITEM_INDENTATION_CURRENT = 'C';
224   static final int QITEM_INDENTATION_AMOUNT = QITEM_BASE_SIZE + 1;
225
226   /** A "block-start" queue item. */
227   static final int QITEM_BLOCK_START_TYPE = 4;
228   static final int QITEM_BLOCK_START_SIZE = QITEM_SECTION_START_SIZE + 3;
229   /** If the QITEM_BLOCK_START_BLOCK_END < 0, it points to
230    * the previous (outer) un-closed block-start.
231    * If QITEM_BLOCK_START_BLOCK_END > 0, it points to the
232    * corresponding block-end node.
233    * In both cases the pointers are relative to the current BLOCK_START. */

234   static final int QITEM_BLOCK_START_BLOCK_END = QITEM_SECTION_START_SIZE;
235   static final int QITEM_BLOCK_START_PREFIX = QITEM_SECTION_START_SIZE + 1;
236   static final int QITEM_BLOCK_START_SUFFIX = QITEM_SECTION_START_SIZE + 2;
237
238   static final int QITEM_BLOCK_END_TYPE = 5;
239   static final int QITEM_BLOCK_END_SIZE = QITEM_BASE_SIZE;
240
241   static final int QITEM_TAB_TYPE = 6;
242   static final int QITEM_TAB_SIZE = QITEM_BASE_SIZE + 3;
243   static final int QITEM_TAB_FLAGS = QITEM_BASE_SIZE;
244   static final int QITEM_TAB_IS_SECTION = 1;
245   static final int QITEM_TAB_IS_RELATIVE = 2;
246   static final int QITEM_TAB_COLNUM = QITEM_BASE_SIZE + 1;
247   static final int QITEM_TAB_COLINC = QITEM_BASE_SIZE + 2;
248
249   private int getSectionColumn()
250   {
251     return blocks[blockDepth+BLOCK_SECTION_COLUMN];
252   }
253
254   private int getStartColumn()
255   {
256     return blocks[blockDepth+BLOCK_START_COLUMN];
257   }
258
259   private int getPerLinePrefixEnd()
260   {
261     return blocks[blockDepth+BLOCK_PER_LINE_PREFIX_END];
262   }
263
264   private int getPrefixLength()
265   {
266     return blocks[blockDepth+BLOCK_PREFIX_LENGTH];
267   }
268
269   private int getSuffixLength()
270   {
271     return blocks[blockDepth+BLOCK_SUFFIX_LENGTH];
272   }
273
274   private int getSectionStartLine()
275   {
276     return blocks[blockDepth+BLOCK_SECTION_START_LINE];
277   }
278
279   boolean wordEndSeen;
280
281   /** Note the end of a "word". See {@link #writeWordStart}. */
282   public void writeWordEnd ()
283   {
284     wordEndSeen = true;
285   }
286
287   /** Maybe write a word-separating space.
288    * Specifically, write a space if the previous output
289    * was {@link #writeWordEnd}. Otherwise, do nothing.
290    */

291   public void writeWordStart ()
292   {
293     if (wordEndSeen)
294       write(' ');
295     wordEndSeen = false;
296   }
297
298   public void clearWordEnd ()
299   {
300     wordEndSeen = false;
301   }
302
303   public void write (int ch)
304   {
305     wordEndSeen = false;
306     //log("{WRITE-ch: "+((char)ch)+"}");
307
if (ch == '\n' && prettyPrintingMode > 0)
308       enqueueNewline(NEWLINE_LITERAL);
309     else
310       {
311     ensureSpaceInBuffer(1);
312     int fillPointer = bufferFillPointer;
313     buffer[fillPointer] = (char) ch;
314     bufferFillPointer = 1 + fillPointer;
315     if (ch == ' ' && prettyPrintingMode > 1 && currentBlock < 0)
316       enqueueNewline(NEWLINE_SPACE);
317       }
318   }
319
320   public void write (String JavaDoc str)
321   {
322     write(str, 0, str.length());
323   }
324
325   public void write (String JavaDoc str, int start, int count)
326   {
327     wordEndSeen = false;
328     //log("{WRITE-str: "+str.substring(start, start+count)+"}");
329
while (count > 0)
330       {
331     int cnt = count;
332     // May allocate for space than we need (if the buffer gets fluhed). FIXME
333
int available = ensureSpaceInBuffer(count);
334     if (cnt > available)
335       cnt = available;
336     int fillPointer = bufferFillPointer;
337     count -= cnt;
338     while (--cnt >= 0)
339       {
340         char ch = str.charAt(start++);
341         if (ch == '\n' && prettyPrintingMode > 0)
342           {
343         bufferFillPointer = fillPointer;
344         enqueueNewline(NEWLINE_LITERAL);
345         fillPointer = bufferFillPointer;
346           }
347         else
348           {
349         buffer[fillPointer++] = (char) ch;
350         if (ch == ' ' && prettyPrintingMode > 1 && currentBlock < 0)
351           {
352             bufferFillPointer = fillPointer;
353             enqueueNewline(NEWLINE_SPACE);
354             fillPointer = bufferFillPointer;
355           }
356           }
357       }
358     bufferFillPointer = fillPointer;
359       }
360   }
361
362   public void write (char[] str)
363   {
364     write(str, 0, str.length);
365   }
366
367   public void write (char[] str, int start, int count)
368   {
369     wordEndSeen = false;
370     //log("{WRITE: "+new String(str, start, count)+"}");
371
int end = start + count;
372   retry:
373     while (count > 0)
374       {
375     // Look for newline. Should be merged with following loop. FIXME.
376
for (int i = start; i < end; i++)
377       {
378         char c;
379         if (prettyPrintingMode > 0
380         && ((c = str[i]) == '\n'
381             || (c == ' ' && currentBlock < 0)))
382           {
383         write(str, start, i - start); // Recurse
384
write(c);
385         start = i + 1;
386         count = end - start;
387         continue retry;
388           }
389       }
390
391     for (;;)
392       {
393         int available = ensureSpaceInBuffer(count);
394         int cnt = available < count ? available : count;
395         int fillPointer = bufferFillPointer;
396         int newFillPtr = fillPointer + cnt;
397         for (int i = fillPointer; i < newFillPtr; i++)
398           buffer[i] = str[start++];
399         bufferFillPointer = newFillPtr;
400         count -= cnt;
401         if (count == 0)
402           break;
403       }
404       }
405   }
406
407   private void pushLogicalBlock(int column,
408                 int perLineEnd,
409                 int prefixLength, int suffixLength,
410                 int sectionStartLine)
411   {
412     int newLength = blockDepth + LOGICAL_BLOCK_LENGTH;
413     if (newLength >= blocks.length)
414       {
415     int[] newBlocks = new int[2 * blocks.length];
416     System.arraycopy(blocks, 0, newBlocks, 0, blockDepth);
417     blocks = newBlocks;
418       }
419     blockDepth = newLength;
420     blocks[blockDepth + BLOCK_START_COLUMN] = column;
421     blocks[blockDepth + BLOCK_SECTION_COLUMN] = column;
422     blocks[blockDepth + BLOCK_PER_LINE_PREFIX_END] = perLineEnd;
423     blocks[blockDepth + BLOCK_PREFIX_LENGTH] = prefixLength;
424     blocks[blockDepth + BLOCK_SUFFIX_LENGTH] = suffixLength;
425     blocks[blockDepth + BLOCK_SECTION_START_LINE] = sectionStartLine;
426   }
427   
428   void reallyStartLogicalBlock(int column, String JavaDoc prefix, String JavaDoc suffix)
429   {
430     int perLineEnd = getPerLinePrefixEnd();
431     int prefixLength = getPrefixLength();
432     int suffixLength = getSuffixLength();
433     pushLogicalBlock(column, perLineEnd, prefixLength, suffixLength,
434              lineNumber);
435     setIndentation(column);
436     if (prefix != null)
437       {
438     blocks[blockDepth + BLOCK_PER_LINE_PREFIX_END] = column;
439     int plen = prefix.length();
440     prefix.getChars(0, plen, this.suffix, column - plen);
441       }
442     if (suffix != null)
443       {
444     // Prepend the new suffix in front of the old suffix in this.suffix.
445
// The suffix is stored at the "right" (high-index) end of
446
// this.suffix to make it easier to prepend new suffixes.
447
char[] totalSuffix = this.suffix;
448     int totalSuffixLen = totalSuffix.length;
449     int additional = suffix.length();
450     int newSuffixLen = suffixLength + additional;
451     if (newSuffixLen > totalSuffixLen)
452       {
453         int newTotalSuffixLen = enoughSpace(totalSuffixLen, additional);
454         this.suffix = new char[newTotalSuffixLen];
455         System.arraycopy(totalSuffix, totalSuffixLen - suffixLength,
456                  this.suffix, newTotalSuffixLen - suffixLength,
457                  suffixLength);
458         totalSuffixLen = newTotalSuffixLen;
459       }
460     suffix.getChars(0, additional,
461             totalSuffix, totalSuffixLen - newSuffixLen);
462     blocks[blockDepth + BLOCK_SUFFIX_LENGTH] = newSuffixLen;
463       }
464
465   }
466
467   int enqueueTab (int flags, int colnum, int colinc) // DONE
468
{
469     int addr = enqueue(QITEM_TAB_TYPE, QITEM_TAB_SIZE);
470     queueInts[addr + QITEM_TAB_FLAGS] = flags;
471     queueInts[addr + QITEM_TAB_COLNUM] = colnum;
472     queueInts[addr + QITEM_TAB_COLINC] = colinc;
473     return addr;
474   }
475
476   /** Calculate how much space to allocate for a buffer.
477    * @param current the current size of the buffer
478    * @param want how much more space is needed
479    */

480   private static int enoughSpace(int current, int want)
481   {
482     int doubled = 2 * current;
483     int enough = current + ((5 * want) >> 2);
484     return doubled > enough ? doubled : enough;
485   }
486
487   public void setIndentation (int column)
488   {
489     char[] prefix = this.prefix;
490     int prefixLen = prefix.length;
491     int current = getPrefixLength();
492     int minimum = getPerLinePrefixEnd();
493     if (minimum > column)
494       column = minimum;
495     if (column > prefixLen)
496       {
497     prefix = new char[enoughSpace(prefixLen, column - prefixLen)];
498     System.arraycopy(this.prefix, 0, prefix, 0, current);
499     this.prefix = prefix;
500       }
501     if (column > current)
502       {
503     for (int i = current; i < column; i++)
504       prefix[i] = ' ';
505       }
506     blocks[blockDepth + BLOCK_PREFIX_LENGTH] = column;
507   }
508
509   void reallyEndLogicalBlock ()
510   {
511     int oldIndent = getPrefixLength();
512     blockDepth -= LOGICAL_BLOCK_LENGTH; // Pop
513
int newIndent = getPrefixLength();
514     if (newIndent > oldIndent)
515       {
516     for (int i = oldIndent; i < newIndent; i++)
517       prefix[i] = ' ';
518       }
519   }
520
521   public int enqueue (int kind, int size)
522   {
523     int oldLength = queueInts.length;
524     int endAvail = oldLength - queueTail - queueSize;
525     if (endAvail > 0 && size > endAvail)
526       enqueue(QITEM_NOP_TYPE, endAvail);
527     if (queueSize + size > oldLength)
528       {
529     int newLength = enoughSpace(oldLength, size);
530     int[] newInts = new int[newLength];
531     String JavaDoc[] newStrings = new String JavaDoc[newLength];
532     int queueHead = queueTail + queueSize - oldLength;
533     if (queueHead > 0)
534       { // Wraps around.
535
System.arraycopy(queueInts, 0, newInts, 0, queueHead);
536         System.arraycopy(queueStrings, 0, newStrings, 0, queueHead);
537       }
538     int part1Len = oldLength - queueTail;
539     int deltaLength = newLength - oldLength;
540     System.arraycopy(queueInts, queueTail,
541              newInts, queueTail + deltaLength,
542              part1Len);
543     System.arraycopy(queueStrings, queueTail,
544              newStrings, queueTail + deltaLength,
545              part1Len);
546     queueInts = newInts;
547     queueStrings = newStrings;
548     if (currentBlock >= queueTail)
549       currentBlock += deltaLength;
550     queueTail += deltaLength;
551       }
552     int addr = queueTail + queueSize;
553     if (addr >= queueInts.length)
554       addr -= queueInts.length;
555     queueInts[addr + QITEM_TYPE_AND_SIZE] = kind | (size << 16);
556     if (size > 1)
557       queueInts[addr + QITEM_POSN] = indexPosn(bufferFillPointer);
558     //log("enqueue "+itemKindString(kind)+" size:"+size+" at:"+queueSize+enqueueExtraLog); enqueueExtraLog = "";
559
queueSize += size;
560     return addr;
561   }
562
563   public void enqueueNewline (int kind)
564   {
565     wordEndSeen = false;
566     int depth = pendingBlocksCount;
567     //enqueueExtraLog = " kind:"+(char) kind;
568
int newline = enqueue(QITEM_NEWLINE_TYPE, QITEM_NEWLINE_SIZE);
569     queueInts[newline + QITEM_NEWLINE_KIND] = kind;
570     queueInts[newline + QITEM_SECTION_START_DEPTH] = pendingBlocksCount;
571     queueInts[newline + QITEM_SECTION_START_SECTION_END] = 0;
572     int entry = queueTail;
573     int todo = queueSize;
574     while (todo > 0)
575       {
576     if (entry == queueInts.length)
577       entry = 0;
578     if (entry == newline)
579       break;
580     int type = getQueueType(entry);
581     if ((type == QITEM_NEWLINE_TYPE
582          || type == QITEM_BLOCK_START_TYPE)
583         && queueInts[entry + QITEM_SECTION_START_SECTION_END] == 0
584         && depth <= queueInts[entry + QITEM_SECTION_START_DEPTH])
585       {
586         int delta = newline - entry;
587         if (delta < 0)
588           delta += queueInts.length;
589         queueInts[entry + QITEM_SECTION_START_SECTION_END] = delta;
590       }
591     int size = getQueueSize(entry);
592     todo -= size;
593     entry += size;
594       }
595     maybeOutput (kind == NEWLINE_LITERAL || kind == NEWLINE_MANDATORY, false);
596   }
597
598   public final void writeBreak(int kind)
599   {
600     if (prettyPrintingMode > 0)
601       enqueueNewline(kind);
602   }
603
604   public int enqueueIndent (char kind, int amount)
605   {
606     //enqueueExtraLog = " kind:"+kind+" amount:"+amount;
607
int result = enqueue(QITEM_INDENTATION_TYPE, QITEM_INDENTATION_SIZE);
608     queueInts[result + QITEM_INDENTATION_KIND] = kind;
609     queueInts[result + QITEM_INDENTATION_AMOUNT] = amount;
610     return result;
611   }
612
613   public void addIndentation(int amount, boolean current)
614   {
615     if (prettyPrintingMode > 0)
616       enqueueIndent((current ? QITEM_INDENTATION_CURRENT
617              : QITEM_INDENTATION_BLOCK),
618             amount);
619   }
620
621   public void startLogicalBlock (String JavaDoc prefix, boolean perLine, String JavaDoc suffix)
622   {
623     // If the queue is empty, it is a good time to check if line-length etc
624
// have been changed.
625
if (queueSize == 0 && bufferFillPointer == 0)
626       {
627         Object JavaDoc llen = lineLengthLoc.get(null);
628         if (llen == null)
629           lineLength = 80;
630         else
631           lineLength = Integer.parseInt(llen.toString());
632
633         Object JavaDoc mwidth = miserWidthLoc.get(null);
634         if (mwidth == null || mwidth == Boolean.FALSE
635             // For Common Lisp nil. Should we use Language.isTrue() FIXME.
636
|| mwidth == LList.Empty)
637           miserWidth = -1;
638         else
639           miserWidth = Integer.parseInt(mwidth.toString());
640
641         Object JavaDoc indent = indentLoc.get(null);
642         // if (indent == null || indent ...
643
}
644     if (prefix != null)
645       write(prefix);
646     if (prettyPrintingMode == 0)
647       return;
648     int start = enqueue (QITEM_BLOCK_START_TYPE,
649              QITEM_BLOCK_START_SIZE);
650     queueInts[start + QITEM_SECTION_START_DEPTH] = pendingBlocksCount;
651     queueStrings[start + QITEM_BLOCK_START_PREFIX]
652       = perLine ? prefix : null;
653     queueStrings[start + QITEM_BLOCK_START_SUFFIX] = suffix;
654     pendingBlocksCount++;
655     int outerBlock = currentBlock;
656     if (outerBlock < 0)
657       outerBlock = 0;
658     else
659       {
660     outerBlock -= start;
661     if (outerBlock > 0)
662       outerBlock -= queueInts.length;
663       }
664     queueInts[start + QITEM_BLOCK_START_BLOCK_END] = outerBlock;
665     queueInts[start + QITEM_SECTION_START_SECTION_END] = 0;
666     currentBlock = start;
667   }
668
669   public void endLogicalBlock ()
670   {
671     int end = enqueue (QITEM_BLOCK_END_TYPE, QITEM_BLOCK_END_SIZE);
672     pendingBlocksCount--;
673     if (currentBlock < 0)
674       {
675     // reallyStartLogicalBlock has been called for the matching
676
// BEGIN_BLOCK, so it is no longer in the queue. Instead it is in
677
// the 'blocks' stack.
678
int suffixLength = blocks[blockDepth+BLOCK_SUFFIX_LENGTH];
679     int suffixPreviousLength
680       = blocks[blockDepth - LOGICAL_BLOCK_LENGTH + BLOCK_SUFFIX_LENGTH];
681     if (suffixLength > suffixPreviousLength)
682       write(this.suffix,
683         this.suffix.length - suffixLength,
684         suffixLength - suffixPreviousLength);
685     currentBlock = -1;
686     return;
687       }
688     int start = currentBlock;
689     int outerBlock = queueInts[start + QITEM_BLOCK_START_BLOCK_END];
690     if (outerBlock == 0)
691       currentBlock = -1;
692     else
693       {
694     int qtailFromStart = queueTail - start;
695     if (qtailFromStart > 0)
696       qtailFromStart -= queueInts.length;
697     if (outerBlock < qtailFromStart)
698       {
699         // reallyStartLogicalBlock has been called for the outer block,
700
// so there is no currentBlock.
701
currentBlock = -1;
702       }
703     else
704       {
705         // Make currentBlock absolute instead of relative.
706
outerBlock += start;
707         if (outerBlock < 0)
708           outerBlock += queueInts.length;
709         currentBlock = outerBlock;
710       }
711       }
712     String JavaDoc suffix = queueStrings[start + QITEM_BLOCK_START_SUFFIX];
713     if (suffix != null)
714       write(suffix);
715     int endFromStart = end - start;
716     if (endFromStart < 0) // wrap-around.
717
endFromStart += queueInts.length;
718     queueInts[start + QITEM_BLOCK_START_BLOCK_END] = endFromStart;
719     //log("endLogicalBlock end:"+end+" start:"+start+" rel:"+endFromStart);
720
}
721
722   public void endLogicalBlock (String JavaDoc suffix)
723   {
724     if (prettyPrintingMode > 0)
725       endLogicalBlock();
726     else if (suffix != null)
727       write(suffix);
728   }
729
730   // Tab support
731

732   int computeTabSize (int tab, int sectionStart, int column) // DONE
733
{
734     int flags = queueInts[tab + QITEM_TAB_FLAGS];
735     boolean isSection = (flags & QITEM_TAB_IS_SECTION) != 0;
736     boolean isRelative = (flags & QITEM_TAB_IS_RELATIVE) != 0;
737     int origin = isSection ? sectionStart : 0;
738     int colnum = queueInts[tab + QITEM_TAB_COLNUM];
739     int colinc = queueInts[tab + QITEM_TAB_COLINC];
740     if (isRelative)
741       {
742     if (colinc > 1)
743       {
744         int newposn = column + colnum;
745         int rem = newposn % colinc;
746         if (rem != 0)
747           colnum += colinc = rem;
748       }
749     return colnum;
750       }
751     else if (column <= colnum + origin)
752       return column + origin - column;
753     else
754       return colinc - (column - origin) % colinc;
755   }
756
757   int indexColumn(int index)
758   {
759     int column = bufferStartColumn;
760     int sectionStart = getSectionColumn();
761     int endPosn = indexPosn(index);
762     int op = queueTail;
763     int todo = queueSize;
764     while (todo > 0)
765       {
766     // If at end of queueInts, skip.
767
if (op >= queueInts.length)
768       op = 0;
769     int type = getQueueType(op);
770     if (type != QITEM_NOP_TYPE)
771       {
772         int posn = queueInts[op + QITEM_POSN];
773         if (posn >= endPosn)
774           break;
775         if (type == QITEM_TAB_TYPE)
776           column += computeTabSize(op, sectionStart,
777                        column + posnIndex (posn));
778         else if (type == QITEM_NEWLINE_TYPE
779              || type == QITEM_BLOCK_START_TYPE)
780           sectionStart
781         = column + posnIndex(queueInts[op + QITEM_POSN]);
782       }
783     int size = getQueueSize(op);
784     todo -= size;
785     op += size;
786       }
787     return column + index;
788   }
789
790   void expandTabs (int through)
791   {
792     int numInsertions = 0;
793     int additional = 0;
794     int column = bufferStartColumn;
795     int sectionStart = getSectionColumn();
796     int op = queueTail;
797     int todo = queueSize;
798     int blocksUsed = LOGICAL_BLOCK_LENGTH * pendingBlocksCount;
799     while (todo > 0)
800       {
801     if (op == queueInts.length)
802       op = 0;
803     if (op == through)
804       break;
805     int type = getQueueType(op);
806     if (type == QITEM_TAB_TYPE)
807       {
808         int index = posnIndex(queueInts[op + QITEM_POSN]);
809         int tabsize = computeTabSize (op, sectionStart, column + index);
810         if (tabsize != 0)
811           {
812         // We use the blocks array for a temporary tab buffer.
813
if (blocksUsed + 2 * numInsertions + 1 >= blocks.length)
814           {
815             int[] newBlocks = new int[2 * blocks.length];
816             System.arraycopy(blocks, 0, newBlocks, 0, blocks.length);
817             blocks = newBlocks;
818           }
819         blocks[blocksUsed + 2 * numInsertions] = index;
820         blocks[blocksUsed + 2 * numInsertions + 1] = tabsize;
821         numInsertions++;
822         additional += tabsize;
823         column += tabsize;
824           }
825       }
826     else if (op == QITEM_NEWLINE_TYPE || op == QITEM_BLOCK_START_TYPE)
827       {
828         sectionStart = column + posnIndex(queueInts[op + QITEM_POSN]);
829       }
830     int size = getQueueSize(op);
831     todo -= size;
832     op += size;
833       }
834     if (numInsertions > 0)
835       {
836     int fillPtr = bufferFillPointer;
837     int newFillPtr = fillPtr + additional;
838     char[] buffer = this.buffer;
839     char[] newBuffer = buffer;
840     int length = buffer.length;
841     int end = fillPtr;
842     if (newFillPtr > length)
843       {
844         int newLength = enoughSpace (fillPtr, additional);
845         newBuffer = new char[newLength];
846         this.buffer = newBuffer;
847       }
848     bufferFillPointer = newFillPtr;
849     bufferOffset -= additional;
850     for (int i = numInsertions; --i >= 0; )
851       {
852         int srcpos = blocks[blocksUsed + 2 * i];
853         int amount = blocks[blocksUsed + 2 * i + 1];
854         int dstpos = srcpos + additional;
855         System.arraycopy(buffer, srcpos, newBuffer, dstpos, end - srcpos);
856         for (int j = dstpos - amount; j < dstpos; j++)
857           newBuffer[j] = ' ';
858         additional -= amount;
859         end = srcpos;
860       }
861     if (newBuffer != buffer)
862       System.arraycopy(buffer, 0, newBuffer, 0, end);
863       }
864   }
865
866   // stuff to do the actual outputting
867

868   int ensureSpaceInBuffer (int want)
869   {
870     char[] buffer = this.buffer;
871     int length = buffer.length;
872     int fillPtr = bufferFillPointer;
873     int available = length - fillPtr;
874     if (available > 0)
875       return available;
876     else if (prettyPrintingMode > 0 && fillPtr > lineLength)
877       {
878     if (! maybeOutput(false, false))
879       outputPartialLine();
880     return ensureSpaceInBuffer(want);
881       }
882     else
883       {
884     int newLength = enoughSpace(length, want);
885     char[] newBuffer = new char[newLength];
886     this.buffer = newBuffer;
887     for (int i = fillPtr; --i >= 0; )
888       newBuffer[i] = buffer[i];
889     return newLength - fillPtr;
890       }
891   }
892
893   boolean maybeOutput(boolean forceNewlines, boolean flushing)
894   {
895     boolean outputAnything = false;
896     //log("maybeOutput("+forceNewlines+"):"); dumpQueue();
897
loop:
898     while (queueSize > 0)
899       {
900     if (queueTail >= queueInts.length)
901       queueTail = 0;
902     int next = queueTail;
903     int type = getQueueType(next);
904     switch (type)
905       {
906       case QITEM_NEWLINE_TYPE:
907         boolean cond;
908             int fits = -1;
909         switch (queueInts[next+QITEM_NEWLINE_KIND])
910           {
911           default: // LINEAR, LITERAL, or MANDATORY:
912
cond = true;
913         break;
914           case NEWLINE_MISER:
915         cond = isMisering();
916         break;
917           case NEWLINE_FILL:
918         if (isMisering()
919             || (lineNumber > getSectionStartLine()))
920           {
921             cond = true;
922             break;
923           }
924         /// ... fall through to ...
925
case NEWLINE_SPACE:
926         int end = queueInts[next+QITEM_SECTION_START_SECTION_END];
927         if (end == 0)
928           end = -1;
929         else
930           { // convert relative->absolute.
931
end = next + end;
932             if (end >= queueInts.length)
933               end -= queueInts.length;
934           }
935         fits = fitsOnLine(end, forceNewlines);
936         if (fits > 0)
937           cond = false;
938         else if (fits < 0 || flushing)
939           cond = true;
940         else
941           break loop;
942         break;
943           }
944         if (cond)
945           {
946         outputAnything = true;
947         try
948           {
949                     if (flushing && fits == 0)
950                       outputPartialLine();
951                     else
952                       outputLine(next);
953           }
954         catch (IOException ex)
955           {
956             throw new RuntimeException JavaDoc(ex.toString());
957           }
958           }
959         break;
960       case QITEM_INDENTATION_TYPE:
961         if (! isMisering())
962           {
963         int kind = queueInts[next+QITEM_INDENTATION_KIND];
964         int indent = queueInts[next+QITEM_INDENTATION_AMOUNT];
965         if (kind == QITEM_INDENTATION_BLOCK)
966           indent += getStartColumn();
967         else
968           indent += posnColumn(queueInts[next+QITEM_POSN]);
969         //log("setIndent from "+next+": "+queueInts[next+QITEM_INDENTATION_AMOUNT]+" column:"+indent);
970
setIndentation(indent);
971           }
972         break;
973       case QITEM_BLOCK_START_TYPE:
974         int start = next;
975         int end = queueInts[next + QITEM_SECTION_START_SECTION_END];
976         // Convert relative offset to absolute index:
977
end = end > 0 ? (end + next) % queueInts.length : -1;
978         fits = fitsOnLine (end, forceNewlines);
979         //log("block-start @"+next+" end:"+end+" force:"+forceNewlines+" fits:"+fits);
980
if (fits > 0)
981           {
982         // Just nuke the whole logical block and make it look
983
// like one nice long literal.
984
int endr = queueInts[next + QITEM_BLOCK_START_BLOCK_END];
985         // make absolute:
986
next = (endr + next) % queueInts.length;
987         expandTabs(next);
988         queueTail = next;
989         queueSize -= endr;
990         //log("remove block -> next:"+next+" endr:"+endr+" qSize:"+queueSize);
991
}
992         else if (fits < 0 || flushing)
993           {
994         String JavaDoc prefix = queueStrings[next + QITEM_BLOCK_START_PREFIX];
995         String JavaDoc suffix = queueStrings[next + QITEM_BLOCK_START_SUFFIX];
996         //log("reallyStartLogicalBlock: "+blockDepth+" at:"+next);
997
reallyStartLogicalBlock (posnColumn(queueInts[next + QITEM_POSN]),
998                      prefix, suffix);
999           }
1000        else // Don't know.
1001
break loop;
1002        if (currentBlock == start)
1003          currentBlock = -1;
1004        break;
1005      case QITEM_BLOCK_END_TYPE:
1006        //log("reallyEndLogicalBlock: "+blockDepth+" at:"+next);
1007
reallyEndLogicalBlock();
1008        break;
1009      case QITEM_TAB_TYPE:
1010        expandTabs(next);
1011        break;
1012      }
1013    int size = getQueueSize(queueTail);
1014    queueSize -= size;
1015    //log("maybeWrite size: "+size+" ->"+queueSize);
1016
queueTail = next + size;
1017      }
1018    return outputAnything;
1019  }
1020
1021  protected int getMiserWidth () // DONE
1022
{
1023    // CommonLisp: Use *print-miser-width*.
1024
return miserWidth;
1025  }
1026
1027  boolean isMisering() // DONE
1028
{
1029    int mwidth = getMiserWidth ();
1030    return (mwidth > 0
1031        && lineLength - getStartColumn() <= mwidth);
1032  }
1033
1034  int getMaxLines ()
1035  {
1036    // Should be value of CommonLisp *print-lines*.
1037
return -1;
1038  }
1039
1040  boolean printReadably()
1041  {
1042    // Should be value of CommonLisp *print-readably*.
1043
return true;
1044  }
1045
1046  /** Return 1 if true; -1 if false; 0 if don't know. */
1047  int fitsOnLine (int sectionEnd, boolean forceNewlines) // DONE
1048
{
1049    int available = lineLength;
1050    if (! printReadably() && getMaxLines() == lineNumber)
1051      {
1052    available -= 3; // For the " ..".
1053
available -= getSuffixLength();
1054      }
1055    if (sectionEnd >= 0)
1056      return posnColumn(queueInts[sectionEnd + QITEM_POSN]) <= available ? 1 : -1;
1057    if (forceNewlines)
1058      return -1;
1059    if (indexColumn(bufferFillPointer) > available)
1060      return -1;
1061    return 0; // don't know.
1062
}
1063
1064  public void lineAbbreviationHappened()
1065  {
1066    // Hook.
1067
}
1068
1069  /** Output a new line.
1070   * @param newline index of a newline queue item
1071   */

1072  void outputLine (int newline) throws IOException
1073  {
1074    char[] buffer = this.buffer;
1075    int kind = queueInts[newline + QITEM_NEWLINE_KIND];
1076    boolean isLiteral = kind == NEWLINE_LITERAL;
1077    int amountToConsume = posnIndex(queueInts[newline + QITEM_POSN]);
1078    int amountToPrint;
1079    if (isLiteral)
1080      amountToPrint = amountToConsume;
1081    else
1082      {
1083    // Skip trailing spaces.
1084
for (int i = amountToConsume; ; )
1085      {
1086        if (--i < 0)
1087          {
1088        amountToPrint = 0;
1089        break;
1090          }
1091        if (buffer[i] != ' ')
1092          {
1093        amountToPrint = i + 1;
1094        break;
1095          }
1096      }
1097      }
1098    out.write(buffer, 0, amountToPrint);
1099    int lineNumber = this.lineNumber;
1100    //log("outputLine#"+lineNumber+": \""+new String(buffer, 0, amountToPrint)+"\" curBlock:"+currentBlock);
1101
lineNumber++;
1102    if (! printReadably())
1103      {
1104    int maxLines = getMaxLines();
1105    if (maxLines > 0 && lineNumber >= maxLines)
1106      {
1107        out.write(" ..");
1108        int suffixLength = getSuffixLength();
1109        if (suffixLength != 0)
1110          {
1111        char[] suffix = this.suffix;
1112        int len = suffix.length;
1113        out.write(suffix, len - suffixLength, suffixLength);
1114          }
1115        // (throw 'line-limit-abbreviation-happened t))
1116
lineAbbreviationHappened();
1117      }
1118      }
1119    this.lineNumber = lineNumber;
1120    out.write('\n');
1121    bufferStartColumn = 0;
1122    int fillPtr = bufferFillPointer;
1123    int prefixLen = isLiteral ? getPerLinePrefixEnd() : getPrefixLength();
1124    int shift = amountToConsume - prefixLen;
1125    int newFillPtr = fillPtr - shift;
1126    char[] newBuffer = buffer;
1127    int bufferLength = buffer.length;
1128    if (newFillPtr > bufferLength)
1129      {
1130    newBuffer = new char[enoughSpace(bufferLength,
1131                     newFillPtr - bufferLength)];
1132    this.buffer = newBuffer;
1133      }
1134    System.arraycopy(buffer, amountToConsume, newBuffer, prefixLen,
1135             fillPtr - amountToConsume);
1136    System.arraycopy(prefix, 0, newBuffer, 0, prefixLen);
1137    bufferFillPointer = newFillPtr;
1138    bufferOffset += shift;
1139    if (! isLiteral)
1140      {
1141    blocks[blockDepth+BLOCK_SECTION_COLUMN] = prefixLen;
1142    blocks[blockDepth+BLOCK_SECTION_START_LINE] = lineNumber;
1143      }
1144  }
1145
1146  void outputPartialLine ()
1147  {
1148    //log("outputPartialLine");
1149
int tail = queueTail;
1150    while (queueSize > 0 && getQueueType(tail) == QITEM_NOP_TYPE)
1151      {
1152    int size = getQueueSize(tail);
1153    queueSize -= size;
1154    tail += size;
1155    if (tail == queueInts.length)
1156      tail = 0;
1157    queueTail = tail;
1158      }
1159    int fillPtr = bufferFillPointer;
1160    int count = queueSize > 0 ? posnIndex (queueInts[tail + QITEM_POSN])
1161      : fillPtr;
1162    int newFillPtr = fillPtr - count;
1163    if (count <= 0)
1164      throw new Error JavaDoc("outputPartialLine called when nothing can be output.");
1165    try
1166      {
1167    out.write(buffer, 0, count);
1168    //log("outputPartial: \""+new String(buffer, 0, count)+'\"');
1169
}
1170    catch (IOException ex)
1171      {
1172    throw new RuntimeException JavaDoc(ex.toString());
1173      }
1174    bufferStartColumn += count;
1175    System.arraycopy(buffer, count, buffer, 0, newFillPtr);
1176    bufferFillPointer = newFillPtr;
1177    bufferOffset += count;
1178  }
1179
1180  public void forcePrettyOutput () throws IOException
1181  {
1182    maybeOutput(false, true);
1183    if (bufferFillPointer > 0)
1184      outputPartialLine();
1185    expandTabs(-1);
1186    bufferStartColumn = getColumnNumber();
1187    out.write(buffer, 0, bufferFillPointer);
1188    bufferFillPointer = 0;
1189    queueSize = 0;
1190  }
1191
1192  public void flush()
1193  {
1194    if (out == null)
1195      return;
1196    try
1197      {
1198    forcePrettyOutput();
1199    out.flush();
1200      }
1201    catch (IOException ex)
1202      {
1203    throw new RuntimeException JavaDoc(ex.toString());
1204      }
1205  }
1206
1207  public void close() throws IOException
1208  {
1209    if (out != null)
1210      {
1211    forcePrettyOutput();
1212        out.close();
1213        out = null;
1214      }
1215    buffer = null;
1216  }
1217
1218  /** Not meaningful if {@code prettyPrintingMode > 0}. */
1219  public int getColumnNumber ()
1220  {
1221    int i = bufferFillPointer;
1222    for (;;)
1223      {
1224    if (--i < 0)
1225      return bufferStartColumn + bufferFillPointer;
1226    char ch = buffer[i];
1227    if (ch == '\n' || ch == '\r')
1228      return bufferFillPointer - (i+1);
1229      }
1230  }
1231
1232  public void setColumnNumber (int column)
1233  {
1234    bufferStartColumn += column - getColumnNumber ();
1235  }
1236
1237  public void clearBuffer ()
1238  {
1239    bufferStartColumn = 0;
1240    bufferFillPointer = 0;
1241    lineNumber = 0;
1242    bufferOffset = 0;
1243    blockDepth = LOGICAL_BLOCK_LENGTH;
1244    queueTail = 0;
1245    queueSize = 0;
1246    pendingBlocksCount = 0;
1247  }
1248
1249  /*
1250  public static PrintWriter log;
1251  static {
1252    try { log = new PrintWriter(new FileOutputStream("/tmp/pplog")); }
1253    catch (Throwable ex) { ex.printStackTrace(); }
1254  }
1255  void log(String str)
1256  {
1257    log.println(str);
1258    log.flush();
1259  }
1260  void dumpQueue()
1261  {
1262    log.println("Queue tail:"+queueTail+" size:"+queueSize
1263        +" length:"+queueInts.length+" startCol:"+bufferStartColumn);
1264    dumpQueue(queueTail, queueSize, log);
1265  }
1266
1267  void dumpQueue(int start, int todo, PrintWriter out)
1268  {
1269    int bufIndex = 0;
1270    while (todo > 0)
1271      {
1272    if (start == queueInts.length)
1273      start = 0;
1274    if (start < 0 || start >= queueInts.length)
1275      {
1276        out.print('@'); out.print(start); out.print(": ");
1277        out.print("out of bounds - queueInts length is ");
1278        out.println(queueInts.length);
1279        break;
1280      }
1281    int type = getQueueType(start);
1282    int size = getQueueSize(start);
1283    if (type != QITEM_NOP_TYPE)
1284      {
1285        int newIndex = posnIndex(queueInts[start+QITEM_POSN]);
1286        int count = newIndex - bufIndex;
1287        if (count > 0)
1288          {
1289        out.print(count); out.print(" chars: \"");
1290        out.write(buffer, bufIndex, count);
1291        out.println('\"');
1292        bufIndex = newIndex;
1293          }
1294      }
1295    out.print('@'); out.print(start); out.print(": ");
1296    out.print("type:"); out.print(type);
1297    switch (type)
1298      {
1299      case QITEM_NEWLINE_TYPE:
1300        out.print("(newline)"); break;
1301      case QITEM_INDENTATION_TYPE:
1302        out.print("(indentation)"); break;
1303      case QITEM_BLOCK_START_TYPE:
1304        out.print("(block-start)"); break;
1305      case QITEM_BLOCK_END_TYPE:
1306        out.print("(block-end)"); break;
1307      case QITEM_TAB_TYPE: out.print("(tab)");
1308        break;
1309      case QITEM_NOP_TYPE:
1310        out.print("(nop)"); break;
1311      }
1312    out.print(" size:"); out.print(size);
1313    out.print("; @"); out.print(start+QITEM_POSN);
1314    if (type != QITEM_NOP_TYPE)
1315      {
1316        out.print(": posn:");
1317        int posn = queueInts[start+QITEM_POSN];
1318        out.print(posn);
1319        out.print(" index:");
1320        out.println(posnIndex(posn));
1321      }
1322    if (type == QITEM_NEWLINE_TYPE
1323        || type == QITEM_BLOCK_START_TYPE)
1324        
1325      {
1326        out.print('@'); out.print(start+QITEM_SECTION_START_DEPTH);
1327        out.print(": - depth:");
1328        out.print(queueInts[start+QITEM_SECTION_START_DEPTH]);
1329        out.print("; @");
1330        out.print(start+QITEM_SECTION_START_SECTION_END);
1331        out.print(": section-end:");
1332        out.println(queueInts[start+QITEM_SECTION_START_SECTION_END]);
1333      }
1334    switch (type)
1335      {
1336      case QITEM_BLOCK_START_TYPE:
1337        printQueueWord(start, QITEM_BLOCK_START_BLOCK_END, "block-end", out);
1338        printQueueStringWord(start, QITEM_BLOCK_START_PREFIX, "prefix", out);
1339        printQueueStringWord(start, QITEM_BLOCK_START_SUFFIX, "suffix", out);
1340        break;
1341      case QITEM_NEWLINE_TYPE:
1342        out.print('@');
1343        out.print(start+QITEM_NEWLINE_KIND);
1344        out.print(": - kind: ");
1345        int kind = queueInts[start+QITEM_NEWLINE_KIND];
1346        String skind = "???";
1347        switch (kind)
1348          {
1349          case NEWLINE_LINEAR: skind = "linear"; break;
1350          case NEWLINE_LITERAL: skind = "literal"; break;
1351          case NEWLINE_FILL: skind = "fill"; break;
1352          case NEWLINE_SPACE: skind = "space"; break;
1353          case NEWLINE_MISER: skind = "miser"; break;
1354          case NEWLINE_MANDATORY: skind = "mandatory"; break;
1355          }
1356        out.print(kind);
1357        out.print('(');
1358        out.print(skind);
1359        out.println(')');
1360        break;
1361          case QITEM_INDENTATION_TYPE:
1362        printQueueWord(start, QITEM_INDENTATION_KIND, "kind", out);
1363        printQueueWord(start, QITEM_INDENTATION_AMOUNT, "amount", out);
1364        break;
1365      default:
1366        for (int i = 2; i < size; i++)
1367          printQueueWord(start, i, "word#"+i, out);
1368      }
1369    todo -= size;
1370    start += size;
1371      }
1372    int count = bufferFillPointer - bufIndex;
1373    if (count > 0)
1374      {
1375    out.print(count); out.print(" chars: \"");
1376    out.write(buffer, bufIndex, count);
1377    out.println('\"');
1378      }
1379  }
1380
1381  private void printQueueWord(int start, int offset,
1382                  String fname, PrintWriter out)
1383  {
1384    out.print('@');
1385    out.print(start+offset);
1386    out.print(": - ");
1387    out.print(fname);
1388    out.print(": ");
1389    out.println(queueInts[start+offset]);
1390  }
1391
1392  private void printQueueStringWord(int start, int offset,
1393                    String fname, PrintWriter out)
1394  {
1395    out.print('@');
1396    out.print(start+offset);
1397    out.print(": - ");
1398    out.print(fname);
1399    out.print(": ");
1400    String str = queueStrings[start+offset];
1401    if (str == null)
1402      out.println("null");
1403    else
1404      {
1405    out.print('\"');
1406    out.print(str);
1407    out.print('\"');
1408    out.print(" length: ");
1409    out.println(str.length());
1410      }
1411  }
1412
1413  void check (String where)
1414  {
1415    String msg = null;
1416    if (currentBlock != -1
1417    && ! (currentBlock < queueInts.length
1418          && currentBlock >= queueTail
1419          ? currentBlock < queueTail + queueSize
1420          : currentBlock < queueTail + queueSize - queueInts.length))
1421      msg = ("currentBlock ("+currentBlock
1422         +") >= queue length ("+queueInts.length+")");
1423    if (msg != null)
1424      {
1425    if (where != null)
1426      msg = "in "+where+": "+msg;
1427    log.println(msg);
1428    dumpQueue();
1429    log.flush();
1430    throw new Error(msg);
1431      }
1432  }
1433
1434  String itemKindString (int kind)
1435  {
1436    switch (kind)
1437      {
1438      case QITEM_NOP_TYPE: return "nop";
1439      case QITEM_NEWLINE_TYPE: return "newline";
1440      case QITEM_INDENTATION_TYPE: return "indentation";
1441      case QITEM_BLOCK_START_TYPE: return "block-start";
1442      case QITEM_BLOCK_END_TYPE: return "block-end";
1443      case QITEM_TAB_TYPE: return "tab";
1444      default: return "("+kind+" - unknown)";
1445      }
1446  }
1447  String enqueueExtraLog = "";
1448  */

1449}
1450
Popular Tags