Logo Search packages:      
Sourcecode: ecj version File versions

CharOperation.java

/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Luiz-Otavio Zorzella <zorzella at gmail dot com> - Improve CamelCase algorithm
 *******************************************************************************/
package org.eclipse.jdt.core.compiler;

import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;

/**
 * This class is a collection of helper methods to manipulate char arrays.
 * <p>
 * This class is not intended to be instantiated or subclassed by clients.
 * </p>
 * 
 * @since 2.1
 */
00024 public final class CharOperation {

      /**
       * Constant for an empty char array
       */
00029       public static final char[] NO_CHAR = new char[0];

      /**
       * Constant for an empty char array with two dimensions.
       */
00034       public static final char[][] NO_CHAR_CHAR = new char[0][];
      
      /**
       * Constant for an empty String array.
       * @since 3.1
       */
00040       public static final String[] NO_STRINGS = new String[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
 */
00065 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 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', '0' }
 *    index = 2
 *    array = { 'c', 'd' }
 *    start = 0
 *    end = 1
 *    => result = { 'a', 'b' , 'c' }
 * </pre>
 * </li>
 * <li><pre>
 *    target = { 'a', 'b' }
 *    index = 2
 *    array = { 'c', 'd' }
 *    start = 0
 *    end = 1
 *    => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
 * </pre></li>
 * <li><pre>
 *    target = { 'a', 'b', 'c' }
 *    index = 1
 *    array = { 'c', 'd', 'e', 'f' }
 *    start = 1
 *    end = 4
 *    => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
 * </pre></li>
 * </ol>
 * 
 * @param target the given target
 * @param index the given index
 * @param array the given array
 * @param start the given start index
 * @param end the given end index
 * 
 * @return the new array
 * @throws NullPointerException if the target array is null
 */
00117 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.
 */
00166 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 true if the pattern matches the given name using CamelCase rules, or false otherwise. 
 * char[] CamelCase matching does NOT accept explicit wild-cards '*' and '?' and is inherently case sensitive.
 * <br>
 * CamelCase denotes the convention of writing compound names without spaces, and capitalizing every term.
 * This function recognizes both upper and lower CamelCase, depending whether the leading character is capitalized
 * or not. The leading part of an upper CamelCase pattern is assumed to contain a sequence of capitals which are appearing
 * in the matching name; e.g. 'NPE' will match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
 * uses a lowercase first character. In Java, type names follow the upper CamelCase convention, whereas method or field
 * names follow the lower CamelCase convention.
 * <br>
 * The pattern may contain lowercase characters, which will be match in a case sensitive way. These characters must
 * appear in sequence in the name. For instance, 'NPExcep' will match 'NullPointerException', but not 'NullPointerExCEPTION'
 * or 'NuPoEx' will match 'NullPointerException', but not 'NoPointerException'.
 * <br><br>
 * Examples:
 * <ol>
 * <li><pre>
 *    pattern = { 'N', 'P', 'E' }
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'P', 'E' }
 *    name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
 *    name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'n', p', 'e' }
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    result => false
 * </pre>
 * </li>
 * </ol>
 * 
 * @param pattern the given pattern
 * @param name the given name
 * @return true if the pattern matches the given name, false otherwise
 * @since 3.2
 */
00234 public static final boolean camelCaseMatch(char[] pattern, char[] name) {
      if (pattern == null)
            return true; // null pattern is equivalent to '*'
      if (name == null)
            return false; // null name cannot match

      return camelCaseMatch(pattern, 0, pattern.length, name, 0, name.length);
}

/**
 * Answers true if a sub-pattern matches the subpart of the given name using CamelCase rules, or false otherwise.  
 * char[] CamelCase matching does NOT accept explicit wild-cards '*' and '?' and is inherently case sensitive. 
 * Can match only subset of name/pattern, considering end positions as non-inclusive.
 * The subpattern is defined by the patternStart and patternEnd positions.
 * <br>
 * CamelCase denotes the convention of writing compound names without spaces, and capitalizing every term.
 * This function recognizes both upper and lower CamelCase, depending whether the leading character is capitalized
 * or not. The leading part of an upper CamelCase pattern is assumed to contain a sequence of capitals which are appearing
 * in the matching name; e.g. 'NPE' will match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern
 * uses a lowercase first character. In Java, type names follow the upper CamelCase convention, whereas method or field
 * names follow the lower CamelCase convention.
 * <br>
 * The pattern may contain lowercase characters, which will be match in a case sensitive way. These characters must
 * appear in sequence in the name. For instance, 'NPExcep' will match 'NullPointerException', but not 'NullPointerExCEPTION'
 * or 'NuPoEx' will match 'NullPointerException', but not 'NoPointerException'.
 * <br><br>
 * Examples:
 * <ol>
 * <li><pre>
 *    pattern = { 'N', 'P', 'E' }
 *    patternStart = 0
 *    patternEnd = 3
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    nameStart = 0
 *    nameEnd = 20
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'P', 'E' }
 *    patternStart = 0
 *    patternEnd = 3
 *    name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    nameStart = 0
 *    nameEnd = 21
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
 *    patternStart = 0
 *    patternEnd = 6
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    nameStart = 0
 *    nameEnd = 20
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'N', 'u', 'P', 'o', 'E', 'x' }
 *    patternStart = 0
 *    patternEnd = 6
 *    name = { 'N', 'o', 'P', 'e', 'r', 'm', 'i', 's', 's', 'i', 'o', 'n', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    nameStart = 0
 *    nameEnd = 21
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    pattern = { 'n', p', 'e' }
 *    patternStart = 0
 *    patternEnd = 3
 *    name = { 'N', 'u','l', 'l', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
 *    nameStart = 0
 *    nameEnd = 20
 *    result => false
 * </pre>
 * </li>
 * </ol>
 * 
 * @param pattern the given pattern
 * @param patternStart the start index of the pattern, inclusive
 * @param patternEnd the end index of the pattern, exclusive
 * @param name the given name
 * @param nameStart the start index of the name, inclusive
 * @param nameEnd the end index of the name, exclusive
 * @return true if a sub-pattern matches the subpart of the given name, false otherwise
 * @since 3.2
 */
00323 public static final boolean camelCaseMatch(char[] pattern, int patternStart, int patternEnd, char[] name, int nameStart, int nameEnd) {
      if (name == null)
            return false; // null name cannot match
      if (pattern == null)
            return true; // null pattern is equivalent to '*'
      if (patternEnd < 0)     patternEnd = pattern.length;
      if (nameEnd < 0) nameEnd = name.length;

      if (patternEnd <= patternStart) return nameEnd <= nameStart;
      if (nameEnd <= nameStart) return false;
      // check first pattern char
      if (name[nameStart] != pattern[patternStart]) {
            // first char must strictly match (upper/lower)
            return false;
      }

      char patternChar, nameChar;
      int iPattern = patternStart;
      int iName = nameStart;

      // Main loop is on pattern characters
      while (true) {

            iPattern++;
            iName++;

            if (iPattern == patternEnd) {
                  // We have exhausted pattern, so it's a match
                  return true;
            }

            if (iName == nameEnd){
                  // We have exhausted name (and not pattern), so it's not a match 
                  return false;
            }

            // For as long as we're exactly matching, bring it on (even if it's a lower case character)
            if ((patternChar = pattern[iPattern]) == name[iName]) {
                  continue;
            }

            // If characters are not equals, then it's not a match if patternChar is lowercase
            if (patternChar < ScannerHelper.MAX_OBVIOUS) {
                  if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & ScannerHelper.C_UPPER_LETTER) == 0) {
                        return false;
                  }
            }
            else if (Character.isJavaIdentifierPart(patternChar) && !Character.isUpperCase(patternChar)) {
                  return false;
            }

            // patternChar is uppercase, so let's find the next uppercase in name
            while (true) {
                  if (iName == nameEnd){
                  //    We have exhausted name (and not pattern), so it's not a match
                        return false;
                  }

                  nameChar = name[iName];
                  if (nameChar < ScannerHelper.MAX_OBVIOUS) {
                        if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] & (ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_SPECIAL | ScannerHelper.C_DIGIT)) != 0) {
                              // nameChar is lowercase    
                              iName++;
                        // nameChar is uppercase...
                        } else  if (patternChar != nameChar) {
                              //.. and it does not match patternChar, so it's not a match
                              return false;
                        } else {
                              //.. and it matched patternChar. Back to the big loop
                              break;
                        }
                  }
                  else if (Character.isJavaIdentifierPart(nameChar) && !Character.isUpperCase(nameChar)) {
                        // nameChar is lowercase    
                        iName++;
                  // nameChar is uppercase...
                  } else  if (patternChar != nameChar) {
                        //.. and it does not match patternChar, so it's not a match
                        return false;
                  } else {
                        //.. and it matched patternChar. Back to the big loop
                        break;
                  }
            }
            // At this point, either name has been exhausted, or it is at an uppercase letter.
            // Since pattern is also at an uppercase letter
      }
}     

/**
 * Returns the char arrays as an array of Strings
 * 
 * @param charArrays the char array to convert
 * @return the char arrays as an array of Strings or null if the given char arrays is null.
 * @since 3.0
 */
00419 public static String[] charArrayToStringArray(char[][] charArrays) {
      if (charArrays == null)
            return null;
      int length = charArrays.length;
      if (length == 0)
            return NO_STRINGS;
      String[] strings= new String[length];
      for (int i= 0; i < length; i++)
            strings[i]= new String(charArrays[i]);
      return strings;
}

/**
 * Returns the char array as a String

 * @param charArray the char array to convert
 * @return the char array as a String or null if the given char array is null.
 * @since 3.0
 */
00438 public static String charToString(char[] charArray) {
      if (charArray == null) return null;
      return new String(charArray);
}

/**
 * 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.
 */
00475 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;
}

/**
 * Compares the contents of the two arrays array and prefix. Returns
 * <ul>
 * <li>zero if the array starts with the prefix contents</li>
 * <li>the difference between the first two characters that are not equal </li>
 * <li>one if array length is lower than the prefix length and that the prefix starts with the 
 * array contents.</li>
 * </ul>
 * <p>
 * For example:
 * <ol>
 * <li><pre>
 *    array = null
 *    prefix = null
 *    => result = NullPointerException
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a', 'b', 'c', 'd', 'e' }
 *    prefix = { 'a', 'b', 'c'}
 *    => result = 0
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a', 'b', 'c', 'd', 'e' }
 *    prefix = { 'a', 'B', 'c'}
 *    => result = 32
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'd', 'b', 'c', 'd', 'e' }
 *    prefix = { 'a', 'b', 'c'}
 *    => result = 3
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a', 'b', 'c', 'd', 'e' }
 *    prefix = { 'd', 'b', 'c'}
 *    => result = -3
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a', 'a', 'c', 'd', 'e' }
 *    prefix = { 'a', 'e', 'c'}
 *    => result = -4
 * </pre>
 * </li>
 * </ol>
 * </p>
 * 
 * @param array the given array
 * @param prefix the given prefix
 * @return the result of the comparison (>=0 if array>prefix)
 * @throws NullPointerException if either array or prefix is null
 */
00543 public static final int compareWith(char[] array, char[] prefix) {
      int arrayLength = array.length;
      int prefixLength = prefix.length;
      int min = Math.min(arrayLength, prefixLength);
      int i = 0;
      while (min-- != 0) {
            char c1 = array[i];
            char c2 = prefix[i++];
            if (c1 != c2)
                  return c1 - c2;
      }
      if (prefixLength == i)
            return 0;
      return -1;  // array is shorter than prefix (e.g. array:'ab' < prefix:'abc').
}

/**
 * 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.
 */
00591 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.
 */
00657 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.
 */
00716 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 
 * first 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 it answers the concatenation of first and third inserting
 * the sep1 character between them.
 * If the third array is null, then it answers the concatenation of first and second inserting
 * the sep1 character between them.
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    first = null
 *    sep1 = '/'
 *    second = { 'a' }
 *    sep2 = ':'
 *    third = { 'b' }
 *    => result = { ' a' , ':', 'b' }
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    sep1 = '/'
 *    second = null
 *    sep2 = ':'
 *    third = { 'b' }
 *    => result = { ' a' , '/', 'b' }
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    sep1 = '/'
 *    second = { 'b' }
 *    sep2 = ':'
 *    third = null
 *    => result = { ' a' , '/', 'b' }
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    sep1 = '/'
 *    second = { 'b' }
 *    sep2 = ':'
 *    third = { 'c' }
 *    => result = { ' a' , '/', 'b' , ':', 'c' }
 * </pre>
 * </li>
 * </ol>
 * 
 * @param first the first array to concatenate
 * @param sep1 the character to insert
 * @param second the second array to concatenate
 * @param sep2 the character to insert
 * @param third the second array to concatenate
 * @return the concatenation of the three arrays inserting the sep1 character between the 
 * two arrays and sep2 between the last two.
 */
00799 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
 */
00852 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
 */
00898 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
 */
00963 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
 */
01017 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
 * @return true if the array contains an occurrence of character, false otherwise.
 * @throws NullPointerException if array is null.
 */
01076 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
 * @return true if the array contains an occurrence of character, false otherwise.
 * @throws NullPointerException if array is null.
 */
01112 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 true if the array contains an occurrence of one of the characters, false otherwise.
 * 
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    characters = { 'c', 'd' }
 *    array = { 'a', ' b'  }
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    characters = { 'c', 'd' }
 *    array = { 'a', ' b', 'c'  }
 *    result => true
 * </pre>
 * </li>
 * </ol>
 * 
 * @param characters the characters to search
 * @param array the array in which the search is done
 * @return true if the array contains an occurrence of one of the characters, false otherwise.
 * @throws NullPointerException if array is null.
 * @since 3.1
 */
01146 public static final boolean contains(char[] characters, char[] array) {
      for (int i = array.length; --i >= 0;)
            for (int j = characters.length; --j >= 0;)
                  if (array[i] == characters[j])
                        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.
 */

01161 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
 * @return true if array ends with the sequence of characters contained in toBeFound, 
 * otherwise false.
 * @throws NullPointerException if array is null or toBeFound is null
 */
01201 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
 */
01249 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
 */
01308 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
 */
01365 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;
}

/**
 * Answers true if the first array is identical character by character to a portion of the second array
 * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false.
 * The equality is case sensitive.
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    first = null
 *    second = null
 *    secondStart = 0
 *    secondEnd = 0
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    first = { }
 *    second = null
 *    secondStart = 0
 *    secondEnd = 0
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    second = { 'a' }
 *    secondStart = 0
 *    secondEnd = 1
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    second = { 'A' }
 *    secondStart = 0
 *    secondEnd = 1
 *    result => false
 * </pre>
 * </li>
 * </ol>
 * @param first the first array
 * @param second the second array
 * @param secondStart inclusive start position in the second array to compare
 * @param secondEnd exclusive end position in the second array to compare
 * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false
 * @since 3.0
 */
01427 public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd) {
      return equals(first, second, secondStart, secondEnd, true);
}
/**
 * <p>Answers true if the first array is identical character by character to a portion of the second array
 * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. The equality could be either 
 * case sensitive or case insensitive according to the value of the <code>isCaseSensitive</code> parameter.
 * </p>
 * <p>For example:</p>
 * <ol>
 * <li><pre>
 *    first = null
 *    second = null
 *    secondStart = 0
 *    secondEnd = 0
 *    isCaseSensitive = false
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    first = { }
 *    second = null
 *    secondStart = 0
 *    secondEnd = 0
 *    isCaseSensitive = false
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    second = { 'a' }
 *    secondStart = 0
 *    secondEnd = 1
 *    isCaseSensitive = true
 *    result => true
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    second = { 'A' }
 *    secondStart = 0
 *    secondEnd = 1
 *    isCaseSensitive = true
 *    result => false
 * </pre>
 * </li>
 * <li><pre>
 *    first = { 'a' }
 *    second = { 'A' }
 *    secondStart = 0
 *    secondEnd = 1
 *    isCaseSensitive = false
 *    result => true
 * </pre>
 * </li>
 * </ol>
 * @param first the first array
 * @param second the second array
 * @param secondStart inclusive start position in the second array to compare
 * @param secondEnd exclusive end position in the second array to compare
 * @param isCaseSensitive check whether or not the equality should be case sensitive
 * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false
 * @since 3.2
 */
01491 public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd, boolean isCaseSensitive) {
      if (first == second)
            return true;
      if (first == null || second == null)
            return false;
      if (first.length != secondEnd - secondStart)
            return false;
      if (isCaseSensitive) {
            for (int i = first.length; --i >= 0;)
                  if (first[i] != second[i+secondStart])
                        return false;
      } else {
            for (int i = first.length; --i >= 0;)
                  if (ScannerHelper.toLowerCase(first[i]) != ScannerHelper.toLowerCase(second[i+secondStart]))
                        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
 */
01555 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 (ScannerHelper.toLowerCase(first[i])
                  != ScannerHelper.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 name 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.
 * @throws NullPointerException if fragment or name is null.
 */
01627 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 (ScannerHelper.toLowerCase(fragment[i])
                  != ScannerHelper.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
 * @throws NullPointerException if array is null
 */
01660 public static final int hashCode(char[] array) {
      int length = array.length;
      int hash = length == 0 ? 31 : array[0];
      if (length < 8) {
            for (int i = length; --i > 0;)
                  hash = (hash * 31) + array[i];
      } else {
            // 8 characters is enough to compute a decent hash code, don't waste time examining every character
            for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2)
                  hash = (hash * 31) + array[i];
      }
      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.
 */
01695 public static boolean isWhitespace(char c) {
      return c < ScannerHelper.MAX_OBVIOUS && ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_JLS_SPACE) != 0);
}

/**
 * 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
 * @throws NullPointerException if array is null
 */
01726 public static final int indexOf(char toBeFound, char[] array) {
      return indexOf(toBeFound, array, 0);
}

/**
 * Answers the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule. Answers -1 if no match 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 subarray to search
 * @param array the array to be searched
 * @param isCaseSensitive flag to know if the matching should be case sensitive
 * @return the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule, -1 otherwise
 * @throws NullPointerException if array is null or toBeFound is null
 * @since 3.2
 */
01759 public static final int indexOf(char[] toBeFound, char[] array, boolean isCaseSensitive) {
      return indexOf(toBeFound, array, isCaseSensitive, 0);
}

/**
 * Answers the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule starting at the index start. Answers -1 if no match 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 subarray to search
 * @param array the array to be searched
 * @param isCaseSensitive flag to know if the matching should be case sensitive
 * @param start the starting index 
 * @return the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule starting at the index start, -1 otherwise
 * @throws NullPointerException if array is null or toBeFound is null
 * @since 3.2
 */
01793 public static final int indexOf(final char[] toBeFound, final char[] array, final boolean isCaseSensitive, final int start) {
      return indexOf(toBeFound, array, isCaseSensitive, start, array.length);
}

/**
 * Answers the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule starting at the index start. Answers -1 if no match 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 subarray to search
 * @param array the array to be searched
 * @param isCaseSensitive flag to know if the matching should be case sensitive
 * @param start the starting index (inclusive)
 * @param end the end index (exclusive)
 * @return the first index in the array for which the toBeFound array is a matching
 * subarray following the case rule starting at the index start, -1 otherwise
 * @throws NullPointerException if array is null or toBeFound is null
 * @since 3.2
 */
01828 public static final int indexOf(final char[] toBeFound, final char[] array, final boolean isCaseSensitive, final int start, final int end) {
      final int arrayLength = end;
      final int toBeFoundLength = toBeFound.length;
      if (toBeFoundLength > arrayLength) return -1;
      if (toBeFoundLength == 0) return 0;
      if (toBeFoundLength == arrayLength) {
            if (isCaseSensitive) {
                  for (int i = start; i < arrayLength; i++) {
                        if (array[i] != toBeFound[i]) return -1;
                  }
                  return 0;
            } else {
                  for (int i = start; i < arrayLength; i++) {
                        if (ScannerHelper.toLowerCase(array[i]) != ScannerHelper.toLowerCase(toBeFound[i])) return -1;
                  }
                  return 0;
            }
      }
      if (isCaseSensitive) {
            arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) {
                  if (array[i] == toBeFound[0]) {
                        for (int j = 1; j < toBeFoundLength; j++) {
                              if (array[i + j] != toBeFound[j]) continue arrayLoop;
                        }
                        return i;
                  }
            }
      } else {
            arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) {
                  if (ScannerHelper.toLowerCase(array[i]) == ScannerHelper.toLowerCase(toBeFound[0])) {
                        for (int j = 1; j < toBeFoundLength; j++) {
                              if (ScannerHelper.toLowerCase(array[i + j]) != ScannerHelper.toLowerCase(toBeFound[j])) continue arrayLoop;
                        }
                        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
 * @throws NullPointerException if array is null
 * @throws ArrayIndexOutOfBoundsException if  start is lower than 0
 */
01907 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 first index in the array for which the corresponding character is
 * equal to toBeFound starting the search at index start and before the ending index.
 * 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 (inclusive)
 * @param end the ending index (exclusive)
 * @return the first index in the array for which the corresponding character is
 * equal to toBeFound, -1 otherwise
 * @throws NullPointerException if array is null
 * @throws ArrayIndexOutOfBoundsException if  start is lower than 0 or ending greater than array length
 * @since 3.2
 */
01955 public static final int indexOf(char toBeFound, char[] array, int start, int end) {
      for (int i = start; i < end; 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
 * @throws NullPointerException if array is null
 */
01990 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
 * @throws NullPointerException if array is null
 * @throws ArrayIndexOutOfBoundsException if startIndex is lower than 0
 */
02036 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
 * @throws NullPointerException if array is null
 * @throws ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0
 */
02089 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
 * @throws NullPointerException if array is null
 */
02114 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
 */
02161 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 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 a sub-pattern matches the subpart of the given name, false otherwise
 */
02225 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]
                        : ScannerHelper.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] : ScannerHelper.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 rule: 
 * - foo\  is equivalent to foo\**   
 * 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
 */
02320 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 '*'

      // offsets inside pattern
      int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0;
      int pLength = pattern.length;
      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
            && !(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 {
            if (pSegmentStart >= pLength) return fSegmentStart >= fLength; // true if filepath is done too.
            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
 * @throws NullPointerException if array is null
 */
02529 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
 * @param start the given index
 * @return the number of occurrences of the given character in the given array, 0 if any
 * @throws NullPointerException if array is null
 * @throws ArrayIndexOutOfBoundsException if start is lower than 0
 */
02568 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
 * @throws NullPointerException if the given name is null or if the given prefix is null
 */
02605 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
 * @throws NullPointerException if the given name is null or if the given prefix is null
 */
02647 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 (ScannerHelper.toLowerCase(prefix[i])
                  != ScannerHelper.toLowerCase(name[i]))
                  return false;
      return true;
}

/**
 * Answers a new array removing a given character. Answers the given array if there is
 * no occurence of the character to remove.
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'c', 'b', 'a' }
 *    toBeRemoved = 'b'
 *    return { 'a' , 'c', 'a' }
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
 *    toBeRemoved = 'c'
 *    return array
 * </pre>
 * </li>
 * </ol>
 * 
 * @param array the given array
 * @param toBeRemoved the character to be removed
 * @return a new array removing given character
 * @since 3.2
 */
02699 public static final char[] remove(char[] array, char toBeRemoved) {

      if (array == null) return null;
      int length = array.length;
      if (length == 0) return array;
      char[] result = null;
      int count = 0;
      for (int i = 0; i < length; i++) {
            char c = array[i];
            if (c == toBeRemoved) {
                  if (result == null) {
                        result = new char[length];
                        System.arraycopy(array, 0, result, 0, i);
                        count = i;
                  }
            } else if (result != null) {
                  result[count++] = c;
            }
      }
      if (result == null) return array;
      System.arraycopy(result, 0, result = new char[count], 0, count);
      return result;
}

/**
 * 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
 * @throws NullPointerException if the given array is null
 */
02751 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;
            }
      }
}

/**
 * Replace all occurrences of characters to be replaced with the remplacement character in the
 * given array.
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
 *    toBeReplaced = { 'b', 'c' }
 *    replacementChar = 'a'
 *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
 * </pre>
 * </li>
 * </ol>
 * 
 * @param array the given array
 * @param toBeReplaced characters to be replaced
 * @param replacementChar the replacement character
 * @throws NullPointerException if arrays are null.
 * @since 3.1
 */
02785 public static final void replace(char[] array, char[] toBeReplaced, char replacementChar) {
      replace(array, toBeReplaced, replacementChar, 0, array.length);
}

/**
 * Replace all occurrences of characters to be replaced with the remplacement character in the
 * given array from the start position (inclusive) to the end position (exclusive).
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
 *    toBeReplaced = { 'b', 'c' }
 *    replacementChar = 'a'
 *    start = 4
 *    end = 8
 *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'c', 'a', 'a', 'a', 'a' }
 * </pre>
 * </li>
 * </ol>
 * 
 * @param array the given array
 * @param toBeReplaced characters to be replaced
 * @param replacementChar the replacement character
 * @param start the given start position (inclusive)
 * @param end  the given end position (exclusive)
 * @throws NullPointerException if arrays are null.
 * @since 3.2
 */
02815 public static final void replace(char[] array, char[] toBeReplaced, char replacementChar, int start, int end) {
      for (int i = end; --i >= start;)
            for (int j = toBeReplaced.length; --j >= 0;)
                  if (array[i] == toBeReplaced[j])
                        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 array the given array
 * @param toBeReplaced characters to be replaced
 * @param replacementChars the replacement characters
 * @return a new array of characters with substitutions or the given array if none
 * @throws NullPointerException if the given array is null
 */
02851 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;
}

/**
 * Replace all occurrence of the character to be replaced with the remplacement character 
 * in a copy of the given array. Returns the given array if no occurrences of the character
 * to be replaced are found.
 * <br>
 * <br>
 * For example:
 * <ol>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
 *    toBeReplaced = 'b'
 *    replacementChar = 'a'
 *    result => A new array that is equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
 * </pre>
 * </li>
 * <li><pre>
 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
 *    toBeReplaced = 'c'
 *    replacementChar = 'a'
 *    result => The original array that remains unchanged.
 * </pre>
 * </li>
 * </ol>
 * 
 * @param array the given array
 * @param toBeReplaced the character to be replaced
 * @param replacementChar the replacement character
 * @throws NullPointerException if the given array is null
 * @since 3.1
 */
02938 public static final char[] replaceOnCopy(
      char[] array,
      char toBeReplaced,
      char replacementChar) {
      
      char[] result = null;
      for (int i = 0, length = array.length; i < length; i++) {
            char c = array[i];
            if (c == toBeReplaced) {
                  if (result == null) {
                        result = new char[length];
                        System.arraycopy(array, 0, result, 0, i);
                  }
                  result[i] = replacementChar;
            } else if (result != null) {
                  result[i] = c;
            }
      }
      if (result == null) return array;
      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 ' '
 */
02998 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
 */
03071 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
 * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length
 */
03123 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 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
 * @throws NullPointerException if the given array is null
 */
03187 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
 * @throws NullPointerException if the given array is null
 */
03234 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
 */
03272 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 = ScannerHelper.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 (' ')
 */
03317 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 array the given array
 * @return a string which is the concatenation of the given array using the '.' as a separator
 */
03356 final static public String toString(char[][] array) {
      char[] result = concatWith(array, '.');
      return new String(result);
}

/**
 * Answers an array of strings from the given array of char array.
 * 
 * @param array the given array
 * @return an array of strings
 * @since 3.0
 */
03368 final static public String[] toStrings(char[][] array) {
      if (array == null) return NO_STRINGS;
      int length = array.length;
      if (length == 0) return NO_STRINGS;
      String[] result = new String[length];
      for (int i = 0; i < length; i++)
            result[i] = new String(array[i]);
      return result;
}
}

Generated by  Doxygen 1.6.0   Back to index