php formatter based on the JDT java formatter (very early version)
authorkhartlage <khartlage>
Thu, 20 Mar 2003 20:38:51 +0000 (20:38 +0000)
committerkhartlage <khartlage>
Thu, 20 Mar 2003 20:38:51 +0000 (20:38 +0000)
20 files changed:
net.sourceforge.phpeclipse/plugin.xml
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ToolFactory.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/compiler/CharOperation.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/compiler/ITerminalSymbols.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Scanner.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/codemanipulation/StubUtility.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusUtil.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreferencePage.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreviewCode.txt [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaFormattingStrategy.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TabFolderLayout.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPCore.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPSourceViewerConfiguration.java
net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/CodeFormatter.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/Options.properties [new file with mode: 0644]
net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/FormatterOptions.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/SplitLine.java [new file with mode: 0644]

index ddafca2..0dd2df1 100644 (file)
@@ -548,6 +548,12 @@ Temporarily replaced until errors can be ironed out...
             class="net.sourceforge.phpdt.internal.ui.preferences.TemplatePreferencePage"
             id="net.sourceforge.phpeclipse.preference.TemplatePreferencePage">
       </page>
+      <page 
+        name="Formatter"
+               id="net.sourceforge.phpeclipse.preference.CodeFormatterPreferencePage"
+               class="net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage"
+               category="net.sourceforge.phpeclipse.preference.PHPEclipsePreferencePage">
+         </page>
       <page
             name="Language Settings"
             category="net.sourceforge.phpeclipse.preference.PHPEclipsePreferencePage"
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java
new file mode 100644 (file)
index 0000000..478d867
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+/**
+ * Specification for a generic source code formatter. Client plug-ins can contribute
+ * an implementation for an ICodeFormatter, through the extension point "org.phpeclipse.phpdt.core.codeFormatter".
+ * In case none is found, a default formatter can be provided through the ToolFactory.
+ * 
+ * @see ToolFactory#createCodeFormatter()
+ * @see ToolFactory#createDefaultCodeFormatter(Map options)
+ * @since 2.0
+ */
+public interface ICodeFormatter {
+
+       /** 
+        * Formats the String <code>sourceString</code>,
+        * and returns a string containing the formatted version.
+        * 
+        * @param string the string to format
+        * @param indentationLevel the initial indentation level, used 
+        *      to shift left/right the entire source fragment. An initial indentation
+        *      level of zero has no effect.
+        * @param positions an array of positions to map. These are
+        *      character-based source positions inside the original source,
+        *     for which corresponding positions in the formatted source will
+        *     be computed (so as to relocate elements associated with the original
+        *     source). It updates the positions array with updated positions.
+        *     If set to <code>null</code>, then no positions are mapped.
+        * @param lineSeparator the line separator to use in formatted source,
+        *     if set to <code>null</code>, then the platform default one will be used.
+        * @return the formatted output string.
+        */
+       String format(String string, int indentationLevel, int[] positions, String lineSeparator);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ToolFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ToolFactory.java
new file mode 100644 (file)
index 0000000..249dbec
--- /dev/null
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     IBM Corporation - added #createScanner allowing to make comment check stricter
+ ******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import java.util.Map;
+
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.runtime.Plugin;
+import org.phpeclipse.phpdt.internal.formatter.CodeFormatter;
+
+/**
+ * Factory for creating various compiler tools, such as scanners, parsers and compilers.
+ * <p>
+ *  This class provides static methods only; it is not intended to be instantiated or subclassed by clients.
+ * </p>
+ * 
+ * @since 2.0
+ */
+public class ToolFactory {
+
+       /**
+        * Create an instance of a code formatter. A code formatter implementation can be contributed via the 
+        * extension point "org.phpeclipse.phpdt.core.codeFormatter". If unable to find a registered extension, the factory 
+        * will default to using the default code formatter.
+        * 
+        * @return an instance of a code formatter
+        * @see ICodeFormatter
+        * @see ToolFactory#createDefaultCodeFormatter(Map)
+        */
+       public static ICodeFormatter createCodeFormatter(){
+               
+                       Plugin jdtCorePlugin = PHPCore.getPlugin();
+                       if (jdtCorePlugin == null) return null;
+               
+//                     IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.FORMATTER_EXTPOINT_ID);
+//                     if (extension != null) {
+//                             IExtension[] extensions =  extension.getExtensions();
+//                             for(int i = 0; i < extensions.length; i++){
+//                                     IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
+//                                     for(int j = 0; j < configElements.length; j++){
+//                                             try {
+//                                                     Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
+//                                                     if (execExt instanceof ICodeFormatter){
+//                                                             // use first contribution found
+//                                                             return (ICodeFormatter)execExt;
+//                                                     }
+//                                             } catch(CoreException e){
+//                                             }
+//                                     }
+//                             }       
+//                     }
+               // no proper contribution found, use default formatter                  
+               return createDefaultCodeFormatter(null);
+       }
+
+       /**
+        * Create an instance of the built-in code formatter. A code formatter implementation can be contributed via the 
+        * extension point "org.phpeclipse.phpdt.core.codeFormatter". If unable to find a registered extension, the factory will 
+        * default to using the default code formatter.
+        * 
+        * @param options - the options map to use for formatting with the default code formatter. Recognized options
+        *      are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use 
+        *      the current settings from <code>JavaCore#getOptions</code>.
+        * @return an instance of the built-in code formatter
+        * @see ICodeFormatter
+        * @see ToolFactory#createCodeFormatter()
+        * @see JavaCore#getOptions()
+        */
+       public static ICodeFormatter createDefaultCodeFormatter(Map options){
+
+               if (options == null) options = PHPCore.getOptions();
+               return new CodeFormatter(options);
+       }
+       
+       /**
+        * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
+        * used to tokenize some source in a Java aware way.
+        * Here is a typical scanning loop:
+        * 
+        * <code>
+        * <pre>
+        *   IScanner scanner = ToolFactory.createScanner(false, false, false, false);
+        *   scanner.setSource("int i = 0;".toCharArray());
+        *   while (true) {
+        *     int token = scanner.getNextToken();
+        *     if (token == ITerminalSymbols.TokenNameEOF) break;
+        *     System.out.println(token + " : " + new String(scanner.getCurrentTokenSource()));
+        *   }
+        * </pre>
+        * </code>
+        * 
+        * <p>
+        * The returned scanner will tolerate unterminated line comments (missing line separator). It can be made stricter
+        * by using API with extra boolean parameter (<code>strictCommentMode</code>).
+        * <p>
+        * @param tokenizeComments if set to <code>false</code>, comments will be silently consumed
+        * @param tokenizeWhiteSpace if set to <code>false</code>, white spaces will be silently consumed,
+        * @param assertKeyword if set to <code>false</code>, occurrences of 'assert' will be reported as identifiers
+        * (<code>ITerminalSymbols#TokenNameIdentifier</code>), whereas if set to <code>true</code>, it
+        * would report assert keywords (<code>ITerminalSymbols#TokenNameassert</code>). Java 1.4 has introduced
+        * a new 'assert' keyword.
+        * @param recordLineSeparator if set to <code>true</code>, the scanner will record positions of encountered line 
+        * separator ends. In case of multi-character line separators, the last character position is considered. These positions
+        * can then be extracted using <code>IScanner#getLineEnds</code>. Only non-unicode escape sequences are 
+        * considered as valid line separators.
+        * @return a scanner
+        * @see ToolFactory#createScanner(boolean,boolean,boolean,boolean, boolean)
+        * @see org.phpeclipse.phpdt.core.compiler.IScanner
+        */
+//     public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean assertMode, boolean recordLineSeparator){
+//             return createScanner(tokenizeComments, tokenizeWhiteSpace, assertMode, recordLineSeparator, false);
+//     }
+       
+       /**
+        * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
+        * used to tokenize some source in a Java aware way.
+        * Here is a typical scanning loop:
+        * 
+        * <code>
+        * <pre>
+        *   IScanner scanner = ToolFactory.createScanner(false, false, false, false);
+        *   scanner.setSource("int i = 0;".toCharArray());
+        *   while (true) {
+        *     int token = scanner.getNextToken();
+        *     if (token == ITerminalSymbols.TokenNameEOF) break;
+        *     System.out.println(token + " : " + new String(scanner.getCurrentTokenSource()));
+        *   }
+        * </pre>
+        * </code>
+        * 
+        * @param tokenizeComments if set to <code>false</code>, comments will be silently consumed
+        * @param tokenizeWhiteSpace if set to <code>false</code>, white spaces will be silently consumed,
+        * @param assertMode if set to <code>false</code>, occurrences of 'assert' will be reported as identifiers
+        * (<code>ITerminalSymbols#TokenNameIdentifier</code>), whereas if set to <code>true</code>, it
+        * would report assert keywords (<code>ITerminalSymbols#TokenNameassert</code>). Java 1.4 has introduced
+        * a new 'assert' keyword.
+        * @param recordLineSeparator if set to <code>true</code>, the scanner will record positions of encountered line 
+        * separator ends. In case of multi-character line separators, the last character position is considered. These positions
+        * can then be extracted using <code>IScanner#getLineEnds</code>. Only non-unicode escape sequences are 
+        * considered as valid line separators.
+        * @param strictCommentMode if set to <code>true</code>, line comments with no trailing line separator will be
+        * treated as invalid tokens.
+        * @return a scanner
+        * 
+        * @see org.phpeclipse.phpdt.core.compiler.IScanner
+        * @since 2.1
+        */
+//     public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean assertMode, boolean recordLineSeparator, boolean strictCommentMode){
+//
+//             PublicScanner scanner = new PublicScanner(tokenizeComments, tokenizeWhiteSpace, false/*nls*/, assertMode, strictCommentMode /*strict comment*/, null/*taskTags*/, null/*taskPriorities*/);
+//             scanner.recordLineSeparator = recordLineSeparator;
+//             return scanner;
+//     }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/compiler/CharOperation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/compiler/CharOperation.java
new file mode 100644 (file)
index 0000000..ae0ed10
--- /dev/null
@@ -0,0 +1,2528 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package net.sourceforge.phpdt.core.compiler;
+
+/**
+ * This class is a collection of helper methods to manipulate char arrays.
+ * 
+ * @since 2.1
+ */
+public final class CharOperation {
+
+       /**
+        * Constant for an empty char array
+        */
+       public static final char[] NO_CHAR = new char[0];
+
+       /**
+        * Constant for an empty char array with two dimensions.
+        */
+       public static final char[][] NO_CHAR_CHAR = new char[0][];
+       
+       /**
+        * Answers a new array with appending the suffix character at the end of the array.
+        * <br>
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    array = { 'a', 'b' }
+        *    suffix = 'c'
+        *    => result = { 'a', 'b' , 'c' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = null
+        *    suffix = 'c'
+        *    => result = { 'c' }
+        * </pre></li>
+        * </ol>
+        * 
+        * @param array the array that is concanated with the suffix character
+        * @param suffix the suffix character
+        * @return the new array
+        */
+       public static final char[] append(char[] array, char suffix) {
+               if (array == null)
+                       return new char[] { suffix };
+               int length = array.length;
+               System.arraycopy(array, 0, array = new char[length + 1], 0, length);
+               array[length] = suffix;
+               return array;
+       }
+       /**
+        * Append the given subarray to append to the target array starting at the given index in the target array.
+        * The start of the subarray is inclusive, the end is exclusive.
+        * Answers a new target array if it needs to grow, otherwise answers the same target array.
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    target = { 'a', 'b', -1 }
+        *    index = 0
+        *    array = { 'c', 'd' }
+        *    start = 0
+        *    end = 1
+        *    => result = { 'a', 'b' , 'c' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    target = { 'a', 'b' }
+        *    index = 0
+        *    array = { 'c', 'd' }
+        *    start = 0
+        *    end = 1
+        *    => result = new { 'a', 'b' , 'c', -1 }
+        * </pre></li>
+        * <li><pre>
+        *    target = { 'a', 'b', 'c' }
+        *    index = 1
+        *    array = { 'c', 'd', 'e', 'f' }
+        *    start = 1
+        *    end = 4
+        *    => result = new { 'a', 'd' , 'e', 'f', -1, -1 }
+        * </pre></li>
+        * </ol>
+        */
+       public static final char[] append(char[] target, int index, char[] array, int start, int end) {
+               int targetLength = target.length;
+               int subLength = end-start;
+               int newTargetLength = subLength+index;
+               if (newTargetLength > targetLength) {
+                       System.arraycopy(target, 0, target = new char[newTargetLength*2], 0, index);
+               }
+               System.arraycopy(array, start, target, index, subLength);
+               return target;
+       }
+
+       /**
+        * Answers the concatenation of the two arrays. It answers null if the two arrays are null.
+        * If the first array is null, then the second array is returned.
+        * If the second array is null, then the first array is returned.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    => result = null
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { ' a' } }
+        *    second = null
+        *    => result = { { ' a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = null
+        *    second = { { ' a' } }
+        *    => result = { { ' a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { ' b' } }
+        *    second = { { ' a' } }
+        *    => result = { { ' b' }, { ' a' } }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the second array to concatenate
+        * @return the concatenation of the two arrays, or null if the two arrays are null.
+        */
+       public static final char[][] arrayConcat(char[][] first, char[][] second) {
+               if (first == null)
+                       return second;
+               if (second == null)
+                       return first;
+
+               int length1 = first.length;
+               int length2 = second.length;
+               char[][] result = new char[length1 + length2][];
+               System.arraycopy(first, 0, result, 0, length1);
+               System.arraycopy(second, 0, result, length1, length2);
+               return result;
+       }
+
+       /**
+        * Answers a new array adding the second array at the end of first array.
+        * It answers null if the first and second are null.
+        * If the first array is null, then a new array char[][] is created with second.
+        * If the second array is null, then the first array is returned.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = { 'a' }
+        *    => result = { { ' a' } }
+        * </pre>
+        * <li><pre>
+        *    first = { { ' a' } }
+        *    second = null
+        *    => result = { { ' a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { ' a' } }
+        *    second = { ' b' }
+        *    => result = { { ' a' } , { ' b' } }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the array to add at the end of the first array
+        * @return a new array adding the second array at the end of first array, or null if the two arrays are null.
+        */
+       public static final char[][] arrayConcat(char[][] first, char[] second) {
+               if (second == null)
+                       return first;
+               if (first == null)
+                       return new char[][] { second };
+
+               int length = first.length;
+               char[][] result = new char[length + 1][];
+               System.arraycopy(first, 0, result, 0, length);
+               result[length] = second;
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the two arrays. It answers null if the two arrays are null.
+        * If the first array is null, then the second array is returned.
+        * If the second array is null, then the first array is returned.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = { 'a' }
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = null
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = { ' b' }
+        *    => result = { ' a' , ' b' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the second array to concatenate
+        * @return the concatenation of the two arrays, or null if the two arrays are null.
+        */
+       public static final char[] concat(char[] first, char[] second) {
+               if (first == null)
+                       return second;
+               if (second == null)
+                       return first;
+
+               int length1 = first.length;
+               int length2 = second.length;
+               char[] result = new char[length1 + length2];
+               System.arraycopy(first, 0, result, 0, length1);
+               System.arraycopy(second, 0, result, length1, length2);
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the three arrays. It answers null if the three arrays are null.
+        * If first is null, it answers the concatenation of second and third.
+        * If second is null, it answers the concatenation of first and third.
+        * If third is null, it answers the concatenation of first and second.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = { 'a' }
+        *    third = { 'b' }
+        *    => result = { ' a', 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'a' }
+        *    second = null
+        *    third = { 'b' }
+        *    => result = { ' a', 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'a' }
+        *    second = { 'b' }
+        *    third = null
+        *    => result = { ' a', 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    third = null
+        *    => result = null
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'a' }
+        *    second = { 'b' }
+        *    third = { 'c' }
+        *    => result = { 'a', 'b', 'c' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the second array to concatenate
+        * @param third the third array to concatenate
+        * 
+        * @return the concatenation of the three arrays, or null if the three arrays are null.
+        */
+       public static final char[] concat(
+               char[] first,
+               char[] second,
+               char[] third) {
+               if (first == null)
+                       return concat(second, third);
+               if (second == null)
+                       return concat(first, third);
+               if (third == null)
+                       return concat(first, second);
+
+               int length1 = first.length;
+               int length2 = second.length;
+               int length3 = third.length;
+               char[] result = new char[length1 + length2 + length3];
+               System.arraycopy(first, 0, result, 0, length1);
+               System.arraycopy(second, 0, result, length1, length2);
+               System.arraycopy(third, 0, result, length1 + length2, length3);
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the two arrays inserting the separator character between the two arrays.
+        * It answers null if the two arrays are null.
+        * If the first array is null, then the second array is returned.
+        * If the second array is null, then the first array is returned.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = { 'a' }
+        *    separator = '/'
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = null
+        *    separator = '/'
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = { ' b' }
+        *    separator = '/'
+        *    => result = { ' a' , '/', 'b' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the second array to concatenate
+        * @param separator the character to insert
+        * @return the concatenation of the two arrays inserting the separator character 
+        * between the two arrays , or null if the two arrays are null.
+        */
+       public static final char[] concat(
+               char[] first,
+               char[] second,
+               char separator) {
+               if (first == null)
+                       return second;
+               if (second == null)
+                       return first;
+
+               int length1 = first.length;
+               if (length1 == 0)
+                       return second;
+               int length2 = second.length;
+               if (length2 == 0)
+                       return first;
+
+               char[] result = new char[length1 + length2 + 1];
+               System.arraycopy(first, 0, result, 0, length1);
+               result[length1] = separator;
+               System.arraycopy(second, 0, result, length1 + 1, length2);
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the three arrays inserting the sep1 character between the 
+        * two arrays and sep2 between the last two.
+        * It answers null if the three arrays are null.
+        * If the first array is null, then it answers the concatenation of second and third inserting
+        * the sep2 character between them.
+        * If the second array is null, then the first array is returned.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = { 'a' }
+        *    separator = '/'
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = null
+        *    separator = '/'
+        *    => result = { ' a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { ' a' }
+        *    second = { ' b' }
+        *    separator = '/'
+        *    => result = { ' a' , '/', 'b' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array to concatenate
+        * @param second the second array to concatenate
+        * @param separator the character to insert
+        * @return the concatenation of the two arrays inserting the separator character 
+        * between the two arrays , or null if the two arrays are null.
+        */
+       public static final char[] concat(
+               char[] first,
+               char sep1,
+               char[] second,
+               char sep2,
+               char[] third) {
+               if (first == null)
+                       return concat(second, third, sep2);
+               if (second == null)
+                       return concat(first, third, sep1);
+               if (third == null)
+                       return concat(first, second, sep1);
+
+               int length1 = first.length;
+               int length2 = second.length;
+               int length3 = third.length;
+               char[] result = new char[length1 + length2 + length3 + 2];
+               System.arraycopy(first, 0, result, 0, length1);
+               result[length1] = sep1;
+               System.arraycopy(second, 0, result, length1 + 1, length2);
+               result[length1 + length2 + 1] = sep2;
+               System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
+               return result;
+       }
+
+       /**
+        * Answers a new array with prepending the prefix character and appending the suffix 
+        * character at the end of the array. If array is null, it answers a new array containing the 
+        * prefix and the suffix characters.
+        * <br>
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    prefix = 'a'
+        *    array = { 'b' }
+        *    suffix = 'c'
+        *    => result = { 'a', 'b' , 'c' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    prefix = 'a'
+        *    array = null
+        *    suffix = 'c'
+        *    => result = { 'a', 'c' }
+        * </pre></li>
+        * </ol>
+        * 
+        * @param prefix the prefix character
+        * @param array the array that is concanated with the prefix and suffix characters
+        * @param suffix the suffix character
+        * @return the new array
+        */
+       public static final char[] concat(char prefix, char[] array, char suffix) {
+               if (array == null)
+                       return new char[] { prefix, suffix };
+
+               int length = array.length;
+               char[] result = new char[length + 2];
+               result[0] = prefix;
+               System.arraycopy(array, 0, result, 1, length);
+               result[length + 1] = suffix;
+               return result;
+       }
+       
+       /**
+        * Answers the concatenation of the given array parts using the given separator between each
+        * part and appending the given name at the end.
+        * <br>
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    name = { 'c' }
+        *    array = { { 'a' }, { 'b' } }
+        *    separator = '.'
+        *    => result = { 'a', '.', 'b' , '.', 'c' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    name = null
+        *    array = { { 'a' }, { 'b' } }
+        *    separator = '.'
+        *    => result = { 'a', '.', 'b' }
+        * </pre></li>
+        * <li><pre>
+        *    name = { ' c' }
+        *    array = null
+        *    separator = '.'
+        *    => result = { 'c' }
+        * </pre></li>
+        * </ol>
+        * 
+        * @param name the given name
+        * @param array the given array
+        * @param separator the given separator
+        * @return the concatenation of the given array parts using the given separator between each
+        * part and appending the given name at the end
+        */
+       public static final char[] concatWith(
+               char[] name,
+               char[][] array,
+               char separator) {
+               int nameLength = name == null ? 0 : name.length;
+               if (nameLength == 0)
+                       return concatWith(array, separator);
+
+               int length = array == null ? 0 : array.length;
+               if (length == 0)
+                       return name;
+
+               int size = nameLength;
+               int index = length;
+               while (--index >= 0)
+                       if (array[index].length > 0)
+                               size += array[index].length + 1;
+               char[] result = new char[size];
+               index = size;
+               for (int i = length - 1; i >= 0; i--) {
+                       int subLength = array[i].length;
+                       if (subLength > 0) {
+                               index -= subLength;
+                               System.arraycopy(array[i], 0, result, index, subLength);
+                               result[--index] = separator;
+                       }
+               }
+               System.arraycopy(name, 0, result, 0, nameLength);
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the given array parts using the given separator between each
+        * part and appending the given name at the end.
+        * <br>
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    name = { 'c' }
+        *    array = { { 'a' }, { 'b' } }
+        *    separator = '.'
+        *    => result = { 'a', '.', 'b' , '.', 'c' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    name = null
+        *    array = { { 'a' }, { 'b' } }
+        *    separator = '.'
+        *    => result = { 'a', '.', 'b' }
+        * </pre></li>
+        * <li><pre>
+        *    name = { ' c' }
+        *    array = null
+        *    separator = '.'
+        *    => result = { 'c' }
+        * </pre></li>
+        * </ol>
+        * 
+        * @param array the given array
+        * @param name the given name
+        * @param separator the given separator
+        * @return the concatenation of the given array parts using the given separator between each
+        * part and appending the given name at the end
+        */
+       public static final char[] concatWith(
+               char[][] array,
+               char[] name,
+               char separator) {
+               int nameLength = name == null ? 0 : name.length;
+               if (nameLength == 0)
+                       return concatWith(array, separator);
+
+               int length = array == null ? 0 : array.length;
+               if (length == 0)
+                       return name;
+
+               int size = nameLength;
+               int index = length;
+               while (--index >= 0)
+                       if (array[index].length > 0)
+                               size += array[index].length + 1;
+               char[] result = new char[size];
+               index = 0;
+               for (int i = 0; i < length; i++) {
+                       int subLength = array[i].length;
+                       if (subLength > 0) {
+                               System.arraycopy(array[i], 0, result, index, subLength);
+                               index += subLength;
+                               result[index++] = separator;
+                       }
+               }
+               System.arraycopy(name, 0, result, index, nameLength);
+               return result;
+       }
+
+       /**
+        * Answers the concatenation of the given array parts using the given separator between each part.
+        * <br>
+        * <br>
+        * For example:<br>
+        * <ol>
+        * <li><pre>
+        *    array = { { 'a' }, { 'b' } }
+        *    separator = '.'
+        *    => result = { 'a', '.', 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = null
+        *    separator = '.'
+        *    => result = { }
+        * </pre></li>
+        * </ol>
+        * 
+        * @param array the given array
+        * @param separator the given separator
+        * @return the concatenation of the given array parts using the given separator between each part
+        */
+       public static final char[] concatWith(char[][] array, char separator) {
+               int length = array == null ? 0 : array.length;
+               if (length == 0)
+                       return CharOperation.NO_CHAR;
+
+               int size = length - 1;
+               int index = length;
+               while (--index >= 0) {
+                       if (array[index].length == 0)
+                               size--;
+                       else
+                               size += array[index].length;
+               }
+               if (size <= 0)
+                       return CharOperation.NO_CHAR;
+               char[] result = new char[size];
+               index = length;
+               while (--index >= 0) {
+                       length = array[index].length;
+                       if (length > 0) {
+                               System.arraycopy(
+                                       array[index],
+                                       0,
+                                       result,
+                                       (size -= length),
+                                       length);
+                               if (--size >= 0)
+                                       result[size] = separator;
+                       }
+               }
+               return result;
+       }
+       
+       /**
+        * Answers true if the array contains an occurrence of character, false otherwise.
+        * 
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    character = 'c'
+        *    array = { { ' a' }, { ' b' } }
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    character = 'a'
+        *    array = { { ' a' }, { ' b' } }
+        *    result => true
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param character the character to search
+        * @param array the array in which the search is done
+        * @exception NullPointerException if array is null.
+        * 
+        * @return true if the array contains an occurrence of character, false otherwise.
+        */
+       public static final boolean contains(char character, char[][] array) {
+               for (int i = array.length; --i >= 0;) {
+                       char[] subarray = array[i];
+                       for (int j = subarray.length; --j >= 0;)
+                               if (subarray[j] == character)
+                                       return true;
+               }
+               return false;
+       }
+
+       /**
+        * Answers true if the array contains an occurrence of character, false otherwise.
+        * 
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    character = 'c'
+        *    array = { ' b'  }
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    character = 'a'
+        *    array = { ' a' , ' b' }
+        *    result => true
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param character the character to search
+        * @param array the array in which the search is done
+        * @exception NullPointerException if array is null.
+        * 
+        * @return true if the array contains an occurrence of character, false otherwise.
+        */
+       public static final boolean contains(char character, char[] array) {
+               for (int i = array.length; --i >= 0;)
+                       if (array[i] == character)
+                               return true;
+               return false;
+       }
+       
+       /**
+        * Answers a deep copy of the toCopy array.
+        * 
+        * @param toCopy the array to copy
+        * @return a deep copy of the toCopy array.
+        */
+       public static final char[][] deepCopy(char[][] toCopy) {
+               int toCopyLength = toCopy.length;
+               char[][] result = new char[toCopyLength][];
+               for (int i = 0; i < toCopyLength; i++) {
+                       char[] toElement = toCopy[i];
+                       int toElementLength = toElement.length;
+                       char[] resultElement = new char[toElementLength];
+                       System.arraycopy(toElement, 0, resultElement, 0, toElementLength);
+                       result[i] = resultElement;
+               }
+               return result;
+       }
+
+       /**
+        * Return true if array ends with the sequence of characters contained in toBeFound, 
+        * otherwise false.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { 'a', 'b', 'c', 'd' }
+        *    toBeFound = { 'b', 'c' }
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'a', 'b', 'c' }
+        *    toBeFound = { 'b', 'c' }
+        *    result => true
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param array the array to check
+        * @param toBeFound the array to find
+        * @exception NullPointerException if array is null or toBeFound is null
+        * @return true if array ends with the sequence of characters contained in toBeFound, 
+        * otherwise false.
+        */
+       public static final boolean endsWith(char[] array, char[] toBeFound) {
+               int i = toBeFound.length;
+               int j = array.length - i;
+
+               if (j < 0)
+                       return false;
+               while (--i >= 0)
+                       if (toBeFound[i] != array[i + j])
+                               return false;
+               return true;
+       }
+
+       /**
+        * Answers true if the two arrays are identical character by character, otherwise false.
+        * The equality is case sensitive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { } }
+        *    second = null
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { 'a' } }
+        *    second = { { 'a' } }
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { 'A' } }
+        *    second = { { 'a' } }
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * @param first the first array
+        * @param second the second array
+        * @return true if the two arrays are identical character by character, otherwise false
+        */
+       public static final boolean equals(char[][] first, char[][] second) {
+               if (first == second)
+                       return true;
+               if (first == null || second == null)
+                       return false;
+               if (first.length != second.length)
+                       return false;
+
+               for (int i = first.length; --i >= 0;)
+                       if (!equals(first[i], second[i]))
+                               return false;
+               return true;
+       }
+
+       /**
+        * If isCaseSensite is true, answers true if the two arrays are identical character
+        * by character, otherwise false.
+        * If it is false, answers true if the two arrays are identical character by 
+        * character without checking the case, otherwise false.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    isCaseSensitive = true
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { } }
+        *    second = null
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { 'A' } }
+        *    second = { { 'a' } }
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { { 'A' } }
+        *    second = { { 'a' } }
+        *    isCaseSensitive = false
+        *    result => true
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array
+        * @param second the second array
+        * @param isCaseSensitive check whether or not the equality should be case sensitive
+        * @return true if the two arrays are identical character by character according to the value
+        * of isCaseSensitive, otherwise false
+        */
+       public static final boolean equals(
+               char[][] first,
+               char[][] second,
+               boolean isCaseSensitive) {
+
+               if (isCaseSensitive) {
+                       return equals(first, second);
+               }
+               if (first == second)
+                       return true;
+               if (first == null || second == null)
+                       return false;
+               if (first.length != second.length)
+                       return false;
+
+               for (int i = first.length; --i >= 0;)
+                       if (!equals(first[i], second[i], false))
+                               return false;
+               return true;
+       }
+
+       /**
+        * Answers true if the two arrays are identical character by character, otherwise false.
+        * The equality is case sensitive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { }
+        *    second = null
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'a' }
+        *    second = { 'a' }
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'a' }
+        *    second = { 'A' }
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * @param first the first array
+        * @param second the second array
+        * @return true if the two arrays are identical character by character, otherwise false
+        */
+       public static final boolean equals(char[] first, char[] second) {
+               if (first == second)
+                       return true;
+               if (first == null || second == null)
+                       return false;
+               if (first.length != second.length)
+                       return false;
+
+               for (int i = first.length; --i >= 0;)
+                       if (first[i] != second[i])
+                               return false;
+               return true;
+       }
+
+       /**
+        * If isCaseSensite is true, answers true if the two arrays are identical character
+        * by character, otherwise false.
+        * If it is false, answers true if the two arrays are identical character by 
+        * character without checking the case, otherwise false.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    first = null
+        *    second = null
+        *    isCaseSensitive = true
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { }
+        *    second = null
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'A' }
+        *    second = { 'a' }
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    first = { 'A' }
+        *    second = { 'a' }
+        *    isCaseSensitive = false
+        *    result => true
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param first the first array
+        * @param second the second array
+        * @param isCaseSensitive check whether or not the equality should be case sensitive
+        * @return true if the two arrays are identical character by character according to the value
+        * of isCaseSensitive, otherwise false
+        */
+       public static final boolean equals(
+               char[] first,
+               char[] second,
+               boolean isCaseSensitive) {
+
+               if (isCaseSensitive) {
+                       return equals(first, second);
+               }
+               if (first == second)
+                       return true;
+               if (first == null || second == null)
+                       return false;
+               if (first.length != second.length)
+                       return false;
+
+               for (int i = first.length; --i >= 0;)
+                       if (Character.toLowerCase(first[i])
+                               != Character.toLowerCase(second[i]))
+                               return false;
+               return true;
+       }
+       /**
+        * If isCaseSensite is true, the equality is case sensitive, otherwise it is case insensitive.
+        * 
+        * Answers true if the name contains the fragment at the starting index startIndex, otherwise false.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    fragment = { 'b', 'c' , 'd' }
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    startIndex = 1
+        *    isCaseSensitive = true
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    fragment = { 'b', 'c' , 'd' }
+        *    name = { 'a', 'b', 'C' , 'd' }
+        *    startIndex = 1
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    fragment = { 'b', 'c' , 'd' }
+        *    name = { 'a', 'b', 'C' , 'd' }
+        *    startIndex = 0
+        *    isCaseSensitive = false
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    fragment = { 'b', 'c' , 'd' }
+        *    name = { 'a', 'b'}
+        *    startIndex = 0
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param fragment the fragment to check
+        * @param second the array to check
+        * @param startIndex the starting index
+        * @param isCaseSensitive check whether or not the equality should be case sensitive
+        * @return true if the name contains the fragment at the starting index startIndex according to the 
+        * value of isCaseSensitive, otherwise false.
+        * @exception NullPointerException if fragment or name is null.
+        */
+       public static final boolean fragmentEquals(
+               char[] fragment,
+               char[] name,
+               int startIndex,
+               boolean isCaseSensitive) {
+
+               int max = fragment.length;
+               if (name.length < max + startIndex)
+                       return false;
+               if (isCaseSensitive) {
+                       for (int i = max;
+                               --i >= 0;
+                               ) // assumes the prefix is not larger than the name
+                               if (fragment[i] != name[i + startIndex])
+                                       return false;
+                       return true;
+               }
+               for (int i = max;
+                       --i >= 0;
+                       ) // assumes the prefix is not larger than the name
+                       if (Character.toLowerCase(fragment[i])
+                               != Character.toLowerCase(name[i + startIndex]))
+                               return false;
+               return true;
+       }
+
+       /**
+        * Answers a hashcode for the array
+        * 
+        * @param array the array for which a hashcode is required
+        * @return the hashcode
+        * @exception NullPointerException if array is null
+        */
+       public static final int hashCode(char[] array) {
+               int hash = 0;
+               int offset = 0;
+               int length = array.length;
+               if (length < 16) {
+                       for (int i = length; i > 0; i--)
+                               hash = (hash * 37) + array[offset++];
+               } else {
+                       // only sample some characters
+                       int skip = length / 8;
+                       for (int i = length; i > 0; i -= skip, offset += skip)
+                               hash = (hash * 39) + array[offset];
+               }
+               return hash & 0x7FFFFFFF;
+       }
+       /**
+        * Answers true if c is a whitespace according to the JLS (&#92;u000a, &#92;u000c, &#92;u000d, &#92;u0009), otherwise false.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    c = ' '
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    c = '&#92;u3000'
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param c the character to check
+        * @return true if c is a whitespace according to the JLS, otherwise false.
+        */
+       public static boolean isWhitespace(char c) {
+               switch (c) {
+                       case 10 : /* \ u000a: LINE FEED               */
+                       case 12 : /* \ u000c: FORM FEED               */
+                       case 13 : /* \ u000d: CARRIAGE RETURN         */
+                       case 32 : /* \ u0020: SPACE                   */
+                       case 9 : /* \ u0009: HORIZONTAL TABULATION   */
+                               return true;
+                       default :
+                               return false;
+               }
+       }
+       
+       /**
+        * Answers the first index in the array for which the corresponding character is
+        * equal to toBeFound. Answers -1 if no occurrence of this character is found.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    result => 2
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'e'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    result => -1
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param toBeFound the character to search
+        * @param array the array to be searched
+        * @return the first index in the array for which the corresponding character is
+        * equal to toBeFound, -1 otherwise
+        * @exception NullPointerException if array is null
+        */
+       public static final int indexOf(char toBeFound, char[] array) {
+               for (int i = 0; i < array.length; i++)
+                       if (toBeFound == array[i])
+                               return i;
+               return -1;
+       }
+
+       /**
+        * Answers the first index in the array for which the corresponding character is
+        * equal to toBeFound starting the search at index start.
+        * Answers -1 if no occurrence of this character is found.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    start = 2
+        *    result => 2
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    start = 3
+        *    result => -1
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'e'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    start = 1
+        *    result => -1
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param toBeFound the character to search
+        * @param array the array to be searched
+        * @param start the starting index
+        * @return the first index in the array for which the corresponding character is
+        * equal to toBeFound, -1 otherwise
+        * @exception NullPointerException if array is null
+        * @exception ArrayIndexOutOfBoundsException if  start is lower than 0
+        */
+       public static final int indexOf(char toBeFound, char[] array, int start) {
+               for (int i = start; i < array.length; i++)
+                       if (toBeFound == array[i])
+                               return i;
+               return -1;
+       }
+
+       /**
+        * Answers the last index in the array for which the corresponding character is
+        * equal to toBeFound starting from the end of the array.
+        * Answers -1 if no occurrence of this character is found.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
+        *    result => 4
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'e'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    result => -1
+        * </pre>
+        * </li>
+        * </ol>
+        *
+        * @param toBeFound the character to search
+        * @param array the array to be searched
+        * @return the last index in the array for which the corresponding character is
+        * equal to toBeFound starting from the end of the array, -1 otherwise
+        * @exception NullPointerException if array is null
+        */
+       public static final int lastIndexOf(char toBeFound, char[] array) {
+               for (int i = array.length; --i >= 0;)
+                       if (toBeFound == array[i])
+                               return i;
+               return -1;
+       }
+
+       /**
+        * Answers the last index in the array for which the corresponding character is
+        * equal to toBeFound stopping at the index startIndex.
+        * Answers -1 if no occurrence of this character is found.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    startIndex = 2
+        *    result => 2
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd', 'e' }
+        *    startIndex = 3
+        *    result => -1
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'e'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    startIndex = 0
+        *    result => -1
+        * </pre>
+        * </li>
+        * </ol>
+        *
+        * @param toBeFound the character to search
+        * @param array the array to be searched
+        * @param startIndex the stopping index
+        * @return the last index in the array for which the corresponding character is
+        * equal to toBeFound stopping at the index startIndex, -1 otherwise
+        * @exception NullPointerException if array is null
+        * @exception ArrayIndexOutOfBoundsException if startIndex is lower than 0
+        */
+       public static final int lastIndexOf(
+               char toBeFound,
+               char[] array,
+               int startIndex) {
+               for (int i = array.length; --i >= startIndex;)
+                       if (toBeFound == array[i])
+                               return i;
+               return -1;
+       }
+
+       /**
+        * Answers the last index in the array for which the corresponding character is
+        * equal to toBeFound starting from endIndex to startIndex.
+        * Answers -1 if no occurrence of this character is found.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    startIndex = 2
+        *    endIndex = 2
+        *    result => 2
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { ' a', 'b', 'c', 'd', 'e' }
+        *    startIndex = 3
+        *    endIndex = 4
+        *    result => -1
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'e'
+        *    array = { ' a', 'b', 'c', 'd' }
+        *    startIndex = 0
+        *    endIndex = 3
+        *    result => -1
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param toBeFound the character to search
+        * @param array the array to be searched
+        * @param startIndex the stopping index
+        * @param endIndex the starting index
+        * @return the last index in the array for which the corresponding character is
+        * equal to toBeFound starting from endIndex to startIndex, -1 otherwise
+        * @exception NullPointerException if array is null
+        * @exception ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0
+        */
+       public static final int lastIndexOf(
+               char toBeFound,
+               char[] array,
+               int startIndex,
+               int endIndex) {
+               for (int i = endIndex; --i >= startIndex;)
+                       if (toBeFound == array[i])
+                               return i;
+               return -1;
+       }
+       
+       /**
+        * Answers the last portion of a name given a separator.
+        * <br>
+        * <br>
+        * For example,
+        * <pre>
+        *      lastSegment("java.lang.Object".toCharArray(),'.') --> Object
+        * </pre>
+        * 
+        * @param array the array
+        * @param separator the given separator
+        * @return the last portion of a name given a separator
+        * @exception NullPointerException if array is null
+        */
+       final static public char[] lastSegment(char[] array, char separator) {
+               int pos = lastIndexOf(separator, array);
+               if (pos < 0)
+                       return array;
+               return subarray(array, pos + 1, array.length);
+       }
+
+       /**
+        * Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching
+        * accepts wild-cards '*' and '?'.
+        *
+        * When not case sensitive, the pattern is assumed to already be lowercased, the
+        * name will be lowercased character per character as comparing.
+        * If name is null, the answer is false.
+        * If pattern is null, the answer is true if name is not null.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    pattern = { '?', 'b', '*' }
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    isCaseSensitive = true
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    pattern = { '?', 'b', '?' }
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    pattern = { 'b', '*' }
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param pattern the given pattern
+        * @param name the given name
+        * @param isCaseSensitive flag to know whether or not the matching should be case sensitive
+        * @return true if the pattern matches the given name, false otherwise
+        */
+       public static final boolean match(
+               char[] pattern,
+               char[] name,
+               boolean isCaseSensitive) {
+
+               if (name == null)
+                       return false; // null name cannot match
+               if (pattern == null)
+                       return true; // null pattern is equivalent to '*'
+
+               return match(
+                       pattern,
+                       0,
+                       pattern.length,
+                       name,
+                       0,
+                       name.length,
+                       isCaseSensitive);
+       }
+
+       /**
+        * Answers true if the a sub-pattern matches the subpart of the given name, false otherwise.
+        * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only subset of name/pattern.
+        * end positions are non-inclusive.
+        * The subpattern is defined by the patternStart and pattternEnd positions.
+        * When not case sensitive, the pattern is assumed to already be lowercased, the
+        * name will be lowercased character per character as comparing.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    pattern = { '?', 'b', '*' }
+        *    patternStart = 1
+        *    patternEnd = 3
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    nameStart = 1
+        *    nameEnd = 4
+        *    isCaseSensitive = true
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    pattern = { '?', 'b', '*' }
+        *    patternStart = 1
+        *    patternEnd = 2
+        *    name = { 'a', 'b', 'c' , 'd' }
+        *    nameStart = 1
+        *    nameEnd = 2
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param pattern the given pattern
+        * @param patternStart the given pattern start
+        * @param patternEnd the given pattern end
+        * @param name the given name
+        * @param nameStart the given name start
+        * @param nameEnd the given name end
+        * @param isCaseSensitive flag to know if the matching should be case sensitive
+        * @return true if the a sub-pattern matches the subpart of the given name, false otherwise
+        */
+       public static final boolean match(
+               char[] pattern,
+               int patternStart,
+               int patternEnd,
+               char[] name,
+               int nameStart,
+               int nameEnd,
+               boolean isCaseSensitive) {
+
+               if (name == null)
+                       return false; // null name cannot match
+               if (pattern == null)
+                       return true; // null pattern is equivalent to '*'
+               int iPattern = patternStart;
+               int iName = nameStart;
+
+               if (patternEnd < 0)
+                       patternEnd = pattern.length;
+               if (nameEnd < 0)
+                       nameEnd = name.length;
+
+               /* check first segment */
+               char patternChar = 0;
+               while ((iPattern < patternEnd)
+                       && (patternChar = pattern[iPattern]) != '*') {
+                       if (iName == nameEnd)
+                               return false;
+                       if (patternChar
+                               != (isCaseSensitive
+                                       ? name[iName]
+                                       : Character.toLowerCase(name[iName]))
+                               && patternChar != '?') {
+                               return false;
+                       }
+                       iName++;
+                       iPattern++;
+               }
+               /* check sequence of star+segment */
+               int segmentStart;
+               if (patternChar == '*') {
+                       segmentStart = ++iPattern; // skip star
+               } else {
+                       segmentStart = 0; // force iName check
+               }
+               int prefixStart = iName;
+               checkSegment : while (iName < nameEnd) {
+                       if (iPattern == patternEnd) {
+                               iPattern = segmentStart; // mismatch - restart current segment
+                               iName = ++prefixStart;
+                               continue checkSegment;
+                       }
+                       /* segment is ending */
+                       if ((patternChar = pattern[iPattern]) == '*') {
+                               segmentStart = ++iPattern; // skip start
+                               if (segmentStart == patternEnd) {
+                                       return true;
+                               }
+                               prefixStart = iName;
+                               continue checkSegment;
+                       }
+                       /* check current name character */
+                       if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName]))
+                                               != patternChar
+                                       && patternChar != '?') {
+                               iPattern = segmentStart; // mismatch - restart current segment
+                               iName = ++prefixStart;
+                               continue checkSegment;
+                       }
+                       iName++;
+                       iPattern++;
+               }
+
+               return (segmentStart == patternEnd)
+                       || (iName == nameEnd && iPattern == patternEnd)
+                       || (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
+       }
+
+       /**
+        * Answers true if the pattern matches the filepath using the pathSepatator, false otherwise.
+        * 
+        * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks
+        * conventions, also see "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes").
+        * Path pattern matching is enhancing regular pattern matching in supporting extra rule where '**' represent
+        * any folder combination.
+        * Special rules: 
+        * - foo\  is equivalent to foo\**   
+        * - *.php is equivalent to **\*.php
+        * When not case sensitive, the pattern is assumed to already be lowercased, the
+        * name will be lowercased character per character as comparing.
+        * 
+        * @param pattern the given pattern
+        * @param filepath the given path
+        * @param isCaseSensitive to find out whether or not the matching should be case sensitive
+        * @param pathSeparator the given path separator
+        * @return true if the pattern matches the filepath using the pathSepatator, false otherwise
+        */
+       public static final boolean pathMatch(
+               char[] pattern,
+               char[] filepath,
+               boolean isCaseSensitive,
+               char pathSeparator) {
+
+               if (filepath == null)
+                       return false; // null name cannot match
+               if (pattern == null)
+                       return true; // null pattern is equivalent to '*'
+
+               // special case: pattern foo is equivalent to **\foo (not absolute)
+               boolean freeLeadingDoubleStar;
+
+               // offsets inside pattern
+               int pSegmentStart, pLength = pattern.length;
+
+               if (freeLeadingDoubleStar = pattern[0] != pathSeparator){
+                       pSegmentStart = 0;
+               } else {
+                       pSegmentStart = 1;
+               }
+               int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, pSegmentStart+1);
+               if (pSegmentEnd < 0) pSegmentEnd = pLength;
+
+               // special case: pattern foo\ is equivalent to foo\**
+               boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
+
+               // offsets inside filepath
+               int fSegmentStart, fLength = filepath.length;
+               if (filepath[0] != pathSeparator){
+                       fSegmentStart = 0;
+               } else {
+                       fSegmentStart = 1;
+               }
+               if (fSegmentStart != pSegmentStart) {
+                       return false; // both must start with a separator or none.
+               }
+               int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, fSegmentStart+1);
+               if (fSegmentEnd < 0) fSegmentEnd = fLength;
+
+               // first segments
+               while (pSegmentStart < pLength
+                       && !freeLeadingDoubleStar
+                       && !(pSegmentEnd == pLength && freeTrailingDoubleStar
+                                       || (pSegmentEnd == pSegmentStart + 2
+                                                       && pattern[pSegmentStart] == '*'
+                                                       && pattern[pSegmentStart + 1] == '*'))) {
+
+                       if (fSegmentStart >= fLength)
+                               return false;
+                       if (!CharOperation
+                               .match(
+                                       pattern,
+                                       pSegmentStart,
+                                       pSegmentEnd,
+                                       filepath,
+                                       fSegmentStart,
+                                       fSegmentEnd,
+                                       isCaseSensitive)) {
+                               return false;
+                       }
+
+                       // jump to next segment         
+                       pSegmentEnd =
+                               CharOperation.indexOf(
+                                       pathSeparator,
+                                       pattern,
+                                       pSegmentStart = pSegmentEnd + 1);
+                       // skip separator
+                       if (pSegmentEnd < 0)
+                               pSegmentEnd = pLength;
+
+                       fSegmentEnd =
+                               CharOperation.indexOf(
+                                       pathSeparator,
+                                       filepath,
+                                       fSegmentStart = fSegmentEnd + 1);
+                       // skip separator
+                       if (fSegmentEnd < 0) fSegmentEnd = fLength;
+               }
+
+               /* check sequence of doubleStar+segment */
+               int pSegmentRestart;
+               if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
+                               || (pSegmentEnd == pSegmentStart + 2
+                                       && pattern[pSegmentStart] == '*'
+                                       && pattern[pSegmentStart + 1] == '*')) {
+                       pSegmentEnd =
+                               CharOperation.indexOf(
+                                       pathSeparator,
+                                       pattern,
+                                       pSegmentStart = pSegmentEnd + 1);
+                       // skip separator
+                       if (pSegmentEnd < 0) pSegmentEnd = pLength;
+                       pSegmentRestart = pSegmentStart;
+               } else {
+                       pSegmentRestart = 0; // force fSegmentStart check
+               }
+               int fSegmentRestart = fSegmentStart;
+               checkSegment : while (fSegmentStart < fLength) {
+                               
+                       if (pSegmentStart >= pLength) {
+                               if (freeTrailingDoubleStar) return true;
+                               // mismatch - restart current path segment
+                               pSegmentEnd =
+                                       CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart);
+                               if (pSegmentEnd < 0) pSegmentEnd = pLength;
+
+                               fSegmentRestart = 
+                                       CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1);
+                               // skip separator
+                               if (fSegmentRestart < 0) {
+                                       fSegmentRestart = fLength;
+                               } else {
+                                       fSegmentRestart++;
+                               }
+                               fSegmentEnd =
+                                       CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart);
+                               if (fSegmentEnd < 0) fSegmentEnd = fLength;
+                               continue checkSegment;
+                       }
+                       
+                       /* path segment is ending */
+                       if (pSegmentEnd == pSegmentStart + 2
+                               && pattern[pSegmentStart] == '*'
+                               && pattern[pSegmentStart + 1] == '*') {
+                               pSegmentEnd =
+                                       CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1);
+                               // skip separator
+                               if (pSegmentEnd < 0) pSegmentEnd = pLength;
+                               pSegmentRestart = pSegmentStart;
+                               fSegmentRestart = fSegmentStart;
+                               if (pSegmentStart >= pLength) return true;
+                               continue checkSegment;
+                       }
+                       /* chech current path segment */
+                       if (!CharOperation.match(
+                                                               pattern,
+                                                               pSegmentStart,
+                                                               pSegmentEnd,
+                                                               filepath,
+                                                               fSegmentStart,
+                                                               fSegmentEnd,
+                                                               isCaseSensitive)) {
+                               // mismatch - restart current path segment
+                               pSegmentEnd =
+                                       CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart);
+                               if (pSegmentEnd < 0) pSegmentEnd = pLength;
+
+                               fSegmentRestart = 
+                                       CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1);
+                               // skip separator
+                               if (fSegmentRestart < 0) {
+                                       fSegmentRestart = fLength;
+                               } else {
+                                       fSegmentRestart++;
+                               }
+                               fSegmentEnd =
+                                       CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart);
+                               if (fSegmentEnd < 0) fSegmentEnd = fLength;
+                               continue checkSegment;
+                       }
+                       // jump to next segment         
+                       pSegmentEnd =
+                               CharOperation.indexOf(
+                                       pathSeparator,
+                                       pattern,
+                                       pSegmentStart = pSegmentEnd + 1);
+                       // skip separator
+                       if (pSegmentEnd < 0)
+                               pSegmentEnd = pLength;
+
+                       fSegmentEnd =
+                               CharOperation.indexOf(
+                                       pathSeparator,
+                                       filepath,
+                                       fSegmentStart = fSegmentEnd + 1);
+                       // skip separator
+                       if (fSegmentEnd < 0)
+                               fSegmentEnd = fLength;
+               }
+
+               return (pSegmentRestart >= pSegmentEnd)
+                       || (fSegmentStart >= fLength && pSegmentStart >= pLength)
+                       || (pSegmentStart == pLength - 2
+                               && pattern[pSegmentStart] == '*'
+                               && pattern[pSegmentStart + 1] == '*')
+                       || (pSegmentStart == pLength && freeTrailingDoubleStar);
+       }
+
+       /**
+        * Answers the number of occurrences of the given character in the given array, 0 if any.
+        * 
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'b'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => 3
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => 0
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param toBeFound the given character
+        * @param array the given array
+        * @return the number of occurrences of the given character in the given array, 0 if any
+        * @exception NullPointerException if array is null
+        */
+       public static final int occurencesOf(char toBeFound, char[] array) {
+               int count = 0;
+               for (int i = 0; i < array.length; i++)
+                       if (toBeFound == array[i])
+                               count++;
+               return count;
+       }
+
+       /**
+        * Answers the number of occurrences of the given character in the given array starting
+        * at the given index, 0 if any.
+        * 
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = 'b'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    start = 2
+        *    result => 2
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = 'c'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    start = 0
+        *    result => 0
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param toBeFound the given character
+        * @param array the given array
+        * @return the number of occurrences of the given character in the given array, 0 if any
+        * @exception NullPointerException if array is null
+        * @exception ArrayIndexOutOfBoundsException if start is lower than 0
+        */
+       public static final int occurencesOf(
+               char toBeFound,
+               char[] array,
+               int start) {
+               int count = 0;
+               for (int i = start; i < array.length; i++)
+                       if (toBeFound == array[i])
+                               count++;
+               return count;
+       }
+
+       /**
+        * Answers true if the given name starts with the given prefix, false otherwise.
+        * The comparison is case sensitive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    prefix = { 'a' , 'b' }
+        *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    prefix = { 'a' , 'c' }
+        *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param prefix the given prefix
+        * @param name the given name
+        * @return true if the given name starts with the given prefix, false otherwise
+        * @exception NullPointerException if the given name is null or if the given prefix is null
+        */
+       public static final boolean prefixEquals(char[] prefix, char[] name) {
+
+               int max = prefix.length;
+               if (name.length < max)
+                       return false;
+               for (int i = max;
+                       --i >= 0;
+                       ) // assumes the prefix is not larger than the name
+                       if (prefix[i] != name[i])
+                               return false;
+               return true;
+       }
+
+       /**
+        * Answers true if the given name starts with the given prefix, false otherwise.
+        * isCaseSensitive is used to find out whether or not the comparison should be case sensitive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    prefix = { 'a' , 'B' }
+        *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    isCaseSensitive = false
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    prefix = { 'a' , 'B' }
+        *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    isCaseSensitive = true
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param prefix the given prefix
+        * @param name the given name
+        * @param isCaseSensitive to find out whether or not the comparison should be case sensitive
+        * @return true if the given name starts with the given prefix, false otherwise
+        * @exception NullPointerException if the given name is null or if the given prefix is null
+        */
+       public static final boolean prefixEquals(
+               char[] prefix,
+               char[] name,
+               boolean isCaseSensitive) {
+
+               int max = prefix.length;
+               if (name.length < max)
+                       return false;
+               if (isCaseSensitive) {
+                       for (int i = max;
+                               --i >= 0;
+                               ) // assumes the prefix is not larger than the name
+                               if (prefix[i] != name[i])
+                                       return false;
+                       return true;
+               }
+
+               for (int i = max;
+                       --i >= 0;
+                       ) // assumes the prefix is not larger than the name
+                       if (Character.toLowerCase(prefix[i])
+                               != Character.toLowerCase(name[i]))
+                               return false;
+               return true;
+       }
+
+       /**
+        * Replace all occurrence of the character to be replaced with the remplacement character in the
+        * given array.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    toBeReplaced = 'b'
+        *    replacementChar = 'a'
+        *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    toBeReplaced = 'c'
+        *    replacementChar = 'a'
+        *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param array the given array
+        * @param toBeReplaced the character to be replaced
+        * @param replacementChar the replacement character
+        * @exception NullPointerException if the given array is null
+        */
+       public static final void replace(
+               char[] array,
+               char toBeReplaced,
+               char replacementChar) {
+               if (toBeReplaced != replacementChar) {
+                       for (int i = 0, max = array.length; i < max; i++) {
+                               if (array[i] == toBeReplaced)
+                                       array[i] = replacementChar;
+                       }
+               }
+       }
+
+       /**
+        * Answers a new array of characters with substitutions. No side-effect is operated on the original
+        * array, in case no substitution happened, then the result is the same as the
+        * original one.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    toBeReplaced = { 'b' }
+        *    replacementChar = { 'a', 'a' }
+        *    result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    toBeReplaced = { 'c' }
+        *    replacementChar = { 'a' }
+        *    result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param the given array
+        * @param toBeReplaced characters to be replaced
+        * @param the replacement characters
+        * @return a new array of characters with substitutions or the given array if none
+        * @exception NullPointerException if the given array is null
+        */
+       public static final char[] replace(
+               char[] array,
+               char[] toBeReplaced,
+               char[] replacementChars) {
+
+               int max = array.length;
+               int replacedLength = toBeReplaced.length;
+               int replacementLength = replacementChars.length;
+
+               int[] starts = new int[5];
+               int occurrenceCount = 0;
+
+               if (!equals(toBeReplaced, replacementChars)) {
+
+                       next : for (int i = 0; i < max; i++) {
+                               int j = 0;
+                               while (j < replacedLength) {
+                                       if (i + j == max)
+                                               continue next;
+                                       if (array[i + j] != toBeReplaced[j++])
+                                               continue next;
+                               }
+                               if (occurrenceCount == starts.length) {
+                                       System.arraycopy(
+                                               starts,
+                                               0,
+                                               starts = new int[occurrenceCount * 2],
+                                               0,
+                                               occurrenceCount);
+                               }
+                               starts[occurrenceCount++] = i;
+                       }
+               }
+               if (occurrenceCount == 0)
+                       return array;
+               char[] result =
+                       new char[max
+                               + occurrenceCount * (replacementLength - replacedLength)];
+               int inStart = 0, outStart = 0;
+               for (int i = 0; i < occurrenceCount; i++) {
+                       int offset = starts[i] - inStart;
+                       System.arraycopy(array, inStart, result, outStart, offset);
+                       inStart += offset;
+                       outStart += offset;
+                       System.arraycopy(
+                               replacementChars,
+                               0,
+                               result,
+                               outStart,
+                               replacementLength);
+                       inStart += replacedLength;
+                       outStart += replacementLength;
+               }
+               System.arraycopy(array, inStart, result, outStart, max - inStart);
+               return result;
+       }
+
+       /**
+        * Return a new array which is the split of the given array using the given divider and triming each subarray to remove
+        * whitespaces equals to ' '.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    divider = 'b'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    divider = 'c'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    divider = 'b'
+        *    array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
+        *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    divider = 'c'
+        *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
+        *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param divider the given divider
+        * @param array the given array
+        * @return a new array which is the split of the given array using the given divider and triming each subarray to remove
+        * whitespaces equals to ' '
+        */
+       public static final char[][] splitAndTrimOn(char divider, char[] array) {
+               int length = array == null ? 0 : array.length;
+               if (length == 0)
+                       return NO_CHAR_CHAR;
+
+               int wordCount = 1;
+               for (int i = 0; i < length; i++)
+                       if (array[i] == divider)
+                               wordCount++;
+               char[][] split = new char[wordCount][];
+               int last = 0, currentWord = 0;
+               for (int i = 0; i < length; i++) {
+                       if (array[i] == divider) {
+                               int start = last, end = i - 1;
+                               while (start < i && array[start] == ' ')
+                                       start++;
+                               while (end > start && array[end] == ' ')
+                                       end--;
+                               split[currentWord] = new char[end - start + 1];
+                               System.arraycopy(
+                                       array,
+                                       start,
+                                       split[currentWord++],
+                                       0,
+                                       end - start + 1);
+                               last = i + 1;
+                       }
+               }
+               int start = last, end = length - 1;
+               while (start < length && array[start] == ' ')
+                       start++;
+               while (end > start && array[end] == ' ')
+                       end--;
+               split[currentWord] = new char[end - start + 1];
+               System.arraycopy(
+                       array,
+                       start,
+                       split[currentWord++],
+                       0,
+                       end - start + 1);
+               return split;
+       }
+
+       /**
+        * Return a new array which is the split of the given array using the given divider.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    divider = 'b'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    divider = 'c'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    divider = 'c'
+        *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
+        *    result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param divider the given divider
+        * @param array the given array
+        * @return a new array which is the split of the given array using the given divider
+        */
+       public static final char[][] splitOn(char divider, char[] array) {
+               int length = array == null ? 0 : array.length;
+               if (length == 0)
+                       return NO_CHAR_CHAR;
+
+               int wordCount = 1;
+               for (int i = 0; i < length; i++)
+                       if (array[i] == divider)
+                               wordCount++;
+               char[][] split = new char[wordCount][];
+               int last = 0, currentWord = 0;
+               for (int i = 0; i < length; i++) {
+                       if (array[i] == divider) {
+                               split[currentWord] = new char[i - last];
+                               System.arraycopy(
+                                       array,
+                                       last,
+                                       split[currentWord++],
+                                       0,
+                                       i - last);
+                               last = i + 1;
+                       }
+               }
+               split[currentWord] = new char[length - last];
+               System.arraycopy(array, last, split[currentWord], 0, length - last);
+               return split;
+       }
+
+       /**
+        * Return a new array which is the split of the given array using the given divider. The given end 
+        * is exclusive and the given start is inclusive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    divider = 'b'
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    start = 2
+        *    end = 5
+        *    result => { {  }, {  }, { 'a' } }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param divider the given divider
+        * @param array the given array
+        * @param start the given starting index
+        * @param end the given ending index
+        * @return a new array which is the split of the given array using the given divider
+        * @exception ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length
+        */
+       public static final char[][] splitOn(
+               char divider,
+               char[] array,
+               int start,
+               int end) {
+               int length = array == null ? 0 : array.length;
+               if (length == 0 || start > end)
+                       return NO_CHAR_CHAR;
+
+               int wordCount = 1;
+               for (int i = start; i < end; i++)
+                       if (array[i] == divider)
+                               wordCount++;
+               char[][] split = new char[wordCount][];
+               int last = start, currentWord = 0;
+               for (int i = start; i < end; i++) {
+                       if (array[i] == divider) {
+                               split[currentWord] = new char[i - last];
+                               System.arraycopy(
+                                       array,
+                                       last,
+                                       split[currentWord++],
+                                       0,
+                                       i - last);
+                               last = i + 1;
+                       }
+               }
+               split[currentWord] = new char[end - last];
+               System.arraycopy(array, last, split[currentWord], 0, end - last);
+               return split;
+       }
+
+       /**
+        * Answers true if the given array starts with the given characters, false otherwise.
+        * The comparison is case sensitive.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    toBeFound = { 'a' , 'b' }
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => true
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    toBeFound = { 'a' , 'c' }
+        *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+        *    result => false
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param array the given array
+        * @param toBeFound the given character to search
+        * @return true if the given array starts with the given characters, false otherwise
+        * @exception NullPointerException if the given array is null or if the given characters array to be found is null
+        */
+       public static final boolean startsWith(char[] array, char[] toBeFound) {
+               int i = toBeFound.length;
+               if (i > array.length)
+                       return false;
+               while (--i >= 0)
+                       if (toBeFound[i] != array[i])
+                               return false;
+               return true;
+       }
+       
+       /**
+        * Answers a new array which is a copy of the given array starting at the given start and 
+        * ending at the given end. The given start is inclusive and the given end is exclusive.
+        * Answers null if start is greater than end, if start is lower than 0 or if end is greater 
+        * than the length of the given array. If end  equals -1, it is converted to the array length.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { { 'a' } , { 'b' } }
+        *    start = 0
+        *    end = 1
+        *    result => { { 'a' } }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { { 'a' } , { 'b' } }
+        *    start = 0
+        *    end = -1
+        *    result => { { 'a' }, { 'b' } }
+        * </pre>
+        * </li>
+        * </ol>
+        *  
+        * @param array the given array
+        * @param start the given starting index
+        * @param end the given ending index
+        * @return a new array which is a copy of the given array starting at the given start and 
+        * ending at the given end
+        * @exception NullPointerException if the given array is null
+        */
+       public static final char[][] subarray(char[][] array, int start, int end) {
+               if (end == -1)
+                       end = array.length;
+               if (start > end)
+                       return null;
+               if (start < 0)
+                       return null;
+               if (end > array.length)
+                       return null;
+
+               char[][] result = new char[end - start][];
+               System.arraycopy(array, start, result, 0, end - start);
+               return result;
+       }
+
+       /**
+        * Answers a new array which is a copy of the given array starting at the given start and 
+        * ending at the given end. The given start is inclusive and the given end is exclusive.
+        * Answers null if start is greater than end, if start is lower than 0 or if end is greater 
+        * than the length of the given array. If end  equals -1, it is converted to the array length.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { 'a' , 'b' }
+        *    start = 0
+        *    end = 1
+        *    result => { 'a' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'a', 'b' }
+        *    start = 0
+        *    end = -1
+        *    result => { 'a' , 'b' }
+        * </pre>
+        * </li>
+        * </ol>
+        *  
+        * @param array the given array
+        * @param start the given starting index
+        * @param end the given ending index
+        * @return a new array which is a copy of the given array starting at the given start and 
+        * ending at the given end
+        * @exception NullPointerException if the given array is null
+        */
+       public static final char[] subarray(char[] array, int start, int end) {
+               if (end == -1)
+                       end = array.length;
+               if (start > end)
+                       return null;
+               if (start < 0)
+                       return null;
+               if (end > array.length)
+                       return null;
+
+               char[] result = new char[end - start];
+               System.arraycopy(array, start, result, 0, end - start);
+               return result;
+       }
+       /**
+        * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null.
+        * <br>
+        * NOTE: if no conversion was necessary, then answers back the argument one.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    chars = { 'a' , 'b' }
+        *    result => { 'a' , 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'A', 'b' }
+        *    result => { 'a' , 'b' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param chars the chars to convert
+        * @return the result of a char[] conversion to lowercase
+        */
+       final static public char[] toLowerCase(char[] chars) {
+               if (chars == null)
+                       return null;
+               int length = chars.length;
+               char[] lowerChars = null;
+               for (int i = 0; i < length; i++) {
+                       char c = chars[i];
+                       char lc = Character.toLowerCase(c);
+                       if ((c != lc) || (lowerChars != null)) {
+                               if (lowerChars == null) {
+                                       System.arraycopy(
+                                               chars,
+                                               0,
+                                               lowerChars = new char[length],
+                                               0,
+                                               i);
+                               }
+                               lowerChars[i] = lc;
+                       }
+               }
+               return lowerChars == null ? chars : lowerChars;
+       }
+
+       /**
+        * Answers a new array removing leading and trailing spaces (' '). Answers the given array if there is no
+        * space characters to remove.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    chars = { ' ', 'a' , 'b', ' ',  ' ' }
+        *    result => { 'a' , 'b' }
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { 'A', 'b' }
+        *    result => { 'A' , 'b' }
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param chars the given array
+        * @return a new array removing leading and trailing spaces (' ')
+        */
+       final static public char[] trim(char[] chars) {
+
+               if (chars == null)
+                       return null;
+
+               int start = 0, length = chars.length, end = length - 1;
+               while (start < length && chars[start] == ' ') {
+                       start++;
+               }
+               while (end > start && chars[end] == ' ') {
+                       end--;
+               }
+               if (start != 0 || end != length - 1) {
+                       return subarray(chars, start, end + 1);
+               }
+               return chars;
+       }
+
+       /**
+        * Answers a string which is the concatenation of the given array using the '.' as a separator.
+        * <br>
+        * <br>
+        * For example:
+        * <ol>
+        * <li><pre>
+        *    array = { { 'a' } , { 'b' } }
+        *    result => "a.b"
+        * </pre>
+        * </li>
+        * <li><pre>
+        *    array = { { ' ',  'a' } , { 'b' } }
+        *    result => " a.b"
+        * </pre>
+        * </li>
+        * </ol>
+        * 
+        * @param chars the given array
+        * @return a string which is the concatenation of the given array using the '.' as a separator
+        */
+       final static public String toString(char[][] array) {
+               char[] result = concatWith(array, '.');
+               return new String(result);
+       }
+}
index c77f43c..cd6ad90 100644 (file)
@@ -37,7 +37,8 @@ public interface ITerminalSymbols {
   public final static int TokenNameWHITESPACE = 900,
     TokenNameCOMMENT_LINE = 901,
     TokenNameCOMMENT_BLOCK = 902,
-    TokenNameCOMMENT_PHPDOC = 903;
+    TokenNameCOMMENT_PHPDOC = 903,
+    TokenNameHTML = 904;
 
   final static int TokenNameEOF = 0;
   final static int TokenNameERROR = 1;
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ConfigurableOption.java
new file mode 100644 (file)
index 0000000..08a9d96
--- /dev/null
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package net.sourceforge.phpdt.internal.compiler;
+
+/**
+ * Generic option description, which can be modified independently from the
+ * component it belongs to.
+ * 
+ * @deprecated backport 1.0 internal functionality
+ */
+
+import java.util.*;
+
+public class ConfigurableOption {
+       private String componentName;
+       private String optionName;
+       private int id;
+
+       private String category;
+       private String name;
+       private String description;
+       private int currentValueIndex;
+       private int defaultValueIndex;
+       private String[] possibleValues;
+
+       // special value for <possibleValues> indicating that 
+       // the <currentValueIndex> is the actual value
+       public final static String[] NoDiscreteValue = {}; 
+/**
+ * INTERNAL USE ONLY
+ *
+ * Initialize an instance of this class according to a specific locale
+ *
+ * @param loc java.util.Locale
+ */
+public ConfigurableOption(
+       String componentName, 
+       String optionName, 
+       Locale loc, 
+       int currentValueIndex) {
+
+       this.componentName = componentName;
+       this.optionName = optionName;
+       this.currentValueIndex = currentValueIndex;
+               
+       ResourceBundle resource = null;
+       try {
+               String location = componentName.substring(0, componentName.lastIndexOf('.'));
+               resource = ResourceBundle.getBundle(location + ".Options", loc); //$NON-NLS-1$
+       } catch (MissingResourceException e) {
+               category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+               name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+               description = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+               possibleValues = new String[0];
+               id = -1;
+       }
+       if (resource == null) return;
+       try {
+               id = Integer.parseInt(resource.getString(optionName + ".number")); //$NON-NLS-1$
+       } catch (MissingResourceException e) {
+               id = -1;
+       } catch (NumberFormatException e) {
+               id = -1;
+       }
+       try {
+               category = resource.getString(optionName + ".category"); //$NON-NLS-1$
+       } catch (MissingResourceException e) {
+               category = "Missing ressources entries for" + componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       try {
+               name = resource.getString(optionName + ".name"); //$NON-NLS-1$
+       } catch (MissingResourceException e) {
+               name = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       try {
+               StringTokenizer tokenizer = new StringTokenizer(resource.getString(optionName + ".possibleValues"), "|"); //$NON-NLS-1$ //$NON-NLS-2$
+               int numberOfValues = Integer.parseInt(tokenizer.nextToken());
+               if(numberOfValues == -1){
+                       possibleValues = NoDiscreteValue;
+               } else {
+                       possibleValues = new String[numberOfValues];
+                       int index = 0;
+                       while (tokenizer.hasMoreTokens()) {
+                               possibleValues[index] = tokenizer.nextToken();
+                               index++;
+                       }
+               }
+       } catch (MissingResourceException e) {
+               possibleValues = new String[0];
+       } catch (NoSuchElementException e) {
+               possibleValues = new String[0];
+       } catch (NumberFormatException e) {
+               possibleValues = new String[0];
+       }
+       try {
+               description = resource.getString(optionName + ".description");  //$NON-NLS-1$
+       } catch (MissingResourceException e) {
+               description = "Missing ressources entries for"+ componentName + " options"; //$NON-NLS-1$ //$NON-NLS-2$
+       }
+}
+/**
+ * Return a String that represents the localized category of the receiver.
+ * @return java.lang.String
+ */
+public String getCategory() {
+       return category;
+}
+/**
+ * Return a String that identifies the component owner (typically the qualified
+ *     type name of the class which it corresponds to).
+ *
+ * e.g. "org.phpeclipse.phpdt.internal.compiler.api.Compiler"
+ *
+ * @return java.lang.String
+ */
+public String getComponentName() {
+       return componentName;
+}
+/**
+ * Answer the index (in possibleValues array) of the current setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+public int getCurrentValueIndex() {
+       return currentValueIndex;
+}
+/**
+ * Answer the index (in possibleValues array) of the default setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+public int getDefaultValueIndex() {
+       return defaultValueIndex;
+}
+/**
+ * Return an String that represents the localized description of the receiver.
+ *
+ * @return java.lang.String
+ */
+public String getDescription() {
+       return description;
+}
+/**
+ * Internal ID which allows the configurable component to identify this particular option.
+ *
+ * @return int
+ */
+public int getID() {
+       return id;
+}
+/**
+ * Return a String that represents the localized name of the receiver.
+ * @return java.lang.String
+ */
+public String getName() {
+       return name;
+}
+/**
+ * Return an array of String that represents the localized possible values of the receiver.
+ * @return java.lang.String[]
+ */
+public String[] getPossibleValues() {
+       return possibleValues;
+}
+/**
+ * Change the index (in possibleValues array) of the current setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+public void setValueIndex(int newIndex) {
+       currentValueIndex = newIndex;
+}
+public String toString() {
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("Configurable option for "); //$NON-NLS-1$ 
+       buffer.append(this.componentName).append("\n"); //$NON-NLS-1$ 
+       buffer.append("- category:                      ").append(this.category).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+       buffer.append("- name:                          ").append(this.name).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+       /* display current value */
+       buffer.append("- current value: "); //$NON-NLS-1$ 
+       if (possibleValues == NoDiscreteValue){
+               buffer.append(this.currentValueIndex);
+       } else {
+               buffer.append(this.possibleValues[this.currentValueIndex]);
+       }
+       buffer.append("\n"); //$NON-NLS-1$ 
+       
+       /* display possible values */
+       if (possibleValues != NoDiscreteValue){
+               buffer.append("- possible values:       ["); //$NON-NLS-1$ 
+               for (int i = 0, max = possibleValues.length; i < max; i++) {
+                       if (i != 0)
+                               buffer.append(", "); //$NON-NLS-1$ 
+                       buffer.append(possibleValues[i]);
+               }
+               buffer.append("]\n"); //$NON-NLS-1$ 
+               buffer.append("- curr. val. index:      ").append(currentValueIndex).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       buffer.append("- description:           ").append(description).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+       return buffer.toString();
+}
+       /**
+        * Gets the optionName.
+        * @return Returns a String
+        */
+       public String getOptionName() {
+               return optionName;
+       }
+}
index 04c3935..83f8e87 100644 (file)
@@ -719,9 +719,10 @@ public class Scanner implements IScanner, ITerminalSymbols {
   }
 
   public int getNextToken() throws InvalidInputException {
+
     try {
+      int htmlPosition = currentPosition;
       while (!phpMode) {
-        startPosition = currentPosition;
         currentCharacter = source[currentPosition++];
         if (currentCharacter == '<') {
           if (getNextChar('?')) {
@@ -731,6 +732,12 @@ public class Scanner implements IScanner, ITerminalSymbols {
               // <?
               startPosition = currentPosition;
               phpMode = true;
+              if (tokenizeWhiteSpace) {
+                // && (whiteStart != currentPosition - 1)) {
+                // reposition scanner in case we are interested by spaces as tokens
+                startPosition = htmlPosition;
+                return TokenNameHTML;
+              }
             } else {
               boolean phpStart =
                 (currentCharacter == 'P') || (currentCharacter == 'p');
@@ -742,6 +749,13 @@ public class Scanner implements IScanner, ITerminalSymbols {
                     // <?PHP  <?php
                     startPosition = currentPosition;
                     phpMode = true;
+
+                    if (tokenizeWhiteSpace) {
+                      // && (whiteStart != currentPosition - 1)) {
+                      // reposition scanner in case we are interested by spaces as tokens
+                      startPosition = htmlPosition;
+                      return TokenNameHTML;
+                    }
                   }
                 }
               }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/codemanipulation/StubUtility.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/codemanipulation/StubUtility.java
new file mode 100644 (file)
index 0000000..37eee59
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.corext.codemanipulation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+//import org.phpeclipse.phpdt.core.Flags;
+//import org.phpeclipse.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.ICodeFormatter;
+//import org.phpeclipse.phpdt.core.ICompilationUnit;
+//import org.phpeclipse.phpdt.core.IJavaElement;
+//import org.phpeclipse.phpdt.core.IJavaProject;
+//import org.phpeclipse.phpdt.core.IMethod;
+//import org.phpeclipse.phpdt.core.IParent;
+//import org.phpeclipse.phpdt.core.ISourceReference;
+//import org.phpeclipse.phpdt.core.IType;
+//import org.phpeclipse.phpdt.core.ITypeHierarchy;
+import net.sourceforge.phpeclipse.PHPCore;
+//import org.phpeclipse.phpdt.core.JavaModelException;
+//import org.phpeclipse.phpdt.core.Signature;
+import net.sourceforge.phpdt.core.ToolFactory;
+
+//import net.sourceforge.phpdt.internal.corext.util.CodeFormatterUtil;
+//import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+
+public class StubUtility {
+       
+       
+//     public static class GenStubSettings extends CodeGenerationSettings {
+//     
+//             public boolean callSuper;
+//             public boolean methodOverwrites;
+//             public boolean noBody;
+//             
+//             public GenStubSettings(CodeGenerationSettings settings) {
+//                     settings.setSettings(this);     
+//             }
+//             
+//             public GenStubSettings() {
+//             }
+//                     
+//     }
+//     
+//
+//     /**
+//      * Generates a stub. Given a template method, a stub with the same signature
+//      * will be constructed so it can be added to a type.
+//      * @param destTypeName The name of the type to which the method will be added to (Used for the constructor)
+//      * @param method A method template (method belongs to different type than the parent)
+//      * @param options Options as defined above (<code>GenStubSettings</code>)
+//      * @param imports Imports required by the stub are added to the imports structure. If imports structure is <code>null</code>
+//      * all type names are qualified.
+//      * @throws JavaModelException
+//      */
+//     public static String genStub(String destTypeName, IMethod method, GenStubSettings settings, IImportsStructure imports) throws JavaModelException {
+//             IType declaringtype= method.getDeclaringType(); 
+//             StringBuffer buf= new StringBuffer();
+//             String methodName= method.getElementName();
+//             String[] paramTypes= method.getParameterTypes();
+//             String[] paramNames= method.getParameterNames();
+//             String[] excTypes= method.getExceptionTypes();
+//             String retTypeSig= method.getReturnType();
+//             int flags= method.getFlags();
+//             boolean isConstructor= method.isConstructor();
+//             
+//             int lastParam= paramTypes.length -1;            
+//             
+//             
+//             if (settings.createComments) {
+//                     if (isConstructor) {
+//                             String desc= "Constructor for " + destTypeName; //$NON-NLS-1$
+//                             genJavaDocStub(desc, paramNames, Signature.SIG_VOID, excTypes, buf);
+//                     } else {                        
+//                             // php doc
+//                             if (settings.methodOverwrites) {
+//                                     boolean isDeprecated= Flags.isDeprecated(flags);
+//                                     genJavaDocSeeTag(declaringtype, methodName, paramTypes, settings.createNonJavadocComments, isDeprecated, buf);
+//                             } else {
+//                                     // generate a default php doc comment
+//                                     String desc= "Method " + methodName; //$NON-NLS-1$
+//                                     genJavaDocStub(desc, paramNames, retTypeSig, excTypes, buf);
+//                             }
+//                     }
+//                     buf.append('\n');
+//             }
+//             
+//             if (Flags.isPublic(flags) || isConstructor || (declaringtype.isInterface() && !settings.noBody)) {
+//                     buf.append("public "); //$NON-NLS-1$
+//             } else if (Flags.isProtected(flags)) {
+//                     buf.append("protected "); //$NON-NLS-1$
+//             } else if (Flags.isPrivate(flags)) {
+//                     buf.append("private "); //$NON-NLS-1$
+//             }
+//             if (Flags.isSynchronized(flags)) {
+//                     buf.append("synchronized "); //$NON-NLS-1$
+//             }               
+//             if (Flags.isVolatile(flags)) {
+//                     buf.append("volatile "); //$NON-NLS-1$
+//             }
+//             if (Flags.isStrictfp(flags)) {
+//                     buf.append("strictfp "); //$NON-NLS-1$
+//             }
+//             if (Flags.isStatic(flags)) {
+//                     buf.append("static "); //$NON-NLS-1$
+//             }               
+//                     
+//             if (isConstructor) {
+//                     buf.append(destTypeName);
+//             } else {
+//                     String retTypeFrm;
+//                     if (!isPrimitiveType(retTypeSig)) {
+//                             retTypeFrm= resolveAndAdd(retTypeSig, declaringtype, imports);
+//                     } else {
+//                             retTypeFrm= Signature.toString(retTypeSig);
+//                     }
+//                     buf.append(retTypeFrm);
+//                     buf.append(' ');
+//                     buf.append(methodName);
+//             }
+//             buf.append('(');
+//             for (int i= 0; i <= lastParam; i++) {
+//                     String paramTypeSig= paramTypes[i];
+//                     String paramTypeFrm;
+//                     
+//                     if (!isPrimitiveType(paramTypeSig)) {
+//                             paramTypeFrm= resolveAndAdd(paramTypeSig, declaringtype, imports);
+//                     } else {
+//                             paramTypeFrm= Signature.toString(paramTypeSig);
+//                     }
+//                     buf.append(paramTypeFrm);
+//                     buf.append(' ');
+//                     buf.append(paramNames[i]);
+//                     if (i < lastParam) {
+//                             buf.append(", "); //$NON-NLS-1$
+//                     }
+//             }
+//             buf.append(')');
+//             
+//             int lastExc= excTypes.length - 1;
+//             if (lastExc >= 0) {
+//                     buf.append(" throws "); //$NON-NLS-1$
+//                     for (int i= 0; i <= lastExc; i++) {
+//                             String excTypeSig= excTypes[i];
+//                             String excTypeFrm= resolveAndAdd(excTypeSig, declaringtype, imports);
+//                             buf.append(excTypeFrm);
+//                             if (i < lastExc) {
+//                                     buf.append(", "); //$NON-NLS-1$
+//                             }
+//                     }
+//             }
+//             if (settings.noBody) {
+//                     buf.append(";\n\n"); //$NON-NLS-1$
+//             } else {
+//                     buf.append(" {\n\t"); //$NON-NLS-1$
+//                     if (!settings.callSuper) {
+//                             if (retTypeSig != null && !retTypeSig.equals(Signature.SIG_VOID)) {
+//                                     buf.append('\t');
+//                                     if (!isPrimitiveType(retTypeSig) || Signature.getArrayCount(retTypeSig) > 0) {
+//                                             buf.append("return null;\n\t"); //$NON-NLS-1$
+//                                     } else if (retTypeSig.equals(Signature.SIG_BOOLEAN)) {
+//                                             buf.append("return false;\n\t"); //$NON-NLS-1$
+//                                     } else {
+//                                             buf.append("return 0;\n\t"); //$NON-NLS-1$
+//                                     }
+//                             }
+//                     } else {
+//                             buf.append('\t');
+//                             if (!isConstructor) {
+//                                     if (!Signature.SIG_VOID.equals(retTypeSig)) {
+//                                             buf.append("return "); //$NON-NLS-1$
+//                                     }
+//                                     buf.append("super."); //$NON-NLS-1$
+//                                     buf.append(methodName);
+//                             } else {
+//                                     buf.append("super"); //$NON-NLS-1$
+//                             }
+//                             buf.append('(');                        
+//                             for (int i= 0; i <= lastParam; i++) {
+//                                     buf.append(paramNames[i]);
+//                                     if (i < lastParam) {
+//                                             buf.append(", "); //$NON-NLS-1$
+//                                     }
+//                             }
+//                             buf.append(");\n\t"); //$NON-NLS-1$
+//                     }
+//                     buf.append("}\n");                       //$NON-NLS-1$
+//             }
+//             return buf.toString();
+//     }
+//     
+//     private static boolean isSet(int options, int flag) {
+//             return (options & flag) != 0;
+//     }       
+//
+//     private static boolean isPrimitiveType(String typeName) {
+//             char first= Signature.getElementType(typeName).charAt(0);
+//             return (first != Signature.C_RESOLVED && first != Signature.C_UNRESOLVED);
+//     }
+//
+//     private static String resolveAndAdd(String refTypeSig, IType declaringType, IImportsStructure imports) throws JavaModelException {
+//             String resolvedTypeName= JavaModelUtil.getResolvedTypeName(refTypeSig, declaringType);
+//             if (resolvedTypeName != null) {
+//                     StringBuffer buf= new StringBuffer();
+//                     if (imports != null) {
+//                             buf.append(imports.addImport(resolvedTypeName));
+//                     } else {
+//                             buf.append(resolvedTypeName);
+//                     }
+//                     int arrayCount= Signature.getArrayCount(refTypeSig);
+//                     for (int i= 0; i < arrayCount; i++) {
+//                             buf.append("[]"); //$NON-NLS-1$
+//                     }
+//                     return buf.toString();
+//             }
+//             return Signature.toString(refTypeSig);
+//     }
+//     
+//     /**
+//      * Generates a default JavaDoc comment stub for a method.
+//      */
+//     public static void genJavaDocStub(String descr, String[] paramNames, String retTypeSig, String[] excTypeSigs, StringBuffer buf) {
+//             buf.append("/**\n"); //$NON-NLS-1$
+//             buf.append(" * "); buf.append(descr); buf.append(".\n"); //$NON-NLS-2$ //$NON-NLS-1$
+//             for (int i= 0; i < paramNames.length; i++) {
+//                     buf.append(" * @param "); buf.append(paramNames[i]); buf.append('\n'); //$NON-NLS-1$
+//             }
+//             if (retTypeSig != null && !retTypeSig.equals(Signature.SIG_VOID)) {
+//                     String simpleName= Signature.getSimpleName(Signature.toString(retTypeSig));
+//                     buf.append(" * @return "); buf.append(simpleName); buf.append('\n'); //$NON-NLS-1$
+//             }
+//             if (excTypeSigs != null) {
+//                     for (int i= 0; i < excTypeSigs.length; i++) {
+//                             String simpleName= Signature.getSimpleName(Signature.toString(excTypeSigs[i]));
+//                             buf.append(" * @throws "); buf.append(simpleName); buf.append('\n'); //$NON-NLS-1$
+//                     }
+//             }
+//             buf.append(" */"); //$NON-NLS-1$
+//     }
+//     
+//     /**
+//      * Generates a '@see' tag to the defined method.
+//      */
+//     public static void genJavaDocSeeTag(IType declaringType, String methodName, String[] paramTypes, boolean nonJavaDocComment, boolean isDeprecated, StringBuffer buf) throws JavaModelException {
+//             String[] fullParamNames= new String[paramTypes.length];
+//             for (int i= 0; i < paramTypes.length; i++) {
+//                     fullParamNames[i]= JavaModelUtil.getResolvedTypeName(paramTypes[i], declaringType);
+//             }
+//             String fullTypeName= JavaModelUtil.getFullyQualifiedName(declaringType);
+//             
+//             genJavaDocSeeTag(fullTypeName, methodName, fullParamNames, nonJavaDocComment, isDeprecated, buf);
+//     }
+//     
+//     /**
+//      * Generates a '@see' tag to the defined method.
+//      */
+//     public static void genJavaDocSeeTag(String fullyQualifiedTypeName, String methodName, String[] fullParamTypeNames, boolean nonJavaDocComment, boolean isDeprecated, StringBuffer buf) throws JavaModelException {
+//             // create a @see link
+//             buf.append("/*"); //$NON-NLS-1$
+//             if (!nonJavaDocComment) {
+//                     buf.append('*');
+//             } else {
+//                     buf.append(" (non-Javadoc)"); //$NON-NLS-1$
+//             }
+//             buf.append("\n * @see "); //$NON-NLS-1$
+//             buf.append(fullyQualifiedTypeName);
+//             buf.append('#'); 
+//             buf.append(methodName);
+//             buf.append('(');
+//             for (int i= 0; i < fullParamTypeNames.length; i++) {
+//                     if (i > 0) {
+//                             buf.append(", "); //$NON-NLS-1$
+//                     }
+//                     buf.append(fullParamTypeNames[i]);
+//             }
+//             buf.append(")\n"); //$NON-NLS-1$
+//             if (isDeprecated) {
+//                     buf.append(" * @deprecated\n"); //$NON-NLS-1$
+//             }
+//             buf.append(" */"); //$NON-NLS-1$
+//     }       
+//     
+//     
+//
+//     /**
+//      * Finds a method in a list of methods.
+//      * @return The found method or null, if nothing found
+//      */
+//     private static IMethod findMethod(IMethod method, List allMethods) throws JavaModelException {
+//             String name= method.getElementName();
+//             String[] paramTypes= method.getParameterTypes();
+//             boolean isConstructor= method.isConstructor();
+//
+//             for (int i= allMethods.size() - 1; i >= 0; i--) {
+//                     IMethod curr= (IMethod) allMethods.get(i);
+//                     if (JavaModelUtil.isSameMethodSignature(name, paramTypes, isConstructor, curr)) {
+//                             return curr;
+//                     }                       
+//             }
+//             return null;
+//     }
+
+
+       /**
+        * Creates needed constructors for a type.
+        * @param type The type to create constructors for
+        * @param supertype The type's super type
+        * @param settings Options for comment generation
+        * @param imports Required imports are added to the import structure. Structure can be <code>null</code>, types are qualified then.
+        * @return Returns the generated stubs or <code>null</code> if the creation has been canceled
+        */
+//     public static String[] evalConstructors(IType type, IType supertype, CodeGenerationSettings settings, IImportsStructure imports) throws JavaModelException {
+//             IMethod[] superMethods= supertype.getMethods();
+//             String typeName= type.getElementName();
+//             IMethod[] methods= type.getMethods();
+//             GenStubSettings genStubSettings= new GenStubSettings(settings);
+//             genStubSettings.callSuper= true;
+//             ArrayList newMethods= new ArrayList(superMethods.length);
+//             for (int i= 0; i < superMethods.length; i++) {
+//                     IMethod curr= superMethods[i];
+//                     if (curr.isConstructor() && (JavaModelUtil.isVisible(curr, type.getPackageFragment()) || Flags.isProtected(curr.getFlags()))) {
+//                             if (JavaModelUtil.findMethod(typeName, curr.getParameterTypes(), true, methods) == null) {
+//                                     String newStub= genStub(typeName, superMethods[i], genStubSettings, imports);
+//                                     newMethods.add(newStub);
+//                             }
+//                     }
+//             }
+//             return (String[]) newMethods.toArray(new String[newMethods.size()]);
+//     }
+//
+//     /**
+//      * Searches for unimplemented methods of a type.
+//      * @param isSubType If set, the evaluation is for a subtype of the given type. If not set, the
+//      * evaluation is for the type itself.
+//      * @param settings Options for comment generation
+//      * @param selectionQuery If not null will select the methods to implement.
+//      * @param imports Required imports are added to the import structure. Structure can be <code>null</code>, types are qualified then.
+//      * @return Returns the generated stubs or <code>null</code> if the creation has been canceled
+//      */
+//     public static String[] evalUnimplementedMethods(IType type, ITypeHierarchy hierarchy, boolean isSubType, CodeGenerationSettings settings, 
+//                             IOverrideMethodQuery selectionQuery, IImportsStructure imports) throws JavaModelException {
+//             List allMethods= new ArrayList();
+//             List toImplement= new ArrayList();
+//
+//             IMethod[] typeMethods= type.getMethods();
+//             for (int i= 0; i < typeMethods.length; i++) {
+//                     IMethod curr= typeMethods[i];
+//                     if (!curr.isConstructor() && !Flags.isStatic(curr.getFlags()) && !Flags.isPrivate(curr.getFlags())) {
+//                             allMethods.add(curr);
+//                     }
+//             }
+//
+//             IType[] superTypes= hierarchy.getAllSuperclasses(type);
+//             for (int i= 0; i < superTypes.length; i++) {
+//                     IMethod[] methods= superTypes[i].getMethods();
+//                     for (int k= 0; k < methods.length; k++) {
+//                             IMethod curr= methods[k];
+//                             if (!curr.isConstructor() && !Flags.isStatic(curr.getFlags()) && !Flags.isPrivate(curr.getFlags())) {
+//                                     if (findMethod(curr, allMethods) == null) {
+//                                             allMethods.add(curr);
+//                                     }
+//                             }
+//                     }
+//             }
+//
+//             // do not call super
+//             for (int i= 0; i < allMethods.size(); i++) {
+//                     IMethod curr= (IMethod) allMethods.get(i);
+//                     if ((Flags.isAbstract(curr.getFlags()) || curr.getDeclaringType().isInterface()) && (isSubType || !type.equals(curr.getDeclaringType()))) {
+//                             // implement all abstract methods
+//                             toImplement.add(curr);
+//                     }
+//             }
+//
+//             IType[] superInterfaces= hierarchy.getAllSuperInterfaces(type);
+//             for (int i= 0; i < superInterfaces.length; i++) {
+//                     IMethod[] methods= superInterfaces[i].getMethods();
+//                     for (int k= 0; k < methods.length; k++) {
+//                             IMethod curr= methods[k];
+//
+//                             // binary interfaces can contain static initializers (variable intializations)
+//                             // 1G4CKUS
+//                             if (!Flags.isStatic(curr.getFlags())) {
+//                                     IMethod impl= findMethod(curr, allMethods);
+//                                     if (impl == null || ((curr.getExceptionTypes().length < impl.getExceptionTypes().length) && !Flags.isFinal(impl.getFlags()))) {
+//                                             if (impl != null) {
+//                                                     allMethods.remove(impl);
+//                                             }
+//                                             // implement an interface method when it does not exist in the hierarchy
+//                                             // or when it throws less exceptions that the implemented
+//                                             toImplement.add(curr);
+//                                             allMethods.add(curr);
+//                                     }
+//                             }
+//                     }
+//             }
+//             IMethod[] toImplementArray= (IMethod[]) toImplement.toArray(new IMethod[toImplement.size()]);
+//             if (selectionQuery != null) {
+//                     if (!isSubType) {
+//                             allMethods.removeAll(Arrays.asList(typeMethods));
+//                     }
+//                     // remove finals
+//                     for (int i= allMethods.size() - 1; i >= 0; i--) {
+//                             IMethod curr= (IMethod) allMethods.get(i);
+//                             if (Flags.isFinal(curr.getFlags())) {
+//                                     allMethods.remove(i);
+//                             }
+//                     }
+//                     IMethod[] choice= (IMethod[]) allMethods.toArray(new IMethod[allMethods.size()]);
+//                     toImplementArray= selectionQuery.select(choice, toImplementArray, hierarchy);
+//                     if (toImplementArray == null) {
+//                             //cancel pressed
+//                             return null;
+//                     }
+//             }
+//             GenStubSettings genStubSettings= new GenStubSettings(settings);
+//             genStubSettings.methodOverwrites= true;
+//             String[] result= new String[toImplementArray.length];
+//             for (int i= 0; i < toImplementArray.length; i++) {
+//                     IMethod curr= toImplementArray[i];
+//                     IMethod overrides= JavaModelUtil.findMethodImplementationInHierarchy(hierarchy, type, curr.getElementName(), curr.getParameterTypes(), curr.isConstructor());
+//                     genStubSettings.callSuper= (overrides != null);
+//                                             
+//                     IMethod desc= JavaModelUtil.findMethodDeclarationInHierarchy(hierarchy, type, curr.getElementName(), curr.getParameterTypes(), curr.isConstructor());
+//                     if (desc != null) {
+//                             curr= desc;
+//                     }
+//                     result[i]= genStub(type.getElementName(), curr, genStubSettings, imports);
+//             }
+//             return result;
+//     }
+
+       /**
+        * Examines a string and returns the first line delimiter found.
+        */
+//     public static String getLineDelimiterUsed(IJavaElement elem) throws JavaModelException {
+//             ICompilationUnit cu= (ICompilationUnit) elem.getAncestor(IJavaElement.COMPILATION_UNIT);
+//             if (cu != null && cu.exists()) {
+//                     IBuffer buf= cu.getBuffer();
+//                     int length= buf.getLength();
+//                     for (int i= 0; i < length; i++) {
+//                             char ch= buf.getChar(i);
+//                             if (ch == SWT.CR) {
+//                                     if (i + 1 < length) {
+//                                             if (buf.getChar(i + 1) == SWT.LF) {
+//                                                     return "\r\n"; //$NON-NLS-1$
+//                                             }
+//                                     }
+//                                     return "\r"; //$NON-NLS-1$
+//                             } else if (ch == SWT.LF) {
+//                                     return "\n"; //$NON-NLS-1$
+//                             }
+//                     }
+//             }
+//             return System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+//     }
+
+       /**
+        * Embodies the policy which line delimiter to use when inserting into
+        * a document.
+        */     
+       public static String getLineDelimiterFor(IDocument doc) {
+               // new for: 1GF5UU0: ITPJUI:WIN2000 - "Organize Imports" in php editor inserts lines in wrong format
+               String lineDelim= null;
+               try {
+                       lineDelim= doc.getLineDelimiter(0);
+               } catch (BadLocationException e) {
+               }
+               if (lineDelim == null) {
+                       String systemDelimiter= System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       String[] lineDelims= doc.getLegalLineDelimiters();
+                       for (int i= 0; i < lineDelims.length; i++) {
+                               if (lineDelims[i].equals(systemDelimiter)) {
+                                       lineDelim= systemDelimiter;
+                                       break;
+                               }
+                       }
+                       if (lineDelim == null) {
+                               lineDelim= lineDelims.length > 0 ? lineDelims[0] : systemDelimiter;
+                       }
+               }
+               return lineDelim;
+       }
+
+
+       /**
+        * Evaluates the indention used by a Java element. (in tabulators)
+        */     
+//     public static int getIndentUsed(IJavaElement elem) throws JavaModelException {
+//             if (elem instanceof ISourceReference) {
+//                     ICompilationUnit cu= (ICompilationUnit) elem.getAncestor(IJavaElement.COMPILATION_UNIT);
+//                     if (cu != null) {
+//                             IBuffer buf= cu.getBuffer();
+//                             int offset= ((ISourceReference)elem).getSourceRange().getOffset();
+//                             int i= offset;
+//                             // find beginning of line
+//                             while (i > 0 && !Strings.isLineDelimiterChar(buf.getChar(i - 1)) ){
+//                                     i--;
+//                             }
+//                             return Strings.computeIndent(buf.getText(i, offset - i), CodeFormatterUtil.getTabWidth());
+//                     }
+//             }
+//             return 0;
+//     }
+       
+       public static String codeFormat(String sourceString, int initialIndentationLevel, String lineDelim) {
+               ICodeFormatter formatter= ToolFactory.createDefaultCodeFormatter(null);
+               return formatter.format(sourceString, initialIndentationLevel, null, lineDelim);
+       }
+       
+       /**
+        * Returns the element after the give element.
+        */
+//     public static IJavaElement findNextSibling(IJavaElement member) throws JavaModelException {
+//             IJavaElement parent= member.getParent();
+//             if (parent instanceof IParent) {
+//                     IJavaElement[] elements= ((IParent)parent).getChildren();
+//                     for (int i= elements.length - 2; i >= 0 ; i--) {
+//                             if (member.equals(elements[i])) {
+//                                     return elements[i+1];
+//                             }
+//                     }
+//             }
+//             return null;
+//     }
+//     
+//     public static String getTodoTaskTag(IJavaProject project) {
+//             String markers= null;
+//             if (project == null) {
+//                     markers= JavaCore.getOption(JavaCore.COMPILER_TASK_TAGS);
+//             } else {
+//                     markers= project.getOption(JavaCore.COMPILER_TASK_TAGS, true);
+//             }
+//             
+//             if (markers != null && markers.length() > 0) {
+//                     int idx= markers.indexOf(',');
+//                     if (idx == -1) {
+//                             return markers;
+//                     } else {
+//                             return markers.substring(0, idx);
+//                     }
+//             }
+//             return null;
+//     }
+
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusUtil.java
new file mode 100644 (file)
index 0000000..ce895ca
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.jface.dialogs.DialogPage;
+
+/**
+ * A utility class to work with IStatus.
+ */
+public class StatusUtil {
+
+       /**
+        * Compares two instances of <code>IStatus</code>. The more severe is returned:
+        * An error is more severe than a warning, and a warning is more severe
+        * than ok. If the two stati have the same severity, the second is returned.
+        */
+       public static IStatus getMoreSevere(IStatus s1, IStatus s2) {
+               if (s1.getSeverity() > s2.getSeverity()) {
+                       return s1;
+               } else {
+                       return s2;
+               }
+       }
+
+       /**
+        * Finds the most severe status from a array of stati.
+        * An error is more severe than a warning, and a warning is more severe
+        * than ok.
+        */
+       public static IStatus getMostSevere(IStatus[] status) {
+               IStatus max= null;
+               for (int i= 0; i < status.length; i++) {
+                       IStatus curr= status[i];
+                       if (curr.matches(IStatus.ERROR)) {
+                               return curr;
+                       }
+                       if (max == null || curr.getSeverity() > max.getSeverity()) {
+                               max= curr;
+                       }
+               }
+               return max;
+       }
+               
+       /**
+        * Applies the status to the status line of a dialog page.
+        */
+       public static void applyToStatusLine(DialogPage page, IStatus status) {
+               String message= status.getMessage();
+               switch (status.getSeverity()) {
+                       case IStatus.OK:
+                               page.setMessage(message, DialogPage.NONE);
+                               page.setErrorMessage(null);
+                               break;
+                       case IStatus.WARNING:
+                               page.setMessage(message, DialogPage.WARNING);
+                               page.setErrorMessage(null);
+                               break;                          
+                       case IStatus.INFO:
+                               page.setMessage(message, DialogPage.INFORMATION);
+                               page.setErrorMessage(null);
+                               break;                  
+                       default:
+                               if (message.length() == 0) {
+                                       message= null;
+                               }
+                               page.setMessage(null);
+                               page.setErrorMessage(message);
+                               break;          
+               }
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreferencePage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreferencePage.java
new file mode 100644 (file)
index 0000000..0e8d043
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.preferences;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import net.sourceforge.phpdt.core.ICodeFormatter;
+import net.sourceforge.phpdt.core.ToolFactory;
+import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
+import net.sourceforge.phpdt.internal.ui.dialog.StatusInfo;
+import net.sourceforge.phpdt.internal.ui.dialog.StatusUtil;
+import net.sourceforge.phpdt.internal.ui.util.TabFolderLayout;
+import net.sourceforge.phpeclipse.PHPCore;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/*
+ * The page for setting code formatter options
+ */
+public class CodeFormatterPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+       // Preference store keys, see PHPCore.getOptions
+       private static final String PREF_NEWLINE_OPENING_BRACES= PHPCore.FORMATTER_NEWLINE_OPENING_BRACE; 
+       private static final String PREF_NEWLINE_CONTROL_STATEMENT= PHPCore.FORMATTER_NEWLINE_CONTROL;
+       private static final String PREF_NEWLINE_CLEAR_ALL= PHPCore.FORMATTER_CLEAR_BLANK_LINES;
+       private static final String PREF_NEWLINE_ELSE_IF= PHPCore.FORMATTER_NEWLINE_ELSE_IF;
+       private static final String PREF_NEWLINE_EMPTY_BLOCK= PHPCore.FORMATTER_NEWLINE_EMPTY_BLOCK;
+       private static final String PREF_LINE_SPLIT= PHPCore.FORMATTER_LINE_SPLIT;
+       private static final String PREF_STYLE_COMPACT_ASSIGNEMENT= PHPCore.FORMATTER_COMPACT_ASSIGNMENT;
+       private static final String PREF_TAB_CHAR= PHPCore.FORMATTER_TAB_CHAR;
+       private static final String PREF_TAB_SIZE= PHPCore.FORMATTER_TAB_SIZE;
+
+       // values
+       private static final String INSERT=  PHPCore.INSERT;
+       private static final String DO_NOT_INSERT= PHPCore.DO_NOT_INSERT;
+       
+       private static final String COMPACT= PHPCore.COMPACT;
+       private static final String NORMAL= PHPCore.NORMAL;
+       
+       private static final String TAB= PHPCore.TAB;
+       private static final String SPACE= PHPCore.SPACE;
+       
+       private static final String CLEAR_ALL= PHPCore.CLEAR_ALL;
+       private static final String PRESERVE_ONE= PHPCore.PRESERVE_ONE;
+       
+
+       private static String[] getAllKeys() {
+               return new String[] {
+                       PREF_NEWLINE_OPENING_BRACES, PREF_NEWLINE_CONTROL_STATEMENT, PREF_NEWLINE_CLEAR_ALL,
+                       PREF_NEWLINE_ELSE_IF, PREF_NEWLINE_EMPTY_BLOCK, PREF_LINE_SPLIT,
+                       PREF_STYLE_COMPACT_ASSIGNEMENT, PREF_TAB_CHAR, PREF_TAB_SIZE
+               };      
+       }
+       
+       /**
+        * Gets the currently configured tab size
+        * @deprecated Inline to avoid reference to preference page
+        */
+       public static int getTabSize() {
+               String string= (String) PHPCore.getOptions().get(PREF_TAB_SIZE);
+               return getPositiveIntValue(string, 4);
+       }
+       
+       /**
+        * Gets the current compating assignement configuration
+        * @deprecated Inline to avoid reference to preference page
+        */     
+       public static boolean isCompactingAssignment() {
+               return COMPACT.equals(PHPCore.getOptions().get(PREF_STYLE_COMPACT_ASSIGNEMENT));
+       }
+       
+       /**
+        * Gets the current compating assignement configuration
+        * @deprecated Inline to avoid reference to preference page
+        */     
+       public static boolean useSpaces() {
+               return SPACE.equals(PHPCore.getOptions().get(PREF_TAB_CHAR));
+       }       
+       
+       
+       private static int getPositiveIntValue(String string, int dflt) {
+               try {
+                       int i= Integer.parseInt(string);
+                       if (i >= 0) {
+                               return i;
+                       }
+               } catch (NumberFormatException e) {
+               }
+               return dflt;
+       }       
+               
+       private static class ControlData {
+               private String fKey;
+               private String[] fValues;
+               
+               public ControlData(String key, String[] values) {
+                       fKey= key;
+                       fValues= values;
+               }
+               
+               public String getKey() {
+                       return fKey;
+               }
+               
+               public String getValue(boolean selection) {
+                       int index= selection ? 0 : 1;
+                       return fValues[index];
+               }
+               
+               public String getValue(int index) {
+                       return fValues[index];
+               }               
+               
+               public int getSelection(String value) {
+                       for (int i= 0; i < fValues.length; i++) {
+                               if (value.equals(fValues[i])) {
+                                       return i;
+                               }
+                       }
+                       throw new IllegalArgumentException();
+               }
+       }
+       
+       private Hashtable fWorkingValues;
+
+       private ArrayList fCheckBoxes;
+       private ArrayList fTextBoxes;
+       
+       private SelectionListener fButtonSelectionListener;
+       private ModifyListener fTextModifyListener;
+       
+       private String fPreviewText;
+       private IDocument fPreviewDocument;
+       
+       private Text fTabSizeTextBox;
+       // private SourceViewer fSourceViewer;
+       
+
+       public CodeFormatterPreferencePage() {
+               setPreferenceStore(PHPeclipsePlugin.getDefault().getPreferenceStore());         
+               setDescription(PHPUIMessages.getString("CodeFormatterPreferencePage.description")); //$NON-NLS-1$
+       
+               fWorkingValues= PHPCore.getOptions();
+               fCheckBoxes= new ArrayList();
+               fTextBoxes= new ArrayList();
+               
+               fButtonSelectionListener= new SelectionListener() {
+                       public void widgetDefaultSelected(SelectionEvent e) {}
+
+                       public void widgetSelected(SelectionEvent e) {
+                               if (!e.widget.isDisposed()) {
+                                       controlChanged((Button) e.widget);
+                               }
+                       }
+               };
+               
+               fTextModifyListener= new ModifyListener() {
+                       public void modifyText(ModifyEvent e) {
+                               if (!e.widget.isDisposed()) {
+                                       textChanged((Text) e.widget);
+                               }
+                       }
+               };
+               
+               fPreviewDocument= new Document();
+               fPreviewText= loadPreviewFile("CodeFormatterPreviewCode.txt");  //$NON-NLS-1$   
+       }
+
+       /*
+        * @see IWorkbenchPreferencePage#init()
+        */     
+       public void init(IWorkbench workbench) {
+       }
+
+       /*
+        * @see PreferencePage#createControl(Composite)
+        */
+       public void createControl(Composite parent) {
+               super.createControl(parent);
+//             WorkbenchHelp.setHelp(getControl(), IJavaHelpContextIds.CODEFORMATTER_PREFERENCE_PAGE);
+       }       
+
+       /*
+        * @see PreferencePage#createContents(Composite)
+        */
+       protected Control createContents(Composite parent) {
+               
+               GridLayout layout= new GridLayout();
+               layout.marginHeight= 0;
+               layout.marginWidth= 0;
+               
+               Composite composite= new Composite(parent, SWT.NONE);
+               composite.setLayout(layout);
+                               
+                       
+               TabFolder folder= new TabFolder(composite, SWT.NONE);
+               folder.setLayout(new TabFolderLayout());        
+               folder.setLayoutData(new GridData(GridData.FILL_BOTH));
+               
+               String[] insertNotInsert= new String[] { INSERT, DO_NOT_INSERT };
+               
+               layout= new GridLayout();
+               layout.numColumns= 2;
+               
+               Composite newlineComposite= new Composite(folder, SWT.NULL);
+               newlineComposite.setLayout(layout);
+
+               String label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_opening_braces.label"); //$NON-NLS-1$
+               addCheckBox(newlineComposite, label, PREF_NEWLINE_OPENING_BRACES, insertNotInsert);     
+               
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_control_statement.label"); //$NON-NLS-1$
+               addCheckBox(newlineComposite, label, PREF_NEWLINE_CONTROL_STATEMENT, insertNotInsert);  
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_clear_lines"); //$NON-NLS-1$
+               addCheckBox(newlineComposite, label, PREF_NEWLINE_CLEAR_ALL, new String[] { CLEAR_ALL, PRESERVE_ONE } );        
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_else_if.label"); //$NON-NLS-1$
+               addCheckBox(newlineComposite, label, PREF_NEWLINE_ELSE_IF, insertNotInsert);    
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.newline_empty_block.label"); //$NON-NLS-1$
+               addCheckBox(newlineComposite, label, PREF_NEWLINE_EMPTY_BLOCK, insertNotInsert);        
+               
+               layout= new GridLayout();
+               layout.numColumns= 2;   
+               
+               Composite lineSplittingComposite= new Composite(folder, SWT.NULL);
+               lineSplittingComposite.setLayout(layout);
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.split_line.label"); //$NON-NLS-1$
+               addTextField(lineSplittingComposite, label, PREF_LINE_SPLIT);
+
+               layout= new GridLayout();
+               layout.numColumns= 2;   
+               
+               Composite styleComposite= new Composite(folder, SWT.NULL);
+               styleComposite.setLayout(layout);
+               
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.style_compact_assignement.label"); //$NON-NLS-1$
+               addCheckBox(styleComposite, label, PREF_STYLE_COMPACT_ASSIGNEMENT, new String[] { COMPACT, NORMAL } );          
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.tab_char.label"); //$NON-NLS-1$
+               addCheckBox(styleComposite, label, PREF_TAB_CHAR, new String[] { TAB, SPACE } );                
+
+               label= PHPUIMessages.getString("CodeFormatterPreferencePage.tab_size.label"); //$NON-NLS-1$
+               fTabSizeTextBox= addTextField(styleComposite, label, PREF_TAB_SIZE);            
+
+               TabItem item= new TabItem(folder, SWT.NONE);
+               item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.newline.tabtitle")); //$NON-NLS-1$
+               item.setControl(newlineComposite);
+
+               item= new TabItem(folder, SWT.NONE);
+               item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.linesplit.tabtitle")); //$NON-NLS-1$
+               item.setControl(lineSplittingComposite);
+               
+               item= new TabItem(folder, SWT.NONE);
+               item.setText(PHPUIMessages.getString("CodeFormatterPreferencePage.tab.style.tabtitle")); //$NON-NLS-1$
+               item.setControl(styleComposite);                
+               
+       //      fSourceViewer= createPreview(parent);
+                       
+               updatePreview();
+                                       
+               return composite;
+       }
+       
+//     private SourceViewer createPreview(Composite parent) {
+//             SourceViewer previewViewer= new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
+//             JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools();
+//             previewViewer.configure(new PHPSourceViewerConfiguration(tools, null));
+//             previewViewer.getTextWidget().setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
+//             previewViewer.getTextWidget().setTabs(getPositiveIntValue((String) fWorkingValues.get(PREF_TAB_SIZE), 0));
+//             previewViewer.setEditable(false);
+//             previewViewer.setDocument(fPreviewDocument);
+//             Control control= previewViewer.getControl();
+//             GridData gdata= new GridData(GridData.FILL_BOTH);
+//             gdata.widthHint= convertWidthInCharsToPixels(30);
+//             gdata.heightHint= convertHeightInCharsToPixels(5);
+//             control.setLayoutData(gdata);
+//             return previewViewer;
+//     }
+
+       
+       private Button addCheckBox(Composite parent, String label, String key, String[] values) {
+               ControlData data= new ControlData(key, values);
+               
+               GridData gd= new GridData(GridData.FILL_HORIZONTAL);
+               gd.horizontalSpan= 2;
+               
+               Button checkBox= new Button(parent, SWT.CHECK);
+               checkBox.setText(label);
+               checkBox.setData(data);
+               checkBox.setLayoutData(gd);
+               
+               String currValue= (String)fWorkingValues.get(key);      
+               checkBox.setSelection(data.getSelection(currValue) == 0);
+               checkBox.addSelectionListener(fButtonSelectionListener);
+               
+               fCheckBoxes.add(checkBox);
+               return checkBox;
+       }
+       
+       private Text addTextField(Composite parent, String label, String key) { 
+               Label labelControl= new Label(parent, SWT.NONE);
+               labelControl.setText(label);
+               labelControl.setLayoutData(new GridData());
+                               
+               Text textBox= new Text(parent, SWT.BORDER | SWT.SINGLE);
+               textBox.setData(key);
+               textBox.setLayoutData(new GridData());
+               
+               String currValue= (String)fWorkingValues.get(key);      
+               textBox.setText(String.valueOf(getPositiveIntValue(currValue, 1)));
+               textBox.setTextLimit(3);
+               textBox.addModifyListener(fTextModifyListener);
+
+               GridData gd= new GridData();
+               gd.widthHint= convertWidthInCharsToPixels(5);
+               textBox.setLayoutData(gd);
+
+               fTextBoxes.add(textBox);
+               return textBox;
+       }       
+       
+       private void controlChanged(Button button) {
+               ControlData data= (ControlData) button.getData();
+               boolean selection= button.getSelection();
+               String newValue= data.getValue(selection);      
+               fWorkingValues.put(data.getKey(), newValue);
+               updatePreview();
+               
+               if (PREF_TAB_CHAR.equals(data.getKey())) {
+                       updateStatus(new StatusInfo());
+                       if (selection) {
+                               fTabSizeTextBox.setText((String)fWorkingValues.get(PREF_TAB_SIZE));
+                       }
+               }
+       }
+       
+       private void textChanged(Text textControl) {
+               String key= (String) textControl.getData();
+               String number= textControl.getText();
+               IStatus status= validatePositiveNumber(number);
+               if (!status.matches(IStatus.ERROR)) {
+                       fWorkingValues.put(key, number);
+               }
+//             if (PREF_TAB_SIZE.equals(key)) {
+//                     fSourceViewer.getTextWidget().setTabs(getPositiveIntValue(number, 0));
+//             }                       
+               updateStatus(status);
+               updatePreview();
+       }
+               
+       
+       /*
+        * @see IPreferencePage#performOk()
+        */
+       public boolean performOk() {
+               String[] allKeys= getAllKeys();
+               // preserve other options
+               // store in JCore
+               Hashtable actualOptions= PHPCore.getOptions();
+               for (int i= 0; i < allKeys.length; i++) {
+                       String key= allKeys[i];
+                       String val=  (String) fWorkingValues.get(key);
+                       actualOptions.put(key, val);
+               }
+               PHPCore.setOptions(actualOptions);
+               PHPeclipsePlugin.getDefault().savePluginPreferences();
+               return super.performOk();
+       }       
+       
+       /*
+        * @see PreferencePage#performDefaults()
+        */
+       protected void performDefaults() {
+               fWorkingValues= PHPCore.getDefaultOptions();
+               updateControls();
+               super.performDefaults();
+       }
+
+       private String loadPreviewFile(String filename) {
+               String separator= System.getProperty("line.separator"); //$NON-NLS-1$
+               StringBuffer btxt= new StringBuffer(512);
+               BufferedReader rin= null;
+               try {
+                       rin= new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(filename)));
+                       String line;
+                       while ((line= rin.readLine()) != null) {
+                               btxt.append(line);
+                               btxt.append(separator);
+                       }
+               } catch (IOException io) {
+                       PHPeclipsePlugin.log(io);
+               } finally {
+                       if (rin != null) {
+                               try { rin.close(); } catch (IOException e) {}
+                       }
+               }
+               return btxt.toString();
+       }
+
+
+       private void updatePreview() {
+               ICodeFormatter formatter= ToolFactory.createDefaultCodeFormatter(fWorkingValues);
+               fPreviewDocument.set(formatter.format(fPreviewText, 0, null, "\n")); //$NON-NLS-1$
+       }       
+       
+       private void updateControls() {
+               // update the UI
+               for (int i= fCheckBoxes.size() - 1; i >= 0; i--) {
+                       Button curr= (Button) fCheckBoxes.get(i);
+                       ControlData data= (ControlData) curr.getData();
+                                       
+                       String currValue= (String) fWorkingValues.get(data.getKey());   
+                       curr.setSelection(data.getSelection(currValue) == 0);                   
+               }
+               for (int i= fTextBoxes.size() - 1; i >= 0; i--) {
+                       Text curr= (Text) fTextBoxes.get(i);
+                       String key= (String) curr.getData();            
+                       String currValue= (String) fWorkingValues.get(key);
+                       curr.setText(currValue);
+               }
+       }
+       
+       private IStatus validatePositiveNumber(String number) {
+               StatusInfo status= new StatusInfo();
+               if (number.length() == 0) {
+                       status.setError(PHPUIMessages.getString("CodeFormatterPreferencePage.empty_input")); //$NON-NLS-1$
+               } else {
+                       try {
+                               int value= Integer.parseInt(number);
+                               if (value < 0) {
+                                       status.setError(PHPUIMessages.getFormattedString("CodeFormatterPreferencePage.invalid_input", number)); //$NON-NLS-1$
+                               }
+                       } catch (NumberFormatException e) {
+                               status.setError(PHPUIMessages.getFormattedString("CodeFormatterPreferencePage.invalid_input", number)); //$NON-NLS-1$
+                       }
+               }
+               return status;
+       }
+                       
+       
+       private void updateStatus(IStatus status) {
+               if (!status.matches(IStatus.ERROR)) {
+                       // look if there are more severe errors
+                       for (int i= 0; i < fTextBoxes.size(); i++) {
+                               Text curr= (Text) fTextBoxes.get(i);
+                               if (!(curr == fTabSizeTextBox && usesTabs())) {
+                                       IStatus currStatus= validatePositiveNumber(curr.getText());
+                                       status= StatusUtil.getMoreSevere(currStatus, status);
+                               }
+                       }
+               }       
+               setValid(!status.matches(IStatus.ERROR));
+               StatusUtil.applyToStatusLine(this, status);
+       }
+       
+       private boolean usesTabs() {
+               return TAB.equals(fWorkingValues.get(PREF_TAB_CHAR));
+       }
+               
+
+}
+
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreviewCode.txt b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/CodeFormatterPreviewCode.txt
new file mode 100644 (file)
index 0000000..c4ae226
--- /dev/null
@@ -0,0 +1,16 @@
+{
+
+if (size < currentSize) {
+try {
+size = inStream.available();
+} catch (IOException e) {
+}
+}
+else if (size == currentSize) {
+++size;
+}
+else {
+--size;
+}
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaFormattingStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaFormattingStrategy.java
new file mode 100644 (file)
index 0000000..e2a9d52
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.text.java;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.formatter.IFormattingStrategy;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+import net.sourceforge.phpdt.core.ICodeFormatter;
+import net.sourceforge.phpdt.core.ToolFactory;
+
+import net.sourceforge.phpdt.internal.corext.codemanipulation.StubUtility;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+import net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage; 
+
+public class JavaFormattingStrategy implements IFormattingStrategy {
+       
+       private String fInitialIndentation;
+       private ISourceViewer fViewer;  
+
+       public JavaFormattingStrategy(ISourceViewer viewer) {
+               fViewer = viewer;
+       }
+       
+       /**
+        * @see IFormattingStrategy#formatterStarts(String)
+        */
+       public void formatterStarts(String initialIndentation) {
+               fInitialIndentation= initialIndentation;
+       }
+       
+       /**
+        * @see IFormattingStrategy#formatterStops()
+        */
+       public void formatterStops() {
+       }
+       
+       /**
+        * @see IFormattingStrategy#format(String, boolean, String, int[])
+        */
+       public String format(String content, boolean isLineStart, String indentation, int[] positions) {
+               ICodeFormatter formatter= ToolFactory.createCodeFormatter();
+               
+               IDocument doc= fViewer.getDocument();
+               String lineDelimiter= StubUtility.getLineDelimiterFor(doc);
+
+               int indent= 0;
+               if (fInitialIndentation != null) {
+                       indent= Strings.computeIndent(fInitialIndentation, CodeFormatterPreferencePage.getTabSize());
+               }
+               return formatter.format(content, indent, positions, lineDelimiter);
+       }       
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TabFolderLayout.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TabFolderLayout.java
new file mode 100644 (file)
index 0000000..ba37d7b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved
+ */
+package net.sourceforge.phpdt.internal.ui.util;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+
+public class TabFolderLayout extends Layout {
+
+       protected Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache) {
+               if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT)
+                       return new Point(wHint, hHint);
+                       
+               Control [] children = composite.getChildren ();
+               int count = children.length;
+               int maxWidth = 0, maxHeight = 0;
+               for (int i=0; i<count; i++) {
+                       Control child = children [i];
+                       Point pt = child.computeSize (SWT.DEFAULT, SWT.DEFAULT, flushCache);
+                       maxWidth = Math.max (maxWidth, pt.x);
+                       maxHeight = Math.max (maxHeight, pt.y);
+               }
+               
+               if (wHint != SWT.DEFAULT)
+                       maxWidth= wHint;
+               if (hHint != SWT.DEFAULT)
+                       maxHeight= hHint;
+               
+               return new Point(maxWidth, maxHeight);  
+               
+       }
+       
+       protected void layout (Composite composite, boolean flushCache) {
+               Rectangle rect= composite.getClientArea();
+       
+               Control[] children = composite.getChildren();
+               for (int i = 0; i < children.length; i++) {
+                       children[i].setBounds(rect);
+               }
+       }
+}
index 0f812e3..52d906b 100644 (file)
@@ -1,6 +1,9 @@
 package net.sourceforge.phpeclipse;
 
 import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.List;
 
 import net.sourceforge.phpeclipse.resourcesview.PHPFile;
@@ -9,14 +12,668 @@ import net.sourceforge.phpeclipse.resourcesview.PHPProject;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Preferences;
 
 public class PHPCore {
 
+  public static HashSet OptionNames = new HashSet(20);
+  /**
+   * The plug-in identifier of the Java core support
+   * (value <code>"org.phpeclipse.phpdt.core"</code>).
+   */
+  public static final String PLUGIN_ID = "net.sourceforge.phpeclipse.core"; //$NON-NLS-1$
+
+  /**
+     * Possible  configurable option ID.
+     * @see #getDefaultOptions
+     * @since 2.0
+     */
+  public static final String CORE_ENCODING = PLUGIN_ID + ".encoding"; //$NON-NLS-1$
+
+  /**
+     * Possible  configurable option ID.
+     * @see #getDefaultOptions
+     * @since 2.0
+     */
+  public static final String FORMATTER_NEWLINE_OPENING_BRACE = PLUGIN_ID + ".formatter.newline.openingBrace"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_NEWLINE_CONTROL = PLUGIN_ID + ".formatter.newline.controlStatement"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_NEWLINE_ELSE_IF = PLUGIN_ID + ".formatter.newline.elseIf"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_NEWLINE_EMPTY_BLOCK = PLUGIN_ID + ".formatter.newline.emptyBlock"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_CLEAR_BLANK_LINES = PLUGIN_ID + ".formatter.newline.clearAll"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_LINE_SPLIT = PLUGIN_ID + ".formatter.lineSplit"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_COMPACT_ASSIGNMENT = PLUGIN_ID + ".formatter.style.assignment"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_TAB_CHAR = PLUGIN_ID + ".formatter.tabulation.char"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option ID.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String FORMATTER_TAB_SIZE = PLUGIN_ID + ".formatter.tabulation.size"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String INSERT = "insert"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String DO_NOT_INSERT = "do not insert"; //$NON-NLS-1$
+
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String PRESERVE_ONE = "preserve one"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String CLEAR_ALL = "clear all"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String NORMAL = "normal"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String COMPACT = "compact"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String TAB = "tab"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String SPACE = "space"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String ENABLED = "enabled"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.0
+   */
+  public static final String DISABLED = "disabled"; //$NON-NLS-1$
+  /**
+   * Possible  configurable option value.
+   * @see #getDefaultOptions
+   * @since 2.1
+   */
+  public static final String CLEAN = "clean"; //$NON-NLS-1$
+       
+  /**
+   * Returns a table of all known configurable options with their default values.
+   * These options allow to configure the behaviour of the underlying components.
+   * The client may safely use the result as a template that they can modify and
+   * then pass to <code>setOptions</code>.
+   * 
+   * Helper constants have been defined on JavaCore for each of the option ID and 
+   * their possible constant values.
+   * 
+   * Note: more options might be added in further releases.
+   * <pre>
+   * RECOGNIZED OPTIONS:
+   * COMPILER / Generating Local Variable Debug Attribute
+   *    When generated, this attribute will enable local variable names 
+   *    to be displayed in debugger, only in place where variables are 
+   *    definitely assigned (.class file is then bigger)
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.debug.localVariable"
+   *     - possible values:   { "generate", "do not generate" }
+   *     - default:           "generate"
+   *
+   * COMPILER / Generating Line Number Debug Attribute 
+   *    When generated, this attribute will enable source code highlighting in debugger 
+   *    (.class file is then bigger).
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.debug.lineNumber"
+   *     - possible values:   { "generate", "do not generate" }
+   *     - default:           "generate"
+   *    
+   * COMPILER / Generating Source Debug Attribute 
+   *    When generated, this attribute will enable the debugger to present the 
+   *    corresponding source code.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.debug.sourceFile"
+   *     - possible values:   { "generate", "do not generate" }
+   *     - default:           "generate"
+   *    
+   * COMPILER / Preserving Unused Local Variables
+   *    Unless requested to preserve unused local variables (i.e. never read), the 
+   *    compiler will optimize them out, potentially altering debugging
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.codegen.unusedLocal"
+   *     - possible values:   { "preserve", "optimize out" }
+   *     - default:           "preserve"
+   * 
+   * COMPILER / Defining Target Java Platform
+   *    For binary compatibility reason, .class files can be tagged to with certain VM versions and later.
+   *    Note that "1.4" target require to toggle compliance mode to "1.4" too.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.codegen.targetPlatform"
+   *     - possible values:   { "1.1", "1.2", "1.3", "1.4" }
+   *     - default:           "1.1"
+   *
+   * COMPILER / Reporting Unreachable Code
+   *    Unreachable code can optionally be reported as an error, warning or simply 
+   *    ignored. The bytecode generation will always optimized it out.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.unreachableCode"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "error"
+   *
+   * COMPILER / Reporting Invalid Import
+   *    An import statement that cannot be resolved might optionally be reported 
+   *    as an error, as a warning or ignored.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.invalidImport"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "error"
+   *
+   * COMPILER / Reporting Attempt to Override Package-Default Method
+   *    A package default method is not visible in a different package, and thus 
+   *    cannot be overridden. When enabling this option, the compiler will signal 
+   *    such scenarii either as an error or a warning.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.overridingPackageDefaultMethod"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   *
+   * COMPILER / Reporting Method With Constructor Name
+   *    Naming a method with a constructor name is generally considered poor 
+   *    style programming. When enabling this option, the compiler will signal such 
+   *    scenarii either as an error or a warning.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.methodWithConstructorName"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   *
+   * COMPILER / Reporting Deprecation
+   *    When enabled, the compiler will signal use of deprecated API either as an 
+   *    error or a warning.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.deprecation"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   *
+   * COMPILER / Reporting Deprecation Inside Deprecated Code
+   *    When enabled, the compiler will signal use of deprecated API inside deprecated code.
+   *    The severity of the problem is controlled with option "org.phpeclipse.phpdt.core.compiler.problem.deprecation".
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.deprecationInDeprecatedCode"
+   *     - possible values:   { "enabled", "disabled" }
+   *     - default:           "disabled"
+   *
+   * COMPILER / Reporting Hidden Catch Block
+   *    Locally to a try statement, some catch blocks may hide others , e.g.
+   *      try {  throw new java.io.CharConversionException();
+   *      } catch (java.io.CharConversionException e) {
+   *      } catch (java.io.IOException e) {}. 
+   *    When enabling this option, the compiler will issue an error or a warning for hidden 
+   *    catch blocks corresponding to checked exceptions
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.hiddenCatchBlock"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   *
+   * COMPILER / Reporting Unused Local
+   *    When enabled, the compiler will issue an error or a warning for unused local 
+   *    variables (i.e. variables never read from)
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.unusedLocal"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "ignore"
+   *
+   * COMPILER / Reporting Unused Parameter
+   *    When enabled, the compiler will issue an error or a warning for unused method 
+   *    parameters (i.e. parameters never read from)
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.unusedParameter"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "ignore"
+   *
+   * COMPILER / Reporting Unused Import
+   *    When enabled, the compiler will issue an error or a warning for unused import 
+   *    reference 
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.unusedImport"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   *
+   * COMPILER / Reporting Synthetic Access Emulation
+   *    When enabled, the compiler will issue an error or a warning whenever it emulates 
+   *    access to a non-accessible member of an enclosing type. Such access can have
+   *    performance implications.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.syntheticAccessEmulation"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "ignore"
+   *
+   * COMPILER / Reporting Non-Externalized String Literal
+   *    When enabled, the compiler will issue an error or a warning for non externalized 
+   *    String literal (i.e. non tagged with //$NON-NLS-<n>$). 
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.nonExternalizedStringLiteral"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "ignore"
+   * 
+   * COMPILER / Reporting Usage of 'assert' Identifier
+   *    When enabled, the compiler will issue an error or a warning whenever 'assert' is 
+   *    used as an identifier (reserved keyword in 1.4)
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.assertIdentifier"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "ignore"
+   * 
+   * COMPILER / Reporting Usage of expression receiver on static invocation/field access
+   *    When enabled, the compiler will issue an error or a warning whenever a static field
+   *    or method is accessed with an expression receiver.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.staticAccessReceiver"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   * 
+   * COMPILER / Reporting Assignment with no effect
+   *    When enabled, the compiler will issue an error or a warning whenever an assignment
+   *    has no effect (e.g 'x = x').
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.problem.noEffectAssignment"
+   *     - possible values:   { "error", "warning", "ignore" }
+   *     - default:           "warning"
+   * 
+   * COMPILER / Setting Source Compatibility Mode
+   *    Specify whether source is 1.3 or 1.4 compatible. From 1.4 on, 'assert' is a keyword
+   *    reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM
+   *   level should be set to "1.4" and the compliance mode should be "1.4".
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.source"
+   *     - possible values:   { "1.3", "1.4" }
+   *     - default:           "1.3"
+   * 
+   * COMPILER / Setting Compliance Level
+   *    Select the compliance level for the compiler. In "1.3" mode, source and target settings
+   *    should not go beyond "1.3" level.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.compliance"
+   *     - possible values:   { "1.3", "1.4" }
+   *     - default:           "1.3"
+   * 
+   * COMPILER / Maximum number of problems reported per compilation unit
+   *    Specify the maximum number of problems reported on each compilation unit.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.maxProblemPerUnit"
+   *     - possible values:    "<n>" where <n> is zero or a positive integer (if zero then all problems are reported).
+   *     - default:           "100"
+   * 
+   * COMPILER / Define the Automatic Task Tags
+   *    When the tag is non empty, the compiler will issue a task marker whenever it encounters
+   *    one of the corresponding tag inside any comment in Java source code.
+   *    Generated task messages will include the tag, and range until the next line separator or comment ending, and will be trimmed.
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.taskTags"
+   *     - possible values:   { "<tag>[,<tag>]*" } where <tag> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   * COMPILER / Define the Automatic Task Priorities
+   *    In parallel with the Automatic Task Tags, this list defines the priorities (high, normal or low)
+   *    of the task markers issued by the compiler.
+   *    If the default is specified, the priority of each task marker is "NORMAL".
+   *     - option id:         "org.phpeclipse.phpdt.core.compiler.taskPriorities"
+   *     - possible values:   { "<priority>[,<priority>]*" } where <priority> is one of "HIGH", "NORMAL" or "LOW"
+   *     - default:           ""
+   * 
+   * BUILDER / Specifying Filters for Resource Copying Control
+   *    Allow to specify some filters to control the resource copy process.
+   *     - option id:         "org.phpeclipse.phpdt.core.builder.resourceCopyExclusionFilter"
+   *     - possible values:   { "<name>[,<name>]* } where <name> is a file name pattern (* and ? wild-cards allowed)
+   *       or the name of a folder which ends with '/'
+   *     - default:           ""
+   * 
+   * BUILDER / Abort if Invalid Classpath
+   *    Allow to toggle the builder to abort if the classpath is invalid
+   *     - option id:         "org.phpeclipse.phpdt.core.builder.invalidClasspath"
+   *     - possible values:   { "abort", "ignore" }
+   *     - default:           "ignore"
+   * 
+   * BUILDER / Cleaning Output Folder(s)
+   *    Indicate whether the JavaBuilder is allowed to clean the output folders
+   *    when performing full build operations.
+   *     - option id:         "org.phpeclipse.phpdt.core.builder.cleanOutputFolder"
+   *     - possible values:   { "clean", "ignore" }
+   *     - default:           "clean"
+   * 
+   * JAVACORE / Computing Project Build Order
+   *    Indicate whether JavaCore should enforce the project build order to be based on
+   *    the classpath prerequisite chain. When requesting to compute, this takes over
+   *    the platform default order (based on project references).
+   *     - option id:         "org.phpeclipse.phpdt.core.computeJavaBuildOrder"
+   *     - possible values:   { "compute", "ignore" }
+   *     - default:           "ignore"  
+   * 
+   * JAVACORE / Specify Default Source Encoding Format
+   *    Get the encoding format for compiled sources. This setting is read-only, it is equivalent
+   *    to 'ResourcesPlugin.getEncoding()'.
+   *     - option id:         "org.phpeclipse.phpdt.core.encoding"
+   *     - possible values:   { any of the supported encoding name}.
+   *     - default:           <platform default>
+   * 
+   * JAVACORE / Reporting Incomplete Classpath
+   *    An entry on the classpath doesn't exist or is not visible (e.g. a referenced project is closed).
+   *     - option id:         "org.phpeclipse.phpdt.core.incompleteClasspath"
+   *     - possible values:   { "error", "warning"}
+   *     - default:           "error"
+   * 
+   * JAVACORE / Reporting Classpath Cycle
+   *    A project is involved in a cycle.
+   *     - option id:         "org.phpeclipse.phpdt.core.circularClasspath"
+   *     - possible values:   { "error", "warning" }
+   *     - default:           "error"
+   * 
+   *   FORMATTER / Inserting New Line Before Opening Brace
+   *    When Insert, a new line is inserted before an opening brace, otherwise nothing
+   *    is inserted
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.newline.openingBrace"
+   *     - possible values:   { "insert", "do not insert" }
+   *     - default:           "do not insert"
+   * 
+   *   FORMATTER / Inserting New Line Inside Control Statement
+   *    When Insert, a new line is inserted between } and following else, catch, finally
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.newline.controlStatement"
+   *     - possible values:   { "insert", "do not insert" }
+   *     - default:           "do not insert"
+   * 
+   *   FORMATTER / Clearing Blank Lines
+   *    When Clear all, all blank lines are removed. When Preserve one, only one is kept
+   *    and all others removed.
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.newline.clearAll"
+   *     - possible values:   { "clear all", "preserve one" }
+   *     - default:           "preserve one"
+   * 
+   *   FORMATTER / Inserting New Line Between Else/If 
+   *    When Insert, a blank line is inserted between an else and an if when they are 
+   *    contiguous. When choosing to not insert, else-if will be kept on the same
+   *    line when possible.
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.newline.elseIf"
+   *     - possible values:   { "insert", "do not insert" }
+   *     - default:           "do not insert"
+   * 
+   *   FORMATTER / Inserting New Line In Empty Block
+   *    When insert, a line break is inserted between contiguous { and }, if } is not followed
+   *    by a keyword.
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.newline.emptyBlock"
+   *     - possible values:   { "insert", "do not insert" }
+   *     - default:           "insert"
+   * 
+   *   FORMATTER / Splitting Lines Exceeding Length
+   *    Enable splitting of long lines (exceeding the configurable length). Length of 0 will
+   *    disable line splitting
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.lineSplit"
+   *     - possible values:    "<n>", where n is zero or a positive integer
+   *     - default:           "80"
+   * 
+   *   FORMATTER / Compacting Assignment
+   *    Assignments can be formatted asymmetrically, e.g. 'int x= 2;', when Normal, a space
+   *    is inserted before the assignment operator
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.style.assignment"
+   *     - possible values:   { "compact", "normal" }
+   *     - default:           "normal"
+   * 
+   *   FORMATTER / Defining Indentation Character
+   *    Either choose to indent with tab characters or spaces
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.tabulation.char"
+   *     - possible values:   { "tab", "space" }
+   *     - default:           "tab"
+   * 
+   *   FORMATTER / Defining Space Indentation Length
+   *    When using spaces, set the amount of space characters to use for each 
+   *    indentation mark.
+   *     - option id:         "org.phpeclipse.phpdt.core.formatter.tabulation.size"
+   *     - possible values:    "<n>", where n is a positive integer
+   *     - default:           "4"
+   * 
+   *   CODEASSIST / Activate Visibility Sensitive Completion
+   *    When active, completion doesn't show that you can not see
+   *    (e.g. you can not see private methods of a super class).
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.visibilityCheck"
+   *     - possible values:   { "enabled", "disabled" }
+   *     - default:           "disabled"
+   * 
+   *   CODEASSIST / Automatic Qualification of Implicit Members
+   *    When active, completion automatically qualifies completion on implicit
+   *    field references and message expressions.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.forceImplicitQualification"
+   *     - possible values:   { "enabled", "disabled" }
+   *     - default:           "disabled"
+   * 
+   *  CODEASSIST / Define the Prefixes for Field Name
+   *    When the prefixes is non empty, completion for field name will begin with
+   *    one of the proposed prefixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.fieldPrefixes"
+   *     - possible values:   { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Prefixes for Static Field Name
+   *    When the prefixes is non empty, completion for static field name will begin with
+   *    one of the proposed prefixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.staticFieldPrefixes"
+   *     - possible values:   { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Prefixes for Local Variable Name
+   *    When the prefixes is non empty, completion for local variable name will begin with
+   *    one of the proposed prefixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.localPrefixes"
+   *     - possible values:   { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Prefixes for Argument Name
+   *    When the prefixes is non empty, completion for argument name will begin with
+   *    one of the proposed prefixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.argumentPrefixes"
+   *     - possible values:   { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Suffixes for Field Name
+   *    When the suffixes is non empty, completion for field name will end with
+   *    one of the proposed suffixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.fieldSuffixes"
+   *     - possible values:   { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Suffixes for Static Field Name
+   *    When the suffixes is non empty, completion for static field name will end with
+   *    one of the proposed suffixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.staticFieldSuffixes"
+   *     - possible values:   { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Suffixes for Local Variable Name
+   *    When the suffixes is non empty, completion for local variable name will end with
+   *    one of the proposed suffixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.localSuffixes"
+   *     - possible values:   { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card 
+   *     - default:           ""
+   * 
+   *  CODEASSIST / Define the Suffixes for Argument Name
+   *    When the suffixes is non empty, completion for argument name will end with
+   *    one of the proposed suffixes.
+   *     - option id:         "org.phpeclipse.phpdt.core.codeComplete.argumentSuffixes"
+   *     - possible values:   { "<suffix>[,<suffix>]*" } where <prefix> is a String without any wild-card 
+   *     - default:           ""
+   * </pre>
+   * 
+   * @return a mutable table containing the default settings of all known options
+   *   (key type: <code>String</code>; value type: <code>String</code>)
+   * @see #setOptions
+   */
+  public static Hashtable getDefaultOptions() {
+
+    Hashtable defaultOptions = new Hashtable(10);
+
+    // see #initializeDefaultPluginPreferences() for changing default settings
+    Preferences preferences = getPlugin().getPluginPreferences();
+    HashSet optionNames = OptionNames;
+
+    // get preferences set to their default
+    String[] defaultPropertyNames = preferences.defaultPropertyNames();
+    for (int i = 0; i < defaultPropertyNames.length; i++) {
+      String propertyName = defaultPropertyNames[i];
+      if (optionNames.contains(propertyName)) {
+        defaultOptions.put(
+          propertyName,
+          preferences.getDefaultString(propertyName));
+      }
+    }
+    // get preferences not set to their default
+    String[] propertyNames = preferences.propertyNames();
+    for (int i = 0; i < propertyNames.length; i++) {
+      String propertyName = propertyNames[i];
+      if (optionNames.contains(propertyName)) {
+        defaultOptions.put(
+          propertyName,
+          preferences.getDefaultString(propertyName));
+      }
+    }
+    // get encoding through resource plugin
+    defaultOptions.put(CORE_ENCODING, ResourcesPlugin.getEncoding());
+
+    return defaultOptions;
+  }
+  /**
+   * Helper method for returning one option value only. Equivalent to <code>(String)JavaCore.getOptions().get(optionName)</code>
+   * Note that it may answer <code>null</code> if this option does not exist.
+   * <p>
+   * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
+   * </p>
+   * 
+   * @param optionName the name of an option
+   * @return the String value of a given option
+   * @see JavaCore#getDefaultOptions
+   * @since 2.0
+   */
+  public static String getOption(String optionName) {
+
+    if (CORE_ENCODING.equals(optionName)) {
+      return ResourcesPlugin.getEncoding();
+    }
+    if (OptionNames.contains(optionName)) {
+      Preferences preferences = getPlugin().getPluginPreferences();
+      return preferences.getString(optionName).trim();
+    }
+    return null;
+  }
+
+  /**
+   * Returns the table of the current options. Initially, all options have their default values,
+   * and this method returns a table that includes all known options.
+   * <p>
+   * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
+   * </p>
+   * 
+   * @return table of current settings of all options 
+   *   (key type: <code>String</code>; value type: <code>String</code>)
+   * @see JavaCore#getDefaultOptions
+   */
+  public static Hashtable getOptions() {
+
+    Hashtable options = new Hashtable(10);
+
+    // see #initializeDefaultPluginPreferences() for changing default settings
+    Plugin plugin = getPlugin();
+    if (plugin != null) {
+      Preferences preferences = getPlugin().getPluginPreferences();
+      HashSet optionNames = OptionNames;
+
+      // get preferences set to their default
+      String[] defaultPropertyNames = preferences.defaultPropertyNames();
+      for (int i = 0; i < defaultPropertyNames.length; i++) {
+        String propertyName = defaultPropertyNames[i];
+        if (optionNames.contains(propertyName)) {
+          options.put(propertyName, preferences.getDefaultString(propertyName));
+        }
+      }
+      // get preferences not set to their default
+      String[] propertyNames = preferences.propertyNames();
+      for (int i = 0; i < propertyNames.length; i++) {
+        String propertyName = propertyNames[i];
+        if (optionNames.contains(propertyName)) {
+          options.put(propertyName, preferences.getString(propertyName).trim());
+        }
+      }
+      // get encoding through resource plugin
+      options.put(CORE_ENCODING, ResourcesPlugin.getEncoding());
+    }
+    return options;
+  }
+  /**
+   * Sets the current table of options. All and only the options explicitly included in the given table 
+   * are remembered; all previous option settings are forgotten, including ones not explicitly
+   * mentioned.
+   * <p>
+   * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
+   * </p>
+   * 
+   * @param newOptions the new options (key type: <code>String</code>; value type: <code>String</code>),
+   *   or <code>null</code> to reset all options to their default values
+   * @see JavaCore#getDefaultOptions
+   */
+  public static void setOptions(Hashtable newOptions) {
+
+    // see #initializeDefaultPluginPreferences() for changing default settings
+    Preferences preferences = getPlugin().getPluginPreferences();
+
+    if (newOptions == null) {
+      newOptions = getDefaultOptions();
+    }
+    Enumeration keys = newOptions.keys();
+    while (keys.hasMoreElements()) {
+      String key = (String) keys.nextElement();
+      if (!OptionNames.contains(key))
+        continue; // unrecognized option
+      if (key.equals(CORE_ENCODING))
+        continue; // skipped, contributed by resource prefs
+      String value = (String) newOptions.get(key);
+      preferences.setValue(key, value);
+    }
+
+    // persist options
+    getPlugin().savePluginPreferences();
+  }
   public static IProject[] getPHPProjects() {
     List phpProjectsList = new ArrayList();
-    IProject[] workspaceProjects = PHPeclipsePlugin.getWorkspace().getRoot().getProjects();
+    IProject[] workspaceProjects =
+      PHPeclipsePlugin.getWorkspace().getRoot().getProjects();
 
     for (int i = 0; i < workspaceProjects.length; i++) {
       IProject iProject = workspaceProjects[i];
@@ -29,7 +686,8 @@ public class PHPCore {
   }
 
   public static PHPProject getPHPProject(String name) {
-    IProject aProject = PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
+    IProject aProject =
+      PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
     if (isPHPProject(aProject)) {
       PHPProject thePHPProject = new PHPProject();
       thePHPProject.setProject(aProject);
@@ -72,13 +730,15 @@ public class PHPCore {
         return project;
       }
     } catch (CoreException e) {
-      System.err.println("Exception occurred in PHPCore#create(IProject): " + e.toString());
+      System.err.println(
+        "Exception occurred in PHPCore#create(IProject): " + e.toString());
     }
 
     return null;
   }
 
-  public static void addPHPNature(IProject project, IProgressMonitor monitor) throws CoreException {
+  public static void addPHPNature(IProject project, IProgressMonitor monitor)
+    throws CoreException {
     if (!project.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
       IProjectDescription description = project.getDescription();
       String[] prevNatures = description.getNatureIds();
@@ -89,4 +749,184 @@ public class PHPCore {
       project.setDescription(description, monitor);
     }
   }
+
+  /**
+   * Returns the single instance of the PHP core plug-in runtime class.
+   * 
+   * @return the single instance of the PHP core plug-in runtime class
+   */
+  public static Plugin getPlugin() {
+    return PHPeclipsePlugin.getDefault();
+  }
+  
+/**
+   * Initializes the default preferences settings for this plug-in.
+   */
+  protected static void initializeDefaultPluginPreferences() {
+               
+    Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
+    HashSet optionNames = OptionNames;
+               
+//    // Compiler settings
+//    preferences.setDefault(COMPILER_LOCAL_VARIABLE_ATTR, GENERATE);
+//    optionNames.add(COMPILER_LOCAL_VARIABLE_ATTR);
+//
+//    preferences.setDefault(COMPILER_LINE_NUMBER_ATTR, GENERATE); 
+//    optionNames.add(COMPILER_LINE_NUMBER_ATTR);
+//
+//    preferences.setDefault(COMPILER_SOURCE_FILE_ATTR, GENERATE); 
+//    optionNames.add(COMPILER_SOURCE_FILE_ATTR);
+//
+//    preferences.setDefault(COMPILER_CODEGEN_UNUSED_LOCAL, PRESERVE); 
+//    optionNames.add(COMPILER_CODEGEN_UNUSED_LOCAL);
+//
+//    preferences.setDefault(COMPILER_CODEGEN_TARGET_PLATFORM, VERSION_1_1); 
+//    optionNames.add(COMPILER_CODEGEN_TARGET_PLATFORM);
+//
+//    preferences.setDefault(COMPILER_PB_UNREACHABLE_CODE, ERROR); 
+//    optionNames.add(COMPILER_PB_UNREACHABLE_CODE);
+//
+//    preferences.setDefault(COMPILER_PB_INVALID_IMPORT, ERROR); 
+//    optionNames.add(COMPILER_PB_INVALID_IMPORT);
+//
+//    preferences.setDefault(COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD, WARNING); 
+//    optionNames.add(COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD);
+//
+//    preferences.setDefault(COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME, WARNING); 
+//    optionNames.add(COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME);
+//
+//    preferences.setDefault(COMPILER_PB_DEPRECATION, WARNING);
+//    optionNames.add(COMPILER_PB_DEPRECATION);
+//
+//    preferences.setDefault(COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE, DISABLED);
+//    optionNames.add(COMPILER_PB_DEPRECATION_IN_DEPRECATED_CODE);
+//
+//    preferences.setDefault(COMPILER_PB_HIDDEN_CATCH_BLOCK, WARNING); 
+//    optionNames.add(COMPILER_PB_HIDDEN_CATCH_BLOCK);
+//
+//    preferences.setDefault(COMPILER_PB_UNUSED_LOCAL, IGNORE); 
+//    optionNames.add(COMPILER_PB_UNUSED_LOCAL);
+//
+//    preferences.setDefault(COMPILER_PB_UNUSED_PARAMETER, IGNORE); 
+//    optionNames.add(COMPILER_PB_UNUSED_PARAMETER);
+//
+//    preferences.setDefault(COMPILER_PB_UNUSED_IMPORT, WARNING); 
+//    optionNames.add(COMPILER_PB_UNUSED_IMPORT);
+//
+//    preferences.setDefault(COMPILER_PB_SYNTHETIC_ACCESS_EMULATION, IGNORE); 
+//    optionNames.add(COMPILER_PB_SYNTHETIC_ACCESS_EMULATION);
+//
+//    preferences.setDefault(COMPILER_PB_NON_NLS_STRING_LITERAL, IGNORE); 
+//    optionNames.add(COMPILER_PB_NON_NLS_STRING_LITERAL);
+//
+//    preferences.setDefault(COMPILER_PB_ASSERT_IDENTIFIER, IGNORE); 
+//    optionNames.add(COMPILER_PB_ASSERT_IDENTIFIER);
+//
+//    preferences.setDefault(COMPILER_PB_STATIC_ACCESS_RECEIVER, WARNING); 
+//    optionNames.add(COMPILER_PB_STATIC_ACCESS_RECEIVER);
+//
+//    preferences.setDefault(COMPILER_PB_NO_EFFECT_ASSIGNMENT, WARNING); 
+//    optionNames.add(COMPILER_PB_NO_EFFECT_ASSIGNMENT);
+//
+//    preferences.setDefault(COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
+//    optionNames.add(COMPILER_TASK_TAGS);
+//
+//    preferences.setDefault(COMPILER_TASK_PRIORITIES, ""); //$NON-NLS-1$
+//    optionNames.add(COMPILER_TASK_PRIORITIES);
+//
+//    preferences.setDefault(COMPILER_SOURCE, VERSION_1_3);
+//    optionNames.add(COMPILER_SOURCE);
+//
+//    preferences.setDefault(COMPILER_COMPLIANCE, VERSION_1_3); 
+//    optionNames.add(COMPILER_COMPLIANCE);
+//
+//    preferences.setDefault(COMPILER_PB_MAX_PER_UNIT, "100"); //$NON-NLS-1$
+//    optionNames.add(COMPILER_PB_MAX_PER_UNIT);
+//             
+//    // Builder settings
+//    preferences.setDefault(CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$
+//    optionNames.add(CORE_JAVA_BUILD_RESOURCE_COPY_FILTER);
+//
+//    preferences.setDefault(CORE_JAVA_BUILD_INVALID_CLASSPATH, ABORT); 
+//    optionNames.add(CORE_JAVA_BUILD_INVALID_CLASSPATH);
+//     
+//    preferences.setDefault(CORE_JAVA_BUILD_DUPLICATE_RESOURCE, WARNING); 
+//    optionNames.add(CORE_JAVA_BUILD_DUPLICATE_RESOURCE);
+//             
+//    preferences.setDefault(CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, CLEAN); 
+//    optionNames.add(CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER);
+//
+//    // JavaCore settings
+//    preferences.setDefault(CORE_JAVA_BUILD_ORDER, IGNORE); 
+//    optionNames.add(CORE_JAVA_BUILD_ORDER);
+//     
+//    preferences.setDefault(CORE_CIRCULAR_CLASSPATH, ERROR); 
+//    optionNames.add(CORE_CIRCULAR_CLASSPATH);
+//             
+//    preferences.setDefault(CORE_INCOMPLETE_CLASSPATH, ERROR); 
+//    optionNames.add(CORE_INCOMPLETE_CLASSPATH);
+               
+    // encoding setting comes from resource plug-in
+    optionNames.add(CORE_ENCODING);
+               
+    // Formatter settings
+    preferences.setDefault(FORMATTER_NEWLINE_OPENING_BRACE, DO_NOT_INSERT); 
+    optionNames.add(FORMATTER_NEWLINE_OPENING_BRACE);
+
+    preferences.setDefault(FORMATTER_NEWLINE_CONTROL, DO_NOT_INSERT);
+    optionNames.add(FORMATTER_NEWLINE_CONTROL);
+
+    preferences.setDefault(FORMATTER_CLEAR_BLANK_LINES, PRESERVE_ONE); 
+    optionNames.add(FORMATTER_CLEAR_BLANK_LINES);
+
+    preferences.setDefault(FORMATTER_NEWLINE_ELSE_IF, DO_NOT_INSERT);
+    optionNames.add(FORMATTER_NEWLINE_ELSE_IF);
+
+    preferences.setDefault(FORMATTER_NEWLINE_EMPTY_BLOCK, INSERT); 
+    optionNames.add(FORMATTER_NEWLINE_EMPTY_BLOCK);
+
+    preferences.setDefault(FORMATTER_LINE_SPLIT, "80"); //$NON-NLS-1$
+    optionNames.add(FORMATTER_LINE_SPLIT);
+
+    preferences.setDefault(FORMATTER_COMPACT_ASSIGNMENT, NORMAL); 
+    optionNames.add(FORMATTER_COMPACT_ASSIGNMENT);
+
+    preferences.setDefault(FORMATTER_TAB_CHAR, TAB); 
+    optionNames.add(FORMATTER_TAB_CHAR);
+
+    preferences.setDefault(FORMATTER_TAB_SIZE, "4"); //$NON-NLS-1$ 
+    optionNames.add(FORMATTER_TAB_SIZE);
+               
+    // CodeAssist settings
+//    preferences.setDefault(CODEASSIST_VISIBILITY_CHECK, DISABLED); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_VISIBILITY_CHECK);
+//
+//    preferences.setDefault(CODEASSIST_IMPLICIT_QUALIFICATION, DISABLED); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_IMPLICIT_QUALIFICATION);
+//             
+//    preferences.setDefault(CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_FIELD_PREFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_STATIC_FIELD_PREFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_LOCAL_PREFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_ARGUMENT_PREFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_FIELD_SUFFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_STATIC_FIELD_SUFFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_LOCAL_SUFFIXES);
+//             
+//    preferences.setDefault(CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$
+//    optionNames.add(CODEASSIST_ARGUMENT_SUFFIXES);
+               
+  }
 }
\ No newline at end of file
index 7bfbf25..24e9395 100644 (file)
@@ -381,8 +381,10 @@ public class PHPeclipsePlugin
     store.setDefault(PHP_OUTLINE_VAR, "true"); //$NON-NLS-1$
 
     TemplatePreferencePage.initDefaults(store);
-    new PHPSyntaxRdr();
     //this will initialize the static fields in the syntaxrdr class
+    new PHPSyntaxRdr();
+
+    PHPCore.initializeDefaultPluginPreferences();
   }
 
   public void startup() throws CoreException {
index af8b262..09662be 100644 (file)
@@ -13,6 +13,7 @@ package net.sourceforge.phpeclipse.phpeditor;
 
 import java.util.Vector;
 
+import net.sourceforge.phpdt.internal.ui.text.java.JavaFormattingStrategy;
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 import net.sourceforge.phpeclipse.phpeditor.html.HTMLFormattingStrategy;
 import net.sourceforge.phpeclipse.phpeditor.php.HTMLCompletionProcessor;
@@ -33,6 +34,7 @@ import org.eclipse.jface.text.contentassist.ContentAssistant;
 import org.eclipse.jface.text.contentassist.IContentAssistant;
 import org.eclipse.jface.text.formatter.ContentFormatter;
 import org.eclipse.jface.text.formatter.IContentFormatter;
+import org.eclipse.jface.text.formatter.IFormattingStrategy;
 import org.eclipse.jface.text.presentation.IPresentationReconciler;
 import org.eclipse.jface.text.presentation.PresentationReconciler;
 import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
@@ -75,16 +77,39 @@ public class PHPSourceViewerConfiguration extends SourceViewerConfiguration {
    * @see SourceViewerConfiguration#getContentFormatter(ISourceViewer)
    */
   public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) {
+//    if (fFormatter == null) {
+//      fFormatter = new ContentFormatter();
+//      fFormattingStrategy = new HTMLFormattingStrategy(this, sourceViewer);
+//      fFormatter.setFormattingStrategy(fFormattingStrategy, HTML_DEFAULT);
+//      fFormatter.enablePartitionAwareFormatting(false);
+//      fFormatter.setPartitionManagingPositionCategories(getConfiguredContentTypes(null));
+//    }
+//    return fFormatter;
+    
     if (fFormatter == null) {
-      fFormatter = new ContentFormatter();
-      fFormattingStrategy = new HTMLFormattingStrategy(this, sourceViewer);
-      fFormatter.setFormattingStrategy(fFormattingStrategy, HTML_DEFAULT);
-      fFormatter.enablePartitionAwareFormatting(false);
-      fFormatter.setPartitionManagingPositionCategories(getConfiguredContentTypes(null));
+    //ContentFormatter 
+    fFormatter= new ContentFormatter();
+    IFormattingStrategy strategy= new JavaFormattingStrategy(sourceViewer);
+               
+    fFormatter.setFormattingStrategy(strategy, IDocument.DEFAULT_CONTENT_TYPE);
+    fFormatter.enablePartitionAwareFormatting(false);          
+    fFormatter.setPartitionManagingPositionCategories(getPartitionManagingPositionCategories());
     }
     return fFormatter;
   }
   
+  /**
+   * Returns the names of the document position categories used by the document
+   * partitioners created by this object to manage their partition information.
+   * If the partitioners don't use document position categories, the returned
+   * result is <code>null</code>.
+   *
+   * @return the partition managing position categories or <code>null</code> 
+   *                   if there is none
+   */
+  public String[] getPartitionManagingPositionCategories() {
+    return new String[] { DefaultPartitioner.CONTENT_TYPES_CATEGORY };
+  }
 //  /**
 //   * Returns the names of the document position categories used by the document
 //   * partitioners created by this object to manage their partition information.
diff --git a/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/CodeFormatter.java b/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/CodeFormatter.java
new file mode 100644 (file)
index 0000000..0366a03
--- /dev/null
@@ -0,0 +1,2556 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.phpeclipse.phpdt.internal.formatter;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+
+import net.sourceforge.phpdt.core.ICodeFormatter;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
+import net.sourceforge.phpdt.core.compiler.InvalidInputException;
+import net.sourceforge.phpdt.internal.compiler.ConfigurableOption;
+import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+
+import org.phpeclipse.phpdt.internal.formatter.impl.FormatterOptions;
+import org.phpeclipse.phpdt.internal.formatter.impl.SplitLine;
+
+/** <h2>How to format a piece of code ?</h2>
+ * <ul><li>Create an instance of <code>CodeFormatter</code>
+ * <li>Use the method <code>void format(aString)</code>
+ * on this instance to format <code>aString</code>.
+ * It will return the formatted string.</ul>
+*/
+public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
+
+       public FormatterOptions options;
+
+       /** 
+        * Represents a block in the <code>constructions</code> stack.
+        */
+       public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE;
+
+       /** 
+        * Represents a block following a control statement in the <code>constructions</code> stack.
+        */
+       public static final int NONINDENT_BLOCK = -100;
+
+       /** 
+        * Contains the formatted output.
+        */
+       StringBuffer formattedSource;
+
+       /** 
+        * Contains the current line.<br>
+        * Will be dumped at the next "newline"
+        */
+       StringBuffer currentLineBuffer;
+
+       /** 
+        * Used during the formatting to get each token.
+        */
+       Scanner scanner;
+
+       /** 
+        * Contains the tokens responsible for the current indentation level
+        * and the blocks not closed yet.
+        */
+       private int[] constructions;
+
+       /** 
+        * Index in the <code>constructions</code> array.
+        */
+       private int constructionsCount;
+
+       /** 
+        * Level of indentation of the current token (number of tab char put in front of it).
+        */
+       private int indentationLevel;
+
+       /** 
+        * Regular level of indentation of all the lines
+        */
+       private int initialIndentationLevel;
+
+       /** 
+        * Used to split a line.
+        */
+       Scanner splitScanner;
+
+       /** 
+        * To remember the offset between the beginning of the line and the
+        * beginning of the comment.
+        */
+       int currentCommentOffset;
+       int currentLineIndentationLevel;
+       int maxLineSize = 30;
+       private boolean containsOpenCloseBraces;
+       private int indentationLevelForOpenCloseBraces;
+
+       /**
+        * Collections of positions to map
+        */
+       private int[] positionsToMap;
+
+       /**
+        * Collections of mapped positions
+        */
+       private int[] mappedPositions;
+
+       private int indexToMap;
+
+       private int indexInMap;
+
+       private int globalDelta;
+
+       private int lineDelta;
+
+       private int splitDelta;
+
+       private int beginningOfLineIndex;
+
+       private int multipleLineCommentCounter;
+       
+       /** 
+        * Creates a new instance of Code Formatter using the given settings.
+        * 
+        * @deprecated backport 1.0 internal functionality
+        */
+       public CodeFormatter(ConfigurableOption[] settings) {
+               this(convertConfigurableOptions(settings));
+       }
+       
+       /** 
+        * Creates a new instance of Code Formatter using the FormattingOptions object
+        * given as argument
+        * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
+        */
+       public CodeFormatter() {
+               this((Map)null);
+       }
+       /** 
+        * Creates a new instance of Code Formatter using the given settings.
+        */
+       public CodeFormatter(Map settings) {
+
+               // initialize internal state
+               constructionsCount = 0;
+               constructions = new int[10];
+               currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
+               currentCommentOffset = -1;
+
+               // initialize primary and secondary scanners
+               scanner = new Scanner(true /*comment*/, true /*whitespace*/, false /*nls*/, false /*assert*/); // regular scanner for forming lines
+               scanner.recordLineSeparator = true;
+
+               // to remind of the position of the beginning of the line.
+               splitScanner = new Scanner(true /*comment*/, true /*whitespace*/, false /*nls*/, false /*assert*/);
+               // secondary scanner to split long lines formed by primary scanning
+
+               // initialize current line buffer
+               currentLineBuffer = new StringBuffer();
+               this.options = new FormatterOptions(settings);
+       }
+
+       /**
+        * Returns true if a lineSeparator has to be inserted before <code>operator</code>
+        * false otherwise.
+        */
+       private static boolean breakLineBeforeOperator(int operator) {
+               switch (operator) {
+                       case TokenNameCOMMA :
+                       case TokenNameSEMICOLON :
+                       case TokenNameEQUAL :
+                               return false;
+                       default :
+                               return true;
+               }
+       }
+       
+               /** 
+        * @deprecated backport 1.0 internal functionality
+        */
+       private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
+               Hashtable options = new Hashtable(10);
+               
+               for (int i = 0; i < settings.length; i++) {
+                       if(settings[i].getComponentName().equals(CodeFormatter.class.getName())){
+                               String optionName = settings[i].getOptionName();
+                               int valueIndex = settings[i].getCurrentValueIndex();
+                               
+                               if(optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.newline.controlStatement",  valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("newline.clearAll")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.newline.clearAll",  valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("newline.elseIf")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.newline.elseIf",  valueIndex == 0 ? "do not insert" : "insert" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.newline.emptyBlock",  valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("lineSplit")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+                               
+                               } else if(optionName.equals("style.assignment")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.style.assignment",  valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("tabulation.char")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.tabulation.char",  valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                               
+                               } else if(optionName.equals("tabulation.size")) { //$NON-NLS-1$
+                                       options.put("org.phpeclipse.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+                               }
+                       }
+               }
+               
+               return options;
+       }
+
+       /** 
+        * Returns the end of the source code.
+        */
+       private final String copyRemainingSource() {
+               char str[] = scanner.source;
+               int startPosition = scanner.startPosition;
+               int length = str.length - startPosition;
+               StringBuffer bufr = new StringBuffer(length);
+               if (startPosition < str.length) {
+                       bufr.append(str, startPosition, length);
+               }
+               return (bufr.toString());
+       }
+
+       /**
+        * Inserts <code>tabCount</code> tab character or their equivalent number of spaces.
+        */
+       private void dumpTab(int tabCount) {
+               if (options.indentWithTab) {
+                       for (int j = 0; j < tabCount; j++) {
+                               formattedSource.append('\t');
+                               increaseSplitDelta(1);
+                       }
+               } else {
+                       for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
+                               formattedSource.append(' ');
+                               increaseSplitDelta(1);
+                       }
+               }
+       }
+
+       /**
+        * Dumps <code>currentLineBuffer</code> into the formatted string.
+        */
+       private void flushBuffer() {
+               String currentString = currentLineBuffer.toString();
+               splitDelta = 0;
+               beginningOfLineIndex = formattedSource.length();
+               if (containsOpenCloseBraces) {
+                       containsOpenCloseBraces = false;
+                       outputLine(
+                               currentString,
+                               false,
+                               indentationLevelForOpenCloseBraces,
+                               0,
+                               -1,
+                               null,
+                               0);
+                       indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+               } else {
+                       outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0);
+               }
+               int scannerSourceLength = scanner.source.length;
+               if (scannerSourceLength > 2) {
+                       if (scanner.source[scannerSourceLength - 1] == '\n' && 
+                               scanner.source[scannerSourceLength - 2] == '\r') {
+                                       formattedSource.append(options.lineSeparatorSequence);
+                                       increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
+                       } else if (scanner.source[scannerSourceLength - 1] == '\n') {
+                               formattedSource.append(options.lineSeparatorSequence);
+                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                       } else if (scanner.source[scannerSourceLength - 1] == '\r') {
+                               formattedSource.append(options.lineSeparatorSequence);
+                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                       }
+               }
+               updateMappedPositions(scanner.startPosition);
+       }
+
+       /** 
+        * Formats the input string.
+        */
+       private void format() {
+               int token = 0;
+               int previousToken = 0;
+               int previousCompilableToken = 0;
+               int indentationOffset = 0;
+               int newLinesInWhitespace = 0;
+
+               // number of new lines in the previous whitespace token
+               // (used to leave blank lines before comments)
+               int pendingNewLines = 0;
+               boolean expectingOpenBrace = false;
+               boolean clearNonBlockIndents = false;
+               // true if all indentations till the 1st { (usefull after } or ;)
+               boolean pendingSpace = true;
+               boolean pendingNewlineAfterParen = false;
+               // true when a cr is to be put after a ) (in conditional statements)
+               boolean inAssignment = false;
+               boolean inArrayAssignment = false;
+               boolean inThrowsClause = false;
+               boolean inClassOrInterfaceHeader = false;
+
+               // openBracketCount is used to count the number of open brackets not closed yet.
+               int openBracketCount = 0;
+               int unarySignModifier = 0;
+
+               // openParenthesis[0] is used to count the parenthesis not belonging to a condition
+               // (eg foo();). parenthesis in for (...) are count elsewhere in the array.
+               int openParenthesisCount = 1;
+               int[] openParenthesis = new int[10];
+
+               // tokenBeforeColon is used to know what token goes along with the current :
+               // it can be case or ?
+               int tokenBeforeColonCount = 0;
+               int[] tokenBeforeColon = new int[10];
+
+               constructionsCount = 0; // initializes the constructions count.
+
+               // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
+               int nlicsToken = 0;
+
+               // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else 
+               boolean specialElse = false;
+
+               // OPTION (IndentationLevel): initial indentation level may be non-zero.
+               currentLineIndentationLevel += constructionsCount;
+
+               // An InvalidInputException exception might cause the termination of this loop.
+               try {
+                       while (true) {
+                               // Get the next token.  Catch invalid input and output it
+                               // with minimal formatting, also catch end of input and
+                               // exit the loop.
+                               try {
+                                       token = scanner.getNextToken();
+                                       
+                                       // Patch for line comment
+                                       // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096
+                                       if (token == ITerminalSymbols.TokenNameCOMMENT_LINE) {
+                                               int length = scanner.currentPosition;
+                                               loop: for (int index = length - 1; index >= 0; index--) {
+                                                       switch(scanner.source[index]) {
+                                                               case '\r' :
+                                                               case '\n' :
+                                                                       scanner.currentPosition--;
+                                                                       break;
+                                                               default:
+                                                                       break loop;
+                                                       }
+                                               }
+                                       }
+                               } catch (InvalidInputException e) {
+                                       if (!handleInvalidToken(e)) {
+                                               throw e;
+                                       }
+                                       token = 0;
+                               }
+                               if (token == Scanner.TokenNameEOF)
+                                       break;
+
+                               /* ## MODIFYING the indentation level before generating new lines
+                               and indentation in the output string
+                               */
+
+                               // Removes all the indentations made by statements not followed by a block
+                               // except if the current token is ELSE, CATCH or if we are in a switch/case
+                               if (clearNonBlockIndents && (token != Scanner.TokenNameWHITESPACE)) {
+                                       switch (token) {
+                                               case TokenNameelse :
+                                                       if (constructionsCount > 0
+                                                               && constructions[constructionsCount - 1] == TokenNameelse) {
+                                                               pendingNewLines = 1;
+                                                               specialElse = true;
+                                                       }
+                                                       indentationLevel += popInclusiveUntil(TokenNameif);
+                                                       break;
+//                                             case TokenNamecatch :
+//                                                     indentationLevel += popInclusiveUntil(TokenNamecatch);
+//                                                     break;
+//                                             case TokenNamefinally :
+//                                                     indentationLevel += popInclusiveUntil(TokenNamecatch);
+//                                                     break;
+                                               case TokenNamewhile :
+                                                       if (nlicsToken == TokenNamedo) {
+                                                               indentationLevel += pop(TokenNamedo);
+                                                               break;
+                                                       }
+                                               default :
+                                                       indentationLevel += popExclusiveUntilBlockOrCase();
+                                                       // clear until a CASE, DEFAULT or BLOCK is encountered.
+                                                       // Thus, the indentationLevel is correctly cleared either
+                                                       // in a switch/case statement or in any other situation.
+                                       }
+                                       clearNonBlockIndents = false;
+                               }
+                               // returns to the indentation level created by the SWITCH keyword
+                               // if the current token is a CASE or a DEFAULT
+                               if (token == TokenNamecase || token == TokenNamedefault) {
+                                       indentationLevel += pop(TokenNamecase);
+                               }
+//                             if (token == Scanner.TokenNamethrows) {
+//                                     inThrowsClause = true;
+//                             }
+                               if ((token == Scanner.TokenNameclass 
+                               // || token == Scanner.TokenNameinterface
+                                 ) && previousToken != Scanner.TokenNameDOT) {
+                                       inClassOrInterfaceHeader = true;
+                               }
+
+                               /* ## APPEND newlines and indentations to the output string
+                               */
+                               // Do not add a new line between ELSE and IF, if the option elseIfOnSameLine is true.
+                               // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
+                               if (pendingNewlineAfterParen
+                                       && previousCompilableToken == TokenNameelse
+                                       && token == TokenNameif
+                                       && options.compactElseIfMode) {
+                                       pendingNewlineAfterParen = false;
+                                       pendingNewLines = 0;
+                                       indentationLevel += pop(TokenNameelse);
+                                       // because else if is now one single statement,
+                                       // the indentation level after it is increased by one and not by 2
+                                       // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2).
+                               }
+                               // Add a newline & indent to the formatted source string if
+                               // a for/if-else/while statement was scanned and there is no block
+                               // following it.
+                               pendingNewlineAfterParen =
+                                       pendingNewlineAfterParen
+                                               || (previousCompilableToken == TokenNameRPAREN && token == TokenNameLBRACE);
+                               if (pendingNewlineAfterParen && token != Scanner.TokenNameWHITESPACE) {
+                                       pendingNewlineAfterParen = false;
+
+                                       // Do to add a newline & indent sequence if the current token is an
+                                       // open brace or a period or if the current token is a semi-colon and the
+                                       // previous token is a close paren.
+                                       // add a new line if a parenthesis belonging to a for() statement
+                                       // has been closed and the current token is not an opening brace
+                                       if (token != TokenNameLBRACE
+                                               && !isComment(token) // to avoid adding new line between else and a comment
+                                               && token != TokenNameDOT
+                                               && !(previousCompilableToken == TokenNameRPAREN && token == TokenNameSEMICOLON)) {
+                                               newLine(1);
+                                               currentLineIndentationLevel = indentationLevel;
+                                               pendingNewLines = 0;
+                                               pendingSpace = false;
+                                       } else {
+                                               if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode) {
+                                                       newLine(1);
+                                                       if (constructionsCount > 0
+                                                               && constructions[constructionsCount - 1] != BLOCK
+                                                               && constructions[constructionsCount - 1] != NONINDENT_BLOCK) {
+                                                               currentLineIndentationLevel = indentationLevel - 1;
+                                                       } else {
+                                                               currentLineIndentationLevel = indentationLevel;
+                                                       }
+                                                       pendingNewLines = 0;
+                                                       pendingSpace = false;
+                                               }
+                                       }
+                               }
+                               if (token == TokenNameLBRACE
+                                       && options.newLineBeforeOpeningBraceMode
+                                       && constructionsCount > 0
+                                       && constructions[constructionsCount - 1] == TokenNamedo) {
+                                       newLine(1);
+                                       currentLineIndentationLevel = indentationLevel - 1;
+                                       pendingNewLines = 0;
+                                       pendingSpace = false;
+                               }
+                               // see PR 1G5G8EC
+                               if (token == TokenNameLBRACE && inThrowsClause) {
+                                       inThrowsClause = false;
+                                       if (options.newLineBeforeOpeningBraceMode) {
+                                               newLine(1);
+                                               currentLineIndentationLevel = indentationLevel;
+                                               pendingNewLines = 0;
+                                               pendingSpace = false;
+                                       }
+                               }
+                               // see PR 1G5G82G
+                               if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
+                                       inClassOrInterfaceHeader = false;
+                                       if (options.newLineBeforeOpeningBraceMode) {
+                                               newLine(1);
+                                               currentLineIndentationLevel = indentationLevel;
+                                               pendingNewLines = 0;
+                                               pendingSpace = false;
+                                       }
+                               }
+                               // Add pending new lines to the formatted source string.
+                               // Note: pending new lines are not added if the current token
+                               // is a single line comment or whitespace.
+                               // if the comment is between parenthesis, there is no blank line preservation
+                               // (if it's a one-line comment, a blank line is added after it).
+                               if (((pendingNewLines > 0 && (!isComment(token)))
+                                       || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
+                                       || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE))
+                                       && token != Scanner.TokenNameWHITESPACE) {
+
+                                       // Do not add newline & indent between an adjoining close brace and
+                                       // close paren.  Anonymous inner classes may use this form.
+                                       boolean closeBraceAndCloseParen =
+                                               previousToken == TokenNameRBRACE && token == TokenNameRPAREN;
+
+                                       // OPTION (NewLineInCompoundStatement): do not add newline & indent
+                                       // between close brace and else, (do) while, catch, and finally if
+                                       // newlineInCompoundStatement is true.
+                                       boolean nlicsOption =
+                                               previousToken == TokenNameRBRACE
+                                                       && !options.newlineInControlStatementMode
+                                                       && (token == TokenNameelse
+                                                               || (token == TokenNamewhile && nlicsToken == TokenNamedo));
+//                                                             || token == TokenNamecatch
+//                                                             || token == TokenNamefinally);
+
+                                       // Do not add a newline & indent between a close brace and semi-colon.
+                                       boolean semiColonAndCloseBrace =
+                                               previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON;
+
+                                       // Do not add a new line & indent between a multiline comment and a opening brace
+                                       boolean commentAndOpenBrace =
+                                               previousToken == Scanner.TokenNameCOMMENT_BLOCK && token == TokenNameLBRACE;
+
+                                       // Do not add a newline & indent between a close brace and a colon (in array assignments, for example).
+                                       boolean commaAndCloseBrace =
+                                               previousToken == TokenNameRBRACE && token == TokenNameCOMMA;
+
+                                       // Add a newline and indent, if appropriate.
+                                       if (specialElse
+                                               || (!commentAndOpenBrace
+                                                       && !closeBraceAndCloseParen
+                                                       && !nlicsOption
+                                                       && !semiColonAndCloseBrace
+                                                       && !commaAndCloseBrace)) {
+
+                                               // if clearAllBlankLinesMode=false, leaves the blank lines
+                                               // inserted by the user
+                                               // if clearAllBlankLinesMode=true, removes all of then
+                                               // and insert only blank lines required by the formatting.
+                                               if (!options.clearAllBlankLinesMode) {
+                                                       //  (isComment(token))
+                                                       pendingNewLines =
+                                                               (pendingNewLines < newLinesInWhitespace)
+                                                                       ? newLinesInWhitespace
+                                                                       : pendingNewLines;
+                                                       pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines;
+                                               }
+                                               if (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE) {
+                                                       containsOpenCloseBraces = true;
+                                                       indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+                                                       if (isComment(previousToken)) {
+                                                               newLine(pendingNewLines);
+                                                       } else {
+                                                               /*  if (!(constructionsCount > 1
+                                                                       && constructions[constructionsCount-1] == NONINDENT_BLOCK
+                                                                       && (constructions[constructionsCount-2] == TokenNamefor 
+                                                                        || constructions[constructionsCount-2] == TokenNamewhile))) {*/
+                                                               if (options.newLineInEmptyBlockMode) {
+                                                                       if (inArrayAssignment) {
+                                                                               newLine(1); // array assigment with an empty block
+                                                                       } else {
+                                                                               newLine(pendingNewLines);
+                                                                       }
+                                                               }
+                                                               // }
+                                                       }
+                                               } else {
+                                                       // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment before the ';'
+                                                       if (!((previousToken == Scanner.TokenNameCOMMENT_BLOCK
+                                                               || previousToken == Scanner.TokenNameCOMMENT_PHPDOC)
+                                                               && token == TokenNameSEMICOLON)) {
+                                                               newLine(pendingNewLines);
+                                                       }
+                                               }
+                                               if (((previousCompilableToken == TokenNameSEMICOLON)
+                                                       || (previousCompilableToken == TokenNameLBRACE)
+                                                       || (previousCompilableToken == TokenNameRBRACE)
+                                                       || (isComment(previousToken)))
+                                                       && (token == TokenNameRBRACE)) {
+                                                       indentationOffset = -1;
+                                                       indentationLevel += popExclusiveUntilBlock();
+                                               }
+                                               if (previousToken == Scanner.TokenNameCOMMENT_LINE && inAssignment) {
+                                                       // PR 1FI5IPO
+                                                       currentLineIndentationLevel++;
+                                               } else {
+                                                       currentLineIndentationLevel = indentationLevel + indentationOffset;
+                                               }
+                                               pendingSpace = false;
+                                               indentationOffset = 0;
+                                       }
+                                       pendingNewLines = 0;
+                                       newLinesInWhitespace = 0;
+                                       specialElse = false;
+
+                                       if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
+                                               nlicsToken = 0;
+                                       }
+                               }
+                               switch (token) {
+                                       case TokenNameelse :
+       //                              case TokenNamefinally :
+                                               expectingOpenBrace = true;
+                                               pendingNewlineAfterParen = true;
+                                               indentationLevel += pushControlStatement(token);
+                                               break;
+                                       case TokenNamecase :
+                                       case TokenNamedefault :
+                                               if (tokenBeforeColonCount == tokenBeforeColon.length) {
+                                                       System.arraycopy(
+                                                               tokenBeforeColon,
+                                                               0,
+                                                               (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
+                                                               0,
+                                                               tokenBeforeColonCount);
+                                               }
+                                               tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
+                                               indentationLevel += pushControlStatement(TokenNamecase);
+                                               break;
+                                       case TokenNameQUESTION :
+                                               if (tokenBeforeColonCount == tokenBeforeColon.length) {
+                                                       System.arraycopy(
+                                                               tokenBeforeColon,
+                                                               0,
+                                                               (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
+                                                               0,
+                                                               tokenBeforeColonCount);
+                                               }
+                                               tokenBeforeColon[tokenBeforeColonCount++] = token;
+                                               break;
+                                       case TokenNameswitch :
+                                       case TokenNamefor :
+                                       case TokenNameif :
+                                       case TokenNamewhile :
+                                               if (openParenthesisCount == openParenthesis.length) {
+                                                       System.arraycopy(
+                                                               openParenthesis,
+                                                               0,
+                                                               (openParenthesis = new int[openParenthesisCount * 2]),
+                                                               0,
+                                                               openParenthesisCount);
+                                               }
+                                               openParenthesis[openParenthesisCount++] = 0;
+                                               expectingOpenBrace = true;
+
+                                               indentationLevel += pushControlStatement(token);
+                                               break;
+//                                     case TokenNametry :
+//                                             pendingNewlineAfterParen = true;
+//                                     case TokenNamecatch :
+//                                             // several CATCH statements can be contiguous.
+//                                             // a CATCH is encountered pop until first CATCH (if a CATCH follows a TRY it works the same way,
+//                                             // as CATCH and TRY are the same token in the stack).
+//                                             expectingOpenBrace = true;
+//                                             indentationLevel += pushControlStatement(TokenNamecatch);
+//                                             break;
+
+                                       case TokenNamedo :
+                                               expectingOpenBrace = true;
+                                               indentationLevel += pushControlStatement(token);
+                                               nlicsToken = token;
+                                               break;
+                                       case TokenNamenew :
+                                               break;
+                                       case TokenNameLPAREN :
+//                                             if (previousToken == TokenNamesynchronized) {
+//                                                     indentationLevel += pushControlStatement(previousToken);
+//                                             } else {
+                                                       // Put a space between the previous and current token if the
+                                                       // previous token was not a keyword, open paren, logical
+                                                       // compliment (eg: !), semi-colon, open brace, close brace,
+                                                       // super, or this.
+                                                       if (previousCompilableToken != TokenNameLBRACKET
+                                                               && previousToken != TokenNameIdentifier
+                                                               && previousToken != 0
+                                                               && previousToken != TokenNameNOT
+                                                               && previousToken != TokenNameLPAREN
+                                                               && previousToken != TokenNameTWIDDLE
+                                                               && previousToken != TokenNameSEMICOLON
+                                                               && previousToken != TokenNameLBRACE
+                                                               && previousToken != TokenNameRBRACE) {
+//                                                             && previousToken != TokenNamesuper
+//                                                             && previousToken != TokenNamethis) {
+                                                               space();
+                                                       }
+                                                       // If in a for/if/while statement, increase the parenthesis count
+                                                       // for the current openParenthesisCount
+                                                       // else increase the count for stand alone parenthesis.
+                                                       if (openParenthesisCount > 0)
+                                                               openParenthesis[openParenthesisCount - 1]++;
+                                                       else
+                                                               openParenthesis[0]++;
+       
+                                                       pendingSpace = false;
+                       //S                     }
+                                               break;
+                                       case TokenNameRPAREN :
+
+                                               // Decrease the parenthesis count
+                                               // if there is no more unclosed parenthesis,
+                                               // a new line and indent may be append (depending on the next token).
+                                               if ((openParenthesisCount > 1)
+                                                       && (openParenthesis[openParenthesisCount - 1] > 0)) {
+                                                       openParenthesis[openParenthesisCount - 1]--;
+                                                       if (openParenthesis[openParenthesisCount - 1] <= 0) {
+                                                               pendingNewlineAfterParen = true;
+                                                               inAssignment = false;
+                                                               openParenthesisCount--;
+                                                       }
+                                               } else {
+                                                       openParenthesis[0]--;
+                                               }
+                                               pendingSpace = false;
+                                               break;
+                                       case TokenNameLBRACE :
+                                               if ((previousCompilableToken == TokenNameRBRACKET)
+                                                       || (previousCompilableToken == TokenNameEQUAL)) {
+                                                       //                  if (previousCompilableToken == TokenNameRBRACKET) {
+                                                       inArrayAssignment = true;
+                                                       inAssignment = false;
+                                               }
+                                               if (inArrayAssignment) {
+                                                       indentationLevel += pushBlock();
+                                               } else {
+                                                       // Add new line and increase indentation level after open brace.
+                                                       pendingNewLines = 1;
+                                                       indentationLevel += pushBlock();
+                                               }
+                                               break;
+                                       case TokenNameRBRACE :
+                                               if (previousCompilableToken == TokenNameRPAREN) {
+                                                       pendingSpace = false;
+                                               }
+                                               if (inArrayAssignment) {
+                                                       inArrayAssignment = false;
+                                                       pendingNewLines = 1;
+                                                       indentationLevel += popInclusiveUntilBlock();
+                                               } else {
+                                                       pendingNewLines = 1;
+                                                       indentationLevel += popInclusiveUntilBlock();
+
+                                                       if (previousCompilableToken == TokenNameRPAREN) {
+                                                               // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
+                                                               currentLineBuffer.append(options.lineSeparatorSequence);
+                                                               increaseLineDelta(options.lineSeparatorSequence.length);
+                                                       }
+                                                       if (constructionsCount > 0) {
+                                                               switch (constructions[constructionsCount - 1]) {
+                                                                       case TokenNamefor :
+                                                                               //indentationLevel += popExclusiveUntilBlock();
+                                                                               //break;
+                                                                       case TokenNameswitch :
+                                                                       case TokenNameif :
+                                                                       case TokenNameelse :
+//                                                                     case TokenNametry :
+//                                                                     case TokenNamecatch :
+//                                                                     case TokenNamefinally :
+                                                                       case TokenNamewhile :
+                                                                       case TokenNamedo :
+//                                                                     case TokenNamesynchronized :
+                                                                               clearNonBlockIndents = true;
+                                                                       default :
+                                                                               break;
+                                                               }
+                                                       }
+                                               }
+                                               break;
+                                       case TokenNameLBRACKET :
+                                               openBracketCount++;
+                                               pendingSpace = false;
+                                               break;
+                                       case TokenNameRBRACKET :
+                                               openBracketCount -= (openBracketCount > 0) ? 1 : 0;
+                                               // if there is no left bracket to close, the right bracket is ignored.
+                                               pendingSpace = false;
+                                               break;
+                                       case TokenNameCOMMA :
+                                       case TokenNameDOT :
+                                               pendingSpace = false;
+                                               break;
+                                       case TokenNameSEMICOLON :
+
+                                               // Do not generate line terminators in the definition of
+                                               // the for statement.
+                                               // if not in this case, jump a line and reduce indentation after the brace
+                                               // if the block it closes belongs to a conditional statement (if, while, do...).
+                                               if (openParenthesisCount <= 1) {
+                                                       pendingNewLines = 1;
+                                                       if (expectingOpenBrace) {
+                                                               clearNonBlockIndents = true;
+                                                               expectingOpenBrace = false;
+                                                       }
+                                               }
+                                               inAssignment = false;
+                                               pendingSpace = false;
+                                               break;
+                                       case TokenNamePLUS_PLUS :
+                                       case TokenNameMINUS_MINUS :
+
+                                               // Do not put a space between a post-increment/decrement
+                                               // and the identifier being modified.
+                                               if (previousToken == TokenNameIdentifier
+                                                       || previousToken == TokenNameRBRACKET) {
+                                                       pendingSpace = false;
+                                               }
+                                               break;
+                                       case TokenNamePLUS : // previously ADDITION
+                                       case TokenNameMINUS :
+
+                                               // Handle the unary operators plus and minus via a flag
+                                               if (!isLiteralToken(previousToken)
+                                                       && previousToken != TokenNameIdentifier
+                                                       && previousToken != TokenNameRPAREN
+                                                       && previousToken != TokenNameRBRACKET) {
+                                                       unarySignModifier = 1;
+                                               }
+                                               break;
+                                       case TokenNameCOLON :
+                                               // In a switch/case statement, add a newline & indent
+                                               // when a colon is encountered.
+                                               if (tokenBeforeColonCount > 0) {
+                                                       if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenNamecase) {
+                                                               pendingNewLines = 1;
+                                                       }
+                                                       tokenBeforeColonCount--;
+                                               }
+                                               break;
+                                       case TokenNameEQUAL :
+                                               inAssignment = true;
+                                               break;
+                                       case Scanner.TokenNameCOMMENT_LINE :
+                                               pendingNewLines = 1;
+                                               if (inAssignment) {
+                                                       currentLineIndentationLevel++;
+                                               }
+                                               break; // a line is always inserted after a one-line comment
+                                       case Scanner.TokenNameCOMMENT_PHPDOC :
+                                       case Scanner.TokenNameCOMMENT_BLOCK :
+                                               currentCommentOffset = getCurrentCommentOffset();
+                                               pendingNewLines = 1;
+                                               break;
+                                       case Scanner.TokenNameWHITESPACE :
+
+                                               // Count the number of line terminators in the whitespace so
+                                               // line spacing can be preserved near comments.
+                                               char[] source = scanner.source;
+                                               newLinesInWhitespace = 0;
+                                               for (int i = scanner.startPosition, max = scanner.currentPosition;
+                                                       i < max;
+                                                       i++) {
+                                                       if (source[i] == '\r') {
+                                                               if (i < max - 1) {
+                                                                       if (source[++i] == '\n') {
+                                                                               newLinesInWhitespace++;
+                                                                       } else {
+                                                                               newLinesInWhitespace++;
+                                                                       }
+                                                               } else {
+                                                                       newLinesInWhitespace++;
+                                                               }
+                                                       } else if (source[i] == '\n') {
+                                                                       newLinesInWhitespace++;
+                                                       }
+                                               }
+                                               increaseLineDelta(scanner.startPosition - scanner.currentPosition);
+                                               break;
+                                       default :
+                                               if ((token == TokenNameIdentifier)
+                                                       || isLiteralToken(token)) {
+//                                                     || token == TokenNamesuper
+//                                                     || token == TokenNamethis) {
+
+                                                       // Do not put a space between a unary operator
+                                                       // (eg: ++, --, +, -) and the identifier being modified.
+                                                       if (previousToken == TokenNamePLUS_PLUS
+                                                               || previousToken == TokenNameMINUS_MINUS
+                                                               || (previousToken == TokenNamePLUS && unarySignModifier > 0)
+                                                               || (previousToken == TokenNameMINUS && unarySignModifier > 0)) {
+                                                               pendingSpace = false;
+                                                       }
+                                                       unarySignModifier = 0;
+                                               }
+                                               break;
+                               }
+                               // Do not output whitespace tokens.
+                               if (token != Scanner.TokenNameWHITESPACE) {
+
+                                       /* Add pending space to the formatted source string.
+                                       Do not output a space under the following circumstances:
+                                       1) this is the first pass
+                                       2) previous token is an open paren
+                                       3) previous token is a period
+                                       4) previous token is the logical compliment (eg: !)
+                                       5) previous token is the bitwise compliment (eg: ~)
+                                       6) previous token is the open bracket (eg: [)
+                                       7) in an assignment statement, if the previous token is an 
+                                       open brace or the current token is a close brace
+                                       8) previous token is a single line comment
+                                       */
+                                       boolean openAndCloseBrace =
+                                               previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE;
+
+                                       if (pendingSpace
+                                               && insertSpaceAfter(previousToken)
+                                               && !(inAssignment
+                                                       && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
+                                               && previousToken != Scanner.TokenNameCOMMENT_LINE) {
+                                               if ((!(options.compactAssignmentMode && token == TokenNameEQUAL))
+                                                       && !openAndCloseBrace)
+                                                       space();
+                                       }
+                                       // Add the next token to the formatted source string.
+                                       outputCurrentToken(token);
+                                       if (token == Scanner.TokenNameCOMMENT_LINE && openParenthesisCount > 1) {
+                                               pendingNewLines = 0;
+                                               currentLineBuffer.append(options.lineSeparatorSequence);
+                                               increaseLineDelta(options.lineSeparatorSequence.length);
+                                       }
+                                       pendingSpace = true;
+                               }
+                               // Whitespace tokens do not need to be remembered.
+                               if (token != Scanner.TokenNameWHITESPACE) {
+                                       previousToken = token;
+                                       if (token != Scanner.TokenNameCOMMENT_BLOCK
+                                               && token != Scanner.TokenNameCOMMENT_LINE
+                                               && token != Scanner.TokenNameCOMMENT_PHPDOC) {
+                                               previousCompilableToken = token;
+                                       }
+                               }
+                       }
+                       output(copyRemainingSource());
+                       flushBuffer(); // dump the last token of the source in the formatted output.
+               } catch (InvalidInputException e) {
+                       output(copyRemainingSource());
+                       flushBuffer(); // dump the last token of the source in the formatted output.
+               }
+       }
+
+       /** 
+        * Formats the char array <code>sourceString</code>,
+        * and returns a string containing the formatted version.
+        * @return the formatted ouput.
+        */
+       public String formatSourceString(String sourceString) {
+               char[] sourceChars = sourceString.toCharArray();
+               formattedSource = new StringBuffer(sourceChars.length);
+               scanner.setSource(sourceChars);
+               format();
+               return formattedSource.toString();
+       }
+
+       /** 
+        * Formats the char array <code>sourceString</code>,
+        * and returns a string containing the formatted version.
+        * @param string the string to format
+        * @param indentationLevel the initial indentation level
+        * @return the formatted ouput.
+        */
+       public String format(String string, int indentationLevel) {
+               return format(string, indentationLevel, (int[])null);
+       }       
+       
+       /** 
+        * Formats the char array <code>sourceString</code>,
+        * and returns a string containing the formatted version.
+        * The positions array is modified to contain the mapped positions.
+        * @param string the string to format
+        * @param indentationLevel the initial indentation level
+        * @param positions the array of positions to map
+        * @return the formatted ouput.
+        */
+       public String format(String string, int indentationLevel, int[] positions) {
+               return this.format(string, indentationLevel, positions, null);
+       }
+       
+       public String format(String string, int indentationLevel, int[] positions, String lineSeparator) {
+               if (lineSeparator != null){
+                       this.options.setLineSeparator(lineSeparator);
+               }
+               if (positions != null) {
+                       this.setPositionsToMap(positions);
+                       this.setInitialIndentationLevel(indentationLevel);
+                       String formattedString = this.formatSourceString(string);
+                       int[] mappedPositions = this.getMappedPositions();
+                       System.arraycopy(mappedPositions, 0, positions, 0, positions.length);
+                       return formattedString;
+               } else {
+                       this.setInitialIndentationLevel(indentationLevel);
+                       return this.formatSourceString(string);
+               }
+       }       
+       /** 
+        * Formats the char array <code>sourceString</code>,
+        * and returns a string containing the formatted version. The initial indentation level is 0.
+        * @param string the string to format
+        * @return the formatted ouput.
+        */
+       public String format(String string) {
+               return this.format(string, 0, (int[])null);
+       }
+       
+       /** 
+        * Formats a given source string, starting indenting it at a particular 
+        * depth and using the given options
+        * 
+        * @deprecated backport 1.0 internal functionality
+        */
+       public static String format(String sourceString, int initialIndentationLevel, ConfigurableOption[] options) {
+               CodeFormatter formatter = new CodeFormatter(options);
+               formatter.setInitialIndentationLevel(initialIndentationLevel);
+               return formatter.formatSourceString(sourceString);
+       }
+       
+       /**
+        * Returns the number of characters and tab char between the beginning of the line
+        * and the beginning of the comment.
+        */
+       private int getCurrentCommentOffset() {
+               int linePtr = scanner.linePtr;
+               // if there is no beginning of line, return 0.
+               if (linePtr < 0)
+                       return 0;
+               int offset = 0;
+               int beginningOfLine = scanner.lineEnds[linePtr];
+               int currentStartPosition = scanner.startPosition;
+               char[] source = scanner.source;
+
+               // find the position of the beginning of the line containing the comment
+               while (beginningOfLine > currentStartPosition) {
+                       if (linePtr > 0) {
+                               beginningOfLine = scanner.lineEnds[--linePtr];
+                       } else {
+                               beginningOfLine = 0;
+                               break;
+                       }
+               }
+               for (int i = currentStartPosition - 1; i >= beginningOfLine ; i--) {
+                       char currentCharacter = source[i];
+                       switch (currentCharacter) {
+                               case '\t' :
+                                       offset += options.tabSize;
+                                       break;
+                               case ' ' :
+                                       offset++;
+                                       break;
+                               case '\r' :
+                               case '\n' :
+                                       break;
+                               default:
+                                       return offset;
+                       }
+               }
+               return offset;
+       }
+       
+       /**
+        * Returns an array of descriptions for the configurable options.
+        * The descriptions may be changed and passed back to a different
+        * compiler.
+        * 
+        * @deprecated backport 1.0 internal functionality
+        */
+       public static ConfigurableOption[] getDefaultOptions(Locale locale) {
+               String componentName = CodeFormatter.class.getName();
+               FormatterOptions options = new FormatterOptions();
+               return new ConfigurableOption[] {
+                       new ConfigurableOption(componentName, "newline.openingBrace",  locale, options.newLineBeforeOpeningBraceMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "newline.controlStatement",  locale, options.newlineInControlStatementMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "newline.clearAll",  locale, options.clearAllBlankLinesMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "newline.elseIf",  locale, options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "newline.emptyBlock",  locale, options.newLineInEmptyBlockMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "line.split",  locale, options.maxLineLength),//$NON-NLS-1$
+                       new ConfigurableOption(componentName, "style.compactAssignment",  locale, options.compactAssignmentMode ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "tabulation.char",  locale, options.indentWithTab ? 0 : 1), //$NON-NLS-1$
+                       new ConfigurableOption(componentName, "tabulation.size",  locale, options.tabSize)      //$NON-NLS-1$
+               };
+       }
+
+       /**
+        * Returns the array of mapped positions.
+        * Returns null is no positions have been set.
+        * @return int[]
+        * @deprecated There is no need to retrieve the mapped positions anymore.
+        */
+       public int[] getMappedPositions() {
+               return mappedPositions;
+       }
+
+       /**
+        * Returns the priority of the token given as argument<br>
+        * The most prioritary the token is, the smallest the return value is.
+        * @return the priority of <code>token</code>
+        * @param token the token of which the priority is requested
+        */
+       private static int getTokenPriority(int token) {
+               switch (token) {
+                       case TokenNameextends :
+//                     case TokenNameimplements :
+//                     case TokenNamethrows :
+                               return 10;
+                       case TokenNameSEMICOLON : // ;
+                               return 20;
+                       case TokenNameCOMMA : // ,
+                               return 25;
+                       case TokenNameEQUAL : // =
+                               return 30;
+                       case TokenNameAND_AND : // && 
+                       case TokenNameOR_OR : // || 
+                               return 40;
+                       case TokenNameQUESTION : // ? 
+                       case TokenNameCOLON : // :
+                               return 50; // it's better cutting on ?: than on ;
+                       case TokenNameEQUAL_EQUAL : // == 
+                       case TokenNameNOT_EQUAL : // != 
+                               return 60;
+                       case TokenNameLESS : // < 
+                       case TokenNameLESS_EQUAL : // <= 
+                       case TokenNameGREATER : // > 
+                       case TokenNameGREATER_EQUAL : // >= 
+//                     case TokenNameinstanceof : // instanceof
+                               return 70;
+                       case TokenNamePLUS : // + 
+                       case TokenNameMINUS : // - 
+                               return 80;
+                       case TokenNameMULTIPLY : // * 
+                       case TokenNameDIVIDE : // / 
+                       case TokenNameREMAINDER : // % 
+                               return 90;
+                       case TokenNameLEFT_SHIFT : // << 
+                       case TokenNameRIGHT_SHIFT : // >> 
+//                     case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> 
+                               return 100;
+                       case TokenNameAND : // &
+                       case TokenNameOR : // | 
+                       case TokenNameXOR : // ^ 
+                               return 110;
+                       case TokenNameMULTIPLY_EQUAL : // *= 
+                       case TokenNameDIVIDE_EQUAL : // /= 
+                       case TokenNameREMAINDER_EQUAL : // %= 
+                       case TokenNamePLUS_EQUAL : // += 
+                       case TokenNameMINUS_EQUAL : // -= 
+                       case TokenNameLEFT_SHIFT_EQUAL : // <<= 
+                       case TokenNameRIGHT_SHIFT_EQUAL : // >>= 
+//                     case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
+                       case TokenNameAND_EQUAL : // &= 
+                       case TokenNameXOR_EQUAL : // ^= 
+                       case TokenNameOR_EQUAL : // |= 
+                               return 120;
+                       case TokenNameDOT : // .
+                               return 130;
+                       default :
+                               return Integer.MAX_VALUE;
+               }
+       }
+
+       /**
+        * Handles the exception raised when an invalid token is encountered.
+        * Returns true if the exception has been handled, false otherwise.
+        */
+       private boolean handleInvalidToken(Exception e) {
+               if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT)
+                       || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
+                       || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
+                       return true;
+               }
+               return false;
+       }
+
+       private final void increaseGlobalDelta(int offset) {
+               globalDelta += offset;
+       }
+
+       private final void increaseLineDelta(int offset) {
+               lineDelta += offset;
+       }
+
+       private final void increaseSplitDelta(int offset) {
+               splitDelta += offset;
+       }
+
+       /**
+        * Returns true if a space has to be inserted after <code>operator</code>
+        * false otherwise.
+        */
+       private boolean insertSpaceAfter(int token) {
+               switch (token) {
+                       case TokenNameLPAREN :
+                       case TokenNameNOT :
+                       case TokenNameTWIDDLE :
+                       case TokenNameDOT :
+                       case 0 : // no token
+                       case TokenNameLBRACKET :
+                       case Scanner.TokenNameCOMMENT_LINE :
+                               return false;
+                       default :
+                               return true;
+               }
+       }
+
+       /**
+        * Returns true if a space has to be inserted before <code>operator</code>
+        * false otherwise.<br>
+        * Cannot be static as it uses the code formatter options
+        * (to know if the compact assignment mode is on).
+        */
+       private boolean insertSpaceBefore(int token) {
+               switch (token) {
+                       case TokenNameEQUAL :
+                               return (!options.compactAssignmentMode);
+                       default :
+                               return false;
+               }
+       }
+
+       private static boolean isComment(int token) {
+               boolean result =
+                       token == Scanner.TokenNameCOMMENT_BLOCK
+                               || token == Scanner.TokenNameCOMMENT_LINE
+                               || token == Scanner.TokenNameCOMMENT_PHPDOC;
+               return result;
+       }
+
+       private static boolean isLiteralToken(int token) {
+               boolean result =
+                       token == TokenNameIntegerLiteral
+       //                      || token == TokenNameLongLiteral
+       //                      || token == TokenNameFloatingPointLiteral
+                               || token == TokenNameDoubleLiteral
+       //                      || token == TokenNameCharacterLiteral
+                               || token == TokenNameStringLiteral;
+               return result;
+       }
+
+       /**
+        * If the length of <code>oneLineBuffer</code> exceeds <code>maxLineLength</code>,
+        * it is split and the result is dumped in <code>formattedSource</code>
+        * @param newLineCount the number of new lines to append
+        */
+       private void newLine(int newLineCount) {
+
+               // format current line
+               splitDelta = 0;
+               beginningOfLineIndex = formattedSource.length();
+               String currentLine = currentLineBuffer.toString();
+               if (containsOpenCloseBraces) {
+                       containsOpenCloseBraces = false;
+                       outputLine(
+                               currentLine,
+                               false,
+                               indentationLevelForOpenCloseBraces,
+                               0,
+                               -1,
+                               null,
+                               0);
+                       indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+               } else {
+                       outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0);
+               }
+               // dump line break(s)
+               for (int i = 0; i < newLineCount; i++) {
+                       formattedSource.append(options.lineSeparatorSequence);
+                       increaseSplitDelta(options.lineSeparatorSequence.length);
+               }
+               // reset formatter for next line
+               int currentLength = currentLine.length();
+               currentLineBuffer =
+                       new StringBuffer(
+                               currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize);
+
+               increaseGlobalDelta(splitDelta);
+               increaseGlobalDelta(lineDelta);
+               lineDelta = 0;
+               currentLineIndentationLevel = initialIndentationLevel;
+       }
+
+       private String operatorString(int operator) {
+               switch (operator) {
+                       case TokenNameextends :
+                               return "extends"; //$NON-NLS-1$
+
+//                     case TokenNameimplements :
+//                             return "implements"; //$NON-NLS-1$
+//
+//                     case TokenNamethrows :
+//                             return "throws"; //$NON-NLS-1$
+
+                       case TokenNameSEMICOLON : // ;
+                               return ";"; //$NON-NLS-1$
+
+                       case TokenNameCOMMA : // ,
+                               return ","; //$NON-NLS-1$
+
+                       case TokenNameEQUAL : // =
+                               return "="; //$NON-NLS-1$
+
+                       case TokenNameAND_AND : // && (15.22)
+                               return "&&"; //$NON-NLS-1$
+
+                       case TokenNameOR_OR : // || (15.23)
+                               return "||"; //$NON-NLS-1$
+
+                       case TokenNameQUESTION : // ? (15.24)
+                               return "?"; //$NON-NLS-1$
+
+                       case TokenNameCOLON : // : (15.24)
+                               return ":"; //$NON-NLS-1$
+
+                       case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+                               return "=="; //$NON-NLS-1$
+
+                       case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+                               return "!="; //$NON-NLS-1$
+
+                       case TokenNameLESS : // < (15.19.1)
+                               return "<"; //$NON-NLS-1$
+
+                       case TokenNameLESS_EQUAL : // <= (15.19.1)
+                               return "<="; //$NON-NLS-1$
+
+                       case TokenNameGREATER : // > (15.19.1)
+                               return ">"; //$NON-NLS-1$
+
+                       case TokenNameGREATER_EQUAL : // >= (15.19.1)
+                               return ">="; //$NON-NLS-1$
+
+//                     case TokenNameinstanceof : // instanceof
+//                             return "instanceof"; //$NON-NLS-1$
+
+                       case TokenNamePLUS : // + (15.17, 15.17.2)
+                               return "+"; //$NON-NLS-1$
+
+                       case TokenNameMINUS : // - (15.17.2)
+                               return "-"; //$NON-NLS-1$
+
+                       case TokenNameMULTIPLY : // * (15.16.1)
+                               return "*"; //$NON-NLS-1$
+
+                       case TokenNameDIVIDE : // / (15.16.2)
+                               return "/"; //$NON-NLS-1$
+
+                       case TokenNameREMAINDER : // % (15.16.3)
+                               return "%"; //$NON-NLS-1$
+
+                       case TokenNameLEFT_SHIFT : // << (15.18)
+                               return "<<"; //$NON-NLS-1$
+
+                       case TokenNameRIGHT_SHIFT : // >> (15.18)
+                               return ">>"; //$NON-NLS-1$
+
+//                     case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+//                             return ">>>"; //$NON-NLS-1$
+
+                       case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+                               return "&"; //$NON-NLS-1$
+
+                       case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+                               return "|"; //$NON-NLS-1$
+
+                       case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+                               return "^"; //$NON-NLS-1$
+
+                       case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+                               return "*="; //$NON-NLS-1$
+
+                       case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+                               return "/="; //$NON-NLS-1$
+
+                       case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+                               return "%="; //$NON-NLS-1$
+
+                       case TokenNamePLUS_EQUAL : // += (15.25.2)
+                               return "+="; //$NON-NLS-1$
+
+                       case TokenNameMINUS_EQUAL : // -= (15.25.2)
+                               return "-="; //$NON-NLS-1$
+
+                       case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+                               return "<<="; //$NON-NLS-1$
+
+                       case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+                               return ">>="; //$NON-NLS-1$
+
+//                     case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+//                             return ">>>="; //$NON-NLS-1$
+
+                       case TokenNameAND_EQUAL : // &= (15.25.2)
+                               return "&="; //$NON-NLS-1$
+
+                       case TokenNameXOR_EQUAL : // ^= (15.25.2)
+                               return "^="; //$NON-NLS-1$
+
+                       case TokenNameOR_EQUAL : // |= (15.25.2)
+                               return "|="; //$NON-NLS-1$
+
+                       case TokenNameDOT : // .
+                               return "."; //$NON-NLS-1$
+
+                       default :
+                               return ""; //$NON-NLS-1$
+               }
+       }
+
+       /** 
+        * Appends <code>stringToOutput</code> to the formatted output.<br>
+        * If it contains \n, append a LINE_SEPARATOR and indent after it.
+        */
+       private void output(String stringToOutput) {
+               char currentCharacter;
+               for (int i = 0, max = stringToOutput.length(); i < max; i++) {
+                       currentCharacter = stringToOutput.charAt(i);
+                       if (currentCharacter != '\t') {
+                               currentLineBuffer.append(currentCharacter);
+                       }
+               }
+       }
+
+       /** 
+        * Appends <code>token</code> to the formatted output.<br>
+        * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent after it.
+        */
+       private void outputCurrentToken(int token) {
+               char[] source = scanner.source;
+               int startPosition = scanner.startPosition;
+
+               switch (token) {
+                       case Scanner.TokenNameCOMMENT_PHPDOC :
+                       case Scanner.TokenNameCOMMENT_BLOCK :
+                       case Scanner.TokenNameCOMMENT_LINE :
+                               boolean endOfLine = false;
+                               int currentCommentOffset = getCurrentCommentOffset();
+                               int beginningOfLineSpaces = 0;
+                               endOfLine = false;
+                               currentCommentOffset = getCurrentCommentOffset();
+                               beginningOfLineSpaces = 0;
+                               boolean pendingCarriageReturn = false;
+                               for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
+                                       char currentCharacter = source[i];
+                                       updateMappedPositions(i);
+                                       switch (currentCharacter) {
+                                               case '\r' :
+                                                       pendingCarriageReturn = true;
+                                                       endOfLine = true;
+                                                       break;
+                                               case '\n' :
+                                                       if (pendingCarriageReturn) {
+                                                               increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
+                                                       } else {
+                                                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                                                       }
+                                                       pendingCarriageReturn = false;
+                                                       currentLineBuffer.append(options.lineSeparatorSequence);
+                                                       beginningOfLineSpaces = 0;
+                                                       endOfLine = true;
+                                                       break;
+                                               case '\t' :
+                                                       if (pendingCarriageReturn) {
+                                                               pendingCarriageReturn = false;
+                                                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                                                               currentLineBuffer.append(options.lineSeparatorSequence);
+                                                               beginningOfLineSpaces = 0;
+                                                               endOfLine = true;
+                                                       }
+                                                       if (endOfLine) {
+                                                               // we remove a maximum of currentCommentOffset characters (tabs are converted to space numbers).
+                                                               beginningOfLineSpaces += options.tabSize;
+                                                               if (beginningOfLineSpaces > currentCommentOffset) {
+                                                                       currentLineBuffer.append(currentCharacter);
+                                                               } else {
+                                                                       increaseGlobalDelta(-1);
+                                                               }
+                                                       } else {
+                                                               currentLineBuffer.append(currentCharacter);
+                                                       }
+                                                       break;
+                                               case ' ' :
+                                                       if (pendingCarriageReturn) {
+                                                               pendingCarriageReturn = false;
+                                                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                                                               currentLineBuffer.append(options.lineSeparatorSequence);
+                                                               beginningOfLineSpaces = 0;
+                                                               endOfLine = true;
+                                                       }
+                                                       if (endOfLine) {
+                                                               // we remove a maximum of currentCommentOffset characters (tabs are converted to space numbers).
+                                                               beginningOfLineSpaces++;
+                                                               if (beginningOfLineSpaces > currentCommentOffset) {
+                                                                       currentLineBuffer.append(currentCharacter);
+                                                               } else {
+                                                                       increaseGlobalDelta(-1);
+                                                               }
+                                                       } else {
+                                                               currentLineBuffer.append(currentCharacter);
+                                                       }
+                                                       break;
+                                               default :
+                                                       if (pendingCarriageReturn) {
+                                                               pendingCarriageReturn = false;
+                                                               increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+                                                               currentLineBuffer.append(options.lineSeparatorSequence);
+                                                               beginningOfLineSpaces = 0;
+                                                               endOfLine = true;
+                                                       } else {
+                                                               beginningOfLineSpaces = 0;
+                                                               currentLineBuffer.append(currentCharacter);
+                                                               endOfLine = false;                                                              
+                                                       }
+                                       }
+                               }
+                               updateMappedPositions(scanner.currentPosition - 1);
+                               multipleLineCommentCounter++;
+                               break;
+                       default :
+                               for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
+                                       char currentCharacter = source[i];
+                                       updateMappedPositions(i);
+                                       currentLineBuffer.append(currentCharacter);
+                               }
+               }
+       }
+       
+       /**
+        * Outputs <code>currentString</code>:<br>
+        * <ul><li>If its length is < maxLineLength, output
+        * <li>Otherwise it is split.</ul>
+        * @param currentString string to output
+        * @param preIndented whether the string to output was pre-indented
+        * @param depth number of indentation to put in front of <code>currentString</code>
+        * @param operator value of the operator belonging to <code>currentString</code>.
+        */
+       private void outputLine(
+               String currentString,
+               boolean preIndented,
+               int depth,
+               int operator,
+               int substringIndex,
+               int[] startSubstringIndexes,
+               int offsetInGlobalLine) {
+
+               boolean emptyFirstSubString = false;
+               String operatorString = operatorString(operator);
+               boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
+               boolean placeOperatorAhead = !placeOperatorBehind;
+
+               // dump prefix operator?
+               if (placeOperatorAhead) {
+                       if (!preIndented) {
+                               dumpTab(depth);
+                               preIndented = true;
+                       }
+                       if (operator != 0) {
+                               if (insertSpaceBefore(operator)) {
+                                       formattedSource.append(' ');
+                                       increaseSplitDelta(1);
+                               }
+                               formattedSource.append(operatorString);
+                               increaseSplitDelta(operatorString.length());
+
+                               if (insertSpaceAfter(operator)
+               //                      && operator != TokenNameimplements
+                                       && operator != TokenNameextends) {
+               //                      && operator != TokenNamethrows) {
+                                       formattedSource.append(' ');
+                                       increaseSplitDelta(1);
+                               }
+                       }
+               }
+               SplitLine splitLine = null;
+               if (options.maxLineLength == 0
+                       || getLength(currentString, depth) < options.maxLineLength
+                       || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
+
+                       // depending on the type of operator, outputs new line before of after dumping it
+                       // indent before postfix operator
+                       // indent also when the line cannot be split
+                       if (operator == TokenNameextends) {
+//                             || operator == TokenNameimplements
+//                             || operator == TokenNamethrows) {
+                               formattedSource.append(' ');
+                               increaseSplitDelta(1);
+                       }
+                       if (placeOperatorBehind) {
+                               if (!preIndented) {
+                                       dumpTab(depth);
+                               }
+                       }
+                       int max = currentString.length();
+                       if (multipleLineCommentCounter != 0) {
+                               try {
+                                       BufferedReader reader = new BufferedReader(new StringReader(currentString));
+                                       String line = reader.readLine();
+                                       while (line != null) {
+                                               updateMappedPositionsWhileSplitting(
+                                                       beginningOfLineIndex,
+                                                       beginningOfLineIndex + line.length() + options.lineSeparatorSequence.length);
+                                               formattedSource.append(line);
+                                               beginningOfLineIndex = beginningOfLineIndex + line.length();
+                                               if ((line = reader.readLine()) != null) {
+                                                       formattedSource.append(options.lineSeparatorSequence);
+                                                       beginningOfLineIndex += options.lineSeparatorSequence.length;
+                                                       dumpTab(currentLineIndentationLevel);
+                                               }
+                                       }
+                                       reader.close();
+                               } catch(IOException e) {
+                                       e.printStackTrace();
+                               }
+                       } else {
+                               updateMappedPositionsWhileSplitting(
+                                       beginningOfLineIndex,
+                                       beginningOfLineIndex + max);
+                               for (int i = 0; i < max; i++) {
+                                       char currentChar = currentString.charAt(i);
+                                       switch (currentChar) {
+                                               case '\r' :
+                                                       break;
+                                               case '\n' :
+                                                       if (i != max - 1) {
+                                                               // fix for 1FFYL5C: LFCOM:ALL - Incorrect indentation when split with a comment inside a condition
+                                                               // a substring cannot end with a lineSeparatorSequence,
+                                                               // except if it has been added by format() after a one-line comment
+                                                               formattedSource.append(options.lineSeparatorSequence);
+       
+                                                               // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
+                                                               dumpTab(depth - 1);
+                                                       }
+                                                       break;
+                                               default :
+                                                       formattedSource.append(currentChar);
+                                       }
+                               }
+                       }
+                       // update positions inside the mappedPositions table
+                       if (substringIndex != -1) {
+                               if (multipleLineCommentCounter == 0) {
+                                       int startPosition =
+                                               beginningOfLineIndex + startSubstringIndexes[substringIndex];
+                                       updateMappedPositionsWhileSplitting(startPosition, startPosition + max);
+                               }
+
+                               // compute the splitDelta resulting with the operator and blank removal
+                               if (substringIndex + 1 != startSubstringIndexes.length) {
+                                       increaseSplitDelta(
+                                               startSubstringIndexes[substringIndex]
+                                                       + max
+                                                       - startSubstringIndexes[substringIndex + 1]);
+                               }
+                       }
+                       // dump postfix operator?
+                       if (placeOperatorBehind) {
+                               if (insertSpaceBefore(operator)) {
+                                       formattedSource.append(' ');
+                                       if (operator != 0) {
+                                               increaseSplitDelta(1);
+                                       }
+                               }
+                               formattedSource.append(operatorString);
+                               if (operator != 0) {
+                                       increaseSplitDelta(operatorString.length());
+                               }
+                       }
+                       return;
+               }
+               // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
+               // extends has to stand alone on a line when currentString has been split.
+               if (options.maxLineLength != 0
+                       && splitLine != null
+                       && (operator == TokenNameextends)) {
+//                             || operator == TokenNameimplements
+//                             || operator == TokenNamethrows)) {
+                       formattedSource.append(options.lineSeparatorSequence);
+                       increaseSplitDelta(options.lineSeparatorSequence.length);
+                       dumpTab(depth + 1);
+               } else {
+                       if (operator == TokenNameextends) {
+//                             || operator == TokenNameimplements
+//                             || operator == TokenNamethrows) {
+                               formattedSource.append(' ');
+                               increaseSplitDelta(1);
+                       }
+               }
+               // perform actual splitting
+               String result[] = splitLine.substrings;
+               int[] splitOperators = splitLine.operators;
+
+               if (result[0].length() == 0) {
+                       // when the substring 0 is null, the substring 1 is correctly indented.
+                       depth--;
+                       emptyFirstSubString = true;
+               }
+               // the operator going in front of the result[0] string is the operator parameter
+               for (int i = 0, max = result.length; i < max; i++) {
+                       // the new depth is the current one if this is the first substring,
+                       // the current one + 1 otherwise.
+                       // if the substring is a comment, use the current indentation Level instead of the depth
+                       // (-1 because the ouputline increases depth).
+                       // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of line comments)
+                       String currentResult = result[i];
+
+                       if (currentResult.length() != 0 || splitOperators[i] != 0) {
+                                       int newDepth =
+                                               (currentResult.startsWith("/*") //$NON-NLS-1$
+                                                       || currentResult.startsWith("//")) //$NON-NLS-1$ 
+                                                               ? indentationLevel - 1 : depth;
+                               outputLine(
+                                       currentResult,
+                                       i == 0 || (i == 1 && emptyFirstSubString) ? preIndented : false,
+                                       i == 0 ? newDepth : newDepth + 1,
+                                       splitOperators[i],
+                                       i,
+                                       splitLine.startSubstringsIndexes,
+                                       currentString.indexOf(currentResult));
+                               if (i != max - 1) {
+                                       formattedSource.append(options.lineSeparatorSequence);
+                                       increaseSplitDelta(options.lineSeparatorSequence.length);
+                               }
+                       }
+               }
+               if (result.length == splitOperators.length - 1) {
+                       int lastOperator = splitOperators[result.length];
+                       String lastOperatorString = operatorString(lastOperator);
+                       formattedSource.append(options.lineSeparatorSequence);
+                       increaseSplitDelta(options.lineSeparatorSequence.length);
+
+                       if (breakLineBeforeOperator(lastOperator)) {
+                               dumpTab(depth + 1);
+                               if (lastOperator != 0) {
+                                       if (insertSpaceBefore(lastOperator)) {
+                                               formattedSource.append(' ');
+                                               increaseSplitDelta(1);
+                                       }
+                                       formattedSource.append(lastOperatorString);
+                                       increaseSplitDelta(lastOperatorString.length());
+
+                                       if (insertSpaceAfter(lastOperator)
+       //                                      && lastOperator != TokenNameimplements
+                                               && lastOperator != TokenNameextends ) {
+       //                                      && lastOperator != TokenNamethrows) {
+                                               formattedSource.append(' ');
+                                               increaseSplitDelta(1);
+                                       }
+                               }
+                       }
+               }
+               if (placeOperatorBehind) {
+                       if (insertSpaceBefore(operator)) {
+                               formattedSource.append(' ');
+                               increaseSplitDelta(1);
+                       }
+                       formattedSource.append(operatorString);
+                       //increaseSplitDelta(operatorString.length());
+               }
+       }
+       
+       /**
+        * Pops the top statement of the stack if it is <code>token</code>
+        */
+       private int pop(int token) {
+               int delta = 0;
+               if ((constructionsCount > 0)
+                       && (constructions[constructionsCount - 1] == token)) {
+                       delta--;
+                       constructionsCount--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops the top statement of the stack if it is a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.
+        */
+       private int popBlock() {
+               int delta = 0;
+               if ((constructionsCount > 0)
+                       && ((constructions[constructionsCount - 1] == BLOCK)
+                               || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
+                       if (constructions[constructionsCount - 1] == BLOCK)
+                               delta--;
+                       constructionsCount--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
+        * Does not remove <code>token</code> from the stack.
+        * @param token the token to be left as the top of the stack
+        */
+       private int popExclusiveUntil(int token) {
+               int delta = 0;
+               int startCount = constructionsCount;
+               for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+                       if (constructions[i] != NONINDENT_BLOCK)
+                               delta--;
+                       constructionsCount--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops elements until the stack is empty or the top element is
+        * a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+        * Does not remove it from the stack.
+        */
+       private int popExclusiveUntilBlock() {
+               int startCount = constructionsCount;
+               int delta = 0;
+               for (int i = startCount - 1;
+                       i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK;
+                       i--) {
+                       constructionsCount--;
+                       delta--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops elements until the stack is empty or the top element is
+        * a <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a <code>CASE</code>.<br>
+        * Does not remove it from the stack.
+        */
+       private int popExclusiveUntilBlockOrCase() {
+               int startCount = constructionsCount;
+               int delta = 0;
+               for (int i = startCount - 1;
+                       i >= 0
+                               && constructions[i] != BLOCK
+                               && constructions[i] != NONINDENT_BLOCK
+                               && constructions[i] != TokenNamecase;
+                       i--) {
+                       constructionsCount--;
+                       delta--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
+        * Removes <code>token</code> from the stack too.
+        * @param token the token to remove from the stack
+        */
+       private int popInclusiveUntil(int token) {
+               int startCount = constructionsCount;
+               int delta = 0;
+               for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+                       if (constructions[i] != NONINDENT_BLOCK)
+                               delta--;
+                       constructionsCount--;
+               }
+               if (constructionsCount > 0) {
+                       if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
+                               delta--;
+                       constructionsCount--;
+               }
+               return delta;
+       }
+       
+       /**
+        * Pops elements until the stack is empty or the top element is
+        * a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+        * Does not remove it from the stack.
+        */
+       private int popInclusiveUntilBlock() {
+               int startCount = constructionsCount;
+               int delta = 0;
+               for (int i = startCount - 1;
+                       i >= 0 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK);
+                       i--) {
+                       delta--;
+                       constructionsCount--;
+               }
+               if (constructionsCount > 0) {
+                       if (constructions[constructionsCount - 1] == BLOCK)
+                               delta--;
+                       constructionsCount--;
+               }
+               return delta;
+       }
+       
+       /** 
+        * Pushes a block in the stack.<br>
+        * Pushes a <code>BLOCK</code> if the stack is empty or if the top element is a <code>BLOCK</code>,
+        * pushes <code>NONINDENT_BLOCK</code> otherwise.
+        * Creates a new bigger array if the current one is full.
+        */
+       private int pushBlock() {
+               int delta = 0;
+               if (constructionsCount == constructions.length)
+                       System.arraycopy(
+                               constructions,
+                               0,
+                               (constructions = new int[constructionsCount * 2]),
+                               0,
+                               constructionsCount);
+
+               if ((constructionsCount == 0)
+                       || (constructions[constructionsCount - 1] == BLOCK)
+                       || (constructions[constructionsCount - 1] == NONINDENT_BLOCK)
+                       || (constructions[constructionsCount - 1] == TokenNamecase)) {
+                       delta++;
+                       constructions[constructionsCount++] = BLOCK;
+               } else {
+                       constructions[constructionsCount++] = NONINDENT_BLOCK;
+               }
+               return delta;
+       }
+       
+       /** 
+        * Pushes <code>token</code>.<br>
+        * Creates a new bigger array if the current one is full.
+        */
+       private int pushControlStatement(int token) {
+               if (constructionsCount == constructions.length)
+                       System.arraycopy(
+                               constructions,
+                               0,
+                               (constructions = new int[constructionsCount * 2]),
+                               0,
+                               constructionsCount);
+               constructions[constructionsCount++] = token;
+               return 1;
+       }
+       
+       private static boolean separateFirstArgumentOn(int currentToken) {
+               //return (currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON);
+               return currentToken != TokenNameif
+                       && currentToken != TokenNameLPAREN
+                       && currentToken != TokenNameNOT
+                       && currentToken != TokenNamewhile
+                       && currentToken != TokenNamefor
+                       && currentToken != TokenNameswitch;
+       }
+       
+       /**
+        * Set the positions to map. The mapped positions should be retrieved using the
+        * getMappedPositions() method.
+        * @param positions int[]
+        * @deprecated Set the positions to map using the format(String, int, int[]) method.
+        * 
+        * @see #getMappedPositions()
+        */
+       public void setPositionsToMap(int[] positions) {
+               positionsToMap = positions;
+               lineDelta = 0;
+               globalDelta = 0;
+               mappedPositions = new int[positions.length];
+       }
+               
+       /** 
+        * Appends a space character to the current line buffer.
+        */
+       private void space() {
+               currentLineBuffer.append(' ');
+               increaseLineDelta(1);
+       }
+       
+       /**
+        * Splits <code>stringToSplit</code> on the top level token<br>
+        * If there are several identical token at the same level,
+        * the string is cut into many pieces.
+        * @return an object containing the operator and all the substrings
+        * or null if the string cannot be split
+        */
+       public SplitLine split(String stringToSplit) {
+               return split(stringToSplit, 0);
+       }
+       
+       /**
+        * Splits <code>stringToSplit</code> on the top level token<br>
+        * If there are several identical token at the same level,
+        * the string is cut into many pieces.
+        * @return an object containing the operator and all the substrings
+        * or null if the string cannot be split
+        */
+       public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
+               /*
+                * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and
+                * http://dev.eclipse.org/bugs/show_bug.cgi?id=14387 
+                */
+               if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$
+                       return null;
+               }
+               // local variables
+               int currentToken = 0;
+               int splitTokenType = 0;
+               int splitTokenDepth = Integer.MAX_VALUE;
+               int splitTokenPriority = Integer.MAX_VALUE;
+
+               int[] substringsStartPositions = new int[10];
+               // contains the start position of substrings
+               int[] substringsEndPositions = new int[10];
+               // contains the start position of substrings
+               int substringsCount = 1; // index in the substringsStartPosition array
+               int[] splitOperators = new int[10];
+               // contains the start position of substrings
+               int splitOperatorsCount = 0; // index in the substringsStartPosition array
+               int[] openParenthesisPosition = new int[10];
+               int openParenthesisPositionCount = 0;
+               int position = 0;
+               int lastOpenParenthesisPosition = -1;
+               // used to remember the position of the 1st open parenthesis
+               // needed for a pattern like: A.B(C); we want formatted like A.B( split C);
+               // setup the scanner with a new source
+               int lastCommentStartPosition = -1;
+               // to remember the start position of the last comment
+               int firstTokenOnLine = -1;
+               // to remember the first token of the line
+               int previousToken = -1;
+               // to remember the previous token.
+               splitScanner.setSource(stringToSplit.toCharArray());
+
+               try {
+                       // start the loop
+                       while (true) {
+                               // takes the next token
+                               try {
+                                       if (currentToken != Scanner.TokenNameWHITESPACE)
+                                               previousToken = currentToken;
+                                       currentToken = splitScanner.getNextToken();
+                               } catch (InvalidInputException e) {
+                                       if (!handleInvalidToken(e))
+                                               throw e;
+                                       currentToken = 0; // this value is not modify when an exception is raised.
+                               }
+                               if (currentToken == TokenNameEOF)
+                                       break;
+
+                               if (firstTokenOnLine == -1) {
+                                       firstTokenOnLine = currentToken;
+                               }
+                               switch (currentToken) {
+                                       case TokenNameRBRACE :
+                                       case TokenNameRPAREN :
+                                               if (openParenthesisPositionCount > 0) {
+                                                       if (openParenthesisPositionCount == 1
+                                                               && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
+                                                               lastOpenParenthesisPosition = openParenthesisPosition[0];
+                                                       } else if (
+                                                               (splitTokenDepth == Integer.MAX_VALUE)
+                                                                       || (splitTokenDepth > openParenthesisPositionCount
+                                                                               && openParenthesisPositionCount == 1)) {
+                                                               splitTokenType = 0;
+                                                               splitTokenDepth = openParenthesisPositionCount;
+                                                               splitTokenPriority = Integer.MAX_VALUE;
+                                                               substringsStartPositions[0] = 0;
+                                                               // better token means the whole line until now is the first substring
+                                                               substringsCount = 1; // resets the count of substrings
+                                                               substringsEndPositions[0] = openParenthesisPosition[0];
+                                                               // substring ends on operator start
+                                                               position = openParenthesisPosition[0];
+                                                               // the string mustn't be cut before the closing parenthesis but after the opening one.
+                                                               splitOperatorsCount = 1; // resets the count of split operators
+                                                               splitOperators[0] = 0;
+                                                       }
+                                                       openParenthesisPositionCount--;
+                                               }
+                                               break;
+                                       case TokenNameLBRACE :
+                                       case TokenNameLPAREN :
+                                               if (openParenthesisPositionCount == openParenthesisPosition.length) {
+                                                       System.arraycopy(
+                                                               openParenthesisPosition,
+                                                               0,
+                                                               (openParenthesisPosition = new int[openParenthesisPositionCount * 2]),
+                                                               0,
+                                                               openParenthesisPositionCount);
+                                               }
+                                               openParenthesisPosition[openParenthesisPositionCount++] =
+                                                       splitScanner.currentPosition;
+                                               if (currentToken == TokenNameLPAREN && previousToken == TokenNameRPAREN) {
+                                                       openParenthesisPosition[openParenthesisPositionCount - 1] =
+                                                               splitScanner.startPosition;
+                                               }
+                                               break;
+                                       case TokenNameSEMICOLON : // ;
+                                       case TokenNameCOMMA : // ,
+                                       case TokenNameEQUAL : // =
+                                               if (openParenthesisPositionCount < splitTokenDepth
+                                                       || (openParenthesisPositionCount == splitTokenDepth
+                                                               && splitTokenPriority > getTokenPriority(currentToken))) {
+                                                       // the current token is better than the one we currently have
+                                                       // (in level or in priority if same level)
+                                                       // reset the substringsCount
+                                                       splitTokenDepth = openParenthesisPositionCount;
+                                                       splitTokenType = currentToken;
+                                                       splitTokenPriority = getTokenPriority(currentToken);
+                                                       substringsStartPositions[0] = 0;
+                                                       // better token means the whole line until now is the first substring
+
+                                                       if (separateFirstArgumentOn(firstTokenOnLine)
+                                                               && openParenthesisPositionCount > 0) {
+                                                               substringsCount = 2; // resets the count of substrings
+
+                                                               substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
+                                                               substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
+                                                               substringsEndPositions[1] = splitScanner.startPosition;
+                                                               splitOperatorsCount = 2; // resets the count of split operators
+                                                               splitOperators[0] = 0;
+                                                               splitOperators[1] = currentToken;
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                       } else {
+                                                               substringsCount = 1; // resets the count of substrings
+
+                                                               substringsEndPositions[0] = splitScanner.startPosition;
+                                                               // substring ends on operator start
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                               splitOperatorsCount = 1; // resets the count of split operators
+                                                               splitOperators[0] = currentToken;
+                                                       }
+                                               } else {
+                                                       if ((openParenthesisPositionCount == splitTokenDepth
+                                                               && splitTokenPriority == getTokenPriority(currentToken))
+                                                               && splitTokenType != TokenNameEQUAL
+                                                               && currentToken != TokenNameEQUAL) {
+                                                               // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after split
+                                                               // take only the 1st = into account.
+                                                               // if another token with the same priority is found,
+                                                               // push the start position of the substring and
+                                                               // push the token into the stack.
+                                                               // create a new array object if the current one is full.
+                                                               if (substringsCount == substringsStartPositions.length) {
+                                                                       System.arraycopy(
+                                                                               substringsStartPositions,
+                                                                               0,
+                                                                               (substringsStartPositions = new int[substringsCount * 2]),
+                                                                               0,
+                                                                               substringsCount);
+                                                                       System.arraycopy(
+                                                                               substringsEndPositions,
+                                                                               0,
+                                                                               (substringsEndPositions = new int[substringsCount * 2]),
+                                                                               0,
+                                                                               substringsCount);
+                                                               }
+                                                               if (splitOperatorsCount == splitOperators.length) {
+                                                                       System.arraycopy(
+                                                                               splitOperators,
+                                                                               0,
+                                                                               (splitOperators = new int[splitOperatorsCount * 2]),
+                                                                               0,
+                                                                               splitOperatorsCount);
+                                                               }
+                                                               substringsStartPositions[substringsCount] = position;
+                                                               substringsEndPositions[substringsCount++] = splitScanner.startPosition;
+                                                               // substring ends on operator start
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                               splitOperators[splitOperatorsCount++] = currentToken;
+                                                       }
+                                               }
+                                               break;
+
+                                       case TokenNameCOLON : // : (15.24)
+                                               // see 1FK7C5R, we only split on a colon, when it is associated with a question-mark.
+                                               // indeed it might appear also behind a case statement, and we do not to break at this point.
+                                               if ((splitOperatorsCount == 0)
+                                                       || splitOperators[splitOperatorsCount - 1] != TokenNameQUESTION) {
+                                                       break;
+                                               }
+                                       case TokenNameextends :
+               //                      case TokenNameimplements :
+               //                      case TokenNamethrows :
+
+                                       case TokenNameDOT : // .
+                                       case TokenNameMULTIPLY : // * (15.16.1)
+                                       case TokenNameDIVIDE : // / (15.16.2)
+                                       case TokenNameREMAINDER : // % (15.16.3)
+                                       case TokenNamePLUS : // + (15.17, 15.17.2)
+                                       case TokenNameMINUS : // - (15.17.2)
+                                       case TokenNameLEFT_SHIFT : // << (15.18)
+                                       case TokenNameRIGHT_SHIFT : // >> (15.18)
+       //                              case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+                                       case TokenNameLESS : // < (15.19.1)
+                                       case TokenNameLESS_EQUAL : // <= (15.19.1)
+                                       case TokenNameGREATER : // > (15.19.1)
+                                       case TokenNameGREATER_EQUAL : // >= (15.19.1)
+       //                              case TokenNameinstanceof : // instanceof
+                                       case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+                                       case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+                                       case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+                                       case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+                                       case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+                                       case TokenNameAND_AND : // && (15.22)
+                                       case TokenNameOR_OR : // || (15.23)
+                                       case TokenNameQUESTION : // ? (15.24)
+                                       case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+                                       case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+                                       case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+                                       case TokenNamePLUS_EQUAL : // += (15.25.2)
+                                       case TokenNameMINUS_EQUAL : // -= (15.25.2)
+                                       case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+                                       case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+//                                     case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+                                       case TokenNameAND_EQUAL : // &= (15.25.2)
+                                       case TokenNameXOR_EQUAL : // ^= (15.25.2)
+                                       case TokenNameOR_EQUAL : // |= (15.25.2)
+
+                                               if ((openParenthesisPositionCount < splitTokenDepth
+                                                       || (openParenthesisPositionCount == splitTokenDepth
+                                                               && splitTokenPriority > getTokenPriority(currentToken)))
+                                                       && !((currentToken == TokenNamePLUS || currentToken == TokenNameMINUS)
+                                                               && (previousToken == TokenNameLBRACE
+                                                                       || previousToken == TokenNameLBRACKET
+                                                                       || splitScanner.startPosition == 0))) {
+                                                       // the current token is better than the one we currently have
+                                                       // (in level or in priority if same level)
+                                                       // reset the substringsCount
+                                                       splitTokenDepth = openParenthesisPositionCount;
+                                                       splitTokenType = currentToken;
+                                                       splitTokenPriority = getTokenPriority(currentToken);
+                                                       substringsStartPositions[0] = 0;
+                                                       // better token means the whole line until now is the first substring
+
+                                                       if (separateFirstArgumentOn(firstTokenOnLine)
+                                                               && openParenthesisPositionCount > 0) {
+                                                               substringsCount = 2; // resets the count of substrings
+
+                                                               substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
+                                                               substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
+                                                               substringsEndPositions[1] = splitScanner.startPosition;
+                                                               splitOperatorsCount = 3; // resets the count of split operators
+                                                               splitOperators[0] = 0;
+                                                               splitOperators[1] = 0;
+                                                               splitOperators[2] = currentToken;
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                       } else {
+                                                               substringsCount = 1; // resets the count of substrings
+
+                                                               substringsEndPositions[0] = splitScanner.startPosition;
+                                                               // substring ends on operator start
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                               splitOperatorsCount = 2; // resets the count of split operators
+                                                               splitOperators[0] = 0;
+                                                               // nothing for first operand since operator will be inserted in front of the second operand
+                                                               splitOperators[1] = currentToken;
+
+                                                       }
+                                               } else {
+                                                       if (openParenthesisPositionCount == splitTokenDepth
+                                                               && splitTokenPriority == getTokenPriority(currentToken)) {
+                                                               // if another token with the same priority is found,
+                                                               // push the start position of the substring and
+                                                               // push the token into the stack.
+                                                               // create a new array object if the current one is full.
+                                                               if (substringsCount == substringsStartPositions.length) {
+                                                                       System.arraycopy(
+                                                                               substringsStartPositions,
+                                                                               0,
+                                                                               (substringsStartPositions = new int[substringsCount * 2]),
+                                                                               0,
+                                                                               substringsCount);
+                                                                       System.arraycopy(
+                                                                               substringsEndPositions,
+                                                                               0,
+                                                                               (substringsEndPositions = new int[substringsCount * 2]),
+                                                                               0,
+                                                                               substringsCount);
+                                                               }
+                                                               if (splitOperatorsCount == splitOperators.length) {
+                                                                       System.arraycopy(
+                                                                               splitOperators,
+                                                                               0,
+                                                                               (splitOperators = new int[splitOperatorsCount * 2]),
+                                                                               0,
+                                                                               splitOperatorsCount);
+                                                               }
+                                                               substringsStartPositions[substringsCount] = position;
+                                                               substringsEndPositions[substringsCount++] = splitScanner.startPosition;
+                                                               // substring ends on operator start
+                                                               position = splitScanner.currentPosition;
+                                                               // next substring will start from operator end
+                                                               splitOperators[splitOperatorsCount++] = currentToken;
+                                                       }
+                                               }
+                                       default :
+                                               break;
+                               }
+                               if (isComment(currentToken)) {
+                                       lastCommentStartPosition = splitScanner.startPosition;
+                               } else {
+                                       lastCommentStartPosition = -1;
+                               }
+                       }
+               } catch (InvalidInputException e) {
+                       return null;
+               }
+               // if the string cannot be split, return null.
+               if (splitOperatorsCount == 0)
+                       return null;
+
+               // ## SPECIAL CASES BEGIN
+               if (((splitOperatorsCount == 2
+                       && splitOperators[1] == TokenNameDOT
+                       && splitTokenDepth == 0
+                       && lastOpenParenthesisPosition > -1)
+                       || (splitOperatorsCount > 2
+                               && splitOperators[1] == TokenNameDOT
+                               && splitTokenDepth == 0
+                               && lastOpenParenthesisPosition > -1
+                               && lastOpenParenthesisPosition <= options.maxLineLength)
+                       || (separateFirstArgumentOn(firstTokenOnLine)
+                               && splitTokenDepth > 0
+                               && lastOpenParenthesisPosition > -1))
+                       && (lastOpenParenthesisPosition < splitScanner.source.length
+                               && splitScanner.source[lastOpenParenthesisPosition] != ')')) {
+                       // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis should not be broken on two lines
+                       // only one split on a top level .
+                       // or more than one split on . and substring before open parenthesis fits one line.
+                       // or split inside parenthesis and first token is not a for/while/if
+                       SplitLine sl =
+                               split(
+                                       stringToSplit.substring(lastOpenParenthesisPosition),
+                                       lastOpenParenthesisPosition);
+                       if (sl == null || sl.operators[0] != TokenNameCOMMA) {
+                               // trim() is used to remove the extra blanks at the end of the substring. See PR 1FGYPI1
+                               return new SplitLine(
+                                       new int[] { 0, 0 },
+                                       new String[] {
+                                               stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
+                                               stringToSplit.substring(lastOpenParenthesisPosition)},
+                                       new int[] {
+                                               offsetInGlobalLine,
+                                               lastOpenParenthesisPosition + offsetInGlobalLine });
+                       } else {
+                               // right substring can be split and is split on comma
+                               // copy substrings and operators
+                               // except if the 1st string is empty.
+                               int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
+                               int subStringsLength = sl.substrings.length + 1 - startIndex;
+                               String[] result = new String[subStringsLength];
+                               int[] startIndexes = new int[subStringsLength];
+                               int operatorsLength = sl.operators.length + 1 - startIndex;
+                               int[] operators = new int[operatorsLength];
+
+                               result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
+                               operators[0] = 0;
+
+                               System.arraycopy(
+                                       sl.startSubstringsIndexes,
+                                       startIndex,
+                                       startIndexes,
+                                       1,
+                                       subStringsLength - 1);
+                               for (int i = subStringsLength - 1; i >= 0; i--) {
+                                       startIndexes[i] += offsetInGlobalLine;
+                               }
+                               System.arraycopy(sl.substrings, startIndex, result, 1, subStringsLength - 1);
+                               System.arraycopy(sl.operators, startIndex, operators, 1, operatorsLength - 1);
+
+                               return new SplitLine(operators, result, startIndexes);
+                       }
+               }
+               // if the last token is a comment and the substring before the comment fits on a line,
+               // split before the comment and return the result.
+               if (lastCommentStartPosition > -1
+                       && lastCommentStartPosition < options.maxLineLength
+                       && splitTokenPriority > 50) {
+                       int end = lastCommentStartPosition;
+                       int start = lastCommentStartPosition;
+                       if (stringToSplit.charAt(end - 1) == ' ') {
+                               end--;
+                       }
+                       if (start != end && stringToSplit.charAt(start) == ' ') {
+                               start++;
+                       }
+                       return new SplitLine(
+                               new int[] { 0, 0 },
+                               new String[] { stringToSplit.substring(0, end), stringToSplit.substring(start)},
+                               new int[] { 0, start });
+               }
+               if (position != stringToSplit.length()) {
+                       if (substringsCount == substringsStartPositions.length) {
+                               System.arraycopy(
+                                       substringsStartPositions,
+                                       0,
+                                       (substringsStartPositions = new int[substringsCount * 2]),
+                                       0,
+                                       substringsCount);
+                               System.arraycopy(
+                                       substringsEndPositions,
+                                       0,
+                                       (substringsEndPositions = new int[substringsCount * 2]),
+                                       0,
+                                       substringsCount);
+                       }
+                       // avoid empty extra substring, e.g. line terminated with a semi-colon
+                       substringsStartPositions[substringsCount] = position;
+                       substringsEndPositions[substringsCount++] = stringToSplit.length();
+               }
+               if (splitOperatorsCount == splitOperators.length) {
+                       System.arraycopy(
+                               splitOperators,
+                               0,
+                               (splitOperators = new int[splitOperatorsCount * 2]),
+                               0,
+                               splitOperatorsCount);
+               }
+               splitOperators[splitOperatorsCount] = 0;
+
+               // the last element of the stack is the position of the end of StringToSPlit
+               // +1 because the substring method excludes the last character
+               String[] result = new String[substringsCount];
+               for (int i = 0; i < substringsCount; i++) {
+                       int start = substringsStartPositions[i];
+                       int end = substringsEndPositions[i];
+                       if (stringToSplit.charAt(start) == ' ') {
+                               start++;
+                               substringsStartPositions[i]++;
+                       }
+                       if (end != start && stringToSplit.charAt(end - 1) == ' ') {
+                               end--;
+                       }
+                       result[i] = stringToSplit.substring(start, end);
+                       substringsStartPositions[i] += offsetInGlobalLine;
+               }
+               if (splitOperatorsCount > substringsCount) {
+                       System.arraycopy(
+                               substringsStartPositions,
+                               0,
+                               (substringsStartPositions = new int[splitOperatorsCount]),
+                               0,
+                               substringsCount);
+                       System.arraycopy(
+                               substringsEndPositions,
+                               0,
+                               (substringsEndPositions = new int[splitOperatorsCount]),
+                               0,
+                               substringsCount);
+                       for (int i = substringsCount; i < splitOperatorsCount; i++) {
+                               substringsStartPositions[i] = position;
+                               substringsEndPositions[i] = position;
+                       }
+                       System.arraycopy(
+                               splitOperators,
+                               0,
+                               (splitOperators = new int[splitOperatorsCount]),
+                               0,
+                               splitOperatorsCount);
+               } else {
+                       System.arraycopy(
+                               substringsStartPositions,
+                               0,
+                               (substringsStartPositions = new int[substringsCount]),
+                               0,
+                               substringsCount);
+                       System.arraycopy(
+                               substringsEndPositions,
+                               0,
+                               (substringsEndPositions = new int[substringsCount]),
+                               0,
+                               substringsCount);
+                       System.arraycopy(
+                               splitOperators,
+                               0,
+                               (splitOperators = new int[substringsCount]),
+                               0,
+                               substringsCount);
+               }
+               SplitLine splitLine =
+                       new SplitLine(splitOperators, result, substringsStartPositions);
+               return splitLine;
+       }
+
+       private void updateMappedPositions(int startPosition) {
+               if (positionsToMap == null) {
+                       return;
+               }
+               char[] source = scanner.source;
+               int sourceLength = source.length;
+               while (indexToMap < positionsToMap.length
+                       && positionsToMap[indexToMap] <= startPosition) {
+                       int posToMap = positionsToMap[indexToMap];
+                       if (posToMap < 0
+                               || posToMap >= sourceLength) { // protection against out of bounds position
+                               if (posToMap == sourceLength) {
+                                       mappedPositions[indexToMap] = formattedSource.length();
+                               }
+                               indexToMap = positionsToMap.length; // no more mapping
+                               return;
+                       }
+                       if (CharOperation.isWhitespace(source[posToMap])) {
+                               mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta;
+                       } else {
+                               if (posToMap == sourceLength - 1) {
+                                       mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta;
+                               } else {
+                                       mappedPositions[indexToMap] = posToMap + globalDelta + lineDelta;
+                               }
+                       }
+                       indexToMap++;
+               }
+       }
+       
+       private void updateMappedPositionsWhileSplitting(
+               int startPosition,
+               int endPosition) {
+               if (mappedPositions == null || mappedPositions.length == indexInMap)
+                       return;
+
+               while (indexInMap < mappedPositions.length
+                       && startPosition <= mappedPositions[indexInMap]
+                       && mappedPositions[indexInMap] < endPosition
+                       && indexInMap < indexToMap) {
+                       mappedPositions[indexInMap] += splitDelta;
+                       indexInMap++;
+               }
+       }
+       
+       private int getLength(String s, int tabDepth) {
+               int length = 0;
+               for (int i = 0; i < tabDepth; i++) {
+                       length += options.tabSize;
+               }
+               for (int i = 0, max = s.length(); i < max; i++) {
+                       char currentChar = s.charAt(i);
+                       switch (currentChar) {
+                               case '\t' :
+                                       length += options.tabSize;
+                                       break;
+                               default :
+                                       length++;
+                       }
+               }
+               return length;
+       }
+       
+       /** 
+       * Sets the initial indentation level
+       * @param indentationLevel new indentation level
+       * 
+       * @deprecated
+       */
+       public void setInitialIndentationLevel(int newIndentationLevel) {
+               this.initialIndentationLevel =
+                       currentLineIndentationLevel = indentationLevel = newIndentationLevel;
+       }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/Options.properties b/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/Options.properties
new file mode 100644 (file)
index 0000000..822c1c9
--- /dev/null
@@ -0,0 +1,59 @@
+newline.openingBrace.number=1
+newline.openingBrace.category=Newline
+newline.openingBrace.name=I&nsert new line before opening brace
+newline.openingBrace.possibleValues=2|Insert|Do not insert
+newline.openingBrace.description=When Insert, a new line is inserted before an opening brace, otherwise nothing is inserted
+
+newline.controlStatement.number=2
+newline.controlStatement.category=Newline
+newline.controlStatement.name=Insert new &line in control statement
+newline.controlStatement.possibleValues=2|Insert|Do not insert
+newline.controlStatement.description=When Insert, a new line is inserted between } and else, catch, finally
+
+newline.clearAll.number=3
+newline.clearAll.category=Newline
+newline.clearAll.name=Clear all &blank lines
+newline.clearAll.possibleValues=2|Clear|Preserve one
+newline.clearAll.description=When Clear, all blank lines are removed. When Preserve one, only one is kept and all others removed.
+
+newline.elseIf.number=4
+newline.elseIf.category=Newline
+newline.elseIf.name=&Keep else if on the same line
+newline.elseIf.possibleValues=2|Yes|No
+newline.elseIf.description=When Yes, a blank line is inserted between a else and a if when they are contiguous
+
+newline.emptyBlock.number=5
+newline.emptyBlock.category=Newline
+newline.emptyBlock.name=In&sert a new line inside an empty block
+newline.emptyBlock.possibleValues=2|Insert|Do not insert
+newline.emptyBlock.description=When insert, a line break is inserted between contiguous { and }, if } is not followed by a keyword.
+
+line.split.number=6
+line.split.category=Line splitting
+line.split.name=Ma&ximum line length
+line.split.possibleValues=-1
+line.split.description=Enable splitting of long lines (exceeding the configurable length). Length of 0 will disable line splitting
+
+style.compactAssignment.number=7
+style.compactAssignment.category=Style
+style.compactAssignment.name=&Compact assignment
+style.compactAssignment.possibleValues=2|Compact|Normal
+style.compactAssignment.description=Assignments can be formatted asymmetrically, e.g. 'int x= 2;', when Normal, a space is inserted before the assignment operator
+
+style.reuseExistingLayout.number=8
+style.reuseExistingLayout.category=Style
+style.reuseExistingLayout.name=&Reuse existing layout
+style.reuseExistingLayout.possibleValues=2|Reuse|Do not reuse
+style.reuseExistingLayout.description=If the user has formatted his code a certain way, the formatter does not try to reformat it
+
+tabulation.char.number=9
+tabulation.char.category=Style
+tabulation.char.name=Indentation is represented by &tab
+tabulation.char.possibleValues=2|Tab|Spaces
+tabulation.char.description=Either choose to indent with tab characters or spaces
+
+tabulation.size.number=10
+tabulation.size.category=Style
+tabulation.size.name=&Amount of spaces representing a tab
+tabulation.size.possibleValues=-1
+tabulation.size.description=Tabulation size in term of space characters
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/FormatterOptions.java b/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/FormatterOptions.java
new file mode 100644 (file)
index 0000000..a10281f
--- /dev/null
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.phpeclipse.phpdt.internal.formatter.impl;
+\rimport java.util.Map;
+
+public class FormatterOptions {        
+\r      /**
+        * Option IDs
+        */
+       public static final String OPTION_InsertNewlineBeforeOpeningBrace = "org.phpeclipse.phpdt.core.formatter.newline.openingBrace"; //$NON-NLS-1$
+       public static final String OPTION_InsertNewlineInControlStatement = "org.phpeclipse.phpdt.core.formatter.newline.controlStatement"; //$NON-NLS-1$
+       public static final String OPTION_InsertNewLineBetweenElseAndIf = "org.phpeclipse.phpdt.core.formatter.newline.elseIf"; //$NON-NLS-1$
+       public static final String OPTION_InsertNewLineInEmptyBlock = "org.phpeclipse.phpdt.core.formatter.newline.emptyBlock"; //$NON-NLS-1$
+       public static final String OPTION_ClearAllBlankLines = "org.phpeclipse.phpdt.core.formatter.newline.clearAll"; //$NON-NLS-1$
+       public static final String OPTION_SplitLineExceedingLength = "org.phpeclipse.phpdt.core.formatter.lineSplit"; //$NON-NLS-1$
+       public static final String OPTION_CompactAssignment = "org.phpeclipse.phpdt.core.formatter.style.assignment"; //$NON-NLS-1$
+       public static final String OPTION_TabulationChar = "org.phpeclipse.phpdt.core.formatter.tabulation.char"; //$NON-NLS-1$
+       public static final String OPTION_TabulationSize = "org.phpeclipse.phpdt.core.formatter.tabulation.size"; //$NON-NLS-1$
+       
+       public static final String INSERT = "insert"; //$NON-NLS-1$
+       public static final String DO_NOT_INSERT = "do not insert"; //$NON-NLS-1$
+       public static final String PRESERVE_ONE = "preserve one"; //$NON-NLS-1$
+       public static final String CLEAR_ALL = "clear all"; //$NON-NLS-1$
+       public static final String NORMAL = "normal"; //$NON-NLS-1$
+       public static final String COMPACT = "compact"; //$NON-NLS-1$
+       public static final String TAB = "tab"; //$NON-NLS-1$
+       public static final String SPACE = "space"; //$NON-NLS-1$
+       
+       // by default, do not insert blank line before opening brace
+       public boolean newLineBeforeOpeningBraceMode = false;
+
+       // by default, do not insert blank line behind keywords (ELSE, CATCH, FINALLY,...) in control statements
+       public boolean newlineInControlStatementMode = false;
+
+       // by default, preserve one blank line per sequence of blank lines
+       public boolean clearAllBlankLinesMode = false;
+       
+       // line splitting will occur when line exceeds this length
+       public int maxLineLength = 80;
+
+       public boolean compactAssignmentMode = false; // if isTrue, assignments look like x= 12 (not like x = 12);
+
+       //number of consecutive spaces used to replace the tab char
+       public int tabSize = 4; // n spaces for one tab
+       public boolean indentWithTab = true;
+
+       public boolean compactElseIfMode = true; // if true, else and if are kept on the same line.
+       public boolean newLineInEmptyBlockMode = true; // if false, no new line in {} if it's empty.
+       
+       public char[] lineSeparatorSequence = System.getProperty("line.separator").toCharArray(); //$NON-NLS-1$
+/** 
+ * Initializing the formatter options with default settings
+ */
+public FormatterOptions(){
+}
+/** 
+ * Initializing the formatter options with external settings
+ */
+public FormatterOptions(Map settings){
+       if (settings == null) return;
+
+       // filter options which are related to the assist component
+       Object[] entries = settings.entrySet().toArray();
+       for (int i = 0, max = entries.length; i < max; i++){
+               Map.Entry entry = (Map.Entry)entries[i];
+               if (!(entry.getKey() instanceof String)) continue;
+               if (!(entry.getValue() instanceof String)) continue;
+               String optionID = (String) entry.getKey();
+               String optionValue = (String) entry.getValue();
+               
+               if(optionID.equals(OPTION_InsertNewlineBeforeOpeningBrace)){
+                       if (optionValue.equals(INSERT)){
+                               this.newLineBeforeOpeningBraceMode = true;
+                       } else if (optionValue.equals(DO_NOT_INSERT)){
+                               this.newLineBeforeOpeningBraceMode = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_InsertNewlineInControlStatement)){
+                       if (optionValue.equals(INSERT)){
+                               this.newlineInControlStatementMode = true;
+                       } else if (optionValue.equals(DO_NOT_INSERT)){
+                               this.newlineInControlStatementMode = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_ClearAllBlankLines)){
+                       if (optionValue.equals(CLEAR_ALL)){
+                               this.clearAllBlankLinesMode = true;
+                       } else if (optionValue.equals(PRESERVE_ONE)){
+                               this.clearAllBlankLinesMode = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_InsertNewLineBetweenElseAndIf)){
+                       if (optionValue.equals(INSERT)){
+                               this.compactElseIfMode = false;
+                       } else if (optionValue.equals(DO_NOT_INSERT)){
+                               this.compactElseIfMode = true;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_InsertNewLineInEmptyBlock)){
+                       if (optionValue.equals(INSERT)){
+                               this.newLineInEmptyBlockMode = true;
+                       } else if (optionValue.equals(DO_NOT_INSERT)){
+                               this.newLineInEmptyBlockMode = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_SplitLineExceedingLength)){
+                       try {
+                               int val = Integer.parseInt(optionValue);
+                               if (val >= 0) this.maxLineLength = val;
+                       } catch(NumberFormatException e){
+                       }
+               }
+               if(optionID.equals(OPTION_CompactAssignment)){
+                       if (optionValue.equals(COMPACT)){
+                               this.compactAssignmentMode = true;
+                       } else if (optionValue.equals(NORMAL)){
+                               this.compactAssignmentMode = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_TabulationChar)){
+                       if (optionValue.equals(TAB)){
+                               this.indentWithTab = true;
+                       } else if (optionValue.equals(SPACE)){
+                               this.indentWithTab = false;
+                       }
+                       continue;
+               }
+               if(optionID.equals(OPTION_TabulationSize)){
+                       try {
+                               int val = Integer.parseInt(optionValue);
+                               if (val > 0) this.tabSize = val;
+                       } catch(NumberFormatException e){
+                       }
+               }
+       }
+}
+
+/**
+ * 
+ * @return int
+ */
+public int getMaxLineLength() {
+       return maxLineLength;
+}
+public int getTabSize() {
+       return tabSize;
+}
+public boolean isAddingNewLineBeforeOpeningBrace() {
+       return newLineBeforeOpeningBraceMode;
+}
+public boolean isAddingNewLineInControlStatement() {
+       return newlineInControlStatementMode;
+}
+public boolean isAddingNewLineInEmptyBlock() {
+       return newLineInEmptyBlockMode;
+}
+public boolean isClearingAllBlankLines() {
+       return clearAllBlankLinesMode;
+}
+public boolean isCompactingAssignment() {
+       return compactAssignmentMode;
+}
+public boolean isCompactingElseIf() {
+       return compactElseIfMode;
+}
+public boolean isUsingTabForIndenting() {
+       return indentWithTab;
+}
+public void setLineSeparator(String lineSeparator) {
+       lineSeparatorSequence = lineSeparator.toCharArray();
+}
+/**
+ * @deprecated - should use a Map when creating the options.
+ */
+public void setMaxLineLength(int maxLineLength) {
+       this.maxLineLength = maxLineLength;
+}
+/**
+ * @deprecated - should use a Map when creating the options.
+ */
+public void setCompactElseIfMode(boolean flag) {
+       compactElseIfMode = flag;
+}
+
+}
diff --git a/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/SplitLine.java b/net.sourceforge.phpeclipse/src/org/phpeclipse/phpdt/internal/formatter/impl/SplitLine.java
new file mode 100644 (file)
index 0000000..275baf0
--- /dev/null
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.phpeclipse.phpdt.internal.formatter.impl;
+
+import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
+
+/** Represents a split line: contains an operator and all substrings
+*/
+public class SplitLine implements ITerminalSymbols{
+       public int[] operators; // the operator on which the string was split.
+       public String[] substrings;
+       public int[] startSubstringsIndexes;
+/**
+ * SplitLine constructor comment.
+ */
+public SplitLine(int[] operators, String[] substrings) {
+       this(operators, substrings, null);
+}
+/**
+ * SplitLine constructor comment.
+ */
+public SplitLine(int[] operators, String[] substrings, int[] startIndexes) {
+       super();
+       this.operators=operators;
+       this.substrings=substrings;
+       this.startSubstringsIndexes = startIndexes;
+}
+/**
+ * Prints a nice representation of the receiver
+ * @return java.lang.String
+ */
+public String toString() {
+       StringBuffer result=new StringBuffer();
+       String operatorString = new String();
+               
+       for (int i=0,max=substrings.length;i<max;i++){
+               int currentOperator = operators[i];
+               String currentString = substrings[i];
+               boolean placeOperatorAhead = currentOperator != TokenNameCOMMA && currentOperator != TokenNameSEMICOLON;
+               boolean placeOperatorBehind = currentOperator == TokenNameCOMMA || currentOperator == TokenNameSEMICOLON;
+               
+
+
+       switch (currentOperator){
+               case TokenNameextends:
+                       operatorString="extends"; //$NON-NLS-1$
+                       break;
+//             case TokenNameimplements:
+//                     operatorString="implements"; //$NON-NLS-1$
+//                     break;
+//             case TokenNamethrows:
+//                     operatorString="throws"; //$NON-NLS-1$
+//                     break;
+               case TokenNameSEMICOLON : // ;
+                       operatorString=";"; //$NON-NLS-1$
+                       break;
+               case TokenNameCOMMA : // ,
+                       operatorString=","; //$NON-NLS-1$
+                       break;
+               case TokenNameEQUAL : // =
+                       operatorString="="; //$NON-NLS-1$
+                       break;
+               case TokenNameAND_AND : // && (15.22)
+                       operatorString="&&"; //$NON-NLS-1$
+                       break;
+               case TokenNameOR_OR : // || (15.23)
+                       operatorString="||"; //$NON-NLS-1$
+                       break;
+               case TokenNameQUESTION : // ? (15.24)
+                       operatorString="?"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameCOLON : // : (15.24)
+                       operatorString=":"; //$NON-NLS-1$
+                       break;
+               case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+                       operatorString="=="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+                       operatorString="!="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameLESS : // < (15.19.1)
+                       operatorString="<"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameLESS_EQUAL : // <= (15.19.1)
+                       operatorString="<="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameGREATER : // > (15.19.1)
+                       operatorString=">"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameGREATER_EQUAL : // >= (15.19.1)
+                       operatorString=">="; //$NON-NLS-1$
+                       break;
+
+//             case TokenNameinstanceof : // instanceof
+//                     operatorString="instanceof"; //$NON-NLS-1$
+//                     break;
+               case TokenNamePLUS : // + (15.17, 15.17.2)
+                       operatorString="+"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameMINUS : // - (15.17.2)
+                       operatorString="-"; //$NON-NLS-1$
+                       break;
+               case TokenNameMULTIPLY : // * (15.16.1)
+                       operatorString="*"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameDIVIDE : // / (15.16.2)
+                       operatorString="/"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameREMAINDER : // % (15.16.3)
+                       operatorString="%"; //$NON-NLS-1$
+                       break;
+               case TokenNameLEFT_SHIFT : // << (15.18)
+                       operatorString="<<"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameRIGHT_SHIFT : // >> (15.18)
+                       operatorString=">>"; //$NON-NLS-1$
+                       break;
+
+//             case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+//                     operatorString=">>>"; //$NON-NLS-1$
+//                     break;
+               case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+                       operatorString="&"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+                       operatorString="|"; //$NON-NLS-1$
+                       break;
+
+               case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+                       operatorString="^"; //$NON-NLS-1$
+                       break;
+               case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+                       operatorString="*="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+                       operatorString="/="; //$NON-NLS-1$
+                       break;
+               case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+                       operatorString="%="; //$NON-NLS-1$
+                       break;
+
+               case TokenNamePLUS_EQUAL : // += (15.25.2)
+                       operatorString="+="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameMINUS_EQUAL : // -= (15.25.2)
+                       operatorString="-="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+                       operatorString="<<="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+                       operatorString=">>="; //$NON-NLS-1$
+                       break;
+
+//             case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+//                     operatorString=">>>="; //$NON-NLS-1$
+//                     break;
+
+               case TokenNameAND_EQUAL : // &= (15.25.2)
+                       operatorString="&="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameXOR_EQUAL : // ^= (15.25.2)
+                       operatorString="^="; //$NON-NLS-1$
+                       break;
+
+               case TokenNameOR_EQUAL : // |= (15.25.2)
+                       operatorString="|="; //$NON-NLS-1$
+                       break;
+               case TokenNameDOT : // .
+                       operatorString="."; //$NON-NLS-1$
+                       break;
+
+               default:
+                       operatorString=""; //$NON-NLS-1$
+       }
+               if (placeOperatorAhead){
+                       result.append(operatorString);
+               }
+               result.append(currentString);
+               if (placeOperatorBehind){
+                       result.append(operatorString);
+               }
+               result.append('\n');
+       }
+       return ""; //$NON-NLS-1$
+}
+}