1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
13 import java.io.BufferedInputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.PrintStream;
17 import java.util.Locale;
18 import java.util.MissingResourceException;
19 import java.util.ResourceBundle;
20 import java.util.StringTokenizer;
22 import net.sourceforge.phpdt.core.IJavaElement;
23 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
24 import net.sourceforge.phpdt.core.IPackageFragment;
25 import net.sourceforge.phpdt.core.JavaModelException;
26 import net.sourceforge.phpdt.core.JavaCore;
27 import net.sourceforge.phpdt.core.Signature;
28 import net.sourceforge.phpdt.core.compiler.CharOperation;
29 import net.sourceforge.phpdt.internal.core.PackageFragmentRoot;
30 import net.sourceforge.phpdt.internal.corext.Assert;
31 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IResource;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IPath;
37 import org.eclipse.core.runtime.IStatus;
38 import org.eclipse.core.runtime.Status;
41 * Provides convenient utility methods to other types in this package.
45 private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
46 private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
47 private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
48 private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$
50 public interface Comparable {
52 * Returns 0 if this and c are equal, >0 if this is greater than c,
53 * or <0 if this is less than c.
55 int compareTo(Comparable c);
58 public interface Comparer {
60 * Returns 0 if a and b are equal, >0 if a is greater than b,
61 * or <0 if a is less than b.
63 int compare(Object a, Object b);
66 public interface Displayable {
67 String displayString(Object o);
70 public static final String[] fgEmptyStringArray = new String[0];
73 * Are we running JDK 1.1?
75 private static boolean JDK1_1 = false;
77 /* Bundle containing messages */
78 protected static ResourceBundle bundle;
79 private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$
81 // public final static char[] SUFFIX_class = ".class".toCharArray(); //$NON-NLS-1$
82 // public final static char[] SUFFIX_CLASS = ".CLASS".toCharArray(); //$NON-NLS-1$
83 // public final static char[] SUFFIX_java = ".java".toCharArray(); //$NON-NLS-1$
84 // public final static char[] SUFFIX_JAVA = ".JAVA".toCharArray(); //$NON-NLS-1$
85 // public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$
86 // public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$
87 // public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$
88 // public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$
91 String ver = System.getProperty("java.version"); //$NON-NLS-1$
92 JDK1_1 = ((ver != null) && ver.startsWith("1.1")); //$NON-NLS-1$
97 * Lookup the message with the given ID in this catalog
99 public static String bind(String id) {
100 return bind(id, (String[])null);
104 * Lookup the message with the given ID in this catalog and bind its
105 * substitution locations with the given string values.
107 public static String bind(String id, String[] bindings) {
109 return "No message available"; //$NON-NLS-1$
110 String message = null;
112 message = bundle.getString(id);
113 } catch (MissingResourceException e) {
114 // If we got an exception looking for the message, fail gracefully by just returning
115 // the id we were looking for. In most cases this is semi-informative so is not too bad.
116 return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
118 // for compatibility with MessageFormat which eliminates double quotes in original message
119 char[] messageWithNoDoubleQuotes =
120 CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
121 message = new String(messageWithNoDoubleQuotes);
123 if (bindings == null)
126 int length = message.length();
129 StringBuffer output = new StringBuffer(80);
131 if ((end = message.indexOf('{', start)) > -1) {
132 output.append(message.substring(start + 1, end));
133 if ((start = message.indexOf('}', end)) > -1) {
136 index = Integer.parseInt(message.substring(end + 1, start));
137 output.append(bindings[index]);
138 } catch (NumberFormatException nfe) {
139 output.append(message.substring(end + 1, start + 1));
140 } catch (ArrayIndexOutOfBoundsException e) {
141 output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
144 output.append(message.substring(end, length));
148 output.append(message.substring(start + 1, length));
152 return output.toString();
156 * Lookup the message with the given ID in this catalog and bind its
157 * substitution locations with the given string.
159 public static String bind(String id, String binding) {
160 return bind(id, new String[] {binding});
164 * Lookup the message with the given ID in this catalog and bind its
165 * substitution locations with the given strings.
167 public static String bind(String id, String binding1, String binding2) {
168 return bind(id, new String[] {binding1, binding2});
172 * Checks the type signature in String sig,
173 * starting at start and ending before end (end is not included).
174 * Returns the index of the character immediately after the signature if valid,
175 * or -1 if not valid.
177 private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) {
178 if (start >= end) return -1;
180 char c = sig.charAt(i++);
181 int nestingDepth = 0;
184 if (i >= end) return -1;
198 if (!allowVoid) return -1;
199 // array of void is not allowed
200 if (nestingDepth != 0) return -1;
203 int semicolon = sig.indexOf(';', i);
204 // Must have at least one character between L and ;
205 if (semicolon <= i || semicolon >= end) return -1;
215 * Combines two hash codes to make a new one.
217 public static int combineHashCodes(int hashCode1, int hashCode2) {
218 return hashCode1 * 17 + hashCode2;
222 * Compares two byte arrays.
223 * Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is null.
224 * Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null.
225 * Returns 0 if they are equal or both null.
227 public static int compare(byte[] a, byte[] b) {
234 int len = Math.min(a.length, b.length);
235 for (int i = 0; i < len; ++i) {
236 int diff = a[i] - b[i];
248 * Compares two char arrays lexicographically.
249 * The comparison is based on the Unicode value of each character in
251 * @return the value <code>0</code> if a is equal to
252 * b; a value less than <code>0</code> if a
253 * is lexicographically less than b; and a
254 * value greater than <code>0</code> if a is
255 * lexicographically greater than b.
257 public static int compare(char[] v1, char[] v2) {
258 int len1 = v1.length;
259 int len2 = v2.length;
260 int n = Math.min(len1, len2);
263 if (v1[i] != v2[i]) {
264 return v1[i] - v2[i];
272 * Concatenate two strings with a char in between.
273 * @see #concat(String, String)
275 public static String concat(String s1, char c, String s2) {
276 if (s1 == null) s1 = "null"; //$NON-NLS-1$
277 if (s2 == null) s2 = "null"; //$NON-NLS-1$
278 int l1 = s1.length();
279 int l2 = s2.length();
280 char[] buf = new char[l1 + 1 + l2];
281 s1.getChars(0, l1, buf, 0);
283 s2.getChars(0, l2, buf, l1 + 1);
284 return new String(buf);
288 * Concatenate two strings.
289 * Much faster than using +, which:
290 * - creates a StringBuffer,
291 * - which is synchronized,
292 * - of default size, so the resulting char array is
293 * often larger than needed.
294 * This implementation creates an extra char array, since the
295 * String constructor copies its argument, but there's no way around this.
297 public static String concat(String s1, String s2) {
298 if (s1 == null) s1 = "null"; //$NON-NLS-1$
299 if (s2 == null) s2 = "null"; //$NON-NLS-1$
300 int l1 = s1.length();
301 int l2 = s2.length();
302 char[] buf = new char[l1 + l2];
303 s1.getChars(0, l1, buf, 0);
304 s2.getChars(0, l2, buf, l1);
305 return new String(buf);
309 * Concatenate three strings.
310 * @see #concat(String, String)
312 public static String concat(String s1, String s2, String s3) {
313 if (s1 == null) s1 = "null"; //$NON-NLS-1$
314 if (s2 == null) s2 = "null"; //$NON-NLS-1$
315 if (s3 == null) s3 = "null"; //$NON-NLS-1$
316 int l1 = s1.length();
317 int l2 = s2.length();
318 int l3 = s3.length();
319 char[] buf = new char[l1 + l2 + l3];
320 s1.getChars(0, l1, buf, 0);
321 s2.getChars(0, l2, buf, l1);
322 s3.getChars(0, l3, buf, l1 + l2);
323 return new String(buf);
327 * Converts a type signature from the IBinaryType representation to the DC representation.
329 public static String convertTypeSignature(char[] sig) {
330 return new String(sig).replace('/', '.');
334 * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
335 * implementation is not creating extra strings.
337 public final static boolean endsWithIgnoreCase(String str, String end) {
339 int strLength = str == null ? 0 : str.length();
340 int endLength = end == null ? 0 : end.length();
342 // return false if the string is smaller than the end.
343 if(endLength > strLength)
346 // return false if any character of the end are
347 // not the same in lower case.
348 for(int i = 1 ; i <= endLength; i++){
349 if(Character.toLowerCase(end.charAt(endLength - i)) != Character.toLowerCase(str.charAt(strLength - i)))
357 * Compares two arrays using equals() on the elements.
358 * Either or both arrays may be null.
359 * Returns true if both are null.
360 * Returns false if only one is null.
361 * If both are arrays, returns true iff they have the same length and
362 * all elements are equal.
364 public static boolean equalArraysOrNull(int[] a, int[] b) {
367 if (a == null || b == null)
372 for (int i = 0; i < len; ++i) {
380 * Compares two arrays using equals() on the elements.
381 * Either or both arrays may be null.
382 * Returns true if both are null.
383 * Returns false if only one is null.
384 * If both are arrays, returns true iff they have the same length and
385 * all elements compare true with equals.
387 public static boolean equalArraysOrNull(Object[] a, Object[] b) {
388 if (a == b) return true;
389 if (a == null || b == null) return false;
392 if (len != b.length) return false;
393 for (int i = 0; i < len; ++i) {
395 if (b[i] != null) return false;
397 if (!a[i].equals(b[i])) return false;
404 * Compares two String arrays using equals() on the elements.
405 * The arrays are first sorted.
406 * Either or both arrays may be null.
407 * Returns true if both are null.
408 * Returns false if only one is null.
409 * If both are arrays, returns true iff they have the same length and
410 * iff, after sorting both arrays, all elements compare true with equals.
411 * The original arrays are left untouched.
413 public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
414 if (a == b) return true;
415 if (a == null || b == null) return false;
417 if (len != b.length) return false;
418 if (len >= 2) { // only need to sort if more than two items
422 for (int i = 0; i < len; ++i) {
423 if (!a[i].equals(b[i])) return false;
429 * Compares two arrays using equals() on the elements.
430 * The arrays are first sorted.
431 * Either or both arrays may be null.
432 * Returns true if both are null.
433 * Returns false if only one is null.
434 * If both are arrays, returns true iff they have the same length and
435 * iff, after sorting both arrays, all elements compare true with equals.
436 * The original arrays are left untouched.
438 public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) {
439 if (a == b) return true;
440 if (a == null || b == null) return false;
442 if (len != b.length) return false;
443 if (len >= 2) { // only need to sort if more than two items
447 for (int i = 0; i < len; ++i) {
448 if (!a[i].equals(b[i])) return false;
454 * Compares two objects using equals().
455 * Either or both array may be null.
456 * Returns true if both are null.
457 * Returns false if only one is null.
458 * Otherwise, return the result of comparing with equals().
460 public static boolean equalOrNull(Object a, Object b) {
464 if (a == null || b == null) {
471 * Given a qualified name, extract the last component.
472 * If the input is not qualified, the same string is answered.
474 public static String extractLastName(String qualifiedName) {
475 int i = qualifiedName.lastIndexOf('.');
476 if (i == -1) return qualifiedName;
477 return qualifiedName.substring(i+1);
481 * Extracts the parameter types from a method signature.
483 public static String[] extractParameterTypes(char[] sig) {
484 int count = getParameterCount(sig);
485 String[] result = new String[count];
488 int i = CharOperation.indexOf('(', sig) + 1;
490 int len = sig.length;
502 i = CharOperation.indexOf(';', sig, i + 1) + 1;
503 Assert.isTrue(i != 0);
504 result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
508 result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
516 * Extracts the return type from a method signature.
518 public static String extractReturnType(String sig) {
519 int i = sig.lastIndexOf(')');
520 Assert.isTrue(i != -1);
521 return sig.substring(i+1);
525 * Finds the first line separator used by the given text.
527 * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>,
528 * or <code>null</code> if none found
530 public static String findLineSeparator(char[] text) {
531 // find the first line separator
532 int length = text.length;
534 char nextChar = text[0];
535 for (int i = 0; i < length; i++) {
536 char currentChar = nextChar;
537 nextChar = i < length-1 ? text[i+1] : ' ';
538 switch (currentChar) {
539 case '\n': return "\n"; //$NON-NLS-1$
540 case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
549 * Returns the line separator used by the given buffer.
550 * Uses the given text if none found.
552 * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>
554 private static String getLineSeparator(char[] text, char[] buffer) {
555 // search in this buffer's contents first
556 String lineSeparator = findLineSeparator(buffer);
557 if (lineSeparator == null) {
558 // search in the given text
559 lineSeparator = findLineSeparator(text);
560 if (lineSeparator == null) {
561 // default to system line separator
562 return System.getProperty("line.separator");
565 return lineSeparator;
569 * Returns the number of parameter types in a method signature.
571 public static int getParameterCount(char[] sig) {
572 int i = CharOperation.indexOf('(', sig) + 1;
573 Assert.isTrue(i != 0);
575 int len = sig.length;
587 i = CharOperation.indexOf(';', sig, i + 1) + 1;
588 Assert.isTrue(i != 0);
598 * Returns the given file's contents as a byte array.
600 public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
601 InputStream stream= null;
603 stream = new BufferedInputStream(file.getContents(true));
604 } catch (CoreException e) {
605 throw new JavaModelException(e);
608 return net.sourceforge.phpdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
609 } catch (IOException e) {
610 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
614 } catch (IOException e) {
620 * Returns the given file's contents as a character array.
622 public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
623 String encoding = JavaCore.create(file.getProject()).getOption(JavaCore.CORE_ENCODING, true);
624 return getResourceContentsAsCharArray(file, encoding);
627 public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
628 InputStream stream= null;
630 stream = new BufferedInputStream(file.getContents(true));
631 } catch (CoreException e) {
632 throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
635 return net.sourceforge.phpdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
636 } catch (IOException e) {
637 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
641 } catch (IOException e) {
647 * Returns a trimmed version the simples names returned by Signature.
649 public static String[] getTrimmedSimpleNames(String name) {
650 String[] result = Signature.getSimpleNames(name);
651 if (result == null) return null;
652 for (int i = 0, length = result.length; i < length; i++) {
653 result[i] = result[i].trim();
659 * Returns true iff str.toLowerCase().endsWith(".class")
660 * implementation is not creating extra strings.
662 // public final static boolean isClassFileName(String name) {
663 // int nameLength = name == null ? 0 : name.length();
664 // int suffixLength = SUFFIX_CLASS.length;
665 // if (nameLength < suffixLength) return false;
667 // for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
668 // char c = name.charAt(offset + i);
669 // if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
675 * Returns whether the given java element is exluded from its root's classpath.
677 public static final boolean isExcluded(IJavaElement element) {
678 int elementType = element.getElementType();
679 PackageFragmentRoot root = null;
680 IResource resource = null;
681 switch (elementType) {
682 // case IJavaElement.PACKAGE_FRAGMENT:
683 // PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
684 // IResource resource = element.getResource();
685 // return resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars());
686 case IJavaElement.COMPILATION_UNIT:
687 root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
688 resource = element.getResource();
689 // if (resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars()))
691 return isExcluded(element.getParent());
693 IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
694 return cu != null && isExcluded(cu);
698 * Returns whether the given resource path matches one of the exclusion
701 * @see IClasspathEntry#getExclusionPatterns
703 public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
704 if (exclusionPatterns == null) return false;
705 char[] path = resourcePath.toString().toCharArray();
706 for (int i = 0, length = exclusionPatterns.length; i < length; i++)
707 if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
713 * Returns whether the given resource matches one of the exclusion patterns.
715 * @see IClasspathEntry#getExclusionPatterns
717 public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
718 IPath path = resource.getFullPath();
719 // ensure that folders are only excluded if all of their children are excluded
720 if (resource.getType() == IResource.FOLDER)
721 path = path.append("*"); //$NON-NLS-1$
722 return isExcluded(path, exclusionPatterns);
726 * Returns true iff str.toLowerCase().endsWith(".jar" or ".zip")
727 * implementation is not creating extra strings.
729 // public final static boolean isArchiveFileName(String name) {
730 // int nameLength = name == null ? 0 : name.length();
731 // int suffixLength = SUFFIX_JAR.length;
732 // if (nameLength < suffixLength) return false;
735 // for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
736 // char c = name.charAt(offset + i);
737 // if (c != SUFFIX_jar[i] && c != SUFFIX_JAR[i]) break;
739 // if (i == suffixLength) return true;
740 // for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
741 // char c = name.charAt(offset + i);
742 // if (c != SUFFIX_zip[i] && c != SUFFIX_ZIP[i]) return false;
748 * Validate the given compilation unit name.
749 * A compilation unit name must obey the following rules:
751 * <li> it must not be null
752 * <li> it must include the <code>".java"</code> suffix
753 * <li> its prefix must be a valid identifier
756 * @param name the name of a compilation unit
757 * @return a status object with code <code>IStatus.OK</code> if
758 * the given name is valid as a compilation unit name, otherwise a status
759 * object indicating what is wrong with the name
761 public static boolean isValidCompilationUnitName(String name) {
762 return PHPFileUtil.isPHPFileName(name);
763 // return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
767 * Validate the given .class file name.
768 * A .class file name must obey the following rules:
770 * <li> it must not be null
771 * <li> it must include the <code>".class"</code> suffix
772 * <li> its prefix must be a valid identifier
775 * @param name the name of a .class file
776 * @return a status object with code <code>IStatus.OK</code> if
777 * the given name is valid as a .class file name, otherwise a status
778 * object indicating what is wrong with the name
780 // public static boolean isValidClassFileName(String name) {
781 // return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
785 * Returns true if the given method signature is valid,
786 * false if it is not.
788 public static boolean isValidMethodSignature(String sig) {
789 int len = sig.length();
790 if (len == 0) return false;
792 char c = sig.charAt(i++);
793 if (c != '(') return false;
794 if (i >= len) return false;
795 while (sig.charAt(i) != ')') {
796 // Void is not allowed as a parameter type.
797 i = checkTypeSignature(sig, i, len, false);
798 if (i == -1) return false;
799 if (i >= len) return false;
802 i = checkTypeSignature(sig, i, len, true);
807 * Returns true if the given type signature is valid,
808 * false if it is not.
810 public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
811 int len = sig.length();
812 return checkTypeSignature(sig, 0, len, allowVoid) == len;
816 * Returns true if the given folder name is valid for a package,
817 * false if it is not.
819 public static boolean isValidFolderNameForPackage(String folderName) {
820 // return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
827 // public static void log(Throwable e, String message) {
828 // Throwable nestedException;
829 // if (e instanceof JavaModelException
830 // && (nestedException = ((JavaModelException)e).getException()) != null) {
831 // e = nestedException;
833 // IStatus status= new Status(
835 // JavaCore.getPlugin().getDescriptor().getUniqueIdentifier(),
839 // JavaCore.getPlugin().getLog().log(status);
844 public static void log(Throwable e, String message) {
845 Throwable nestedException;
846 if (e instanceof JavaModelException
847 && (nestedException = ((JavaModelException)e).getException()) != null) {
850 IStatus status= new Status(
856 JavaCore.getPlugin().getLog().log(status);
859 * Normalizes the cariage returns in the given text.
860 * They are all changed to use the given buffer's line separator.
862 public static char[] normalizeCRs(char[] text, char[] buffer) {
863 CharArrayBuffer result = new CharArrayBuffer();
865 int length = text.length;
866 if (length == 0) return text;
867 String lineSeparator = getLineSeparator(text, buffer);
868 char nextChar = text[0];
869 for (int i = 0; i < length; i++) {
870 char currentChar = nextChar;
871 nextChar = i < length-1 ? text[i+1] : ' ';
872 switch (currentChar) {
874 int lineLength = i-lineStart;
875 char[] line = new char[lineLength];
876 System.arraycopy(text, lineStart, line, 0, lineLength);
878 result.append(lineSeparator);
882 lineLength = i-lineStart;
883 if (lineLength >= 0) {
884 line = new char[lineLength];
885 System.arraycopy(text, lineStart, line, 0, lineLength);
887 result.append(lineSeparator);
888 if (nextChar == '\n') {
892 // when line separator are mixed in the same file
893 // \r might not be followed by a \n. If not, we should increment
894 // lineStart by one and not by two.
898 // when line separator are mixed in the same file
899 // we need to prevent NegativeArraySizeException
907 int lastLineLength = length-lineStart;
908 if (lastLineLength > 0) {
909 lastLine = new char[lastLineLength];
910 System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
911 result.append(lastLine);
913 return result.getContents();
920 * Normalizes the cariage returns in the given text.
921 * They are all changed to use given buffer's line sepatator.
923 public static String normalizeCRs(String text, String buffer) {
924 return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray()));
928 * Sort the objects in the given collection using the given sort order.
930 private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
931 int original_left = left;
932 int original_right = right;
933 int mid = sortOrder[ (left + right) / 2];
935 while (sortOrder[left] < mid) {
938 while (mid < sortOrder[right]) {
942 Object tmp = sortedCollection[left];
943 sortedCollection[left] = sortedCollection[right];
944 sortedCollection[right] = tmp;
945 int tmp2 = sortOrder[left];
946 sortOrder[left] = sortOrder[right];
947 sortOrder[right] = tmp2;
951 } while (left <= right);
952 if (original_left < right) {
953 quickSort(sortedCollection, original_left, right, sortOrder);
955 if (left < original_right) {
956 quickSort(sortedCollection, left, original_right, sortOrder);
961 * Sort the objects in the given collection using the given comparer.
963 private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
964 int original_left = left;
965 int original_right = right;
966 Object mid = sortedCollection[ (left + right) / 2];
968 while (comparer.compare(sortedCollection[left], mid) < 0) {
971 while (comparer.compare(mid, sortedCollection[right]) < 0) {
975 Object tmp = sortedCollection[left];
976 sortedCollection[left] = sortedCollection[right];
977 sortedCollection[right] = tmp;
981 } while (left <= right);
982 if (original_left < right) {
983 quickSort(sortedCollection, original_left, right, comparer);
985 if (left < original_right) {
986 quickSort(sortedCollection, left, original_right, comparer);
991 * Sort the strings in the given collection.
993 private static void quickSort(String[] sortedCollection, int left, int right) {
994 int original_left = left;
995 int original_right = right;
996 String mid = sortedCollection[ (left + right) / 2];
998 while (sortedCollection[left].compareTo(mid) < 0) {
1001 while (mid.compareTo(sortedCollection[right]) < 0) {
1004 if (left <= right) {
1005 String tmp = sortedCollection[left];
1006 sortedCollection[left] = sortedCollection[right];
1007 sortedCollection[right] = tmp;
1011 } while (left <= right);
1012 if (original_left < right) {
1013 quickSort(sortedCollection, original_left, right);
1015 if (left < original_right) {
1016 quickSort(sortedCollection, left, original_right);
1021 * Converts the given relative path into a package name.
1022 * Returns null if the path is not a valid package name.
1024 public static String packageName(IPath pkgPath) {
1025 StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
1026 for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
1027 String segment = pkgPath.segment(j);
1028 if (!isValidFolderNameForPackage(segment)) {
1031 pkgName.append(segment);
1032 if (j < pkgPath.segmentCount() - 1) {
1033 pkgName.append("." ); //$NON-NLS-1$
1036 return pkgName.toString();
1040 * Sort the comparable objects in the given collection.
1042 private static void quickSort(Comparable[] sortedCollection, int left, int right) {
1043 int original_left = left;
1044 int original_right = right;
1045 Comparable mid = sortedCollection[ (left + right) / 2];
1047 while (sortedCollection[left].compareTo(mid) < 0) {
1050 while (mid.compareTo(sortedCollection[right]) < 0) {
1053 if (left <= right) {
1054 Comparable tmp = sortedCollection[left];
1055 sortedCollection[left] = sortedCollection[right];
1056 sortedCollection[right] = tmp;
1060 } while (left <= right);
1061 if (original_left < right) {
1062 quickSort(sortedCollection, original_left, right);
1064 if (left < original_right) {
1065 quickSort(sortedCollection, left, original_right);
1070 * Sort the strings in the given collection in reverse alphabetical order.
1072 private static void quickSortReverse(String[] sortedCollection, int left, int right) {
1073 int original_left = left;
1074 int original_right = right;
1075 String mid = sortedCollection[ (left + right) / 2];
1077 while (sortedCollection[left].compareTo(mid) > 0) {
1080 while (mid.compareTo(sortedCollection[right]) > 0) {
1083 if (left <= right) {
1084 String tmp = sortedCollection[left];
1085 sortedCollection[left] = sortedCollection[right];
1086 sortedCollection[right] = tmp;
1090 } while (left <= right);
1091 if (original_left < right) {
1092 quickSortReverse(sortedCollection, original_left, right);
1094 if (left < original_right) {
1095 quickSortReverse(sortedCollection, left, original_right);
1100 * Sorts an array of objects in place, using the sort order given for each item.
1102 public static void sort(Object[] objects, int[] sortOrder) {
1103 if (objects.length > 1)
1104 quickSort(objects, 0, objects.length - 1, sortOrder);
1108 * Sorts an array of objects in place.
1109 * The given comparer compares pairs of items.
1111 public static void sort(Object[] objects, Comparer comparer) {
1112 if (objects.length > 1)
1113 quickSort(objects, 0, objects.length - 1, comparer);
1117 * Sorts an array of strings in place using quicksort.
1119 public static void sort(String[] strings) {
1120 if (strings.length > 1)
1121 quickSort(strings, 0, strings.length - 1);
1125 * Sorts an array of Comparable objects in place.
1127 public static void sort(Comparable[] objects) {
1128 if (objects.length > 1)
1129 quickSort(objects, 0, objects.length - 1);
1133 * Sorts an array of Strings, returning a new array
1134 * with the sorted items. The original array is left untouched.
1136 public static Object[] sortCopy(Object[] objects, Comparer comparer) {
1137 int len = objects.length;
1138 Object[] copy = new Object[len];
1139 System.arraycopy(objects, 0, copy, 0, len);
1140 sort(copy, comparer);
1145 * Sorts an array of Strings, returning a new array
1146 * with the sorted items. The original array is left untouched.
1148 public static String[] sortCopy(String[] objects) {
1149 int len = objects.length;
1150 String[] copy = new String[len];
1151 System.arraycopy(objects, 0, copy, 0, len);
1157 * Sorts an array of Comparable objects, returning a new array
1158 * with the sorted items. The original array is left untouched.
1160 public static Comparable[] sortCopy(Comparable[] objects) {
1161 int len = objects.length;
1162 Comparable[] copy = new Comparable[len];
1163 System.arraycopy(objects, 0, copy, 0, len);
1169 * Sorts an array of strings in place using quicksort
1170 * in reverse alphabetical order.
1172 public static void sortReverseOrder(String[] strings) {
1173 if (strings.length > 1)
1174 quickSortReverse(strings, 0, strings.length - 1);
1178 * Converts a String[] to char[][].
1180 public static char[][] toCharArrays(String[] a) {
1182 char[][] result = new char[len][];
1183 for (int i = 0; i < len; ++i) {
1184 result[i] = toChars(a[i]);
1190 * Converts a String to char[].
1192 public static char[] toChars(String s) {
1193 int len = s.length();
1194 char[] chars = new char[len];
1195 s.getChars(0, len, chars, 0);
1200 * Converts a String to char[][], where segments are separate by '.'.
1202 public static char[][] toCompoundChars(String s) {
1203 int len = s.length();
1205 return CharOperation.NO_CHAR_CHAR;
1208 for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
1211 char[][] segs = new char[segCount][];
1213 for (int i = 0; i < segCount; ++i) {
1214 int dot = s.indexOf('.', start);
1215 int end = (dot == -1 ? s.length() : dot);
1216 segs[i] = new char[end - start];
1217 s.getChars(start, end, segs[i], 0);
1224 * Converts a char[][] to String, where segments are separated by '.'.
1226 public static String toString(char[][] c) {
1227 StringBuffer sb = new StringBuffer();
1228 for (int i = 0, max = c.length; i < max; ++i) {
1229 if (i != 0) sb.append('.');
1232 return sb.toString();
1236 * Converts a char[][] and a char[] to String, where segments are separated by '.'.
1238 public static String toString(char[][] c, char[] d) {
1239 if (c == null) return new String(d);
1240 StringBuffer sb = new StringBuffer();
1241 for (int i = 0, max = c.length; i < max; ++i) {
1246 return sb.toString();
1250 * Converts a char[] to String.
1252 public static String toString(char[] c) {
1253 return new String(c);
1257 * Converts an array of Objects into String.
1259 public static String toString(Object[] objects) {
1260 return toString(objects,
1262 public String displayString(Object o) {
1263 if (o == null) return "null"; //$NON-NLS-1$
1264 return o.toString();
1270 * Converts an array of Objects into String.
1272 public static String toString(Object[] objects, Displayable renderer) {
1273 if (objects == null) return ""; //$NON-NLS-1$
1274 StringBuffer buffer = new StringBuffer(10);
1275 for (int i = 0; i < objects.length; i++){
1276 if (i > 0) buffer.append(", "); //$NON-NLS-1$
1277 buffer.append(renderer.displayString(objects[i]));
1279 return buffer.toString();
1283 * Asserts that the given method signature is valid.
1285 public static void validateMethodSignature(String sig) {
1286 Assert.isTrue(isValidMethodSignature(sig));
1290 * Asserts that the given type signature is valid.
1292 public static void validateTypeSignature(String sig, boolean allowVoid) {
1293 Assert.isTrue(isValidTypeSignature(sig, allowVoid));
1295 public static void verbose(String log) {
1296 verbose(log, System.out);
1298 public static synchronized void verbose(String log, PrintStream printStream) {
1301 int end = log.indexOf('\n', start);
1302 printStream.print(Thread.currentThread());
1303 printStream.print(" "); //$NON-NLS-1$
1304 printStream.print(log.substring(start, end == -1 ? log.length() : end+1));
1306 } while (start != 0);
1307 printStream.println();
1310 * Creates a NLS catalog for the given locale.
1312 public static void relocalize() {
1314 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1315 } catch(MissingResourceException e) {
1316 System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
1322 * Put all the arguments in one String.
1324 public static String getProblemArgumentsForMarker(String[] arguments){
1325 StringBuffer args = new StringBuffer(10);
1327 args.append(arguments.length);
1331 for (int j = 0; j < arguments.length; j++) {
1333 args.append(ARGUMENTS_DELIMITER);
1335 if(arguments[j].length() == 0) {
1336 args.append(EMPTY_ARGUMENT);
1338 args.append(arguments[j]);
1342 return args.toString();
1346 * Separate all the arguments of a String made by getProblemArgumentsForMarker
1348 public static String[] getProblemArgumentsFromMarker(String argumentsString){
1349 if (argumentsString == null) return null;
1350 int index = argumentsString.indexOf(':');
1354 int length = argumentsString.length();
1357 numberOfArg = Integer.parseInt(argumentsString.substring(0 , index));
1358 } catch (NumberFormatException e) {
1361 argumentsString = argumentsString.substring(index + 1, length);
1363 String[] args = new String[length];
1366 StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
1367 while(tokenizer.hasMoreTokens()) {
1368 String argument = tokenizer.nextToken();
1369 if(argument.equals(EMPTY_ARGUMENT))
1370 argument = ""; //$NON-NLS-1$
1371 args[count++] = argument;
1374 if(count != numberOfArg)
1377 System.arraycopy(args, 0, args = new String[count], 0, count);