3m9 compatible;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / util / Util.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
12
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;
21
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;
32
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;
39
40 /**
41  * Provides convenient utility methods to other types in this package.
42  */
43 public class Util {
44
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$
49
50         public interface Comparable {
51                 /**
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.
54                  */
55                 int compareTo(Comparable c);
56         }
57
58         public interface Comparer {
59                 /**
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.
62                  */
63                 int compare(Object a, Object b);
64         }
65         
66         public interface Displayable {
67                 String displayString(Object o);
68         }
69         
70         public static final String[] fgEmptyStringArray = new String[0];
71
72         /**
73          * Are we running JDK 1.1?
74          */
75         private static boolean JDK1_1 = false;
76
77         /* Bundle containing messages */
78         protected static ResourceBundle bundle;
79         private final static String bundleName = "net.sourceforge.phpdt.internal.core.messages"; //$NON-NLS-1$
80
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$
89
90         static {
91                 String ver = System.getProperty("java.version"); //$NON-NLS-1$
92                 JDK1_1 = ((ver != null) && ver.startsWith("1.1")); //$NON-NLS-1$
93                 relocalize();
94         }       
95         
96         /**
97          * Lookup the message with the given ID in this catalog 
98          */
99         public static String bind(String id) {
100                 return bind(id, (String[])null);
101         }
102         
103         /**
104          * Lookup the message with the given ID in this catalog and bind its
105          * substitution locations with the given string values.
106          */
107         public static String bind(String id, String[] bindings) {
108                 if (id == null)
109                         return "No message available"; //$NON-NLS-1$
110                 String message = null;
111                 try {
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$
117                 }
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);
122         
123                 if (bindings == null)
124                         return message;
125         
126                 int length = message.length();
127                 int start = -1;
128                 int end = length;
129                 StringBuffer output = new StringBuffer(80);
130                 while (true) {
131                         if ((end = message.indexOf('{', start)) > -1) {
132                                 output.append(message.substring(start + 1, end));
133                                 if ((start = message.indexOf('}', end)) > -1) {
134                                         int index = -1;
135                                         try {
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$
142                                         }
143                                 } else {
144                                         output.append(message.substring(end, length));
145                                         break;
146                                 }
147                         } else {
148                                 output.append(message.substring(start + 1, length));
149                                 break;
150                         }
151                 }
152                 return output.toString();
153         }
154
155         /**
156          * Lookup the message with the given ID in this catalog and bind its
157          * substitution locations with the given string.
158          */
159         public static String bind(String id, String binding) {
160                 return bind(id, new String[] {binding});
161         }
162         
163         /**
164          * Lookup the message with the given ID in this catalog and bind its
165          * substitution locations with the given strings.
166          */
167         public static String bind(String id, String binding1, String binding2) {
168                 return bind(id, new String[] {binding1, binding2});
169         }
170
171         /**
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.
176          */
177         private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) {
178                 if (start >= end) return -1;
179                 int i = start;
180                 char c = sig.charAt(i++);
181                 int nestingDepth = 0;
182                 while (c == '[') {
183                         ++nestingDepth;
184                         if (i >= end) return -1;
185                         c = sig.charAt(i++);
186                 }
187                 switch (c) {
188                         case 'B':
189                         case 'C': 
190                         case 'D':
191                         case 'F':
192                         case 'I':
193                         case 'J':
194                         case 'S': 
195                         case 'Z':
196                                 break;
197                         case 'V':
198                                 if (!allowVoid) return -1;
199                                 // array of void is not allowed
200                                 if (nestingDepth != 0) return -1;
201                                 break;
202                         case 'L':
203                                 int semicolon = sig.indexOf(';', i);
204                                 // Must have at least one character between L and ;
205                                 if (semicolon <= i || semicolon >= end) return -1;
206                                 i = semicolon + 1;
207                                 break;
208                         default:
209                                 return -1;
210                 }
211                 return i;
212         }
213         
214         /**
215          * Combines two hash codes to make a new one.
216          */
217         public static int combineHashCodes(int hashCode1, int hashCode2) {
218                 return hashCode1 * 17 + hashCode2;
219         }
220         
221         /**
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.
226          */
227         public static int compare(byte[] a, byte[] b) {
228                 if (a == b)
229                         return 0;
230                 if (a == null)
231                         return -1;
232                 if (b == null)
233                         return 1;
234                 int len = Math.min(a.length, b.length);
235                 for (int i = 0; i < len; ++i) {
236                         int diff = a[i] - b[i];
237                         if (diff != 0)
238                                 return diff;
239                 }
240                 if (a.length > len)
241                         return 1;
242                 if (b.length > len)
243                         return -1;
244                 return 0;
245         }
246
247         /**
248          * Compares two char arrays lexicographically. 
249          * The comparison is based on the Unicode value of each character in
250          * the char arrays. 
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.
256          */
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);
261                 int i = 0;
262                 while (n-- != 0) {
263                         if (v1[i] != v2[i]) {
264                                 return v1[i] - v2[i];
265                         }
266                         ++i;
267                 }
268                 return len1 - len2;
269         }
270
271         /**
272          * Concatenate two strings with a char in between.
273          * @see #concat(String, String)
274          */
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);
282                 buf[l1] = c;
283                 s2.getChars(0, l2, buf, l1 + 1);
284                 return new String(buf);
285         }
286         
287         /**
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.
296          */
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);
306         }
307
308         /**
309          * Concatenate three strings.
310          * @see #concat(String, String)
311          */
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);
324         }
325         
326         /**
327          * Converts a type signature from the IBinaryType representation to the DC representation.
328          */
329         public static String convertTypeSignature(char[] sig) {
330                 return new String(sig).replace('/', '.');
331         }
332
333         /**
334          * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
335          * implementation is not creating extra strings.
336          */
337         public final static boolean endsWithIgnoreCase(String str, String end) {
338                 
339                 int strLength = str == null ? 0 : str.length();
340                 int endLength = end == null ? 0 : end.length();
341                 
342                 // return false if the string is smaller than the end.
343                 if(endLength > strLength)
344                         return false;
345                         
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)))
350                                 return false;
351                 }
352                 
353                 return true;
354         }
355
356         /**
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.
363          */
364         public static boolean equalArraysOrNull(int[] a, int[] b) {
365                 if (a == b)
366                         return true;
367                 if (a == null || b == null)
368                         return false;
369                 int len = a.length;
370                 if (len != b.length)
371                         return false;
372                 for (int i = 0; i < len; ++i) {
373                         if (a[i] != b[i])
374                                 return false;
375                 }
376                 return true;
377         }
378
379         /**
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.
386          */
387         public static boolean equalArraysOrNull(Object[] a, Object[] b) {
388                 if (a == b)     return true;
389                 if (a == null || b == null) return false;
390
391                 int len = a.length;
392                 if (len != b.length) return false;
393                 for (int i = 0; i < len; ++i) {
394                         if (a[i] == null) {
395                                 if (b[i] != null) return false;
396                         } else {
397                                 if (!a[i].equals(b[i])) return false;
398                         }
399                 }
400                 return true;
401         }
402         
403         /**
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.
412          */
413         public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
414                 if (a == b)     return true;
415                 if (a == null || b == null) return false;
416                 int len = a.length;
417                 if (len != b.length) return false;
418                 if (len >= 2) {  // only need to sort if more than two items
419                         a = sortCopy(a);
420                         b = sortCopy(b);
421                 }
422                 for (int i = 0; i < len; ++i) {
423                         if (!a[i].equals(b[i])) return false;
424                 }
425                 return true;
426         }
427         
428         /**
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.
437          */
438         public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) {
439                 if (a == b)     return true;
440                 if (a == null || b == null) return false;
441                 int len = a.length;
442                 if (len != b.length) return false;
443                 if (len >= 2) {  // only need to sort if more than two items
444                         a = sortCopy(a);
445                         b = sortCopy(b);
446                 }
447                 for (int i = 0; i < len; ++i) {
448                         if (!a[i].equals(b[i])) return false;
449                 }
450                 return true;
451         }
452         
453         /**
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().
459          */
460         public static boolean equalOrNull(Object a, Object b) {
461                 if (a == b) {
462                         return true;
463                 }
464                 if (a == null || b == null) {
465                         return false;
466                 }
467                 return a.equals(b);
468         }
469         
470         /**
471          * Given a qualified name, extract the last component.
472          * If the input is not qualified, the same string is answered.
473          */
474         public static String extractLastName(String qualifiedName) {
475                 int i = qualifiedName.lastIndexOf('.');
476                 if (i == -1) return qualifiedName;
477                 return qualifiedName.substring(i+1);
478         }
479         
480         /**
481          * Extracts the parameter types from a method signature.
482          */
483         public static String[] extractParameterTypes(char[] sig) {
484                 int count = getParameterCount(sig);
485                 String[] result = new String[count];
486                 if (count == 0)
487                         return result;
488                 int i = CharOperation.indexOf('(', sig) + 1;
489                 count = 0;
490                 int len = sig.length;
491                 int start = i;
492                 for (;;) {
493                         if (i == len)
494                                 break;
495                         char c = sig[i];
496                         if (c == ')')
497                                 break;
498                         if (c == '[') {
499                                 ++i;
500                         } else
501                                 if (c == 'L') {
502                                         i = CharOperation.indexOf(';', sig, i + 1) + 1;
503                                         Assert.isTrue(i != 0);
504                                         result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
505                                         start = i;
506                                 } else {
507                                         ++i;
508                                         result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
509                                         start = i;
510                                 }
511                 }
512                 return result;
513         }
514
515         /**
516          * Extracts the return type from a method signature.
517          */
518         public static String extractReturnType(String sig) {
519                 int i = sig.lastIndexOf(')');
520                 Assert.isTrue(i != -1);
521                 return sig.substring(i+1);      
522         }
523         
524         /**
525          * Finds the first line separator used by the given text.
526          *
527          * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>,
528          *                      or <code>null</code> if none found
529          */
530         public static String findLineSeparator(char[] text) {
531                 // find the first line separator
532                 int length = text.length;
533                 if (length > 0) {
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$
541                                 }
542                         }
543                 }
544                 // not found
545                 return null;
546         }
547         
548         /**
549          * Returns the line separator used by the given buffer.
550          * Uses the given text if none found.
551          *
552          * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>
553          */
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");
563                         }
564                 }
565                 return lineSeparator;
566         }
567                 
568         /**
569          * Returns the number of parameter types in a method signature.
570          */
571         public static int getParameterCount(char[] sig) {
572                 int i = CharOperation.indexOf('(', sig) + 1;
573                 Assert.isTrue(i != 0);
574                 int count = 0;
575                 int len = sig.length;
576                 for (;;) {
577                         if (i == len)
578                                 break;
579                         char c = sig[i];
580                         if (c == ')')
581                                 break;
582                         if (c == '[') {
583                                 ++i;
584                         } else
585                                 if (c == 'L') {
586                                         ++count;
587                                         i = CharOperation.indexOf(';', sig, i + 1) + 1;
588                                         Assert.isTrue(i != 0);
589                                 } else {
590                                         ++count;
591                                         ++i;
592                                 }
593                 }
594                 return count;
595         }
596         
597         /**
598          * Returns the given file's contents as a byte array.
599          */
600         public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
601                 InputStream stream= null;
602                 try {
603                         stream = new BufferedInputStream(file.getContents(true));
604                 } catch (CoreException e) {
605                         throw new JavaModelException(e);
606                 }
607                 try {
608                         return net.sourceforge.phpdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
609                 } catch (IOException e) {
610                         throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
611                 } finally {
612                         try {
613                                 stream.close();
614                         } catch (IOException e) {
615                         }
616                 }
617         }
618         
619         /**
620          * Returns the given file's contents as a character array.
621          */
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);
625         }
626
627         public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
628                 InputStream stream= null;
629                 try {
630                         stream = new BufferedInputStream(file.getContents(true));
631                 } catch (CoreException e) {
632                         throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
633                 }
634                 try {
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);
638                 } finally {
639                         try {
640                                 stream.close();
641                         } catch (IOException e) {
642                         }
643                 }
644         }
645         
646         /**
647          * Returns a trimmed version the simples names returned by Signature.
648          */
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();
654                 }
655                 return result;
656         }
657         
658         /**
659          * Returns true iff str.toLowerCase().endsWith(".class")
660          * implementation is not creating extra strings.
661          */
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;
666 //
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;
670 //              }
671 //              return true;            
672 //      }
673         
674         /*
675          * Returns whether the given java element is exluded from its root's classpath.
676          */
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()))
690 //                                      return true;
691                                 return isExcluded(element.getParent());
692                         default:
693                                 IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
694                                 return cu != null && isExcluded(cu);
695                 }
696         }
697         /*
698          * Returns whether the given resource path matches one of the exclusion
699          * patterns.
700          * 
701          * @see IClasspathEntry#getExclusionPatterns
702          */
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, '/'))
708                                 return true;
709                 return false;
710         }       
711         
712         /*
713          * Returns whether the given resource matches one of the exclusion patterns.
714          * 
715          * @see IClasspathEntry#getExclusionPatterns
716          */
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);
723         }
724
725         /**
726          * Returns true iff str.toLowerCase().endsWith(".jar" or ".zip")
727          * implementation is not creating extra strings.
728          */
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;
733 //
734 //              int i, offset;
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;
738 //              }
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;
743 //              }
744 //              return true;
745 //      }
746         
747         /**
748          * Validate the given compilation unit name.
749          * A compilation unit name must obey the following rules:
750          * <ul>
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
754          * </ul>
755          * </p>
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
760          */
761         public static boolean isValidCompilationUnitName(String name) {
762                 return PHPFileUtil.isPHPFileName(name);
763 //              return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
764         }
765
766         /**
767          * Validate the given .class file name.
768          * A .class file name must obey the following rules:
769          * <ul>
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
773          * </ul>
774          * </p>
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
779          */
780 //      public static boolean isValidClassFileName(String name) {
781 //              return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
782 //      }
783
784         /**
785          * Returns true if the given method signature is valid,
786          * false if it is not.
787          */
788         public static boolean isValidMethodSignature(String sig) {
789                 int len = sig.length();
790                 if (len == 0) return false;
791                 int i = 0;
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;
800                 }
801                 ++i;
802                 i = checkTypeSignature(sig, i, len, true);
803                 return i == len;
804         }
805         
806         /**
807          * Returns true if the given type signature is valid,
808          * false if it is not.
809          */
810         public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
811                 int len = sig.length();
812                 return checkTypeSignature(sig, 0, len, allowVoid) == len;
813         }
814         
815         /**
816          * Returns true if the given folder name is valid for a package,
817          * false if it is not.
818          */
819         public static boolean isValidFolderNameForPackage(String folderName) {
820 //              return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
821           return true;
822         }       
823
824         /*
825          * Add a log entry
826          */
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;
832                 }
833                 IStatus status= new Status(
834                         IStatus.ERROR, 
835                         JavaCore.getPlugin().getDescriptor().getUniqueIdentifier(), 
836                         IStatus.ERROR, 
837                         message, 
838                         e); 
839                 JavaCore.getPlugin().getLog().log(status);
840         }       
841         
842         /**
843          * Normalizes the cariage returns in the given text.
844          * They are all changed  to use the given buffer's line separator.
845          */
846         public static char[] normalizeCRs(char[] text, char[] buffer) {
847                 CharArrayBuffer result = new CharArrayBuffer();
848                 int lineStart = 0;
849                 int length = text.length;
850                 if (length == 0) return text;
851                 String lineSeparator = getLineSeparator(text, buffer);
852                 char nextChar = text[0];
853                 for (int i = 0; i < length; i++) {
854                         char currentChar = nextChar;
855                         nextChar = i < length-1 ? text[i+1] : ' ';
856                         switch (currentChar) {
857                                 case '\n':
858                                         int lineLength = i-lineStart;
859                                         char[] line = new char[lineLength];
860                                         System.arraycopy(text, lineStart, line, 0, lineLength);
861                                         result.append(line);
862                                         result.append(lineSeparator);
863                                         lineStart = i+1;
864                                         break;
865                                 case '\r':
866                                         lineLength = i-lineStart;
867                                         if (lineLength >= 0) {
868                                                 line = new char[lineLength];
869                                                 System.arraycopy(text, lineStart, line, 0, lineLength);
870                                                 result.append(line);
871                                                 result.append(lineSeparator);
872                                                 if (nextChar == '\n') {
873                                                         nextChar = ' ';
874                                                         lineStart = i+2;
875                                                 } else {
876                                                         // when line separator are mixed in the same file
877                                                         // \r might not be followed by a \n. If not, we should increment
878                                                         // lineStart by one and not by two.
879                                                         lineStart = i+1;
880                                                 }
881                                         } else {
882                                                 // when line separator are mixed in the same file
883                                                 // we need to prevent NegativeArraySizeException
884                                                 lineStart = i+1;
885                                         }
886                                         break;
887                         }
888                 }
889                 char[] lastLine;
890                 if (lineStart > 0) {
891                         int lastLineLength = length-lineStart;
892                         if (lastLineLength > 0) {
893                                 lastLine = new char[lastLineLength];
894                                 System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
895                                 result.append(lastLine);
896                         }
897                         return result.getContents();
898                 } else {
899                         return text;
900                 }
901         }
902
903         /**
904          * Normalizes the cariage returns in the given text.
905          * They are all changed  to use given buffer's line sepatator.
906          */
907         public static String normalizeCRs(String text, String buffer) {
908                 return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray()));
909         }
910
911         /**
912          * Sort the objects in the given collection using the given sort order.
913          */
914         private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
915                 int original_left = left;
916                 int original_right = right;
917                 int mid = sortOrder[ (left + right) / 2];
918                 do {
919                         while (sortOrder[left] < mid) {
920                                 left++;
921                         }
922                         while (mid < sortOrder[right]) {
923                                 right--;
924                         }
925                         if (left <= right) {
926                                 Object tmp = sortedCollection[left];
927                                 sortedCollection[left] = sortedCollection[right];
928                                 sortedCollection[right] = tmp;
929                                 int tmp2 = sortOrder[left];
930                                 sortOrder[left] = sortOrder[right];
931                                 sortOrder[right] = tmp2;
932                                 left++;
933                                 right--;
934                         }
935                 } while (left <= right);
936                 if (original_left < right) {
937                         quickSort(sortedCollection, original_left, right, sortOrder);
938                 }
939                 if (left < original_right) {
940                         quickSort(sortedCollection, left, original_right, sortOrder);
941                 }
942         }
943
944         /**
945          * Sort the objects in the given collection using the given comparer.
946          */
947         private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
948                 int original_left = left;
949                 int original_right = right;
950                 Object mid = sortedCollection[ (left + right) / 2];
951                 do {
952                         while (comparer.compare(sortedCollection[left], mid) < 0) {
953                                 left++;
954                         }
955                         while (comparer.compare(mid, sortedCollection[right]) < 0) {
956                                 right--;
957                         }
958                         if (left <= right) {
959                                 Object tmp = sortedCollection[left];
960                                 sortedCollection[left] = sortedCollection[right];
961                                 sortedCollection[right] = tmp;
962                                 left++;
963                                 right--;
964                         }
965                 } while (left <= right);
966                 if (original_left < right) {
967                         quickSort(sortedCollection, original_left, right, comparer);
968                 }
969                 if (left < original_right) {
970                         quickSort(sortedCollection, left, original_right, comparer);
971                 }
972         }
973
974         /**
975          * Sort the strings in the given collection.
976          */
977         private static void quickSort(String[] sortedCollection, int left, int right) {
978                 int original_left = left;
979                 int original_right = right;
980                 String mid = sortedCollection[ (left + right) / 2];
981                 do {
982                         while (sortedCollection[left].compareTo(mid) < 0) {
983                                 left++;
984                         }
985                         while (mid.compareTo(sortedCollection[right]) < 0) {
986                                 right--;
987                         }
988                         if (left <= right) {
989                                 String tmp = sortedCollection[left];
990                                 sortedCollection[left] = sortedCollection[right];
991                                 sortedCollection[right] = tmp;
992                                 left++;
993                                 right--;
994                         }
995                 } while (left <= right);
996                 if (original_left < right) {
997                         quickSort(sortedCollection, original_left, right);
998                 }
999                 if (left < original_right) {
1000                         quickSort(sortedCollection, left, original_right);
1001                 }
1002         }
1003
1004         /**
1005          * Converts the given relative path into a package name.
1006          * Returns null if the path is not a valid package name.
1007          */
1008         public static String packageName(IPath pkgPath) {
1009                 StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
1010                 for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
1011                         String segment = pkgPath.segment(j);
1012                         if (!isValidFolderNameForPackage(segment)) {
1013                                 return null;
1014                         }
1015                         pkgName.append(segment);
1016                         if (j < pkgPath.segmentCount() - 1) {
1017                                 pkgName.append("." ); //$NON-NLS-1$
1018                         }
1019                 }
1020                 return pkgName.toString();
1021         }
1022
1023         /**
1024          * Sort the comparable objects in the given collection.
1025          */
1026         private static void quickSort(Comparable[] sortedCollection, int left, int right) {
1027                 int original_left = left;
1028                 int original_right = right;
1029                 Comparable mid = sortedCollection[ (left + right) / 2];
1030                 do {
1031                         while (sortedCollection[left].compareTo(mid) < 0) {
1032                                 left++;
1033                         }
1034                         while (mid.compareTo(sortedCollection[right]) < 0) {
1035                                 right--;
1036                         }
1037                         if (left <= right) {
1038                                 Comparable tmp = sortedCollection[left];
1039                                 sortedCollection[left] = sortedCollection[right];
1040                                 sortedCollection[right] = tmp;
1041                                 left++;
1042                                 right--;
1043                         }
1044                 } while (left <= right);
1045                 if (original_left < right) {
1046                         quickSort(sortedCollection, original_left, right);
1047                 }
1048                 if (left < original_right) {
1049                         quickSort(sortedCollection, left, original_right);
1050                 }
1051         }
1052
1053         /**
1054          * Sort the strings in the given collection in reverse alphabetical order.
1055          */
1056         private static void quickSortReverse(String[] sortedCollection, int left, int right) {
1057                 int original_left = left;
1058                 int original_right = right;
1059                 String mid = sortedCollection[ (left + right) / 2];
1060                 do {
1061                         while (sortedCollection[left].compareTo(mid) > 0) {
1062                                 left++;
1063                         }
1064                         while (mid.compareTo(sortedCollection[right]) > 0) {
1065                                 right--;
1066                         }
1067                         if (left <= right) {
1068                                 String tmp = sortedCollection[left];
1069                                 sortedCollection[left] = sortedCollection[right];
1070                                 sortedCollection[right] = tmp;
1071                                 left++;
1072                                 right--;
1073                         }
1074                 } while (left <= right);
1075                 if (original_left < right) {
1076                         quickSortReverse(sortedCollection, original_left, right);
1077                 }
1078                 if (left < original_right) {
1079                         quickSortReverse(sortedCollection, left, original_right);
1080                 }
1081         }
1082
1083         /**
1084          * Sorts an array of objects in place, using the sort order given for each item.
1085          */
1086         public static void sort(Object[] objects, int[] sortOrder) {
1087                 if (objects.length > 1)
1088                         quickSort(objects, 0, objects.length - 1, sortOrder);
1089         }
1090
1091         /**
1092          * Sorts an array of objects in place.
1093          * The given comparer compares pairs of items.
1094          */
1095         public static void sort(Object[] objects, Comparer comparer) {
1096                 if (objects.length > 1)
1097                         quickSort(objects, 0, objects.length - 1, comparer);
1098         }
1099
1100         /**
1101          * Sorts an array of strings in place using quicksort.
1102          */
1103         public static void sort(String[] strings) {
1104                 if (strings.length > 1)
1105                         quickSort(strings, 0, strings.length - 1);
1106         }
1107
1108         /**
1109          * Sorts an array of Comparable objects in place.
1110          */
1111         public static void sort(Comparable[] objects) {
1112                 if (objects.length > 1)
1113                         quickSort(objects, 0, objects.length - 1);
1114         }
1115
1116         /**
1117          * Sorts an array of Strings, returning a new array
1118          * with the sorted items.  The original array is left untouched.
1119          */
1120         public static Object[] sortCopy(Object[] objects, Comparer comparer) {
1121                 int len = objects.length;
1122                 Object[] copy = new Object[len];
1123                 System.arraycopy(objects, 0, copy, 0, len);
1124                 sort(copy, comparer);
1125                 return copy;
1126         }
1127
1128         /**
1129          * Sorts an array of Strings, returning a new array
1130          * with the sorted items.  The original array is left untouched.
1131          */
1132         public static String[] sortCopy(String[] objects) {
1133                 int len = objects.length;
1134                 String[] copy = new String[len];
1135                 System.arraycopy(objects, 0, copy, 0, len);
1136                 sort(copy);
1137                 return copy;
1138         }
1139
1140         /**
1141          * Sorts an array of Comparable objects, returning a new array
1142          * with the sorted items.  The original array is left untouched.
1143          */
1144         public static Comparable[] sortCopy(Comparable[] objects) {
1145                 int len = objects.length;
1146                 Comparable[] copy = new Comparable[len];
1147                 System.arraycopy(objects, 0, copy, 0, len);
1148                 sort(copy);
1149                 return copy;
1150         }
1151
1152         /**
1153          * Sorts an array of strings in place using quicksort
1154          * in reverse alphabetical order.
1155          */
1156         public static void sortReverseOrder(String[] strings) {
1157                 if (strings.length > 1)
1158                         quickSortReverse(strings, 0, strings.length - 1);
1159         }
1160
1161         /**
1162          * Converts a String[] to char[][].
1163          */
1164         public static char[][] toCharArrays(String[] a) {
1165                 int len = a.length;
1166                 char[][] result = new char[len][];
1167                 for (int i = 0; i < len; ++i) {
1168                         result[i] = toChars(a[i]);
1169                 }
1170                 return result;
1171         }
1172
1173         /**
1174          * Converts a String to char[].
1175          */
1176         public static char[] toChars(String s) {
1177                 int len = s.length();
1178                 char[] chars = new char[len];
1179                 s.getChars(0, len, chars, 0);
1180                 return chars;
1181         }
1182
1183         /**
1184          * Converts a String to char[][], where segments are separate by '.'.
1185          */
1186         public static char[][] toCompoundChars(String s) {
1187                 int len = s.length();
1188                 if (len == 0) {
1189                         return CharOperation.NO_CHAR_CHAR;
1190                 }
1191                 int segCount = 1;
1192                 for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
1193                         ++segCount;
1194                 }
1195                 char[][] segs = new char[segCount][];
1196                 int start = 0;
1197                 for (int i = 0; i < segCount; ++i) {
1198                         int dot = s.indexOf('.', start);
1199                         int end = (dot == -1 ? s.length() : dot);
1200                         segs[i] = new char[end - start];
1201                         s.getChars(start, end, segs[i], 0);
1202                         start = end + 1;
1203                 }
1204                 return segs;
1205         }
1206
1207         /**
1208          * Converts a char[][] to String, where segments are separated by '.'.
1209          */
1210         public static String toString(char[][] c) {
1211                 StringBuffer sb = new StringBuffer();
1212                 for (int i = 0, max = c.length; i < max; ++i) {
1213                         if (i != 0) sb.append('.');
1214                         sb.append(c[i]);
1215                 }
1216                 return sb.toString();
1217         }
1218
1219         /**
1220          * Converts a char[][] and a char[] to String, where segments are separated by '.'.
1221          */
1222         public static String toString(char[][] c, char[] d) {
1223                 if (c == null) return new String(d);
1224                 StringBuffer sb = new StringBuffer();
1225                 for (int i = 0, max = c.length; i < max; ++i) {
1226                         sb.append(c[i]);
1227                         sb.append('.');
1228                 }
1229                 sb.append(d);
1230                 return sb.toString();
1231         }
1232
1233         /**
1234          * Converts a char[] to String.
1235          */
1236         public static String toString(char[] c) {
1237                 return new String(c);
1238         }
1239
1240         /**
1241          * Converts an array of Objects into String.
1242          */
1243         public static String toString(Object[] objects) {
1244                 return toString(objects, 
1245                         new Displayable(){ 
1246                                 public String displayString(Object o) { 
1247                                         if (o == null) return "null"; //$NON-NLS-1$
1248                                         return o.toString(); 
1249                                 }
1250                         });
1251         }
1252
1253         /**
1254          * Converts an array of Objects into String.
1255          */
1256         public static String toString(Object[] objects, Displayable renderer) {
1257                 if (objects == null) return ""; //$NON-NLS-1$
1258                 StringBuffer buffer = new StringBuffer(10);
1259                 for (int i = 0; i < objects.length; i++){
1260                         if (i > 0) buffer.append(", "); //$NON-NLS-1$
1261                         buffer.append(renderer.displayString(objects[i]));
1262                 }
1263                 return buffer.toString();
1264         }
1265         
1266         /**
1267          * Asserts that the given method signature is valid.
1268          */
1269         public static void validateMethodSignature(String sig) {
1270                 Assert.isTrue(isValidMethodSignature(sig));
1271         }
1272
1273         /**
1274          * Asserts that the given type signature is valid.
1275          */
1276         public static void validateTypeSignature(String sig, boolean allowVoid) {
1277                 Assert.isTrue(isValidTypeSignature(sig, allowVoid));
1278         }
1279         public static void verbose(String log) {
1280                 verbose(log, System.out);
1281         }
1282         public static synchronized void verbose(String log, PrintStream printStream) {
1283                 int start = 0;
1284                 do {
1285                         int end = log.indexOf('\n', start);
1286                         printStream.print(Thread.currentThread());
1287                         printStream.print(" "); //$NON-NLS-1$
1288                         printStream.print(log.substring(start, end == -1 ? log.length() : end+1));
1289                         start = end+1;
1290                 } while (start != 0);
1291                 printStream.println();
1292         }
1293         /**
1294          * Creates a NLS catalog for the given locale.
1295          */
1296         public static void relocalize() {
1297                 try {
1298                         bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1299                 } catch(MissingResourceException e) {
1300                         System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
1301                         throw e;
1302                 }
1303         }
1304         
1305         /**
1306          * Put all the arguments in one String.
1307          */
1308         public static String getProblemArgumentsForMarker(String[] arguments){
1309                 StringBuffer args = new StringBuffer(10);
1310                 
1311                 args.append(arguments.length);
1312                 args.append(':');
1313                 
1314                         
1315                 for (int j = 0; j < arguments.length; j++) {
1316                         if(j != 0)
1317                                 args.append(ARGUMENTS_DELIMITER);
1318                         
1319                         if(arguments[j].length() == 0) {
1320                                 args.append(EMPTY_ARGUMENT);
1321                         } else {                        
1322                                 args.append(arguments[j]);
1323                         }
1324                 }
1325                 
1326                 return args.toString();
1327         }
1328         
1329         /**
1330          * Separate all the arguments of a String made by getProblemArgumentsForMarker
1331          */
1332         public static String[] getProblemArgumentsFromMarker(String argumentsString){
1333                 if (argumentsString == null) return null;
1334                 int index = argumentsString.indexOf(':');
1335                 if(index == -1)
1336                         return null;
1337                 
1338                 int length = argumentsString.length();
1339                 int numberOfArg;
1340                 try{
1341                         numberOfArg = Integer.parseInt(argumentsString.substring(0 , index));
1342                 } catch (NumberFormatException e) {
1343                         return null;
1344                 }
1345                 argumentsString = argumentsString.substring(index + 1, length);
1346                 
1347                 String[] args = new String[length];
1348                 int count = 0;
1349                 
1350                 StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
1351                 while(tokenizer.hasMoreTokens()) {
1352                         String argument = tokenizer.nextToken();
1353                         if(argument.equals(EMPTY_ARGUMENT))
1354                                 argument = "";  //$NON-NLS-1$
1355                         args[count++] = argument;
1356                 }
1357                 
1358                 if(count != numberOfArg)
1359                         return null;
1360                 
1361                 System.arraycopy(args, 0, args = new String[count], 0, count);
1362                 return args;
1363         }
1364         
1365 }