Merge from mainline
[official-gcc.git] / libjava / gnu / gcj / tools / gcj_dbtool / Main.java
blobc34aa7bc0a9256a58ca80aa9754789bae7e39faf
1 /* Copyright (C) 2004, 2005, 2006 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
7 details. */
9 package gnu.gcj.tools.gcj_dbtool;
12 import gnu.gcj.runtime.PersistentByteMap;
13 import java.io.*;
14 import java.nio.channels.*;
15 import java.util.*;
16 import java.util.jar.*;
17 import java.security.MessageDigest;
19 public class Main
21 static private boolean verbose = false;
23 public static void main (String[] s)
25 boolean fileListFromStdin = false;
26 char filenameSeparator = ' ';
28 insist (s.length >= 1);
30 if (s[0].equals("-") ||
31 s[0].equals("-0"))
33 if (s[0].equals("-0"))
34 filenameSeparator = (char)0;
35 fileListFromStdin = true;
36 String[] newArgs = new String[s.length - 1];
37 System.arraycopy(s, 1, newArgs, 0, s.length - 1);
38 s = newArgs;
41 if (s[0].equals("-v") || s[0].equals("--version"))
43 insist (s.length == 1);
44 System.out.println("gcj-dbtool ("
45 + System.getProperty("java.vm.name")
46 + ") "
47 + System.getProperty("java.vm.version"));
48 System.out.println();
49 System.out.println("Copyright 2006 Free Software Foundation, Inc.");
50 System.out.println("This is free software; see the source for copying conditions. There is NO");
51 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
52 return;
54 if (s[0].equals("--help"))
56 usage(System.out);
57 return;
60 if (s[0].equals("-n"))
62 // Create a new database.
63 insist (s.length >= 2 && s.length <= 3);
65 int capacity = 32749;
67 if (s.length == 3)
69 capacity = Integer.parseInt(s[2]);
71 if (capacity <= 2)
73 usage(System.err);
74 System.exit(1);
78 try
80 PersistentByteMap b
81 = PersistentByteMap.emptyPersistentByteMap(new File(s[1]),
82 capacity, capacity*32);
84 catch (Exception e)
86 System.err.println ("error: could not create "
87 + s[1] + ": " + e.toString());
88 System.exit(2);
90 return;
93 if (s[0].equals("-a") || s[0].equals("-f"))
95 // Add a jar file to a database, creating it if necessary.
96 // Copies the database, adds the jar file to the copy, and
97 // then renames the new database over the old.
98 try
100 insist (s.length == 4);
101 File database = new File(s[1]);
102 database = database.getAbsoluteFile();
103 File jar = new File(s[2]);
104 PersistentByteMap map;
105 if (database.isFile())
106 map = new PersistentByteMap(database,
107 PersistentByteMap.AccessMode.READ_ONLY);
108 else
109 map = PersistentByteMap.emptyPersistentByteMap(database,
110 100, 100*32);
111 File soFile = new File(s[3]);
112 if (! s[0].equals("-f") && ! soFile.isFile())
113 throw new IllegalArgumentException(s[3] + " is not a file");
114 map = addJar(jar, map, soFile);
116 catch (Exception e)
118 System.err.println ("error: could not update " + s[1]
119 + ": " + e.toString());
120 System.exit(2);
122 return;
125 if (s[0].equals("-t"))
127 // Test
130 insist (s.length == 2);
131 PersistentByteMap b
132 = new PersistentByteMap(new File(s[1]),
133 PersistentByteMap.AccessMode.READ_ONLY);
134 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
136 while (iterator.hasNext())
138 PersistentByteMap.MapEntry entry
139 = (PersistentByteMap.MapEntry)iterator.next();
140 byte[] key = (byte[])entry.getKey();
141 byte[] value = (byte[])b.get(key);
142 if (! Arrays.equals (value, (byte[])entry.getValue()))
144 String err
145 = ("Key " + bytesToString(key) + " at bucket "
146 + entry.getBucket());
148 throw new RuntimeException(err);
152 catch (Exception e)
154 e.printStackTrace();
155 System.exit(3);
157 return;
160 if (s[0].equals("-m"))
162 // Merge databases.
163 insist (s.length >= 3
164 || fileListFromStdin && s.length == 2);
167 File database = new File(s[1]);
168 database = database.getAbsoluteFile();
169 File temp = File.createTempFile(database.getName(), "",
170 database.getParentFile());
172 int newSize = 0;
173 int newStringTableSize = 0;
174 Fileset files = getFiles(s, 2, fileListFromStdin,
175 filenameSeparator);
176 PersistentByteMap[] sourceMaps
177 = new PersistentByteMap[files.size()];
179 // Scan all the input files, calculating worst case string
180 // table and hash table use.
182 Iterator it = files.iterator();
183 int i = 0;
184 while (it.hasNext())
186 PersistentByteMap b
187 = new PersistentByteMap((File)it.next(),
188 PersistentByteMap.AccessMode.READ_ONLY);
189 newSize += b.size();
190 newStringTableSize += b.stringTableSize();
191 sourceMaps[i++] = b;
195 newSize *= 1.5; // Scaling the new size by 1.5 results in
196 // fewer collisions.
197 PersistentByteMap map
198 = PersistentByteMap.emptyPersistentByteMap
199 (temp, newSize, newStringTableSize);
201 for (int i = 0; i < sourceMaps.length; i++)
203 if (verbose)
204 System.err.println("adding " + sourceMaps[i].size()
205 + " elements from "
206 + sourceMaps[i].getFile());
207 map.putAll(sourceMaps[i]);
209 map.close();
210 temp.renameTo(database);
212 catch (Exception e)
214 e.printStackTrace();
215 System.exit(3);
217 return;
220 if (s[0].equals("-l"))
222 // List a database.
223 insist (s.length == 2);
226 PersistentByteMap b
227 = new PersistentByteMap(new File(s[1]),
228 PersistentByteMap.AccessMode.READ_ONLY);
230 System.out.println ("Capacity: " + b.capacity());
231 System.out.println ("Size: " + b.size());
232 System.out.println ();
234 System.out.println ("Elements: ");
235 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
237 while (iterator.hasNext())
239 PersistentByteMap.MapEntry entry
240 = (PersistentByteMap.MapEntry)iterator.next();
241 byte[] digest = (byte[])entry.getKey();
242 System.out.print ("[" + entry.getBucket() + "] "
243 + bytesToString(digest)
244 + " -> ");
245 System.out.println (new String((byte[])entry.getValue()));
248 catch (Exception e)
250 System.err.println ("error: could not list "
251 + s[1] + ": " + e.toString());
252 System.exit(2);
254 return;
257 if (s[0].equals("-d"))
259 // For testing only: fill the byte map with random data.
260 insist (s.length == 2);
263 MessageDigest md = MessageDigest.getInstance("MD5");
264 PersistentByteMap b
265 = new PersistentByteMap(new File(s[1]),
266 PersistentByteMap.AccessMode.READ_WRITE);
267 int N = b.capacity();
268 byte[] bytes = new byte[1];
269 byte digest[] = md.digest(bytes);
270 for (int i = 0; i < N; i++)
272 digest = md.digest(digest);
273 b.put(digest, digest);
276 catch (Exception e)
278 e.printStackTrace();
279 System.exit(3);
281 return;
284 if (s[0].equals("-p"))
286 insist (s.length == 1 || s.length == 2);
287 String result;
289 if (s.length == 1)
290 result = System.getProperty("gnu.gcj.precompiled.db.path", "");
291 else
292 result = (s[1]
293 + (s[1].endsWith(File.separator) ? "" : File.separator)
294 + getDbPathTail ());
296 System.out.println (result);
297 return;
300 usage(System.err);
301 System.exit(1);
304 private static native String getDbPathTail ();
306 private static void insist(boolean ok)
308 if (! ok)
310 usage(System.err);
311 System.exit(1);
315 private static void usage(PrintStream out)
317 out.println
318 ("gcj-dbtool: Manipulate gcj map database files\n"
319 + "\n"
320 + " Usage: \n"
321 + " gcj-dbtool -n file.gcjdb [size] - Create a new gcj map database\n"
322 + " gcj-dbtool -a file.gcjdb file.jar file.so\n"
323 + " - Add the contents of file.jar to a gcj map database\n"
324 + " gcj-dbtool -f file.gcjdb file.jar file.so\n"
325 + " - Add the contents of file.jar to a gcj map database\n"
326 + " gcj-dbtool -t file.gcjdb - Test a gcj map database\n"
327 + " gcj-dbtool -l file.gcjdb - List a gcj map database\n"
328 + " gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
329 + " - Merge gcj map databases into dest\n"
330 + " Replaces dest\n"
331 + " To add to dest, include dest in the list of sources\n"
332 + " If the first arg is -, read the list from stdin\n"
333 + " If the first arg is -0, filenames separated by nul\n"
334 + " gcj-dbtool -p [LIBDIR] - Print default database name"
338 // Add a jar to a map. This copies the map first and returns a
339 // different map that contains the data. The original map is
340 // closed.
342 private static PersistentByteMap
343 addJar(File f, PersistentByteMap b, File soFile)
344 throws Exception
346 MessageDigest md = MessageDigest.getInstance("MD5");
348 JarFile jar = new JarFile (f);
350 int count = 0;
352 Enumeration entries = jar.entries();
353 while (entries.hasMoreElements())
355 JarEntry classfile = (JarEntry)entries.nextElement();
356 if (classfile.getName().endsWith(".class"))
357 count++;
361 if (verbose)
362 System.err.println("adding " + count + " elements from "
363 + f + " to " + b.getFile());
365 // Maybe resize the destination map. We're allowing plenty of
366 // extra space by using a loadFactor of 2.
367 b = resizeMap(b, (b.size() + count) * 2, true);
369 Enumeration entries = jar.entries();
371 byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
372 while (entries.hasMoreElements())
374 JarEntry classfile = (JarEntry)entries.nextElement();
375 if (classfile.getName().endsWith(".class"))
377 InputStream str = jar.getInputStream(classfile);
378 int length = (int) classfile.getSize();
379 if (length == -1)
380 throw new EOFException();
382 byte[] data = new byte[length];
383 int pos = 0;
384 while (length - pos > 0)
386 int len = str.read(data, pos, length - pos);
387 if (len == -1)
388 throw new EOFException("Not enough data reading from: "
389 + classfile.getName());
390 pos += len;
392 b.put(md.digest(data), soFileName);
395 return b;
398 // Resize a map by creating a new one with the same data and
399 // renaming it. If close is true, close the original map.
401 static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
402 throws IOException, IllegalAccessException
404 newCapacity = Math.max(m.capacity(), newCapacity);
405 File name = m.getFile();
406 File copy = File.createTempFile(name.getName(), "", name.getParentFile());
409 PersistentByteMap dest
410 = PersistentByteMap.emptyPersistentByteMap
411 (copy, newCapacity, newCapacity*32);
412 dest.putAll(m);
413 dest.force();
414 if (close)
415 m.close();
416 copy.renameTo(name);
417 return dest;
419 catch (Exception e)
421 copy.delete();
423 return null;
427 static String bytesToString(byte[] b)
429 StringBuffer hexBytes = new StringBuffer();
430 int length = b.length;
431 for (int i = 0; i < length; ++i)
432 hexBytes.append(Integer.toHexString(b[i] & 0xff));
433 return hexBytes.toString();
437 // Return a Fileset, either from a String array or from System.in,
438 // depending on fileListFromStdin.
439 private static final Fileset getFiles(String[] s, int startPos,
440 boolean fileListFromStdin,
441 char separator)
443 if (fileListFromStdin)
444 return new Fileset(System.in, separator);
445 else
446 return new Fileset(s, startPos, s.length);
450 // Parse a stream into tokens. The separator can be any char, and
451 // space is equivalent to any whitepace character.
452 class Tokenizer
454 final Reader r;
455 final char separator;
457 Tokenizer(Reader r, char separator)
459 this.r = r;
460 this.separator = separator;
463 boolean isSeparator(int c)
465 if (Character.isWhitespace(separator))
466 return Character.isWhitespace((char)c);
467 else
468 return c == separator;
471 // Parse a token from the input stream. Return the empty string
472 // when the stream is exhausted.
473 String nextToken ()
475 StringBuffer buf = new StringBuffer();
476 int c;
479 while ((c = r.read()) != -1)
481 if (! isSeparator(c))
483 buf.append((char)c);
484 break;
487 while ((c = r.read()) != -1)
489 if (isSeparator(c))
490 break;
491 else
492 buf.append((char)c);
495 catch (java.io.IOException e)
498 return buf.toString();
502 // A Fileset is a container for a set of files; it can be created
503 // either from a string array or from an input stream, given a
504 // separator character.
505 class Fileset
507 LinkedHashSet files = new LinkedHashSet();
509 Fileset (String[] s, int start, int end)
511 for (int i = start; i < end; i++)
513 files.add(new File(s[i]));
517 Fileset (InputStream is, char separator)
519 Reader r = new BufferedReader(new InputStreamReader(is));
520 Tokenizer st = new Tokenizer(r, separator);
521 String name;
522 while (! "".equals(name = st.nextToken()))
523 files.add(new File(name));
526 Iterator iterator()
528 return files.iterator();
531 int size()
533 return files.size();