OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved |
| 2 * |
| 3 * This program is distributed under the terms of |
| 4 * the GNU General Public License Version 2. See the LICENSE file |
| 5 * at the top of the source tree. |
| 6 */ |
| 7 package org.pantsbuild.jmake; |
| 8 |
| 9 import java.io.File; |
| 10 import java.io.FileInputStream; |
| 11 import java.io.IOException; |
| 12 import java.io.InputStream; |
| 13 import java.io.OutputStream; |
| 14 import java.io.PrintStream; |
| 15 import java.util.zip.ZipEntry; |
| 16 import java.util.zip.ZipFile; |
| 17 |
| 18 /** |
| 19 * Utility functions used by other classes from this package. |
| 20 * |
| 21 * @author Misha Dmitriev |
| 22 * 23 January 2003 |
| 23 */ |
| 24 public class Utils { |
| 25 |
| 26 static final String REPORT_PROBLEM = |
| 27 "Please report this problem to Mikhail.Dmitriev@sun.com"; |
| 28 static final byte[] MAGIC = {'J', 'a', 'v', 'a', 'm', 'a', 'k', 'e', ' ', 'P
', 'r', 'o', 'j', 'e', 'c', 't', ' ', 'D', 'a', 't', 'a', 'b', 'a', 's', 'e', '
', 'F', 'i', 'l', 'e'}; |
| 29 static final int magicLength = MAGIC.length; |
| 30 static final int PDB_FORMAT_CODE_OLD = 1; |
| 31 static final int PDB_FORMAT_CODE_133 = 0x01030300; |
| 32 static final int PDB_FORMAT_CODE_LATEST = PDB_FORMAT_CODE_133; |
| 33 static final int JAVAC_TARGET_RELEASE_OLDEST = 0x01040000; // 1.4 and previ
ous versions |
| 34 static final int JAVAC_TARGET_RELEASE_15 = 0x01050000; // if class is compi
led with -target 1.5 |
| 35 static final int JAVAC_TARGET_RELEASE_16 = 0x01060000; // if class is compi
led with -target 1.6 |
| 36 static final int JAVAC_TARGET_RELEASE_17 = 0x01070000; // if class is compi
led with -target 1.7 |
| 37 static final int JAVAC_TARGET_RELEASE_18 = 0x01080000; // if class is compi
led with -target 1.8 |
| 38 static int warningLimit = 20; // Maximum number of warnings to print |
| 39 static final int TIMING_TOTAL = 0; |
| 40 static final int TIMING_PDBREAD = 1; |
| 41 static final int TIMING_SYNCHRO = 2; |
| 42 static final int TIMING_SYNCHRO_CHECK_JAVA_FILES = 3; |
| 43 static final int TIMING_FIND_UPDATED_JAVA_FILES = 4; |
| 44 static final int TIMING_CLASS_FILE_OBSOLETE_OR_DELETED = 5; |
| 45 static final int TIMING_COMPILE = 6; |
| 46 static final int TIMING_FIND_UPDATED_CLASSES = 7; |
| 47 static final int TIMING_CHECK_UPDATED_CLASSES = 8; |
| 48 static final int TIMING_PDBWRITE = 9; |
| 49 static final int TIMING_SYNCHRO_CHECK_TMP = 10; |
| 50 static final int TIMING_CLASS_FILE_OBSOLETE_TMP = 11; |
| 51 static final int TIMING_PDBUPDATE = 12; |
| 52 static final int TIMING_ARRAY_LENGTH = 13; |
| 53 private static long timings[] = new long[TIMING_ARRAY_LENGTH]; |
| 54 private static boolean timingOn = false; |
| 55 |
| 56 |
| 57 // -------------------------------------------------------------------------
------ |
| 58 // Name manipulation stuff |
| 59 // -------------------------------------------------------------------------
------ |
| 60 /** |
| 61 * Returns package name for the given class. In case of no package, returns
an |
| 62 * empty, but non-null string. Returned string is interned. |
| 63 */ |
| 64 public static String getPackageName(String clazzName) { |
| 65 int ldi = clazzName.lastIndexOf('/'); // For convenience, we use system
-internal slashes, not dots |
| 66 if (ldi == -1) { |
| 67 return ""; |
| 68 } else { |
| 69 return clazzName.substring(0, ldi).intern(); |
| 70 } |
| 71 } |
| 72 |
| 73 /** |
| 74 * Returns directly enclosing class name for the given class. If the given c
lass is not a |
| 75 * nested class, returns empty, but non-null string. Returned string is inte
rned. |
| 76 * NOTE FOR JDK 1.5: this function has to work with both old (1.4 and before
) and new (1.5) ways |
| 77 * of naming non-member classes. javacTargetRelease determines the javac ver
sion for this class; |
| 78 * however on rare occasions (when checking a deleted non-project class) it
may be 0, denoting |
| 79 * that javac version is not known. |
| 80 * In that case, we use the old algorithm, which is error-prone due to a bug
in nested class |
| 81 * naming that existed prior to JDK 1.5, where both a non-member local neste
d class B of A, and a |
| 82 * member nested class B of anonymous class A$1, are named A$1$B. |
| 83 */ |
| 84 public static String getDirectlyEnclosingClass(String clazzName, int javacTa
rgetRelease) { |
| 85 int ldi = clazzName.lastIndexOf('$'); |
| 86 if (ldi == -1) { |
| 87 return ""; |
| 88 } |
| 89 |
| 90 if (javacTargetRelease >= JAVAC_TARGET_RELEASE_15) { |
| 91 return clazzName.substring(0, ldi).intern(); |
| 92 } else { // JAVAC_TARGET_RELEASE_OLDEST or unknown |
| 93 // Take into account local classes which are named like "EncClass$1$
LocalClass", where EncClass |
| 94 // is directly enclosing class. |
| 95 int lldi = clazzName.lastIndexOf('$', ldi - 1); |
| 96 if (lldi == -1 || !Character.isDigit(clazzName.charAt(lldi + 1))) { |
| 97 return clazzName.substring(0, ldi).intern(); |
| 98 } else { |
| 99 return clazzName.substring(0, lldi).intern(); |
| 100 } |
| 101 } |
| 102 } |
| 103 |
| 104 /** |
| 105 * Returns top-level enclosing class name for the given class. If the given
class is not a |
| 106 * nested class, returns empty, but non-null string. Returned string is inte
rned. |
| 107 */ |
| 108 public static String getTopLevelEnclosingClass(String clazzName) { |
| 109 int fdi = clazzName.indexOf('$'); |
| 110 if (fdi == -1) { |
| 111 return ""; |
| 112 } |
| 113 |
| 114 return clazzName.substring(0, fdi).intern(); |
| 115 } |
| 116 |
| 117 /** |
| 118 * Given the full path for the enclosing class file and the full name for th
e nested class, return the supposed |
| 119 * full path for the nested class. |
| 120 */ |
| 121 public static String getClassFileFullPathForNestedClass(String enclosingClas
sFileFullPath, String nestedClassFullName) { |
| 122 String enclosingClassDir = enclosingClassFileFullPath; |
| 123 int cutIndex = enclosingClassDir.lastIndexOf(File.separatorChar); |
| 124 enclosingClassDir = enclosingClassDir.substring(0, cutIndex + 1); // If
slash is present, it's included, otherwise we get "" |
| 125 cutIndex = nestedClassFullName.lastIndexOf('/'); |
| 126 String nestedClassLocalName; |
| 127 if (cutIndex < 0) { |
| 128 nestedClassLocalName = nestedClassFullName; |
| 129 } else { |
| 130 nestedClassLocalName = nestedClassFullName.substring(cutIndex + 1); |
| 131 } |
| 132 return enclosingClassDir + nestedClassLocalName + ".class"; |
| 133 } |
| 134 |
| 135 /** |
| 136 * For two strings representing signatures, check if the number of parameter
s in |
| 137 * both is the same. |
| 138 */ |
| 139 public static boolean sameParamNumber(String sig1, String sig2) { |
| 140 return getParamNumber(sig1) == getParamNumber(sig2); |
| 141 } |
| 142 |
| 143 private static int getParamNumber(String sig) { |
| 144 char ch; |
| 145 int parNo = 0, pos = 0; |
| 146 do { |
| 147 ch = sig.charAt(++pos); |
| 148 if (ch == ')') { |
| 149 break; |
| 150 } |
| 151 while (ch == '[') { |
| 152 ch = sig.charAt(++pos); |
| 153 } |
| 154 parNo++; |
| 155 if (ch == '@') { |
| 156 // We replaced all "Lclassname;" in signatures with "@classname#
" |
| 157 while (ch != '#') { |
| 158 ch = sig.charAt(++pos); |
| 159 } |
| 160 } |
| 161 } while (ch != ')'); |
| 162 return parNo; |
| 163 } |
| 164 |
| 165 |
| 166 // -------------------------------------------------------------------------
------ |
| 167 // File related stuff |
| 168 // -------------------------------------------------------------------------
------ |
| 169 public static File checkFileForName(String name) { |
| 170 // For each .java file, a File object is created two times when jmake ex
ecutes: first when we synchronise the PCD |
| 171 // and the supplied .java file list (we make sure that the .java file ex
ists), and second time when we check if a class |
| 172 // file was updated (we compare time stamps of the .java and the .class
file). I tried to call this routine for a .java |
| 173 // class both times, and cached File objects, but it looks as if this do
es not bring any real speed-up (and in fact may |
| 174 // even slow down the application). Most of the time seems to go to the
underlying code creating internal File |
| 175 // representation; once it is created, it takes little time to execute a
nother "new File()" for it. Also, all operations |
| 176 // on files like getCanonicalPath() or lastModified() seem to be quite e
xpensive, so their unnecessary repetition should |
| 177 // be avoided as much as possible. |
| 178 if (name == null) { |
| 179 return null; |
| 180 } |
| 181 File file = new File(name); |
| 182 if (file.exists()) { |
| 183 return file; |
| 184 } |
| 185 return null; |
| 186 } |
| 187 |
| 188 public static File checkOrCreateDirForName(String name) { |
| 189 File file = new File(name); |
| 190 if (!file.exists()) { |
| 191 file.mkdirs(); |
| 192 } |
| 193 if (file.exists()) { |
| 194 if (!file.isDirectory()) { |
| 195 throw new PrivateException(new PublicExceptions.InternalExceptio
n(file + " is not a directory.")); |
| 196 } |
| 197 return file; |
| 198 } |
| 199 return null; |
| 200 } |
| 201 |
| 202 public static byte[] readFileIntoBuffer(File file) { |
| 203 try { |
| 204 InputStream in = new FileInputStream(file); |
| 205 int len = (int) file.length(); |
| 206 return readInputStreamIntoBuffer(in, len); |
| 207 } catch (IOException e) { |
| 208 throw new PrivateException(e); |
| 209 } |
| 210 } |
| 211 |
| 212 public static byte[] readZipEntryIntoBuffer(ZipFile file, ZipEntry entry) { |
| 213 try { |
| 214 InputStream in = file.getInputStream(entry); |
| 215 int len = (int) entry.getSize(); |
| 216 return Utils.readInputStreamIntoBuffer(in, len); |
| 217 } catch (IOException e) { |
| 218 throw new PrivateException(e); |
| 219 } |
| 220 } |
| 221 |
| 222 public static byte[] readInputStreamIntoBuffer(InputStream in, int len) thro
ws IOException { |
| 223 byte buf[] = new byte[len]; |
| 224 int readBytes, ofs = 0, remBytes = len; |
| 225 do { |
| 226 readBytes = in.read(buf, ofs, remBytes); |
| 227 ofs += readBytes; |
| 228 remBytes -= readBytes; |
| 229 } while (ofs < len); |
| 230 in.close(); |
| 231 return buf; |
| 232 } |
| 233 |
| 234 public static void readAndPrintBytesFromStream(InputStream in, OutputStream
out) throws IOException { |
| 235 int avail = in.available(); |
| 236 if (avail > 0) { |
| 237 byte outbytes[] = new byte[avail]; |
| 238 int realOutBytes = in.read(outbytes); |
| 239 out.write(outbytes, 0, realOutBytes); |
| 240 } |
| 241 } |
| 242 |
| 243 /** For a Windows path, convert the drive letter to the lower case */ |
| 244 public static String convertDriveLetterToLowerCase(String path) { |
| 245 if (path.charAt(1) != ':') { |
| 246 return path; |
| 247 } |
| 248 char drive = path.charAt(0); |
| 249 if (Character.isUpperCase(drive)) { |
| 250 drive = Character.toLowerCase(drive); |
| 251 char[] chars = path.toCharArray(); |
| 252 chars[0] = drive; |
| 253 path = new String(chars); |
| 254 } |
| 255 return path; |
| 256 } |
| 257 |
| 258 public static void ignore(Exception e) { |
| 259 // Ignore this exception |
| 260 } |
| 261 |
| 262 /** Used when invoking a third-party executable compiler app */ |
| 263 public static void delay(int ms) { |
| 264 Object o = new Object(); |
| 265 synchronized (o) { |
| 266 try { |
| 267 o.wait(ms); |
| 268 } catch (InterruptedException e) { |
| 269 } |
| 270 } |
| 271 } |
| 272 // -------------------------------------------------------------------------
------ |
| 273 // Custom printing stuff |
| 274 // -------------------------------------------------------------------------
------ |
| 275 private static PrintStream out = System.out; |
| 276 private static PrintStream warn = System.out; |
| 277 private static PrintStream err = System.err; |
| 278 private static boolean printInfoMessages = true; |
| 279 private static boolean printWarningMessages = true; |
| 280 private static boolean printErrorMessages = true; |
| 281 private static int warningNo; |
| 282 |
| 283 public static void setOutputStreams(PrintStream out, PrintStream warn, Print
Stream err) { |
| 284 Utils.out = out; |
| 285 Utils.warn = warn; |
| 286 Utils.err = err; |
| 287 } |
| 288 |
| 289 public static void customizeOutput(boolean printInfoMessages, boolean printW
arningMessages, boolean printErrorMessages) { |
| 290 Utils.printInfoMessages = printInfoMessages; |
| 291 Utils.printWarningMessages = printWarningMessages; |
| 292 Utils.printErrorMessages = printErrorMessages; |
| 293 } |
| 294 |
| 295 public static void printInfoMessage(String message) { |
| 296 if (printInfoMessages) { |
| 297 out.println(message); |
| 298 } |
| 299 } |
| 300 |
| 301 public static void printInfoMessageNoEOL(String message) { |
| 302 if (printInfoMessages) { |
| 303 out.print(message); |
| 304 } |
| 305 } |
| 306 |
| 307 public static void printWarningMessage(String message) { |
| 308 if (!printWarningMessages) { |
| 309 return; |
| 310 } |
| 311 if (warningNo < warningLimit) { |
| 312 warn.println(message); |
| 313 } else if (warningNo == warningLimit) { |
| 314 warn.println("jmake: more than " + warningLimit + " warnings."); |
| 315 } |
| 316 warningNo++; |
| 317 } |
| 318 |
| 319 public static void printErrorMessage(String message) { |
| 320 if (printErrorMessages) { |
| 321 err.println("jmake: " + message); |
| 322 } |
| 323 } |
| 324 |
| 325 // -------------------------------------------------------------------------
------ |
| 326 // Measuring stuff |
| 327 // -------------------------------------------------------------------------
------ |
| 328 public static void setTimingOn() { |
| 329 timingOn = true; |
| 330 } |
| 331 |
| 332 public static void startTiming(int slot) { |
| 333 timings[slot] = System.currentTimeMillis(); |
| 334 } |
| 335 |
| 336 public static void stopAndPrintTiming(String message, int slot) { |
| 337 if (timingOn) { |
| 338 long time = System.currentTimeMillis() - timings[slot]; |
| 339 printInfoMessage("========== " + message + " time = " + time); |
| 340 } |
| 341 } |
| 342 |
| 343 public static void printTiming(String message, int slot) { |
| 344 if (timingOn) { |
| 345 printInfoMessage("========== " + message + " time = " + timings[slot
]); |
| 346 } |
| 347 } |
| 348 |
| 349 public static void stopAndAddTiming(int slot1, int slot2) { |
| 350 if (timingOn) { |
| 351 long time = System.currentTimeMillis() - timings[slot1]; |
| 352 timings[slot2] += time; |
| 353 } |
| 354 } |
| 355 } |
OLD | NEW |