1) Added missing strings for italic, underline and strike through.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / formatter / CodeFormatter.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v0.5
5  *
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/cpl-v05.html
8  *
9  * Contributors:
10  *     IBM Corporation - initial API and implementation
11  ******************************************************************************/
12 package net.sourceforge.phpdt.internal.formatter;
13
14 import java.io.BufferedReader;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.util.Hashtable;
18 //import java.util.Locale;
19 import java.util.Map;
20
21 //import javax.swing.text.html.Option;
22
23 import net.sourceforge.phpdt.core.ICodeFormatter;
24 import net.sourceforge.phpdt.core.compiler.CharOperation;
25 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
26 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
27 import net.sourceforge.phpdt.internal.compiler.ConfigurableOption;
28 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
29 import net.sourceforge.phpdt.internal.formatter.impl.FormatterOptions;
30 import net.sourceforge.phpdt.internal.formatter.impl.SplitLine;
31
32 /**
33  * <h2>How to format a piece of code ?</h2>
34  * <ul>
35  * <li>Create an instance of <code>CodeFormatter</code>
36  * <li>Use the method <code>void format(aString)</code> on this instance to
37  * format <code>aString</code>. It will return the formatted string.
38  * </ul>
39  */
40 public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
41         // IContentFormatterExtension {
42         public FormatterOptions options;
43
44         /**
45          * Represents a block in the <code>constructions</code> stack.
46          */
47         public static final TokenName BLOCK = TokenName.LBRACE;
48
49         /**
50          * Represents a block following a control statement in the
51          * <code>constructions</code> stack.
52          */
53         public static final TokenName NONINDENT_BLOCK = TokenName.NONE_INDENT_BLOCK;
54
55         /**
56          * Contains the formatted output.
57          */
58         StringBuffer formattedSource;
59
60         /**
61          * Contains the current line. <br>
62          * Will be dumped at the next "newline"
63          */
64         StringBuffer currentLineBuffer;
65
66         /**
67          * Used during the formatting to get each token.
68          */
69         Scanner scanner;
70
71         /**
72          * Contains the tokens responsible for the current indentation level and the
73          * blocks not closed yet.
74          */
75         private TokenName[] constructions;
76
77         /**
78          * Index in the <code>constructions</code> array.
79          */
80         private int constructionsCount;
81
82         /**
83          * Level of indentation of the current token (number of tab char put in
84          * front of it).
85          */
86         private int indentationLevel;
87
88         /**
89          * Regular level of indentation of all the lines
90          */
91         private int initialIndentationLevel;
92
93         /**
94          * Used to split a line.
95          */
96         Scanner splitScanner;
97
98         /**
99          * To remember the offset between the beginning of the line and the
100          * beginning of the comment.
101          */
102         int currentCommentOffset;
103
104         int currentLineIndentationLevel;
105
106         int maxLineSize = 30;
107
108         private boolean containsOpenCloseBraces;
109
110         private int indentationLevelForOpenCloseBraces;
111
112         /**
113          * Collections of positions to map
114          */
115         private int[] positionsToMap;
116
117         /**
118          * Collections of mapped positions
119          */
120         private int[] mappedPositions;
121
122         private int indexToMap;
123
124         private int indexInMap;
125
126         private int globalDelta;
127
128         private int lineDelta;
129
130         private int splitDelta;
131
132         private int beginningOfLineIndex;
133
134         private int multipleLineCommentCounter;
135
136         /**
137          * Creates a new instance of Code Formatter using the given settings.
138          * 
139          * @deprecated backport 1.0 internal functionality
140          */
141         public CodeFormatter(ConfigurableOption[] settings) {
142                 this(convertConfigurableOptions(settings));
143         }
144
145         /**
146          * Creates a new instance of Code Formatter using the FormattingOptions
147          * object given as argument
148          * 
149          * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
150          */
151 //      public CodeFormatter() {
152 //              this((Map) null);
153 //      }
154
155         /**
156          * Creates a new instance of Code Formatter using the given settings.
157          */
158         public CodeFormatter(Map settings) {
159                 // initialize internal state
160                 constructionsCount = 0;
161                 constructions = new TokenName[10];
162                 currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
163                 currentCommentOffset = -1;
164                 // initialize primary and secondary scanners
165                 scanner = new Scanner(true /* comment */
166                 , true /* whitespace */
167                 , false /* nls */
168                 , false /* assert */
169                 , true, /* tokenizeStrings */
170                 null, null, true /* taskCaseSensitive */); // regular scanner for
171                                                                                                         // forming lines
172                 scanner.recordLineSeparator = true;
173                 scanner.ignorePHPOneLiner = true;
174                 // to remind of the position of the beginning of the line.
175                 splitScanner = new Scanner(true /* comment */
176                 , true /* whitespace */
177                 , false /* nls */
178                 , false /* assert */
179                 , true, /* tokenizeStrings */
180                 null, null, true /* taskCaseSensitive */);
181                 splitScanner.ignorePHPOneLiner = true;
182                 // secondary scanner to split long lines formed by primary scanning
183                 // initialize current line buffer
184                 currentLineBuffer = new StringBuffer();
185                 this.options = new FormatterOptions(settings);
186         }
187
188         /**
189          * Returns true if a lineSeparator has to be inserted before
190          * <code>operator</code> false otherwise.
191          */
192         private static boolean breakLineBeforeOperator(TokenName operator) {
193                 switch (operator) {
194                 case COMMA:
195                 case SEMICOLON:
196                 case EQUAL:
197                         return false;
198                 default:
199                         return true;
200                 }
201         }
202
203         /**
204          * @deprecated backport 1.0 internal functionality
205          */
206         private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
207                 Hashtable options = new Hashtable(10);
208                 for (int i = 0; i < settings.length; i++) {
209                         if (settings[i].getComponentName().equals(
210                                         CodeFormatter.class.getName())) {
211                                 String optionName = settings[i].getOptionName();
212                                 int valueIndex = settings[i].getCurrentValueIndex();
213                                 if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
214                                         options
215                                                         .put(
216                                                                         "net.sourceforge.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
217                                 } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
218                                         options
219                                                         .put(
220                                                                         "net.sourceforge.phpdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
221                                 } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
222                                         options
223                                                         .put(
224                                                                         "net.sourceforge.phpdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
225                                 } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
226                                         options
227                                                         .put(
228                                                                         "net.sourceforge.phpdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
229                                 } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
230                                         options
231                                                         .put(
232                                                                         "net.sourceforge.phpdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
233                                 } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
234                                         options
235                                                         .put(
236                                                                         "net.sourceforge.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
237                                 } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
238                                         options
239                                                         .put(
240                                                                         "net.sourceforge.phpdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
241                                 } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
242                                         options
243                                                         .put(
244                                                                         "net.sourceforge.phpdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
245                                 } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
246                                         options
247                                                         .put(
248                                                                         "net.sourceforge.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
249                                 }
250                         }
251                 }
252                 return options;
253         }
254
255         /**
256          * Returns the end of the source code.
257          */
258         private final String copyRemainingSource() {
259                 char str[] = scanner.source;
260                 int startPosition = scanner.startPosition;
261                 int length = str.length - startPosition;
262                 StringBuffer bufr = new StringBuffer(length);
263                 if (startPosition < str.length) {
264                         bufr.append(str, startPosition, length);
265                 }
266                 return (bufr.toString());
267         }
268
269         /**
270          * Inserts <code>tabCount</code> tab character or their equivalent number
271          * of spaces.
272          */
273         private void dumpTab(int tabCount) {
274                 if (options.indentWithTab) {
275                         for (int j = 0; j < tabCount; j++) {
276                                 formattedSource.append('\t');
277                                 increaseSplitDelta(1);
278                         }
279                 } else {
280                         for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
281                                 formattedSource.append(' ');
282                                 increaseSplitDelta(1);
283                         }
284                 }
285         }
286
287         /**
288          * Dumps <code>currentLineBuffer</code> into the formatted string.
289          */
290         private void flushBuffer() {
291                 String currentString = currentLineBuffer.toString();
292                 splitDelta = 0;
293                 beginningOfLineIndex = formattedSource.length();
294                 if (containsOpenCloseBraces) {
295                         containsOpenCloseBraces = false;
296                         outputLine(currentString, 
297                                    false,
298                                            indentationLevelForOpenCloseBraces, 
299                                            TokenName.NONE,
300                                            -1, null, 0);
301                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
302                 } else {
303                         outputLine(currentString, 
304                                    false, 
305                                    currentLineIndentationLevel, 
306                                    TokenName.NONE,
307                                            -1, null, 0);
308                 }
309                 int scannerSourceLength = scanner.source.length;
310                 if ((scannerSourceLength > 2)
311                                 && (scanner.startPosition < scannerSourceLength)) {
312                         if (scanner.source[scannerSourceLength - 1] == '\n'
313                                         && scanner.source[scannerSourceLength - 2] == '\r') {
314                                 formattedSource.append(options.lineSeparatorSequence);
315                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
316                         } else if (scanner.source[scannerSourceLength - 1] == '\n') {
317                                 formattedSource.append(options.lineSeparatorSequence);
318                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
319                         } else if (scanner.source[scannerSourceLength - 1] == '\r') {
320                                 formattedSource.append(options.lineSeparatorSequence);
321                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
322                         }
323                 }
324                 updateMappedPositions(scanner.startPosition);
325         }
326
327         /**
328          * Formats the input string.
329          */
330         private void format() {
331                 TokenName token                   = TokenName.NONE;
332                 TokenName previousToken           = TokenName.NONE;
333                 TokenName previousCompilableToken = TokenName.NONE;
334                 
335                 int indentationOffset = 0;
336                 int newLinesInWhitespace = 0;
337                 // number of new lines in the previous whitespace token
338                 // (used to leave blank lines before comments)
339                 int pendingNewLines = 0;
340                 boolean expectingOpenBrace = false;
341                 boolean clearNonBlockIndents = false;
342                 // true if all indentations till the 1st { (usefull after } or ;)
343                 boolean pendingSpace = true;
344                 boolean pendingNewlineAfterParen = false;
345                 // true when a cr is to be put after a ) (in conditional statements)
346                 boolean inAssignment = false;
347                 boolean inArrayAssignment = false;
348                 boolean inThrowsClause = false;
349                 boolean inClassOrInterfaceHeader = false;
350                 int dollarBraceCount = 0;
351                 // openBracketCount is used to count the number of open brackets not
352                 // closed
353                 // yet.
354                 int openBracketCount = 0;
355                 int unarySignModifier = 0;
356                 // openParenthesis[0] is used to count the parenthesis not belonging to
357                 // a
358                 // condition
359                 // (eg foo();). parenthesis in for (...) are count elsewhere in the
360                 // array.
361                 int openParenthesisCount = 1;
362                 int[] openParenthesis = new int[10];
363                 // tokenBeforeColon is used to know what token goes along with the
364                 // current
365                 // :
366                 // it can be case or ?
367                 int tokenBeforeColonCount = 0;
368                 TokenName[] tokenBeforeColon = new TokenName[10];
369                 constructionsCount = 0; // initializes the constructions count.
370                 // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
371                 TokenName nlicsToken = ITerminalSymbols.TokenName.NONE;
372                 // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and
373                 // else
374                 boolean specialElse = false;
375                 // OPTION (IndentationLevel): initial indentation level may be non-zero.
376                 currentLineIndentationLevel += constructionsCount;
377                 // An InvalidInputException exception might cause the termination of
378                 // this
379                 // loop.
380                 int arrayDeclarationCount = 0;
381                 int[] arrayDeclarationParenthesis = new int[10];
382                 try {
383                         while (true) {
384                                 // Get the next token. Catch invalid input and output it
385                                 // with minimal formatting, also catch end of input and
386                                 // exit the loop.
387                                 try {
388                                         token = scanner.getNextToken();
389                                         if (Scanner.DEBUG) {
390                                                 int currentEndPosition = scanner
391                                                                 .getCurrentTokenEndPosition();
392                                                 int currentStartPosition = scanner
393                                                                 .getCurrentTokenStartPosition();
394                                                 System.out.print(currentStartPosition + ","
395                                                                 + currentEndPosition + ": ");
396                                                 System.out.println(scanner.toStringAction(token));
397                                         }
398                                         // Patch for line comment
399                                         // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096
400                                         if (token == ITerminalSymbols.TokenName.COMMENT_LINE) {
401                                                 int length = scanner.currentPosition;
402                                                 loop: for (int index = length - 1; index >= 0; index--) {
403                                                         switch (scanner.source[index]) {
404                                                         case '\r':
405                                                         case '\n':
406                                                                 scanner.currentPosition--;
407                                                                 break;
408                                                         default:
409                                                                 break loop;
410                                                         }
411                                                 }
412                                         }
413                                 } catch (InvalidInputException e) {
414                                         if (!handleInvalidToken(e)) {
415                                                 throw e;
416                                         }
417                                         token = ITerminalSymbols.TokenName.NONE;
418                                 }
419                                 if (token == Scanner.TokenName.EOF) {
420                                         break;
421                                 } else if (token == Scanner.TokenName.HEREDOC) {
422                                         // no indentation for heredocs and HTML !
423                                         outputCurrentTokenWithoutIndent(Scanner.TokenName.HEREDOC, 0);
424                                         continue;
425                                 } else if (token == Scanner.TokenName.INLINE_HTML) {
426                                         // no indentation for heredocs and HTML !
427                                         int newLineCount = 1;
428                                         if (scanner.startPosition == 0) {
429                                                 newLineCount = 0;
430                                         }
431                                         outputCurrentTokenWithoutIndent(
432                                                         Scanner.TokenName.INLINE_HTML, newLineCount);
433                                         int srcLen = scanner.source.length;
434                                         if (scanner.currentPosition < srcLen - 1) {
435                                                 newLine(1);
436                                         }
437                                         continue;
438                                 }
439                                 /*
440                                  * ## MODIFYING the indentation level before generating new
441                                  * lines and indentation in the output string
442                                  */
443                                 // Removes all the indentations made by statements not followed
444                                 // by a
445                                 // block
446                                 // except if the current token is ELSE, CATCH or if we are in a
447                                 // switch/case
448                                 if (clearNonBlockIndents
449                                                 && (token != Scanner.TokenName.WHITESPACE)) {
450                                         switch (token) {
451                                         case ELSE:
452                                                 if (constructionsCount > 0
453                                                                 && constructions[constructionsCount - 1] == TokenName.ELSE) {
454                                                         pendingNewLines = 1;
455                                                         specialElse = true;
456                                                 }
457                                                 indentationLevel += popInclusiveUntil(TokenName.IF);
458                                                 break;
459                                         // case TokenName.catch :
460                                         // indentationLevel += popInclusiveUntil(TokenName.catch);
461                                         // break;
462                                         // case TokenName.finally :
463                                         // indentationLevel += popInclusiveUntil(TokenName.catch);
464                                         // break;
465                                         case WHILE:
466                                                 if (nlicsToken == TokenName.DO) {
467                                                         indentationLevel += pop(TokenName.DO);
468                                                         break;
469                                                 }
470                                         default:
471                                                 indentationLevel += popExclusiveUntilBlockOrCase();
472                                                 // clear until a CASE, DEFAULT or BLOCK is encountered.
473                                                 // Thus, the indentationLevel is correctly cleared
474                                                 // either
475                                                 // in a switch/case statement or in any other situation.
476                                         }
477                                         clearNonBlockIndents = false;
478                                 }
479                                 // returns to the indentation level created by the SWITCH
480                                 // keyword
481                                 // if the current token is a CASE or a DEFAULT
482                                 if (token == TokenName.CASE || token == TokenName.DEFAULT) {
483                                         indentationLevel += pop(TokenName.CASE);
484                                 }
485                                 // if (token == Scanner.TokenName.throws) {
486                                 // inThrowsClause = true;
487                                 // }
488                                 if ((token == Scanner.TokenName.CLASS || token == Scanner.TokenName.INTERFACE)
489                                                 && previousToken != Scanner.TokenName.DOT) {
490                                         inClassOrInterfaceHeader = true;
491                                 }
492                                 /*
493                                  * ## APPEND newlines and indentations to the output string
494                                  */
495                                 // Do not add a new line between ELSE and IF, if the option
496                                 // elseIfOnSameLine is true.
497                                 // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
498                                 // if (pendingNewlineAfterParen
499                                 // && previousCompilableToken == TokenName.else
500                                 // && token == TokenName.if
501                                 // && options.compactElseIfMode) {
502                                 // pendingNewlineAfterParen = false;
503                                 // pendingNewLines = 0;
504                                 // indentationLevel += pop(TokenName.else);
505                                 // // because else if is now one single statement,
506                                 // // the indentation level after it is increased by one and not
507                                 // by 2
508                                 // // (else = 1 indent, if = 1 indent, but else if = 1 indent,
509                                 // not 2).
510                                 // }
511                                 // Add a newline & indent to the formatted source string if
512                                 // a for/if-else/while statement was scanned and there is no
513                                 // block
514                                 // following it.
515                                 pendingNewlineAfterParen = pendingNewlineAfterParen
516                                                 || (previousCompilableToken == TokenName.RPAREN && token == TokenName.LBRACE);
517                                 if (pendingNewlineAfterParen
518                                                 && token != Scanner.TokenName.WHITESPACE) {
519                                         pendingNewlineAfterParen = false;
520                                         // Do to add a newline & indent sequence if the current
521                                         // token is an
522                                         // open brace or a period or if the current token is a
523                                         // semi-colon and
524                                         // the
525                                         // previous token is a close paren.
526                                         // add a new line if a parenthesis belonging to a for()
527                                         // statement
528                                         // has been closed and the current token is not an opening
529                                         // brace
530                                         if (token != TokenName.LBRACE && !isComment(token)
531                                                         // to avoid adding new line between else and a
532                                                         // comment
533                                                         && token != TokenName.DOT
534                                                         && !(previousCompilableToken == TokenName.RPAREN && token == TokenName.SEMICOLON)) {
535                                                 newLine(1);
536                                                 currentLineIndentationLevel = indentationLevel;
537                                                 pendingNewLines = 0;
538                                                 pendingSpace = false;
539                                         } else {
540                                                 if (token == TokenName.LBRACE
541                                                                 && options.newLineBeforeOpeningBraceMode) {
542                                                         newLine(1);
543                                                         if (constructionsCount > 0
544                                                                         && constructions[constructionsCount - 1] != BLOCK
545                                                                         && constructions[constructionsCount - 1] != NONINDENT_BLOCK) {
546                                                                 currentLineIndentationLevel = indentationLevel - 1;
547                                                         } else {
548                                                                 currentLineIndentationLevel = indentationLevel;
549                                                         }
550                                                         pendingNewLines = 0;
551                                                         pendingSpace = false;
552                                                 }
553                                         }
554                                 }
555                                 if (token == TokenName.LBRACE
556                                                 && options.newLineBeforeOpeningBraceMode
557                                                 && constructionsCount > 0
558                                                 && constructions[constructionsCount - 1] == TokenName.DO) {
559                                         newLine(1);
560                                         currentLineIndentationLevel = indentationLevel - 1;
561                                         pendingNewLines = 0;
562                                         pendingSpace = false;
563                                 }
564                                 // see PR 1G5G8EC
565                                 if (token == TokenName.LBRACE && inThrowsClause) {
566                                         inThrowsClause = false;
567                                         if (options.newLineBeforeOpeningBraceMode) {
568                                                 newLine(1);
569                                                 currentLineIndentationLevel = indentationLevel;
570                                                 pendingNewLines = 0;
571                                                 pendingSpace = false;
572                                         }
573                                 }
574                                 // see PR 1G5G82G
575                                 if (token == TokenName.LBRACE && inClassOrInterfaceHeader) {
576                                         inClassOrInterfaceHeader = false;
577                                         if (options.newLineBeforeOpeningBraceMode) {
578                                                 newLine(1);
579                                                 currentLineIndentationLevel = indentationLevel;
580                                                 pendingNewLines = 0;
581                                                 pendingSpace = false;
582                                         }
583                                 }
584                                 // don't linebreak empty array declarations
585                                 if (token == TokenName.RPAREN && arrayDeclarationCount > 0) {
586                                         if (previousCompilableToken == TokenName.LPAREN) {
587                                                 pendingNewLines = 0;
588                                         }
589                                 }
590                                 // Add pending new lines to the formatted source string.
591                                 // Note: pending new lines are not added if the current token
592                                 // is a single line comment or whitespace.
593                                 // if the comment is between parenthesis, there is no blank line
594                                 // preservation
595                                 // (if it's a one-line comment, a blank line is added after it).
596                                 if (((pendingNewLines > 0 && (!isComment(token)))
597                                                 || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
598                                                 || (previousCompilableToken == TokenName.LBRACE && token == TokenName.RBRACE) || (newLinesInWhitespace > 0 && previousCompilableToken == TokenName.DOT))
599                                                 && token != Scanner.TokenName.WHITESPACE) {
600                                         // Do not add newline & indent between an adjoining close
601                                         // brace and
602                                         // close paren. Anonymous inner classes may use this form.
603                                         boolean closeBraceAndCloseParen = previousToken == TokenName.RBRACE
604                                                         && token == TokenName.RPAREN;
605                                         // OPTION (NewLineInCompoundStatement): do not add newline &
606                                         // indent
607                                         // between close brace and else, (do) while, catch, and
608                                         // finally if
609                                         // newlineInCompoundStatement is true.
610                                         boolean nlicsOption = previousToken == TokenName.RBRACE
611                                                         && !options.newlineInControlStatementMode
612                                                         && (token == TokenName.ELSE
613                                                                         || (token == TokenName.WHILE && nlicsToken == TokenName.DO)
614                                                                         || token == TokenName.CATCH || token == TokenName.FINALLY);
615                                         // Do not add a newline & indent between a close brace and
616                                         // semi-colon.
617                                         boolean semiColonAndCloseBrace = previousToken == TokenName.RBRACE
618                                                         && token == TokenName.SEMICOLON;
619                                         // Do not add a new line & indent between a multiline
620                                         // comment and a
621                                         // opening brace
622                                         boolean commentAndOpenBrace = previousToken == Scanner.TokenName.COMMENT_BLOCK
623                                                         && token == TokenName.LBRACE;
624                                         // Do not add a newline & indent between a close brace and a
625                                         // colon
626                                         // (in array assignments, for example).
627                                         boolean commaAndCloseBrace = previousToken == TokenName.RBRACE
628                                                         && token == TokenName.COMMA;
629                                         // Add a newline and indent, if appropriate.
630                                         if (specialElse
631                                                         || (!commentAndOpenBrace
632                                                                         && !closeBraceAndCloseParen && !nlicsOption
633                                                                         && !semiColonAndCloseBrace && !commaAndCloseBrace)) {
634                                                 // if clearAllBlankLinesMode=false, leaves the blank
635                                                 // lines
636                                                 // inserted by the user
637                                                 // if clearAllBlankLinesMode=true, removes all of then
638                                                 // and insert only blank lines required by the
639                                                 // formatting.
640                                                 if (!options.clearAllBlankLinesMode) {
641                                                         // (isComment(token))
642                                                         pendingNewLines = (pendingNewLines < newLinesInWhitespace) ? newLinesInWhitespace
643                                                                         : pendingNewLines;
644                                                         pendingNewLines = (pendingNewLines > 2) ? 2
645                                                                         : pendingNewLines;
646                                                 }
647                                                 if (previousCompilableToken == TokenName.LBRACE
648                                                                 && token == TokenName.RBRACE) {
649                                                         containsOpenCloseBraces = true;
650                                                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
651                                                         if (isComment(previousToken)) {
652                                                                 newLine(pendingNewLines);
653                                                         } else {
654                                                                 /*
655                                                                  * if (!(constructionsCount > 1 &&
656                                                                  * constructions[constructionsCount-1] ==
657                                                                  * NONINDENT_BLOCK &&
658                                                                  * (constructions[constructionsCount-2] ==
659                                                                  * TokenName.for
660                                                                  */
661                                                                 if (options.newLineInEmptyBlockMode) {
662                                                                         if (inArrayAssignment) {
663                                                                                 newLine(1); // array assigment with an
664                                                                                                         // empty block
665                                                                         } else {
666                                                                                 newLine(pendingNewLines);
667                                                                         }
668                                                                 }
669                                                                 // }
670                                                         }
671                                                 } else {
672                                                         // see PR 1FKKC3U: LFCOM:WINNT - Format problem with
673                                                         // a comment
674                                                         // before the ';'
675                                                         if (!((previousToken == Scanner.TokenName.COMMENT_BLOCK || previousToken == Scanner.TokenName.COMMENT_PHPDOC) && token == TokenName.SEMICOLON)) {
676                                                                 newLine(pendingNewLines);
677                                                         }
678                                                 }
679                                                 if (((previousCompilableToken == TokenName.SEMICOLON)
680                                                                 || (previousCompilableToken == TokenName.LBRACE)
681                                                                 || (previousCompilableToken == TokenName.RBRACE) || (isComment(previousToken)))
682                                                                 && (token == TokenName.RBRACE)) {
683                                                         indentationOffset = -1;
684                                                         indentationLevel += popExclusiveUntilBlock();
685                                                 }
686                                                 if (previousToken == Scanner.TokenName.COMMENT_LINE
687                                                                 && inAssignment) {
688                                                         // PR 1FI5IPO
689                                                         currentLineIndentationLevel++;
690                                                 } else {
691                                                         currentLineIndentationLevel = indentationLevel
692                                                                         + indentationOffset;
693                                                 }
694                                                 pendingSpace = false;
695                                                 indentationOffset = 0;
696                                         }
697                                         pendingNewLines = 0;
698                                         newLinesInWhitespace = 0;
699                                         specialElse = false;
700                                         if (nlicsToken == TokenName.DO && token == TokenName.WHILE) {
701                                                 nlicsToken = ITerminalSymbols.TokenName.NONE;
702                                         }
703                                 }
704                                 boolean phpTagAndWhitespace = previousToken == TokenName.INLINE_HTML
705                                                 && token == TokenName.WHITESPACE;
706                                 switch (token) {
707                                 // case TokenName.DOLLAR :
708                                 // dollarBraceCount++;
709                                 // break;
710                                 case ELSE:
711                                         // case TokenName.finally :
712                                         expectingOpenBrace = true;
713                                         pendingNewlineAfterParen = true;
714                                         indentationLevel += pushControlStatement(token);
715                                         break;
716                                 case CASE:
717                                 case DEFAULT:
718                                         if (tokenBeforeColonCount == tokenBeforeColon.length) {
719                                                 System
720                                                                 .arraycopy(
721                                                                                 tokenBeforeColon,
722                                                                                 0,
723                                                                                 (tokenBeforeColon = new TokenName[tokenBeforeColonCount * 2]),
724                                                                                 0, tokenBeforeColonCount);
725                                         }
726                                         tokenBeforeColon[tokenBeforeColonCount++] = TokenName.CASE;
727                                         indentationLevel += pushControlStatement(TokenName.CASE);
728                                         break;
729                                 case QUESTION:
730                                         if (tokenBeforeColonCount == tokenBeforeColon.length) {
731                                                 System
732                                                                 .arraycopy(
733                                                                                 tokenBeforeColon,
734                                                                                 0,
735                                                                                 (tokenBeforeColon = new TokenName[tokenBeforeColonCount * 2]),
736                                                                                 0, tokenBeforeColonCount);
737                                         }
738                                         tokenBeforeColon[tokenBeforeColonCount++] = token;
739                                         break;
740                                 case SWITCH:
741                                 case FOR:
742                                 case FOREACH:
743                                 case IF:
744                                 case WHILE:
745                                         if (openParenthesisCount == openParenthesis.length) {
746                                                 System
747                                                                 .arraycopy(
748                                                                                 openParenthesis,
749                                                                                 0,
750                                                                                 (openParenthesis = new int[openParenthesisCount * 2]),
751                                                                                 0, openParenthesisCount);
752                                         }
753                                         openParenthesis[openParenthesisCount++] = 0;
754                                         expectingOpenBrace = true;
755                                         indentationLevel += pushControlStatement(token);
756                                         break;
757                                 case TRY:
758                                         pendingNewlineAfterParen = true;
759                                 case CATCH:
760                                         // several CATCH statements can be contiguous.
761                                         // a CATCH is encountered pop until first CATCH (if a CATCH
762                                         // follows a TRY it works the same way,
763                                         // as CATCH and TRY are the same token in the stack).
764                                         expectingOpenBrace = true;
765                                         indentationLevel += pushControlStatement(TokenName.CATCH);
766                                         break;
767                                 case DO:
768                                         expectingOpenBrace = true;
769                                         indentationLevel += pushControlStatement(token);
770                                         nlicsToken = token;
771                                         break;
772                                 case NEW:
773                                         break;
774                                 case LPAREN:
775                                         // if (previousToken == TokenName.synchronized) {
776                                         // indentationLevel += pushControlStatement(previousToken);
777                                         // } else {
778                                         // Put a space between the previous and current token if the
779                                         // previous token was not a keyword, open paren, logical
780                                         // compliment (eg: !), semi-colon, open brace, close brace,
781                                         // super, or this.
782                                         if (previousCompilableToken != TokenName.LBRACKET
783                                                         && previousToken != TokenName.IDENTIFIER
784                                                         && previousToken != TokenName.NONE
785                                                         && previousToken != TokenName.NOT
786                                                         && previousToken != TokenName.LPAREN
787                                                         && previousToken != TokenName.TWIDDLE
788                                                         && previousToken != TokenName.SEMICOLON
789                                                         && previousToken != TokenName.LBRACE
790                                                         && previousToken != TokenName.RBRACE
791                                                         && previousToken != TokenName.SUPER) {
792                                                 // && previousToken != TokenName.THIS) {
793                                                 if (!options.compactArrays) {
794                                                         space();
795                                                 }
796                                         }
797                                         // If in a for/if/while statement, increase the parenthesis
798                                         // count
799                                         // for the current openParenthesisCount
800                                         // else increase the count for stand alone parenthesis.
801                                         if (openParenthesisCount > 0)
802                                                 openParenthesis[openParenthesisCount - 1]++;
803                                         else
804                                                 openParenthesis[0]++;
805                                         pendingSpace = false;
806                                         // recognize array declaration for nice output
807                                         if (previousCompilableToken == TokenName.ARRAY) {
808                                                 arrayDeclarationCount++;
809                                                 arrayDeclarationParenthesis[arrayDeclarationCount] = openParenthesis[openParenthesisCount - 1];
810                                                 if (!options.compactArrays) {
811                                                         indentationLevel++;
812                                                         pendingNewLines = 1;
813                                                 }
814                                         }
815                                         // S }
816                                         break;
817                                 case RPAREN:
818                                         // check for closing array declaration
819                                         if (arrayDeclarationCount > 0) {
820                                                 if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
821                                                         if (previousCompilableToken != TokenName.LPAREN) {
822                                                                 if (!options.compactArrays) {
823                                                                         newLine(1);
824                                                                 }
825                                                         } else if (previousToken == TokenName.COMMENT_LINE
826                                                                         || previousToken == TokenName.COMMENT_BLOCK
827                                                                         || previousToken == TokenName.COMMENT_PHPDOC) {
828                                                                 // prevent to combine comment line and statement line (#1475484)
829                                                                 if (!options.compactArrays) {
830                                                                         newLine(1);
831                                                                 }
832                                                         }
833                                                         if (!options.compactArrays) {
834                                                                 indentationLevel--;
835                                                                 
836                                                         }
837                                                         currentLineIndentationLevel = indentationLevel;
838                                                         pendingNewLines = 0;
839                                                         arrayDeclarationCount--;
840                                                 }
841                                         }
842                                         // Decrease the parenthesis count
843                                         // if there is no more unclosed parenthesis,
844                                         // a new line and indent may be append (depending on the
845                                         // next
846                                         // token).
847                                         if ((openParenthesisCount > 1)
848                                                         && (openParenthesis[openParenthesisCount - 1] > 0)) {
849                                                 openParenthesis[openParenthesisCount - 1]--;
850                                                 if (openParenthesis[openParenthesisCount - 1] <= 0) {
851                                                         pendingNewlineAfterParen = true;
852                                                         inAssignment = false;
853                                                         openParenthesisCount--;
854                                                 }
855                                         } else {
856                                                 openParenthesis[0]--;
857                                         }
858                                         pendingSpace = false;
859                                         break;
860                                 case LBRACE:
861                                         if (previousCompilableToken == TokenName.DOLLAR) {
862                                                 dollarBraceCount++;
863                                         } else {
864                                                 if ((previousCompilableToken == TokenName.RBRACKET)
865                                                                 || (previousCompilableToken == TokenName.EQUAL)) {
866                                                         // if (previousCompilableToken == TokenName.RBRACKET)
867                                                         // {
868                                                         inArrayAssignment = true;
869                                                         inAssignment = false;
870                                                 }
871                                                 if (inArrayAssignment) {
872                                                         indentationLevel += pushBlock();
873                                                 } else {
874                                                         // Add new line and increase indentation level after
875                                                         // open brace.
876                                                         pendingNewLines = 1;
877                                                         indentationLevel += pushBlock();
878                                                         inAssignment = false;
879                                                 }
880                                         }
881                                         break;
882                                 case RBRACE:
883                                         if (dollarBraceCount > 0) {
884                                                 dollarBraceCount--;
885                                                 break;
886                                         }
887                                         if (previousCompilableToken == TokenName.RPAREN) {
888                                                 pendingSpace = false;
889                                         }
890                                         if (inArrayAssignment) {
891                                                 inArrayAssignment = false;
892                                                 pendingNewLines = 1;
893                                                 indentationLevel += popInclusiveUntilBlock();
894                                         } else {
895                                                 pendingNewLines = 1;
896                                                 indentationLevel += popInclusiveUntilBlock();
897                                                 if (previousCompilableToken == TokenName.RPAREN) {
898                                                         // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on
899                                                         // message
900                                                         // expression
901                                                         currentLineBuffer
902                                                                         .append(options.lineSeparatorSequence);
903                                                         increaseLineDelta(options.lineSeparatorSequence.length);
904                                                 }
905                                                 if (constructionsCount > 0) {
906                                                         switch (constructions[constructionsCount - 1]) {
907                                                         case FOR:
908                                                         case FOREACH:
909                                                                 // indentationLevel += popExclusiveUntilBlock();
910                                                                 // break;
911                                                         case SWITCH:
912                                                         case IF:
913                                                         case ELSE:
914                                                         case TRY:
915                                                         case CATCH:
916                                                         case FINALLY:
917                                                         case WHILE:
918                                                         case DO:
919                                                                 // case TokenName.synchronized :
920                                                                 clearNonBlockIndents = true;
921                                                         default:
922                                                                 break;
923                                                         }
924                                                 }
925                                         }
926                                         break;
927                                 case LBRACKET:
928                                         openBracketCount++;
929                                         pendingSpace = false;
930                                         break;
931                                 case RBRACKET:
932                                         openBracketCount -= (openBracketCount > 0) ? 1 : 0;
933                                         // if there is no left bracket to close, the right bracket
934                                         // is
935                                         // ignored.
936                                         pendingSpace = false;
937                                         break;
938                                 case COMMA:
939                                         pendingSpace = false;
940                                         if (arrayDeclarationCount > 0) {
941                                                 if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
942                                                         // there is no left parenthesis to close in current array declaration (#1475484)
943                                                         if (!options.compactArrays) {
944                                                                 pendingNewLines = 1;                                                            
945                                                         }
946                                                 }
947                                         }
948                                         break;
949                                 case DOT:
950                                         if (!options.compactStringConcatenation) {
951                                                 space();
952                                         }
953                                         pendingSpace = false;
954                                         break;
955                                 case SEMICOLON:
956                                         // Do not generate line terminators in the definition of
957                                         // the for statement.
958                                         // if not in this case, jump a line and reduce indentation
959                                         // after
960                                         // the brace
961                                         // if the block it closes belongs to a conditional statement
962                                         // (if,
963                                         // while, do...).
964                                         if (openParenthesisCount <= 1) {
965                                                 pendingNewLines = 1;
966                                                 if (expectingOpenBrace) {
967                                                         clearNonBlockIndents = true;
968                                                         expectingOpenBrace = false;
969                                                 }
970                                         }
971                                         inAssignment = false;
972                                         pendingSpace = false;
973                                         break;
974                                 case PLUS_PLUS:
975                                 case MINUS_MINUS:
976                                         // Do not put a space between a post-increment/decrement
977                                         // and the identifier being modified.
978                                         if (previousToken == TokenName.IDENTIFIER
979                                                         || previousToken == TokenName.RBRACKET
980                                                         || previousToken == TokenName.VARIABLE) {
981                                                 pendingSpace = false;
982                                         }
983                                         break;
984                                 case PLUS:
985                                         // previously ADDITION
986                                 case MINUS:
987                                         // Handle the unary operators plus and minus via a flag
988                                         if (!isLiteralToken(previousToken)
989                                                         && previousToken != TokenName.IDENTIFIER
990                                                         && previousToken != TokenName.RPAREN
991                                                         && previousToken != TokenName.RBRACKET) {
992                                                 unarySignModifier = 1;
993                                         }
994                                         break;
995                                 case COLON:
996                                         // In a switch/case statement, add a newline & indent
997                                         // when a colon is encountered.
998                                         if (tokenBeforeColonCount > 0) {
999                                                 if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenName.CASE) {
1000                                                         pendingNewLines = 1;
1001                                                 }
1002                                                 tokenBeforeColonCount--;
1003                                         }
1004                                         break;
1005                                 case EQUAL:
1006                                         inAssignment = true;
1007                                         break;
1008                                 case COMMENT_LINE:
1009                                         pendingNewLines = 1;
1010                                         //if (inAssignment) {
1011                                         //      currentLineIndentationLevel++;
1012                                         //}
1013                                         break; // a line is always inserted after a one-line
1014                                                         // comment
1015                                 case COMMENT_PHPDOC:
1016                                 case COMMENT_BLOCK:
1017                                         currentCommentOffset = getCurrentCommentOffset();
1018                                         pendingNewLines = 1;
1019                                         break;
1020                                 case WHITESPACE:
1021                                         if (!phpTagAndWhitespace) {
1022                                                 // Count the number of line terminators in the
1023                                                 // whitespace so
1024                                                 // line spacing can be preserved near comments.
1025                                                 char[] source = scanner.source;
1026                                                 newLinesInWhitespace = 0;
1027                                                 for (int i = scanner.startPosition, max = scanner.currentPosition; i < max; i++) {
1028                                                         if (source[i] == '\r') {
1029                                                                 if (i < max - 1) {
1030                                                                         if (source[++i] == '\n') {
1031                                                                                 newLinesInWhitespace++;
1032                                                                         } else {
1033                                                                                 newLinesInWhitespace++;
1034                                                                         }
1035                                                                 } else {
1036                                                                         newLinesInWhitespace++;
1037                                                                 }
1038                                                         } else if (source[i] == '\n') {
1039                                                                 newLinesInWhitespace++;
1040                                                         }
1041                                                 }
1042                                                 increaseLineDelta(scanner.startPosition
1043                                                                 - scanner.currentPosition);
1044                                                 break;
1045                                         }
1046                                         // case TokenName.HTML :
1047                                         // // Add the next token to the formatted source string.
1048                                         // // outputCurrentToken(token);
1049                                         // int startPosition = scanner.startPosition;
1050                                         // flushBuffer();
1051                                         // for (int i = startPosition, max =
1052                                         // scanner.currentPosition; i <
1053                                         // max; i++) {
1054                                         // char currentCharacter = scanner.source[i];
1055                                         // updateMappedPositions(i);
1056                                         // currentLineBuffer.append(currentCharacter);
1057                                         // }
1058                                         // break;
1059                                 default:
1060                                         if ((token == TokenName.IDENTIFIER) || isLiteralToken(token)
1061                                                         || token == TokenName.SUPER) {
1062                                                 // || token == TokenName.this) {
1063                                                 // Do not put a space between a unary operator
1064                                                 // (eg: ++, --, +, -) and the identifier being modified.
1065                                                 if (previousToken == TokenName.PLUS_PLUS
1066                                                                 || previousToken == TokenName.MINUS_MINUS
1067                                                                 || (previousToken == TokenName.MINUS_GREATER && options.compactDereferencingMode) // ->
1068                                                                 || (previousToken == TokenName.PLUS && unarySignModifier > 0)
1069                                                                 || (previousToken == TokenName.MINUS && unarySignModifier > 0)) {
1070                                                         pendingSpace = false;
1071                                                 }
1072                                                 unarySignModifier = 0;
1073                                         }
1074                                         break;
1075                                 }
1076                                 // Do not output whitespace tokens.
1077                                 if (token != Scanner.TokenName.WHITESPACE || phpTagAndWhitespace) {
1078                                         /*
1079                                          * Add pending space to the formatted source string. Do not
1080                                          * output a space under the following circumstances: 1) this
1081                                          * is the first pass 2) previous token is an open paren 3)
1082                                          * previous token is a period 4) previous token is the
1083                                          * logical compliment (eg: !) 5) previous token is the
1084                                          * bitwise compliment (eg: ~) 6) previous token is the open
1085                                          * bracket (eg: [) 7) in an assignment statement, if the
1086                                          * previous token is an open brace or the current token is a
1087                                          * close brace 8) previous token is a single line comment 9)
1088                                          * current token is a '->'
1089                                          */
1090                                         if (token == TokenName.MINUS_GREATER
1091                                                         && options.compactDereferencingMode)
1092                                                 pendingSpace = false;
1093
1094                                         boolean openAndCloseBrace = previousCompilableToken == TokenName.LBRACE
1095                                                         && token == TokenName.RBRACE;
1096                                         if (pendingSpace
1097                                                         && insertSpaceAfter(previousToken)
1098                                                         && !(inAssignment && (previousToken == TokenName.LBRACE || token == TokenName.RBRACE))
1099                                                         && previousToken != Scanner.TokenName.COMMENT_LINE) {
1100                                                 if ((!(options.compactAssignmentMode && token == TokenName.EQUAL))
1101                                                                 && !openAndCloseBrace)
1102                                                         space();
1103                                         }
1104                                         // Add the next token to the formatted source string.
1105                                         outputCurrentToken(token);
1106                                         if (token == Scanner.TokenName.COMMENT_LINE
1107                                                         && openParenthesisCount > 1) {
1108                                                 pendingNewLines = 0;
1109                                                 currentLineBuffer.append(options.lineSeparatorSequence);
1110                                                 increaseLineDelta(options.lineSeparatorSequence.length);
1111                                         }
1112                                         pendingSpace = true;
1113                                 }
1114                                 // Whitespace tokens do not need to be remembered.
1115                                 if (token != Scanner.TokenName.WHITESPACE || phpTagAndWhitespace) {
1116                                         previousToken = token;
1117                                         if (token != Scanner.TokenName.COMMENT_BLOCK
1118                                                         && token != Scanner.TokenName.COMMENT_LINE
1119                                                         && token != Scanner.TokenName.COMMENT_PHPDOC) {
1120                                                 previousCompilableToken = token;
1121                                         }
1122                                 }
1123                         }
1124                         output(copyRemainingSource());
1125                         flushBuffer();
1126                         // dump the last token of the source in the formatted output.
1127                 } catch (InvalidInputException e) {
1128                         output(copyRemainingSource());
1129                         flushBuffer();
1130                         // dump the last token of the source in the formatted output.
1131                 }
1132         }
1133
1134         /**
1135          * Formats the char array <code>sourceString</code>, and returns a string
1136          * containing the formatted version.
1137          * 
1138          * @return the formatted ouput.
1139          */
1140         public String formatSourceString(String sourceString) {
1141                 char[] sourceChars = sourceString.toCharArray();
1142                 formattedSource = new StringBuffer(sourceChars.length);
1143                 scanner.setSource(sourceChars);
1144                 format();
1145                 return formattedSource.toString();
1146         }
1147
1148         /**
1149          * Formats the char array <code>sourceString</code>, and returns a string
1150          * containing the formatted version.
1151          * 
1152          * @param string
1153          *            the string to format
1154          * @param indentationLevel
1155          *            the initial indentation level
1156          * @return the formatted ouput.
1157          */
1158         public String format(String string, int indentationLevel) {
1159                 return format(string, indentationLevel, (int[]) null);
1160         }
1161
1162         /**
1163          * Formats the char array <code>sourceString</code>, and returns a string
1164          * containing the formatted version. The positions array is modified to
1165          * contain the mapped positions.
1166          * 
1167          * @param string
1168          *            the string to format
1169          * @param indentationLevel
1170          *            the initial indentation level
1171          * @param positions
1172          *            the array of positions to map
1173          * @return the formatted ouput.
1174          */
1175         public String format(String string, int indentationLevel, int[] positions) {
1176                 return this.format(string, indentationLevel, positions, null);
1177         }
1178
1179         public String format(String string, int indentationLevel, int[] positions,
1180                         String lineSeparator) {
1181                 if (lineSeparator != null) {
1182                         this.options.setLineSeparator(lineSeparator);
1183                 }
1184                 if (positions != null) {
1185                         this.setPositionsToMap(positions);
1186                         this.setInitialIndentationLevel(indentationLevel);
1187                         String formattedString = this.formatSourceString(string);
1188                         int[] mappedPositions = this.getMappedPositions();
1189                         System
1190                                         .arraycopy(mappedPositions, 0, positions, 0,
1191                                                         positions.length);
1192                         return formattedString;
1193                 } else {
1194                         this.setInitialIndentationLevel(indentationLevel);
1195                         return this.formatSourceString(string);
1196                 }
1197         }
1198
1199         /**
1200          * Formats the char array <code>sourceString</code>, and returns a string
1201          * containing the formatted version. The initial indentation level is 0.
1202          * 
1203          * @param string
1204          *            the string to format
1205          * @return the formatted ouput.
1206          */
1207         public String format(String string) {
1208                 return this.format(string, 0, (int[]) null);
1209         }
1210
1211         /**
1212          * Formats a given source string, starting indenting it at a particular
1213          * depth and using the given options
1214          * 
1215          * @deprecated backport 1.0 internal functionality
1216          */
1217         public static String format(String sourceString,
1218                         int initialIndentationLevel, ConfigurableOption[] options) {
1219                 CodeFormatter formatter = new CodeFormatter(options);
1220                 formatter.setInitialIndentationLevel(initialIndentationLevel);
1221                 return formatter.formatSourceString(sourceString);
1222         }
1223
1224         /**
1225          * Returns the number of characters and tab char between the beginning of
1226          * the line and the beginning of the comment.
1227          */
1228         private int getCurrentCommentOffset() {
1229                 int linePtr = scanner.linePtr;
1230                 // if there is no beginning of line, return 0.
1231                 if (linePtr < 0)
1232                         return 0;
1233                 int offset = 0;
1234                 int beginningOfLine = scanner.lineEnds[linePtr];
1235                 int currentStartPosition = scanner.startPosition;
1236                 char[] source = scanner.source;
1237                 // find the position of the beginning of the line containing the comment
1238                 while (beginningOfLine > currentStartPosition) {
1239                         if (linePtr > 0) {
1240                                 beginningOfLine = scanner.lineEnds[--linePtr];
1241                         } else {
1242                                 beginningOfLine = 0;
1243                                 break;
1244                         }
1245                 }
1246                 for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
1247                         char currentCharacter = source[i];
1248                         switch (currentCharacter) {
1249                         case '\t':
1250                                 offset += options.tabSize;
1251                                 break;
1252                         case ' ':
1253                                 offset++;
1254                                 break;
1255                         case '\r':
1256                         case '\n':
1257                                 break;
1258                         default:
1259                                 return offset;
1260                         }
1261                 }
1262                 return offset;
1263         }
1264
1265         /**
1266          * Returns an array of descriptions for the configurable options. The
1267          * descriptions may be changed and passed back to a different compiler.
1268          * 
1269          * @deprecated backport 1.0 internal functionality
1270          */
1271 //      public static ConfigurableOption[] getDefaultOptions(Locale locale) {
1272 //              String componentName = CodeFormatter.class.getName();
1273 //              FormatterOptions options = new FormatterOptions();
1274 //              return new ConfigurableOption[] {
1275 //                              new ConfigurableOption(componentName, "newline.openingBrace",
1276 //                                              locale, options.newLineBeforeOpeningBraceMode ? 0 : 1),
1277 //                              //$NON-NLS-1$
1278 //                              new ConfigurableOption(componentName,
1279 //                                              "newline.controlStatement", locale,
1280 //                                              options.newlineInControlStatementMode ? 0 : 1),
1281 //                              //$NON-NLS-1$
1282 //                              new ConfigurableOption(componentName, "newline.clearAll",
1283 //                                              locale, options.clearAllBlankLinesMode ? 0 : 1),
1284 //                              //$NON-NLS-1$
1285 //                              // new ConfigurableOption(componentName, "newline.elseIf",
1286 //                              // locale,
1287 //                              // options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
1288 //                              new ConfigurableOption(componentName, "newline.emptyBlock",
1289 //                                              locale, options.newLineInEmptyBlockMode ? 0 : 1),
1290 //                              //$NON-NLS-1$
1291 //                              new ConfigurableOption(componentName, "line.split", locale,
1292 //                                              options.maxLineLength),
1293 //                              //$NON-NLS-1$
1294 //                              new ConfigurableOption(componentName,
1295 //                                              "style.compactAssignment", locale,
1296 //                                              options.compactAssignmentMode ? 0 : 1),
1297 //                              //$NON-NLS-1$
1298 //                              new ConfigurableOption(componentName, "tabulation.char",
1299 //                                              locale, options.indentWithTab ? 0 : 1),
1300 //                              //$NON-NLS-1$
1301 //                              new ConfigurableOption(componentName,
1302 //                                              "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
1303 //              };
1304 //      }
1305
1306         /**
1307          * Returns the array of mapped positions. Returns null is no positions have
1308          * been set.
1309          * 
1310          * @return int[]
1311          * @deprecated There is no need to retrieve the mapped positions anymore.
1312          */
1313         public int[] getMappedPositions() {
1314                 if (null != mappedPositions) {
1315                         for (int i = 0; i < mappedPositions.length; i++) {
1316                                 if (mappedPositions[i] >= formattedSource.length()) {
1317                                         mappedPositions[i] = formattedSource.length() - 1;
1318                                 }
1319                         }
1320                 }
1321                 return mappedPositions;
1322         }
1323
1324         /**
1325          * Returns the priority of the token given as argument <br>
1326          * The most prioritary the token is, the smallest the return value is.
1327          * 
1328          * @return the priority of <code>token</code>
1329          * @param token
1330          *            the token of which the priority is requested
1331          */
1332 //      private static int getTokenPriority(int token) {
1333 //              switch (token) {
1334 //              case TokenName.extends:
1335 //                      // case TokenName.implements :
1336 //                      // case TokenName.throws :
1337 //                      return 10;
1338 //              case TokenName.SEMICOLON:
1339 //                      // ;
1340 //                      return 20;
1341 //              case TokenName.COMMA:
1342 //                      // ,
1343 //                      return 25;
1344 //              case TokenName.EQUAL:
1345 //                      // =
1346 //                      return 30;
1347 //              case TokenName.AND_AND:
1348 //                      // &&
1349 //              case TokenName.OR_OR:
1350 //                      // ||
1351 //                      return 40;
1352 //              case TokenName.QUESTION:
1353 //                      // ?
1354 //              case TokenName.COLON:
1355 //                      // :
1356 //                      return 50; // it's better cutting on ?: than on ;
1357 //              case TokenName.EQUAL_EQUAL:
1358 //                      // ==
1359 //              case TokenName.EQUAL_EQUAL_EQUAL:
1360 //                      // ===
1361 //              case TokenName.NOT_EQUAL:
1362 //                      // !=
1363 //              case TokenName.NOT_EQUAL_EQUAL:
1364 //                      // !=
1365 //                      return 60;
1366 //              case TokenName.LESS:
1367 //                      // <
1368 //              case TokenName.LESS_EQUAL:
1369 //                      // <=
1370 //              case TokenName.GREATER:
1371 //                      // >
1372 //              case TokenName.GREATER_EQUAL:
1373 //                      // >=
1374 //                      // case TokenName.instanceof : // instanceof
1375 //                      return 70;
1376 //              case TokenName.PLUS:
1377 //                      // +
1378 //              case TokenName.MINUS:
1379 //                      // -
1380 //                      return 80;
1381 //              case TokenName.MULTIPLY:
1382 //                      // *
1383 //              case TokenName.DIVIDE:
1384 //                      // /
1385 //              case TokenName.REMAINDER:
1386 //                      // %
1387 //                      return 90;
1388 //              case TokenName.LEFT_SHIFT:
1389 //                      // <<
1390 //              case TokenName.RIGHT_SHIFT:
1391 //                      // >>
1392 //                      // case TokenName.UNSIGNED_RIGHT_SHIFT : // >>>
1393 //                      return 100;
1394 //              case TokenName.AND:
1395 //                      // &
1396 //              case TokenName.OR:
1397 //                      // |
1398 //              case TokenName.XOR:
1399 //                      // ^
1400 //                      return 110;
1401 //              case TokenName.MULTIPLY_EQUAL:
1402 //                      // *=
1403 //              case TokenName.DIVIDE_EQUAL:
1404 //                      // /=
1405 //              case TokenName.REMAINDER_EQUAL:
1406 //                      // %=
1407 //              case TokenName.PLUS_EQUAL:
1408 //                      // +=
1409 //              case TokenName.MINUS_EQUAL:
1410 //                      // -=
1411 //              case TokenName.LEFT_SHIFT_EQUAL:
1412 //                      // <<=
1413 //              case TokenName.RIGHT_SHIFT_EQUAL:
1414 //                      // >>=
1415 //                      // case TokenName.UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
1416 //              case TokenName.AND_EQUAL:
1417 //                      // &=
1418 //              case TokenName.XOR_EQUAL:
1419 //                      // ^=
1420 //              case TokenName.OR_EQUAL:
1421 //                      // .=
1422 //              case TokenName.DOT_EQUAL:
1423 //                      // |=
1424 //                      return 120;
1425 //              case TokenName.DOT:
1426 //                      // .
1427 //                      return 130;
1428 //              default:
1429 //                      return Integer.MAX_VALUE;
1430 //              }
1431 //      }
1432
1433         /**
1434          * Handles the exception raised when an invalid token is encountered.
1435          * Returns true if the exception has been handled, false otherwise.
1436          */
1437         private boolean handleInvalidToken(Exception e) {
1438                 if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT)
1439                                 || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
1440                                 || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
1441                         return true;
1442                 }
1443                 return false;
1444         }
1445
1446         private final void increaseGlobalDelta(int offset) {
1447                 globalDelta += offset;
1448         }
1449
1450         private final void increaseLineDelta(int offset) {
1451                 lineDelta += offset;
1452         }
1453
1454         private final void increaseSplitDelta(int offset) {
1455                 splitDelta += offset;
1456         }
1457
1458         /**
1459          * Returns true if a space has to be inserted after <code>operator</code>
1460          * false otherwise.
1461          */
1462         private boolean insertSpaceAfter(TokenName token) {
1463                 switch (token) {
1464                 case LPAREN:
1465                 case NOT:
1466                 case TWIDDLE:
1467                 case NONE:
1468                         // no token
1469                 case WHITESPACE:
1470                 case LBRACKET:
1471                 case DOLLAR:
1472                 case COMMENT_LINE:
1473                         return false;
1474                 case DOT:
1475                         return !options.compactStringConcatenation;
1476                 default:
1477                         return true;
1478                 }
1479         }
1480
1481         /**
1482          * Returns true if a space has to be inserted before <code>operator</code>
1483          * false otherwise. <br>
1484          * Cannot be static as it uses the code formatter options (to know if the
1485          * compact assignment mode is on).
1486          */
1487         private boolean insertSpaceBefore(TokenName token) {
1488                 switch (token) {
1489                 case EQUAL:
1490                         return (!options.compactAssignmentMode);
1491                 default:
1492                         return false;
1493                 }
1494         }
1495
1496         private static boolean isComment(TokenName token) {
1497                 boolean result = token == Scanner.TokenName.COMMENT_BLOCK
1498                                 || token == Scanner.TokenName.COMMENT_LINE
1499                                 || token == Scanner.TokenName.COMMENT_PHPDOC;
1500                 return result;
1501         }
1502
1503         private static boolean isLiteralToken(TokenName token) {
1504                 boolean result = token == TokenName.INTEGERLITERAL
1505                 // || token == TokenName.LongLiteral
1506                                 // || token == TokenName.FloatingPointLiteral
1507                                 || token == TokenName.DOUBLELITERAL
1508                                 // || token == TokenName.CharacterLiteral
1509                                 || token == TokenName.STRINGDOUBLEQUOTE;
1510                 return result;
1511         }
1512
1513         /**
1514          * If the length of <code>oneLineBuffer</code> exceeds
1515          * <code>maxLineLength</code>, it is split and the result is dumped in
1516          * <code>formattedSource</code>
1517          * 
1518          * @param newLineCount
1519          *            the number of new lines to append
1520          */
1521         private void newLine(int newLineCount) {
1522                 // format current line
1523                 splitDelta = 0;
1524                 beginningOfLineIndex = formattedSource.length();
1525                 String currentLine = currentLineBuffer.toString();
1526                 if (containsOpenCloseBraces) {
1527                         containsOpenCloseBraces = false;
1528                         outputLine(currentLine, false, indentationLevelForOpenCloseBraces,
1529                                         TokenName.NONE, -1, null, 0);
1530                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
1531                 } else {
1532                         outputLine(currentLine, false, currentLineIndentationLevel, TokenName.NONE, -1,
1533                                         null, 0);
1534                 }
1535                 // dump line break(s)
1536                 for (int i = 0; i < newLineCount; i++) {
1537                         formattedSource.append(options.lineSeparatorSequence);
1538                         increaseSplitDelta(options.lineSeparatorSequence.length);
1539                 }
1540                 // reset formatter for next line
1541                 int currentLength = currentLine.length();
1542                 currentLineBuffer = new StringBuffer(
1543                                 currentLength > maxLineSize ? maxLineSize = currentLength
1544                                                 : maxLineSize);
1545                 increaseGlobalDelta(splitDelta);
1546                 increaseGlobalDelta(lineDelta);
1547                 lineDelta = 0;
1548                 currentLineIndentationLevel = initialIndentationLevel;
1549         }
1550
1551         private String operatorString(TokenName operator) {
1552                 switch (operator) {
1553                 case EXTENDS:
1554                         return "extends"; //$NON-NLS-1$
1555                         // case TokenName.implements :
1556                         // return "implements"; //$NON-NLS-1$
1557                         //
1558                         // case TokenName.throws :
1559                         // return "throws"; //$NON-NLS-1$
1560                 case SEMICOLON:
1561                         // ;
1562                         return ";"; //$NON-NLS-1$
1563                 case COMMA:
1564                         // ,
1565                         return ","; //$NON-NLS-1$
1566                 case EQUAL:
1567                         // =
1568                         return "="; //$NON-NLS-1$
1569                 case AND_AND:
1570                         // && (15.22)
1571                         return "&&"; //$NON-NLS-1$
1572                 case OR_OR:
1573                         // || (15.23)
1574                         return "||"; //$NON-NLS-1$
1575                 case QUESTION:
1576                         // ? (15.24)
1577                         return "?"; //$NON-NLS-1$
1578                 case COLON:
1579                         // : (15.24)
1580                         return ":"; //$NON-NLS-1$
1581                 case PAAMAYIM_NEKUDOTAYIM:
1582                         // : (15.24)
1583                         return "::"; //$NON-NLS-1$
1584                 case EQUAL_EQUAL:
1585                         // == (15.20, 15.20.1, 15.20.2, 15.20.3)
1586                         return "=="; //$NON-NLS-1$
1587                 case EQUAL_EQUAL_EQUAL:
1588                         // == (15.20, 15.20.1, 15.20.2, 15.20.3)
1589                         return "==="; //$NON-NLS-1$
1590                 case EQUAL_GREATER:
1591                         // -= (15.25.2)
1592                         return "=>"; //$NON-NLS-1$
1593                 case NOT_EQUAL:
1594                         // != (15.20, 15.20.1, 15.20.2, 15.20.3)
1595                         return "!="; //$NON-NLS-1$
1596                 case NOT_EQUAL_EQUAL:
1597                         // != (15.20, 15.20.1, 15.20.2, 15.20.3)
1598                         return "!=="; //$NON-NLS-1$
1599                 case LESS:
1600                         // < (15.19.1)
1601                         return "<"; //$NON-NLS-1$
1602                 case LESS_EQUAL:
1603                         // <= (15.19.1)
1604                         return "<="; //$NON-NLS-1$
1605                 case GREATER:
1606                         // > (15.19.1)
1607                         return ">"; //$NON-NLS-1$
1608                 case GREATER_EQUAL:
1609                         // >= (15.19.1)
1610                         return ">="; //$NON-NLS-1$
1611                         // case instanceof : // instanceof
1612                         // return "instanceof"; //$NON-NLS-1$
1613                 case PLUS:
1614                         // + (15.17, 15.17.2)
1615                         return "+"; //$NON-NLS-1$
1616                 case MINUS:
1617                         // - (15.17.2)
1618                         return "-"; //$NON-NLS-1$
1619                 case MULTIPLY:
1620                         // * (15.16.1)
1621                         return "*"; //$NON-NLS-1$
1622                 case DIVIDE:
1623                         // / (15.16.2)
1624                         return "/"; //$NON-NLS-1$
1625                 case REMAINDER:
1626                         // % (15.16.3)
1627                         return "%"; //$NON-NLS-1$
1628                 case LEFT_SHIFT:
1629                         // << (15.18)
1630                         return "<<"; //$NON-NLS-1$
1631                 case RIGHT_SHIFT:
1632                         // >> (15.18)
1633                         return ">>"; //$NON-NLS-1$
1634                         // case UNSIGNED_RIGHT_SHIFT : // >>> (15.18)
1635                         // return ">>>"; //$NON-NLS-1$
1636                 case OP_AND:
1637                         // & (15.21, 15.21.1, 15.21.2)
1638                         return "&"; //$NON-NLS-1$
1639                 case OP_OR:
1640                         // | (15.21, 15.21.1, 15.21.2)
1641                         return "|"; //$NON-NLS-1$
1642                 case OP_XOR:
1643                         // ^ (15.21, 15.21.1, 15.21.2)
1644                         return "^"; //$NON-NLS-1$
1645                 case MULTIPLY_EQUAL:
1646                         // *= (15.25.2)
1647                         return "*="; //$NON-NLS-1$
1648                 case DIVIDE_EQUAL:
1649                         // /= (15.25.2)
1650                         return "/="; //$NON-NLS-1$
1651                 case REMAINDER_EQUAL:
1652                         // %= (15.25.2)
1653                         return "%="; //$NON-NLS-1$
1654                 case PLUS_EQUAL:
1655                         // += (15.25.2)
1656                         return "+="; //$NON-NLS-1$
1657                 case MINUS_EQUAL:
1658                         // -= (15.25.2)
1659                         return "-="; //$NON-NLS-1$
1660                 case MINUS_GREATER:
1661                         // -= (15.25.2)
1662                         return "->"; //$NON-NLS-1$
1663                 case LEFT_SHIFT_EQUAL:
1664                         // <<= (15.25.2)
1665                         return "<<="; //$NON-NLS-1$
1666                 case RIGHT_SHIFT_EQUAL:
1667                         // >>= (15.25.2)
1668                         return ">>="; //$NON-NLS-1$
1669                         // case UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
1670                         // return ">>>="; //$NON-NLS-1$
1671                 case AND_EQUAL:
1672                         // &= (15.25.2)
1673                         return "&="; //$NON-NLS-1$
1674                 case XOR_EQUAL:
1675                         // ^= (15.25.2)
1676                         return "^="; //$NON-NLS-1$
1677                 case OR_EQUAL:
1678                         // |= (15.25.2)
1679                         return "|="; //$NON-NLS-1$
1680                 case DOT_EQUAL:
1681                         // .=
1682                         return ".="; //$NON-NLS-1$
1683                 case DOT:
1684                         // .
1685                         return "."; //$NON-NLS-1$
1686                 default:
1687                         return ""; //$NON-NLS-1$
1688                 }
1689         }
1690
1691         /**
1692          * Appends <code>stringToOutput</code> to the formatted output. <br>
1693          * If it contains \n, append a LINE_SEPARATOR and indent after it.
1694          */
1695         private void output(String stringToOutput) {
1696                 char currentCharacter;
1697                 for (int i = 0, max = stringToOutput.length(); i < max; i++) {
1698                         currentCharacter = stringToOutput.charAt(i);
1699                         if (currentCharacter != '\t') {
1700                                 currentLineBuffer.append(currentCharacter);
1701                         }
1702                 }
1703         }
1704
1705         private void outputCurrentTokenWithoutIndent(TokenName heredoc, int newLineCount) {
1706                 newLine(newLineCount);
1707                 formattedSource.append(scanner.source, scanner.startPosition,
1708                                 scanner.currentPosition - scanner.startPosition);
1709         }
1710
1711         /**
1712          * Appends <code>token</code> to the formatted output. <br>
1713          * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent
1714          * after it.
1715          */
1716         private void outputCurrentToken(TokenName token) {
1717                 char[] source = scanner.source;
1718                 int startPosition = scanner.startPosition;
1719                 switch (token) {
1720                 case COMMENT_PHPDOC:
1721                 case COMMENT_BLOCK:
1722                 case COMMENT_LINE:
1723                         boolean endOfLine = false;
1724                         int currentCommentOffset = getCurrentCommentOffset();
1725                         int beginningOfLineSpaces = 0;
1726                         endOfLine = false;
1727                         currentCommentOffset = getCurrentCommentOffset();
1728                         beginningOfLineSpaces = 0;
1729                         boolean pendingCarriageReturn = false;
1730                         for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
1731                                 char currentCharacter = source[i];
1732                                 updateMappedPositions(i);
1733                                 switch (currentCharacter) {
1734                                 case '\r':
1735                                         pendingCarriageReturn = true;
1736                                         endOfLine = true;
1737                                         break;
1738                                 case '\n':
1739                                         if (pendingCarriageReturn) {
1740                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
1741                                         } else {
1742                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
1743                                         }
1744                                         pendingCarriageReturn = false;
1745                                         currentLineBuffer.append(options.lineSeparatorSequence);
1746                                         beginningOfLineSpaces = 0;
1747                                         endOfLine = true;
1748                                         break;
1749                                 case '\t':
1750                                         if (pendingCarriageReturn) {
1751                                                 pendingCarriageReturn = false;
1752                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
1753                                                 currentLineBuffer.append(options.lineSeparatorSequence);
1754                                                 beginningOfLineSpaces = 0;
1755                                                 endOfLine = true;
1756                                         }
1757                                         if (endOfLine) {
1758                                                 // we remove a maximum of currentCommentOffset
1759                                                 // characters (tabs
1760                                                 // are converted to space numbers).
1761                                                 beginningOfLineSpaces += options.tabSize;
1762                                                 if (beginningOfLineSpaces > currentCommentOffset) {
1763                                                         currentLineBuffer.append(currentCharacter);
1764                                                 } else {
1765                                                         increaseGlobalDelta(-1);
1766                                                 }
1767                                         } else {
1768                                                 currentLineBuffer.append(currentCharacter);
1769                                         }
1770                                         break;
1771                                 case ' ':
1772                                         if (pendingCarriageReturn) {
1773                                                 pendingCarriageReturn = false;
1774                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
1775                                                 currentLineBuffer.append(options.lineSeparatorSequence);
1776                                                 beginningOfLineSpaces = 0;
1777                                                 endOfLine = true;
1778                                         }
1779                                         if (endOfLine) {
1780                                                 // we remove a maximum of currentCommentOffset
1781                                                 // characters (tabs
1782                                                 // are converted to space numbers).
1783                                                 beginningOfLineSpaces++;
1784                                                 if (beginningOfLineSpaces > currentCommentOffset) {
1785                                                         currentLineBuffer.append(currentCharacter);
1786                                                 } else {
1787                                                         increaseGlobalDelta(-1);
1788                                                 }
1789                                         } else {
1790                                                 currentLineBuffer.append(currentCharacter);
1791                                         }
1792                                         break;
1793                                 default:
1794                                         if (pendingCarriageReturn) {
1795                                                 pendingCarriageReturn = false;
1796                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
1797                                                 currentLineBuffer.append(options.lineSeparatorSequence);
1798                                                 beginningOfLineSpaces = 0;
1799                                                 endOfLine = true;
1800                                         } else {
1801                                                 beginningOfLineSpaces = 0;
1802                                                 currentLineBuffer.append(currentCharacter);
1803                                                 endOfLine = false;
1804                                         }
1805                                 }
1806                         }
1807                         updateMappedPositions(scanner.currentPosition - 1);
1808                         multipleLineCommentCounter++;
1809                         break;
1810                 default:
1811                         for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
1812                                 char currentCharacter = source[i];
1813                                 updateMappedPositions(i);
1814                                 currentLineBuffer.append(currentCharacter);
1815                         }
1816                 }
1817         }
1818
1819         /**
1820          * Outputs <code>currentString</code>:<br>
1821          * <ul>
1822          * <li>If its length is < maxLineLength, output
1823          * <li>Otherwise it is split.
1824          * </ul>
1825          * 
1826          * @param currentString
1827          *            string to output
1828          * @param preIndented
1829          *            whether the string to output was pre-indented
1830          * @param depth
1831          *            number of indentation to put in front of
1832          *            <code>currentString</code>
1833          * @param operator
1834          *            value of the operator belonging to <code>currentString</code>.
1835          */
1836         private void outputLine(String currentString, boolean preIndented,
1837                         int depth, TokenName operator, int substringIndex,
1838                         int[] startSubstringIndexes, int offsetInGlobalLine) {
1839                 boolean emptyFirstSubString = false;
1840                 String operatorString = operatorString(operator);
1841                 boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
1842                 boolean placeOperatorAhead = !placeOperatorBehind;
1843                 // dump prefix operator?
1844                 if (placeOperatorAhead) {
1845                         if (!preIndented) {
1846                                 dumpTab(depth);
1847                                 preIndented = true;
1848                         }
1849                         if (operator.compareTo (TokenName.NONE) > 0) {
1850                                 if (insertSpaceBefore(operator)) {
1851                                         formattedSource.append(' ');
1852                                         increaseSplitDelta(1);
1853                                 }
1854                                 formattedSource.append(operatorString);
1855                                 increaseSplitDelta(operatorString.length());
1856                                 if (insertSpaceAfter(operator)
1857                                                 && operator != TokenName.IMPLEMENTS
1858                                                 && operator != TokenName.EXTENDS) {
1859                                         // && operator != TokenName.throws) {
1860                                         formattedSource.append(' ');
1861                                         increaseSplitDelta(1);
1862                                 }
1863                         }
1864                 }
1865                 SplitLine splitLine = null;
1866                 if (options.maxLineLength == 0
1867                                 || getLength(currentString, depth) < options.maxLineLength
1868                                 || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
1869                         // depending on the type of operator, outputs new line before of
1870                         // after
1871                         // dumping it
1872                         // indent before postfix operator
1873                         // indent also when the line cannot be split
1874                         if (operator == TokenName.EXTENDS || operator == TokenName.IMPLEMENTS) {
1875                                 // || operator == TokenName.throws) {
1876                                 formattedSource.append(' ');
1877                                 increaseSplitDelta(1);
1878                         }
1879                         if (placeOperatorBehind) {
1880                                 if (!preIndented) {
1881                                         dumpTab(depth);
1882                                 }
1883                         }
1884                         int max = currentString.length();
1885                         if (multipleLineCommentCounter != 0) {
1886                                 try {
1887                                         BufferedReader reader = new BufferedReader(
1888                                                         new StringReader(currentString));
1889                                         String line = reader.readLine();
1890                                         while (line != null) {
1891                                                 updateMappedPositionsWhileSplitting(
1892                                                                 beginningOfLineIndex, beginningOfLineIndex
1893                                                                                 + line.length()
1894                                                                                 + options.lineSeparatorSequence.length);
1895                                                 formattedSource.append(line);
1896                                                 beginningOfLineIndex = beginningOfLineIndex
1897                                                                 + line.length();
1898                                                 if ((line = reader.readLine()) != null) {
1899                                                         formattedSource
1900                                                                         .append(options.lineSeparatorSequence);
1901                                                         beginningOfLineIndex += options.lineSeparatorSequence.length;
1902                                                         dumpTab(currentLineIndentationLevel);
1903                                                 }
1904                                         }
1905                                         reader.close();
1906                                 } catch (IOException e) {
1907                                         e.printStackTrace();
1908                                 }
1909                         } else {
1910                                 updateMappedPositionsWhileSplitting(beginningOfLineIndex,
1911                                                 beginningOfLineIndex + max);
1912                                 for (int i = 0; i < max; i++) {
1913                                         char currentChar = currentString.charAt(i);
1914                                         switch (currentChar) {
1915                                         case '\r':
1916                                                 break;
1917                                         case '\n':
1918                                                 if (i != max - 1) {
1919                                                         // fix for 1FFYL5C: LFCOM:ALL - Incorrect
1920                                                         // indentation when
1921                                                         // split with a comment inside a condition
1922                                                         // a substring cannot end with a
1923                                                         // lineSeparatorSequence,
1924                                                         // except if it has been added by format() after a
1925                                                         // one-line
1926                                                         // comment
1927                                                         formattedSource
1928                                                                         .append(options.lineSeparatorSequence);
1929                                                         // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message
1930                                                         // expression
1931                                                         dumpTab(depth - 1);
1932                                                 }
1933                                                 break;
1934                                         default:
1935                                                 formattedSource.append(currentChar);
1936                                         }
1937                                 }
1938                         }
1939                         // update positions inside the mappedPositions table
1940                         if (substringIndex != -1) {
1941                                 if (multipleLineCommentCounter == 0) {
1942                                         int startPosition = beginningOfLineIndex
1943                                                         + startSubstringIndexes[substringIndex];
1944                                         updateMappedPositionsWhileSplitting(startPosition,
1945                                                         startPosition + max);
1946                                 }
1947                                 // compute the splitDelta resulting with the operator and blank
1948                                 // removal
1949                                 if (substringIndex + 1 != startSubstringIndexes.length) {
1950                                         increaseSplitDelta(startSubstringIndexes[substringIndex]
1951                                                         + max - startSubstringIndexes[substringIndex + 1]);
1952                                 }
1953                         }
1954                         // dump postfix operator?
1955                         if (placeOperatorBehind) {
1956                                 if (insertSpaceBefore(operator)) {
1957                                         formattedSource.append(' ');
1958                                         if (operator.compareTo (TokenName.NONE) > 0) {
1959                                                 increaseSplitDelta(1);
1960                                         }
1961                                 }
1962                                 formattedSource.append(operatorString);
1963                                 if (operator.compareTo (TokenName.NONE) > 0) {
1964                                         increaseSplitDelta(operatorString.length());
1965                                 }
1966                         }
1967                         return;
1968                 }
1969                 // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
1970                 // extends has to stand alone on a line when currentString has been
1971                 // split.
1972                 if (options.maxLineLength != 0 && splitLine != null
1973                                 && (operator == TokenName.EXTENDS)) {
1974                         // || operator == TokenName.IMPLEMENTS
1975                         // || operator == TokenName.THROWS)) {
1976                         formattedSource.append(options.lineSeparatorSequence);
1977                         increaseSplitDelta(options.lineSeparatorSequence.length);
1978                         dumpTab(depth + 1);
1979                 } else {
1980                         if (operator == TokenName.EXTENDS) {
1981                                 // || operator == TokenName.implements
1982                                 // || operator == TokenName.throws) {
1983                                 formattedSource.append(' ');
1984                                 increaseSplitDelta(1);
1985                         }
1986                 }
1987                 // perform actual splitting
1988                 String result[] = splitLine.substrings;
1989                 TokenName[] splitOperators = splitLine.operators;
1990                 if (result[0].length() == 0) {
1991                         // when the substring 0 is null, the substring 1 is correctly
1992                         // indented.
1993                         depth--;
1994                         emptyFirstSubString = true;
1995                 }
1996                 // the operator going in front of the result[0] string is the operator
1997                 // parameter
1998                 for (int i = 0, max = result.length; i < max; i++) {
1999                         // the new depth is the current one if this is the first substring,
2000                         // the current one + 1 otherwise.
2001                         // if the substring is a comment, use the current indentation Level
2002                         // instead of the depth
2003                         // (-1 because the ouputline increases depth).
2004                         // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of
2005                         // line
2006                         // comments)
2007                         String currentResult = result[i];
2008                         if (currentResult.length() != 0 || splitOperators[i].compareTo (TokenName.NONE) > 0) {
2009                                 int newDepth = (currentResult.startsWith("/*") //$NON-NLS-1$
2010                                 || currentResult.startsWith("//")) //$NON-NLS-1$
2011                                 ? indentationLevel - 1
2012                                                 : depth;
2013                                 outputLine(currentResult, 
2014                                            i == 0 || (i == 1 && emptyFirstSubString) ? preIndented: false,
2015                                            i == 0 ? newDepth : newDepth + 1,
2016                                                    splitOperators[i], 
2017                                                    i, 
2018                                                    splitLine.startSubstringsIndexes,
2019                                                    currentString.indexOf(currentResult));
2020                                 if (i != max - 1) {
2021                                         formattedSource.append(options.lineSeparatorSequence);
2022                                         increaseSplitDelta(options.lineSeparatorSequence.length);
2023                                 }
2024                         }
2025                 }
2026                 if (result.length == splitOperators.length - 1) {
2027                         TokenName lastOperator = splitOperators[result.length];
2028                         String lastOperatorString = operatorString(lastOperator);
2029                         formattedSource.append(options.lineSeparatorSequence);
2030                         increaseSplitDelta(options.lineSeparatorSequence.length);
2031                         if (breakLineBeforeOperator(lastOperator)) {
2032                                 dumpTab(depth + 1);
2033                                 if (lastOperator.compareTo (TokenName.NONE) > 0) {
2034                                         if (insertSpaceBefore(lastOperator)) {
2035                                                 formattedSource.append(' ');
2036                                                 increaseSplitDelta(1);
2037                                         }
2038                                         formattedSource.append(lastOperatorString);
2039                                         increaseSplitDelta(lastOperatorString.length());
2040                                         if (insertSpaceAfter(lastOperator)
2041                                                         && lastOperator != TokenName.IMPLEMENTS
2042                                                         && lastOperator != TokenName.EXTENDS) {
2043                                                 // && lastOperator != TokenName.throws) {
2044                                                 formattedSource.append(' ');
2045                                                 increaseSplitDelta(1);
2046                                         }
2047                                 }
2048                         }
2049                 }
2050                 if (placeOperatorBehind) {
2051                         if (insertSpaceBefore(operator)) {
2052                                 formattedSource.append(' ');
2053                                 increaseSplitDelta(1);
2054                         }
2055                         formattedSource.append(operatorString);
2056                         // increaseSplitDelta(operatorString.length());
2057                 }
2058         }
2059
2060         /**
2061          * Pops the top statement of the stack if it is <code>token</code>
2062          */
2063         private int pop(TokenName do1) {
2064                 int delta = 0;
2065                 if ((constructionsCount > 0)
2066                                 && (constructions[constructionsCount - 1] == do1)) {
2067                         delta--;
2068                         constructionsCount--;
2069                 }
2070                 return delta;
2071         }
2072
2073         /**
2074          * Pops the top statement of the stack if it is a <code>BLOCK</code> or a
2075          * <code>NONINDENT_BLOCK</code>.
2076          */
2077 //      private int popBlock() {
2078 //              int delta = 0;
2079 //              if ((constructionsCount > 0)
2080 //                              && ((constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
2081 //                      if (constructions[constructionsCount - 1] == BLOCK)
2082 //                              delta--;
2083 //                      constructionsCount--;
2084 //              }
2085 //              return delta;
2086 //      }
2087
2088         /**
2089          * Pops elements until the stack is empty or the top element is
2090          * <code>token</code>.<br>
2091          * Does not remove <code>token</code> from the stack.
2092          * 
2093          * @param token
2094          *            the token to be left as the top of the stack
2095          */
2096 //      private int popExclusiveUntil(int token) {
2097 //              int delta = 0;
2098 //              int startCount = constructionsCount;
2099 //              for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
2100 //                      if (constructions[i] != NONINDENT_BLOCK)
2101 //                              delta--;
2102 //                      constructionsCount--;
2103 //              }
2104 //              return delta;
2105 //      }
2106
2107         /**
2108          * Pops elements until the stack is empty or the top element is a
2109          * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
2110          * Does not remove it from the stack.
2111          */
2112         private int popExclusiveUntilBlock() {
2113                 int startCount = constructionsCount;
2114                 int delta = 0;
2115                 for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
2116                                 && constructions[i] != NONINDENT_BLOCK; i--) {
2117                         constructionsCount--;
2118                         delta--;
2119                 }
2120                 return delta;
2121         }
2122
2123         /**
2124          * Pops elements until the stack is empty or the top element is a
2125          * <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a
2126          * <code>CASE</code>.<br>
2127          * Does not remove it from the stack.
2128          */
2129         private int popExclusiveUntilBlockOrCase() {
2130                 int startCount = constructionsCount;
2131                 int delta = 0;
2132                 for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
2133                                 && constructions[i] != NONINDENT_BLOCK
2134                                 && constructions[i] != TokenName.CASE; i--) {
2135                         constructionsCount--;
2136                         delta--;
2137                 }
2138                 return delta;
2139         }
2140
2141         /**
2142          * Pops elements until the stack is empty or the top element is
2143          * <code>token</code>.<br>
2144          * Removes <code>token</code> from the stack too.
2145          * 
2146          * @param token
2147          *            the token to remove from the stack
2148          */
2149         private int popInclusiveUntil(TokenName token) {
2150                 int startCount = constructionsCount;
2151                 int delta = 0;
2152                 for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
2153                         if (constructions[i] != NONINDENT_BLOCK)
2154                                 delta--;
2155                         constructionsCount--;
2156                 }
2157                 if (constructionsCount > 0) {
2158                         if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
2159                                 delta--;
2160                         constructionsCount--;
2161                 }
2162                 return delta;
2163         }
2164
2165         /**
2166          * Pops elements until the stack is empty or the top element is a
2167          * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
2168          * Does not remove it from the stack.
2169          */
2170         private int popInclusiveUntilBlock() {
2171                 int startCount = constructionsCount;
2172                 int delta = 0;
2173                 for (int i = startCount - 1; i >= 0
2174                                 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK); i--) {
2175                         delta--;
2176                         constructionsCount--;
2177                 }
2178                 if (constructionsCount > 0) {
2179                         if (constructions[constructionsCount - 1] == BLOCK)
2180                                 delta--;
2181                         constructionsCount--;
2182                 }
2183                 return delta;
2184         }
2185
2186         /**
2187          * Pushes a block in the stack. <br>
2188          * Pushes a <code>BLOCK</code> if the stack is empty or if the top element
2189          * is a <code>BLOCK</code>, pushes <code>NONINDENT_BLOCK</code>
2190          * otherwise. Creates a new bigger array if the current one is full.
2191          */
2192         private int pushBlock() {
2193                 int delta = 0;
2194                 if (constructionsCount == constructions.length)
2195                         System.arraycopy(constructions, 0,
2196                                         (constructions = new TokenName[constructionsCount * 2]), 0,
2197                                         constructionsCount);
2198                 if ((constructionsCount == 0)
2199                                 || (constructions[constructionsCount - 1] == BLOCK)
2200                                 || (constructions[constructionsCount - 1] == NONINDENT_BLOCK)
2201                                 || (constructions[constructionsCount - 1] == TokenName.CASE)) {
2202                         delta++;
2203                         constructions[constructionsCount++] = BLOCK;
2204                 } else {
2205                         constructions[constructionsCount++] = NONINDENT_BLOCK;
2206                 }
2207                 return delta;
2208         }
2209
2210         /**
2211          * Pushes <code>token</code>.<br>
2212          * Creates a new bigger array if the current one is full.
2213          */
2214         private int pushControlStatement(TokenName token) {
2215                 if (constructionsCount == constructions.length)
2216                         System.arraycopy(constructions, 0,
2217                                         (constructions = new TokenName[constructionsCount * 2]), 0,
2218                                         constructionsCount);
2219                 constructions[constructionsCount++] = token;
2220                 return 1;
2221         }
2222
2223 //      private static boolean separateFirstArgumentOn(int currentToken) {
2224 //              // return (currentToken == TokenName.COMMA || currentToken ==
2225 //              // TokenName.SEMICOLON);
2226 //              return currentToken != TokenName.if && currentToken != TokenName.LPAREN
2227 //                              && currentToken != TokenName.NOT
2228 //                              && currentToken != TokenName.while
2229 //                              && currentToken != TokenName.for
2230 //                              && currentToken != TokenName.foreach
2231 //                              && currentToken != TokenName.switch;
2232 //      }
2233
2234         /**
2235          * Set the positions to map. The mapped positions should be retrieved using
2236          * the getMappedPositions() method.
2237          * 
2238          * @param positions
2239          *            int[]
2240          * @deprecated Set the positions to map using the format(String, int, int[])
2241          *             method.
2242          * 
2243          * @see #getMappedPositions()
2244          */
2245         public void setPositionsToMap(int[] positions) {
2246                 positionsToMap = positions;
2247                 lineDelta = 0;
2248                 globalDelta = 0;
2249                 mappedPositions = new int[positions.length];
2250         }
2251
2252         /**
2253          * Appends a space character to the current line buffer.
2254          */
2255         private void space() {
2256                 currentLineBuffer.append(' ');
2257                 increaseLineDelta(1);
2258         }
2259
2260         /**
2261          * Splits <code>stringToSplit</code> on the top level token <br>
2262          * If there are several identical token at the same level, the string is cut
2263          * into many pieces.
2264          * 
2265          * @return an object containing the operator and all the substrings or null
2266          *         if the string cannot be split
2267          */
2268 //      public SplitLine split(String stringToSplit) {
2269 //              return split(stringToSplit, 0);
2270 //      }
2271
2272         /**
2273          * Splits <code>stringToSplit</code> on the top level token <br>
2274          * If there are several identical token at the same level, the string is cut
2275          * into many pieces.
2276          * 
2277          * @return an object containing the operator and all the substrings or null
2278          *         if the string cannot be split
2279          */
2280         public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
2281                 /*
2282                  * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and
2283                  * http://dev.eclipse.org/bugs/show_bug.cgi?id=14387
2284                  */
2285                 if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$
2286                         return null;
2287                 }
2288                 // split doesn't work correct for PHP
2289                 return null;
2290                 // local variables
2291                 // int currentToken = 0;
2292                 // int splitTokenType = 0;
2293                 // int splitTokenDepth = Integer.MAX_VALUE;
2294                 // int splitTokenPriority = Integer.MAX_VALUE;
2295                 // int[] substringsStartPositions = new int[10];
2296                 // // contains the start position of substrings
2297                 // int[] substringsEndPositions = new int[10];
2298                 // // contains the start position of substrings
2299                 // int substringsCount = 1; // index in the substringsStartPosition
2300                 // array
2301                 // int[] splitOperators = new int[10];
2302                 // // contains the start position of substrings
2303                 // int splitOperatorsCount = 0; // index in the substringsStartPosition
2304                 // array
2305                 // int[] openParenthesisPosition = new int[10];
2306                 // int openParenthesisPositionCount = 0;
2307                 // int position = 0;
2308                 // int lastOpenParenthesisPosition = -1;
2309                 // // used to remember the position of the 1st open parenthesis
2310                 // // needed for a pattern like: A.B(C); we want formatted like A.B(
2311                 // split C);
2312                 // // setup the scanner with a new source
2313                 // int lastCommentStartPosition = -1;
2314                 // // to remember the start position of the last comment
2315                 // int firstTokenOnLine = -1;
2316                 // // to remember the first token of the line
2317                 // int previousToken = -1;
2318                 // // to remember the previous token.
2319                 // splitScanner.setSource(stringToSplit.toCharArray());
2320                 // try {
2321                 // // start the loop
2322                 // while (true) {
2323                 // // takes the next token
2324                 // try {
2325                 // if (currentToken != Scanner.TokenName.WHITESPACE)
2326                 // previousToken = currentToken;
2327                 // currentToken = splitScanner.getNextToken();
2328                 // if (Scanner.DEBUG) {
2329                 // int currentEndPosition = splitScanner.getCurrentTokenEndPosition();
2330                 // int currentStartPosition = splitScanner
2331                 // .getCurrentTokenStartPosition();
2332                 // System.out.print(currentStartPosition + "," + currentEndPosition
2333                 // + ": ");
2334                 // System.out.println(scanner.toStringAction(currentToken));
2335                 // }
2336                 // } catch (InvalidInputException e) {
2337                 // if (!handleInvalidToken(e))
2338                 // throw e;
2339                 // currentToken = 0;
2340                 // // this value is not modify when an exception is raised.
2341                 // }
2342                 // if (currentToken == TokenName.EOF)
2343                 // break;
2344                 // if (firstTokenOnLine == -1) {
2345                 // firstTokenOnLine = currentToken;
2346                 // }
2347                 // switch (currentToken) {
2348                 // case TokenName.RBRACE :
2349                 // case TokenName.RPAREN :
2350                 // if (openParenthesisPositionCount > 0) {
2351                 // if (openParenthesisPositionCount == 1
2352                 // && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
2353                 // lastOpenParenthesisPosition = openParenthesisPosition[0];
2354                 // } else if ((splitTokenDepth == Integer.MAX_VALUE)
2355                 // || (splitTokenDepth > openParenthesisPositionCount &&
2356                 // openParenthesisPositionCount == 1)) {
2357                 // splitTokenType = 0;
2358                 // splitTokenDepth = openParenthesisPositionCount;
2359                 // splitTokenPriority = Integer.MAX_VALUE;
2360                 // substringsStartPositions[0] = 0;
2361                 // // better token means the whole line until now is the first
2362                 // // substring
2363                 // substringsCount = 1; // resets the count of substrings
2364                 // substringsEndPositions[0] = openParenthesisPosition[0];
2365                 // // substring ends on operator start
2366                 // position = openParenthesisPosition[0];
2367                 // // the string mustn't be cut before the closing parenthesis but
2368                 // // after the opening one.
2369                 // splitOperatorsCount = 1; // resets the count of split operators
2370                 // splitOperators[0] = 0;
2371                 // }
2372                 // openParenthesisPositionCount--;
2373                 // }
2374                 // break;
2375                 // case TokenName.LBRACE :
2376                 // case TokenName.LPAREN :
2377                 // if (openParenthesisPositionCount == openParenthesisPosition.length) {
2378                 // System
2379                 // .arraycopy(
2380                 // openParenthesisPosition,
2381                 // 0,
2382                 // (openParenthesisPosition = new int[openParenthesisPositionCount *
2383                 // 2]),
2384                 // 0, openParenthesisPositionCount);
2385                 // }
2386                 // openParenthesisPosition[openParenthesisPositionCount++] =
2387                 // splitScanner.currentPosition;
2388                 // if (currentToken == TokenName.LPAREN
2389                 // && previousToken == TokenName.RPAREN) {
2390                 // openParenthesisPosition[openParenthesisPositionCount - 1] =
2391                 // splitScanner.startPosition;
2392                 // }
2393                 // break;
2394                 // case TokenName.SEMICOLON :
2395                 // // ;
2396                 // case TokenName.COMMA :
2397                 // // ,
2398                 // case TokenName.EQUAL :
2399                 // // =
2400                 // if (openParenthesisPositionCount < splitTokenDepth
2401                 // || (openParenthesisPositionCount == splitTokenDepth &&
2402                 // splitTokenPriority > getTokenPriority(currentToken))) {
2403                 // // the current token is better than the one we currently have
2404                 // // (in level or in priority if same level)
2405                 // // reset the substringsCount
2406                 // splitTokenDepth = openParenthesisPositionCount;
2407                 // splitTokenType = currentToken;
2408                 // splitTokenPriority = getTokenPriority(currentToken);
2409                 // substringsStartPositions[0] = 0;
2410                 // // better token means the whole line until now is the first
2411                 // // substring
2412                 // if (separateFirstArgumentOn(firstTokenOnLine)
2413                 // && openParenthesisPositionCount > 0) {
2414                 // substringsCount = 2; // resets the count of substrings
2415                 // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
2416                 // 1];
2417                 // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
2418                 // - 1];
2419                 // substringsEndPositions[1] = splitScanner.startPosition;
2420                 // splitOperatorsCount = 2; // resets the count of split operators
2421                 // splitOperators[0] = 0;
2422                 // splitOperators[1] = currentToken;
2423                 // position = splitScanner.currentPosition;
2424                 // // next substring will start from operator end
2425                 // } else {
2426                 // substringsCount = 1; // resets the count of substrings
2427                 // substringsEndPositions[0] = splitScanner.startPosition;
2428                 // // substring ends on operator start
2429                 // position = splitScanner.currentPosition;
2430                 // // next substring will start from operator end
2431                 // splitOperatorsCount = 1; // resets the count of split operators
2432                 // splitOperators[0] = currentToken;
2433                 // }
2434                 // } else {
2435                 // if ((openParenthesisPositionCount == splitTokenDepth &&
2436                 // splitTokenPriority == getTokenPriority(currentToken))
2437                 // && splitTokenType != TokenName.EQUAL
2438                 // && currentToken != TokenName.EQUAL) {
2439                 // // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after
2440                 // // split
2441                 // // take only the 1st = into account.
2442                 // // if another token with the same priority is found,
2443                 // // push the start position of the substring and
2444                 // // push the token into the stack.
2445                 // // create a new array object if the current one is full.
2446                 // if (substringsCount == substringsStartPositions.length) {
2447                 // System
2448                 // .arraycopy(
2449                 // substringsStartPositions,
2450                 // 0,
2451                 // (substringsStartPositions = new int[substringsCount * 2]),
2452                 // 0, substringsCount);
2453                 // System.arraycopy(substringsEndPositions, 0,
2454                 // (substringsEndPositions = new int[substringsCount * 2]),
2455                 // 0, substringsCount);
2456                 // }
2457                 // if (splitOperatorsCount == splitOperators.length) {
2458                 // System.arraycopy(splitOperators, 0,
2459                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
2460                 // splitOperatorsCount);
2461                 // }
2462                 // substringsStartPositions[substringsCount] = position;
2463                 // substringsEndPositions[substringsCount++] =
2464                 // splitScanner.startPosition;
2465                 // // substring ends on operator start
2466                 // position = splitScanner.currentPosition;
2467                 // // next substring will start from operator end
2468                 // splitOperators[splitOperatorsCount++] = currentToken;
2469                 // }
2470                 // }
2471                 // break;
2472                 // case TokenName.COLON :
2473                 // // : (15.24)
2474                 // // see 1FK7C5R, we only split on a colon, when it is associated
2475                 // // with a question-mark.
2476                 // // indeed it might appear also behind a case statement, and we do
2477                 // // not to break at this point.
2478                 // if ((splitOperatorsCount == 0)
2479                 // || splitOperators[splitOperatorsCount - 1] != TokenName.QUESTION) {
2480                 // break;
2481                 // }
2482                 // case TokenName.extends :
2483                 // case TokenName.implements :
2484                 // //case TokenName.throws :
2485                 // case TokenName.DOT :
2486                 // // .
2487                 // case TokenName.MULTIPLY :
2488                 // // * (15.16.1)
2489                 // case TokenName.DIVIDE :
2490                 // // / (15.16.2)
2491                 // case TokenName.REMAINDER :
2492                 // // % (15.16.3)
2493                 // case TokenName.PLUS :
2494                 // // + (15.17, 15.17.2)
2495                 // case TokenName.MINUS :
2496                 // // - (15.17.2)
2497                 // case TokenName.LEFT_SHIFT :
2498                 // // << (15.18)
2499                 // case TokenName.RIGHT_SHIFT :
2500                 // // >> (15.18)
2501                 // // case TokenName.UNSIGNED_RIGHT_SHIFT : // >>> (15.18)
2502                 // case TokenName.LESS :
2503                 // // < (15.19.1)
2504                 // case TokenName.LESS_EQUAL :
2505                 // // <= (15.19.1)
2506                 // case TokenName.GREATER :
2507                 // // > (15.19.1)
2508                 // case TokenName.GREATER_EQUAL :
2509                 // // >= (15.19.1)
2510                 // // case TokenName.instanceof : // instanceof
2511                 // case TokenName.EQUAL_EQUAL :
2512                 // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
2513                 // case TokenName.EQUAL_EQUAL_EQUAL :
2514                 // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
2515                 // case TokenName.NOT_EQUAL :
2516                 // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
2517                 // case TokenName.NOT_EQUAL_EQUAL :
2518                 // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
2519                 // case TokenName.AND :
2520                 // // & (15.21, 15.21.1, 15.21.2)
2521                 // case TokenName.OR :
2522                 // // | (15.21, 15.21.1, 15.21.2)
2523                 // case TokenName.XOR :
2524                 // // ^ (15.21, 15.21.1, 15.21.2)
2525                 // case TokenName.AND_AND :
2526                 // // && (15.22)
2527                 // case TokenName.OR_OR :
2528                 // // || (15.23)
2529                 // case TokenName.QUESTION :
2530                 // // ? (15.24)
2531                 // case TokenName.MULTIPLY_EQUAL :
2532                 // // *= (15.25.2)
2533                 // case TokenName.DIVIDE_EQUAL :
2534                 // // /= (15.25.2)
2535                 // case TokenName.REMAINDER_EQUAL :
2536                 // // %= (15.25.2)
2537                 // case TokenName.PLUS_EQUAL :
2538                 // // += (15.25.2)
2539                 // case TokenName.MINUS_EQUAL :
2540                 // // -= (15.25.2)
2541                 // case TokenName.LEFT_SHIFT_EQUAL :
2542                 // // <<= (15.25.2)
2543                 // case TokenName.RIGHT_SHIFT_EQUAL :
2544                 // // >>= (15.25.2)
2545                 // // case TokenName.UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
2546                 // case TokenName.AND_EQUAL :
2547                 // // &= (15.25.2)
2548                 // case TokenName.XOR_EQUAL :
2549                 // // ^= (15.25.2)
2550                 // case TokenName.OR_EQUAL :
2551                 // // |= (15.25.2)
2552                 // if ((openParenthesisPositionCount < splitTokenDepth ||
2553                 // (openParenthesisPositionCount == splitTokenDepth &&
2554                 // splitTokenPriority
2555                 // > getTokenPriority(currentToken)))
2556                 // && !((currentToken == TokenName.PLUS || currentToken ==
2557                 // TokenName.MINUS) && (previousToken == TokenName.LBRACE
2558                 // || previousToken == TokenName.LBRACKET || splitScanner.startPosition
2559                 // == 0))) {
2560                 // // the current token is better than the one we currently have
2561                 // // (in level or in priority if same level)
2562                 // // reset the substringsCount
2563                 // splitTokenDepth = openParenthesisPositionCount;
2564                 // splitTokenType = currentToken;
2565                 // splitTokenPriority = getTokenPriority(currentToken);
2566                 // substringsStartPositions[0] = 0;
2567                 // // better token means the whole line until now is the first
2568                 // // substring
2569                 // if (separateFirstArgumentOn(firstTokenOnLine)
2570                 // && openParenthesisPositionCount > 0) {
2571                 // substringsCount = 2; // resets the count of substrings
2572                 // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
2573                 // 1];
2574                 // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
2575                 // - 1];
2576                 // substringsEndPositions[1] = splitScanner.startPosition;
2577                 // splitOperatorsCount = 3; // resets the count of split operators
2578                 // splitOperators[0] = 0;
2579                 // splitOperators[1] = 0;
2580                 // splitOperators[2] = currentToken;
2581                 // position = splitScanner.currentPosition;
2582                 // // next substring will start from operator end
2583                 // } else {
2584                 // substringsCount = 1; // resets the count of substrings
2585                 // substringsEndPositions[0] = splitScanner.startPosition;
2586                 // // substring ends on operator start
2587                 // position = splitScanner.currentPosition;
2588                 // // next substring will start from operator end
2589                 // splitOperatorsCount = 2; // resets the count of split operators
2590                 // splitOperators[0] = 0;
2591                 // // nothing for first operand since operator will be inserted in
2592                 // // front of the second operand
2593                 // splitOperators[1] = currentToken;
2594                 // }
2595                 // } else {
2596                 // if (openParenthesisPositionCount == splitTokenDepth
2597                 // && splitTokenPriority == getTokenPriority(currentToken)) {
2598                 // // if another token with the same priority is found,
2599                 // // push the start position of the substring and
2600                 // // push the token into the stack.
2601                 // // create a new array object if the current one is full.
2602                 // if (substringsCount == substringsStartPositions.length) {
2603                 // System
2604                 // .arraycopy(
2605                 // substringsStartPositions,
2606                 // 0,
2607                 // (substringsStartPositions = new int[substringsCount * 2]),
2608                 // 0, substringsCount);
2609                 // System.arraycopy(substringsEndPositions, 0,
2610                 // (substringsEndPositions = new int[substringsCount * 2]),
2611                 // 0, substringsCount);
2612                 // }
2613                 // if (splitOperatorsCount == splitOperators.length) {
2614                 // System.arraycopy(splitOperators, 0,
2615                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
2616                 // splitOperatorsCount);
2617                 // }
2618                 // substringsStartPositions[substringsCount] = position;
2619                 // substringsEndPositions[substringsCount++] =
2620                 // splitScanner.startPosition;
2621                 // // substring ends on operator start
2622                 // position = splitScanner.currentPosition;
2623                 // // next substring will start from operator end
2624                 // splitOperators[splitOperatorsCount++] = currentToken;
2625                 // }
2626                 // }
2627                 // default :
2628                 // break;
2629                 // }
2630                 // if (isComment(currentToken)) {
2631                 // lastCommentStartPosition = splitScanner.startPosition;
2632                 // } else {
2633                 // lastCommentStartPosition = -1;
2634                 // }
2635                 // }
2636                 // } catch (InvalidInputException e) {
2637                 // return null;
2638                 // }
2639                 // // if the string cannot be split, return null.
2640                 // if (splitOperatorsCount == 0)
2641                 // return null;
2642                 // // ## SPECIAL CASES BEGIN
2643                 // if (((splitOperatorsCount == 2 && splitOperators[1] == TokenName.DOT
2644                 // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1)
2645                 // || (splitOperatorsCount > 2 && splitOperators[1] == TokenName.DOT
2646                 // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1 &&
2647                 // lastOpenParenthesisPosition <= options.maxLineLength) ||
2648                 // (separateFirstArgumentOn(firstTokenOnLine)
2649                 // && splitTokenDepth > 0 && lastOpenParenthesisPosition > -1))
2650                 // && (lastOpenParenthesisPosition < splitScanner.source.length &&
2651                 // splitScanner.source[lastOpenParenthesisPosition] != ')')) {
2652                 // // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis
2653                 // should
2654                 // // not be broken on two lines
2655                 // // only one split on a top level .
2656                 // // or more than one split on . and substring before open parenthesis
2657                 // fits
2658                 // // one line.
2659                 // // or split inside parenthesis and first token is not a for/while/if
2660                 // SplitLine sl = split(
2661                 // stringToSplit.substring(lastOpenParenthesisPosition),
2662                 // lastOpenParenthesisPosition);
2663                 // if (sl == null || sl.operators[0] != TokenName.COMMA) {
2664                 // // trim() is used to remove the extra blanks at the end of the
2665                 // // substring. See PR 1FGYPI1
2666                 // return new SplitLine(new int[]{0, 0}, new String[]{
2667                 // stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
2668                 // stringToSplit.substring(lastOpenParenthesisPosition)}, new int[]{
2669                 // offsetInGlobalLine,
2670                 // lastOpenParenthesisPosition + offsetInGlobalLine});
2671                 // } else {
2672                 // // right substring can be split and is split on comma
2673                 // // copy substrings and operators
2674                 // // except if the 1st string is empty.
2675                 // int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
2676                 // int subStringsLength = sl.substrings.length + 1 - startIndex;
2677                 // String[] result = new String[subStringsLength];
2678                 // int[] startIndexes = new int[subStringsLength];
2679                 // int operatorsLength = sl.operators.length + 1 - startIndex;
2680                 // int[] operators = new int[operatorsLength];
2681                 // result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
2682                 // operators[0] = 0;
2683                 // System.arraycopy(sl.startSubstringsIndexes, startIndex, startIndexes,
2684                 // 1, subStringsLength - 1);
2685                 // for (int i = subStringsLength - 1; i >= 0; i--) {
2686                 // startIndexes[i] += offsetInGlobalLine;
2687                 // }
2688                 // System.arraycopy(sl.substrings, startIndex, result, 1,
2689                 // subStringsLength - 1);
2690                 // System.arraycopy(sl.operators, startIndex, operators, 1,
2691                 // operatorsLength - 1);
2692                 // return new SplitLine(operators, result, startIndexes);
2693                 // }
2694                 // }
2695                 // // if the last token is a comment and the substring before the
2696                 // comment fits
2697                 // // on a line,
2698                 // // split before the comment and return the result.
2699                 // if (lastCommentStartPosition > -1
2700                 // && lastCommentStartPosition < options.maxLineLength
2701                 // && splitTokenPriority > 50) {
2702                 // int end = lastCommentStartPosition;
2703                 // int start = lastCommentStartPosition;
2704                 // if (stringToSplit.charAt(end - 1) == ' ') {
2705                 // end--;
2706                 // }
2707                 // if (start != end && stringToSplit.charAt(start) == ' ') {
2708                 // start++;
2709                 // }
2710                 // return new SplitLine(new int[]{0, 0}, new String[]{
2711                 // stringToSplit.substring(0, end), stringToSplit.substring(start)},
2712                 // new int[]{0, start});
2713                 // }
2714                 // if (position != stringToSplit.length()) {
2715                 // if (substringsCount == substringsStartPositions.length) {
2716                 // System.arraycopy(substringsStartPositions, 0,
2717                 // (substringsStartPositions = new int[substringsCount * 2]), 0,
2718                 // substringsCount);
2719                 // System.arraycopy(substringsEndPositions, 0,
2720                 // (substringsEndPositions = new int[substringsCount * 2]), 0,
2721                 // substringsCount);
2722                 // }
2723                 // // avoid empty extra substring, e.g. line terminated with a
2724                 // semi-colon
2725                 // substringsStartPositions[substringsCount] = position;
2726                 // substringsEndPositions[substringsCount++] = stringToSplit.length();
2727                 // }
2728                 // if (splitOperatorsCount == splitOperators.length) {
2729                 // System.arraycopy(splitOperators, 0,
2730                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
2731                 // splitOperatorsCount);
2732                 // }
2733                 // splitOperators[splitOperatorsCount] = 0;
2734                 // // the last element of the stack is the position of the end of
2735                 // // StringToSPlit
2736                 // // +1 because the substring method excludes the last character
2737                 // String[] result = new String[substringsCount];
2738                 // for (int i = 0; i < substringsCount; i++) {
2739                 // int start = substringsStartPositions[i];
2740                 // int end = substringsEndPositions[i];
2741                 // if (stringToSplit.charAt(start) == ' ') {
2742                 // start++;
2743                 // substringsStartPositions[i]++;
2744                 // }
2745                 // if (end != start && stringToSplit.charAt(end - 1) == ' ') {
2746                 // end--;
2747                 // }
2748                 // result[i] = stringToSplit.substring(start, end);
2749                 // substringsStartPositions[i] += offsetInGlobalLine;
2750                 // }
2751                 // if (splitOperatorsCount > substringsCount) {
2752                 // System.arraycopy(substringsStartPositions, 0,
2753                 // (substringsStartPositions = new int[splitOperatorsCount]), 0,
2754                 // substringsCount);
2755                 // System.arraycopy(substringsEndPositions, 0,
2756                 // (substringsEndPositions = new int[splitOperatorsCount]), 0,
2757                 // substringsCount);
2758                 // for (int i = substringsCount; i < splitOperatorsCount; i++) {
2759                 // substringsStartPositions[i] = position;
2760                 // substringsEndPositions[i] = position;
2761                 // }
2762                 // System.arraycopy(splitOperators, 0,
2763                 // (splitOperators = new int[splitOperatorsCount]), 0,
2764                 // splitOperatorsCount);
2765                 // } else {
2766                 // System.arraycopy(substringsStartPositions, 0,
2767                 // (substringsStartPositions = new int[substringsCount]), 0,
2768                 // substringsCount);
2769                 // System.arraycopy(substringsEndPositions, 0,
2770                 // (substringsEndPositions = new int[substringsCount]), 0,
2771                 // substringsCount);
2772                 // System.arraycopy(splitOperators, 0,
2773                 // (splitOperators = new int[substringsCount]), 0, substringsCount);
2774                 // }
2775                 // SplitLine splitLine = new SplitLine(splitOperators, result,
2776                 // substringsStartPositions);
2777                 // return splitLine;
2778         }
2779
2780         private void updateMappedPositions(int startPosition) {
2781                 if (positionsToMap == null) {
2782                         return;
2783                 }
2784                 char[] source = scanner.source;
2785                 int sourceLength = source.length;
2786                 while (indexToMap < positionsToMap.length
2787                                 && positionsToMap[indexToMap] <= startPosition) {
2788                         int posToMap = positionsToMap[indexToMap];
2789                         if (posToMap < 0 || posToMap >= sourceLength) {
2790                                 // protection against out of bounds position
2791                                 if (posToMap == sourceLength) {
2792                                         mappedPositions[indexToMap] = formattedSource.length();
2793                                 }
2794                                 indexToMap = positionsToMap.length; // no more mapping
2795                                 return;
2796                         }
2797                         if (CharOperation.isWhitespace(source[posToMap])) {
2798                                 mappedPositions[indexToMap] = startPosition + globalDelta
2799                                                 + lineDelta;
2800                         } else {
2801                                 if (posToMap == sourceLength - 1) {
2802                                         mappedPositions[indexToMap] = startPosition + globalDelta
2803                                                         + lineDelta;
2804                                 } else {
2805                                         mappedPositions[indexToMap] = posToMap + globalDelta
2806                                                         + lineDelta;
2807                                 }
2808                         }
2809                         indexToMap++;
2810                 }
2811         }
2812
2813         private void updateMappedPositionsWhileSplitting(int startPosition,
2814                         int endPosition) {
2815                 if (mappedPositions == null || mappedPositions.length == indexInMap)
2816                         return;
2817                 while (indexInMap < mappedPositions.length
2818                                 && startPosition <= mappedPositions[indexInMap]
2819                                 && mappedPositions[indexInMap] < endPosition
2820                                 && indexInMap < indexToMap) {
2821                         mappedPositions[indexInMap] += splitDelta;
2822                         indexInMap++;
2823                 }
2824         }
2825
2826         private int getLength(String s, int tabDepth) {
2827                 int length = 0;
2828                 for (int i = 0; i < tabDepth; i++) {
2829                         length += options.tabSize;
2830                 }
2831                 for (int i = 0, max = s.length(); i < max; i++) {
2832                         char currentChar = s.charAt(i);
2833                         switch (currentChar) {
2834                         case '\t':
2835                                 length += options.tabSize;
2836                                 break;
2837                         default:
2838                                 length++;
2839                         }
2840                 }
2841                 return length;
2842         }
2843
2844         /**
2845          * Sets the initial indentation level
2846          * 
2847          * @param indentationLevel
2848          *            new indentation level
2849          * 
2850          * @deprecated
2851          */
2852         public void setInitialIndentationLevel(int newIndentationLevel) {
2853                 this.initialIndentationLevel = currentLineIndentationLevel = indentationLevel = newIndentationLevel;
2854         }
2855
2856 }