aboutsummaryrefslogtreecommitdiff
path: root/libjava/gnu/gcj/tools/gcj_dbtool/Main.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/gnu/gcj/tools/gcj_dbtool/Main.java')
-rw-r--r--libjava/gnu/gcj/tools/gcj_dbtool/Main.java535
1 files changed, 535 insertions, 0 deletions
diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/Main.java b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java
new file mode 100644
index 00000000000..f16a86a3698
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java
@@ -0,0 +1,535 @@
+/* Copyright (C) 2004, 2005 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.tools.gcj_dbtool;
+
+
+import gnu.gcj.runtime.PersistentByteMap;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.util.jar.*;
+import java.security.MessageDigest;
+
+public class Main
+{
+ static private boolean verbose = false;
+
+ public static void main (String[] s)
+ {
+ boolean fileListFromStdin = false;
+ char filenameSeparator = ' ';
+
+ insist (s.length >= 1);
+
+ if (s[0].equals("-") ||
+ s[0].equals("-0"))
+ {
+ if (s[0].equals("-0"))
+ filenameSeparator = (char)0;
+ fileListFromStdin = true;
+ String[] newArgs = new String[s.length - 1];
+ System.arraycopy(s, 1, newArgs, 0, s.length - 1);
+ s = newArgs;
+ }
+
+ if (s[0].equals("-v") || s[0].equals("--version"))
+ {
+ insist (s.length == 1);
+ System.out.println("gcj-dbtool ("
+ + System.getProperty("java.vm.name")
+ + ") "
+ + System.getProperty("java.vm.version"));
+ System.out.println();
+ System.out.println("Copyright 2005 Free Software Foundation, Inc.");
+ System.out.println("This is free software; see the source for copying conditions. There is NO");
+ System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
+ return;
+ }
+ if (s[0].equals("--help"))
+ {
+ usage(System.out);
+ return;
+ }
+
+ if (s[0].equals("-n"))
+ {
+ // Create a new database.
+ insist (s.length >= 2 && s.length <= 3);
+
+ int capacity = 32749;
+
+ if (s.length == 3)
+ {
+ capacity = Integer.parseInt(s[2]);
+
+ if (capacity <= 2)
+ {
+ usage(System.err);
+ System.exit(1);
+ }
+ }
+
+ try
+ {
+ PersistentByteMap b
+ = PersistentByteMap.emptyPersistentByteMap(new File(s[1]),
+ capacity, capacity*32);
+ }
+ catch (Exception e)
+ {
+ System.err.println ("error: could not create "
+ + s[1] + ": " + e.toString());
+ System.exit(2);
+ }
+ return;
+ }
+
+ if (s[0].equals("-a") || s[0].equals("-f"))
+ {
+ // Add a jar file to a database, creating it if necessary.
+ // Copies the database, adds the jar file to the copy, and
+ // then renames the new database over the old.
+ try
+ {
+ insist (s.length == 4);
+ File database = new File(s[1]);
+ database = database.getAbsoluteFile();
+ File jar = new File(s[2]);
+ PersistentByteMap map;
+ if (database.isFile())
+ map = new PersistentByteMap(database,
+ PersistentByteMap.AccessMode.READ_ONLY);
+ else
+ map = PersistentByteMap.emptyPersistentByteMap(database,
+ 100, 100*32);
+ File soFile = new File(s[3]);
+ if (! s[0].equals("-f") && ! soFile.isFile())
+ throw new IllegalArgumentException(s[3] + " is not a file");
+ map = addJar(jar, map, soFile);
+ }
+ catch (Exception e)
+ {
+ System.err.println ("error: could not update " + s[1]
+ + ": " + e.toString());
+ System.exit(2);
+ }
+ return;
+ }
+
+ if (s[0].equals("-t"))
+ {
+ // Test
+ try
+ {
+ insist (s.length == 2);
+ PersistentByteMap b
+ = new PersistentByteMap(new File(s[1]),
+ PersistentByteMap.AccessMode.READ_ONLY);
+ Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
+
+ while (iterator.hasNext())
+ {
+ PersistentByteMap.MapEntry entry
+ = (PersistentByteMap.MapEntry)iterator.next();
+ byte[] key = (byte[])entry.getKey();
+ byte[] value = (byte[])b.get(key);
+ if (! Arrays.equals (value, (byte[])entry.getValue()))
+ {
+ String err
+ = ("Key " + bytesToString(key) + " at bucket "
+ + entry.getBucket());
+
+ throw new RuntimeException(err);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(3);
+ }
+ return;
+ }
+
+ if (s[0].equals("-m"))
+ {
+ // Merge databases.
+ insist (s.length >= 3
+ || fileListFromStdin && s.length == 2);
+ try
+ {
+ File database = new File(s[1]);
+ database = database.getAbsoluteFile();
+ File temp = File.createTempFile(database.getName(), "",
+ database.getParentFile());
+
+ int newSize = 0;
+ int newStringTableSize = 0;
+ Fileset files = getFiles(s, 2, fileListFromStdin,
+ filenameSeparator);
+ PersistentByteMap[] sourceMaps
+ = new PersistentByteMap[files.size()];
+
+ // Scan all the input files, calculating worst case string
+ // table and hash table use.
+ {
+ Iterator it = files.iterator();
+ int i = 0;
+ while (it.hasNext())
+ {
+ PersistentByteMap b
+ = new PersistentByteMap((File)it.next(),
+ PersistentByteMap.AccessMode.READ_ONLY);
+ newSize += b.size();
+ newStringTableSize += b.stringTableSize();
+ sourceMaps[i++] = b;
+ }
+ }
+
+ newSize *= 1.5; // Scaling the new size by 1.5 results in
+ // fewer collisions.
+ PersistentByteMap map
+ = PersistentByteMap.emptyPersistentByteMap
+ (temp, newSize, newStringTableSize);
+
+ for (int i = 0; i < sourceMaps.length; i++)
+ {
+ if (verbose)
+ System.err.println("adding " + sourceMaps[i].size()
+ + " elements from "
+ + sourceMaps[i].getFile());
+ map.putAll(sourceMaps[i]);
+ }
+ map.close();
+ temp.renameTo(database);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(3);
+ }
+ return;
+ }
+
+ if (s[0].equals("-l"))
+ {
+ // List a database.
+ insist (s.length == 2);
+ try
+ {
+ PersistentByteMap b
+ = new PersistentByteMap(new File(s[1]),
+ PersistentByteMap.AccessMode.READ_ONLY);
+
+ System.out.println ("Capacity: " + b.capacity());
+ System.out.println ("Size: " + b.size());
+ System.out.println ();
+
+ System.out.println ("Elements: ");
+ Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
+
+ while (iterator.hasNext())
+ {
+ PersistentByteMap.MapEntry entry
+ = (PersistentByteMap.MapEntry)iterator.next();
+ byte[] digest = (byte[])entry.getKey();
+ System.out.print ("[" + entry.getBucket() + "] "
+ + bytesToString(digest)
+ + " -> ");
+ System.out.println (new String((byte[])entry.getValue()));
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println ("error: could not list "
+ + s[1] + ": " + e.toString());
+ System.exit(2);
+ }
+ return;
+ }
+
+ if (s[0].equals("-d"))
+ {
+ // For testing only: fill the byte map with random data.
+ insist (s.length == 2);
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ PersistentByteMap b
+ = new PersistentByteMap(new File(s[1]),
+ PersistentByteMap.AccessMode.READ_WRITE);
+ int N = b.capacity();
+ byte[] bytes = new byte[1];
+ byte digest[] = md.digest(bytes);
+ for (int i = 0; i < N; i++)
+ {
+ digest = md.digest(digest);
+ b.put(digest, digest);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(3);
+ }
+ return;
+ }
+
+ if (s[0].equals("-p"))
+ {
+ insist (s.length == 1 || s.length == 2);
+ String result;
+
+ if (s.length == 1)
+ result = System.getProperty("gnu.gcj.precompiled.db.path", "");
+ else
+ result = (s[1]
+ + (s[1].endsWith(File.separator) ? "" : File.separator)
+ + getDbPathTail ());
+
+ System.out.println (result);
+ return;
+ }
+
+ usage(System.err);
+ System.exit(1);
+ }
+
+ private static native String getDbPathTail ();
+
+ private static void insist(boolean ok)
+ {
+ if (! ok)
+ {
+ usage(System.err);
+ System.exit(1);
+ }
+ }
+
+ private static void usage(PrintStream out)
+ {
+ out.println
+ ("gcj-dbtool: Manipulate gcj map database files\n"
+ + "\n"
+ + " Usage: \n"
+ + " gcj-dbtool -n file.gcjdb [size] - Create a new gcj map database\n"
+ + " gcj-dbtool -a file.gcjdb file.jar file.so\n"
+ + " - Add the contents of file.jar to a gcj map database\n"
+ + " gcj-dbtool -f file.gcjdb file.jar file.so\n"
+ + " - Add the contents of file.jar to a gcj map database\n"
+ + " gcj-dbtool -t file.gcjdb - Test a gcj map database\n"
+ + " gcj-dbtool -l file.gcjdb - List a gcj map database\n"
+ + " gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
+ + " - Merge gcj map databases into dest\n"
+ + " Replaces dest\n"
+ + " To add to dest, include dest in the list of sources\n"
+ + " If the first arg is -, read the list from stdin\n"
+ + " If the first arg is -0, filenames separated by nul\n"
+ + " gcj-dbtool -p [LIBDIR] - Print default database name"
+ );
+ }
+
+ // Add a jar to a map. This copies the map first and returns a
+ // different map that contains the data. The original map is
+ // closed.
+
+ private static PersistentByteMap
+ addJar(File f, PersistentByteMap b, File soFile)
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ JarFile jar = new JarFile (f);
+
+ int count = 0;
+ {
+ Enumeration entries = jar.entries();
+ while (entries.hasMoreElements())
+ {
+ JarEntry classfile = (JarEntry)entries.nextElement();
+ if (classfile.getName().endsWith(".class"))
+ count++;
+ }
+ }
+
+ if (verbose)
+ System.err.println("adding " + count + " elements from "
+ + f + " to " + b.getFile());
+
+ // Maybe resize the destination map. We're allowing plenty of
+ // extra space by using a loadFactor of 2.
+ b = resizeMap(b, (b.size() + count) * 2, true);
+
+ Enumeration entries = jar.entries();
+
+ byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
+ while (entries.hasMoreElements())
+ {
+ JarEntry classfile = (JarEntry)entries.nextElement();
+ if (classfile.getName().endsWith(".class"))
+ {
+ InputStream str = jar.getInputStream(classfile);
+ int length = (int) classfile.getSize();
+ if (length == -1)
+ throw new EOFException();
+
+ byte[] data = new byte[length];
+ int pos = 0;
+ while (length - pos > 0)
+ {
+ int len = str.read(data, pos, length - pos);
+ if (len == -1)
+ throw new EOFException("Not enough data reading from: "
+ + classfile.getName());
+ pos += len;
+ }
+ b.put(md.digest(data), soFileName);
+ }
+ }
+ return b;
+ }
+
+ // Resize a map by creating a new one with the same data and
+ // renaming it. If close is true, close the original map.
+
+ static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
+ throws IOException, IllegalAccessException
+ {
+ newCapacity = Math.max(m.capacity(), newCapacity);
+ File name = m.getFile();
+ File copy = File.createTempFile(name.getName(), "", name.getParentFile());
+ try
+ {
+ PersistentByteMap dest
+ = PersistentByteMap.emptyPersistentByteMap
+ (copy, newCapacity, newCapacity*32);
+ dest.putAll(m);
+ dest.force();
+ if (close)
+ m.close();
+ copy.renameTo(name);
+ return dest;
+ }
+ catch (Exception e)
+ {
+ copy.delete();
+ }
+ return null;
+ }
+
+
+ static String bytesToString(byte[] b)
+ {
+ StringBuffer hexBytes = new StringBuffer();
+ int length = b.length;
+ for (int i = 0; i < length; ++i)
+ hexBytes.append(Integer.toHexString(b[i] & 0xff));
+ return hexBytes.toString();
+ }
+
+
+ // Return a Fileset, either from a String array or from System.in,
+ // depending on fileListFromStdin.
+ private static final Fileset getFiles(String[] s, int startPos,
+ boolean fileListFromStdin,
+ char separator)
+ {
+ if (fileListFromStdin)
+ return new Fileset(System.in, separator);
+ else
+ return new Fileset(s, startPos, s.length);
+ }
+}
+
+// Parse a stream into tokens. The separator can be any char, and
+// space is equivalent to any whitepace character.
+class Tokenizer
+{
+ final Reader r;
+ final char separator;
+
+ Tokenizer(Reader r, char separator)
+ {
+ this.r = r;
+ this.separator = separator;
+ }
+
+ boolean isSeparator(int c)
+ {
+ if (Character.isWhitespace(separator))
+ return Character.isWhitespace((char)c);
+ else
+ return c == separator;
+ }
+
+ // Parse a token from the input stream. Return the empty string
+ // when the stream is exhausted.
+ String nextToken ()
+ {
+ StringBuffer buf = new StringBuffer();
+ int c;
+ try
+ {
+ while ((c = r.read()) != -1)
+ {
+ if (! isSeparator(c))
+ {
+ buf.append((char)c);
+ break;
+ }
+ }
+ while ((c = r.read()) != -1)
+ {
+ if (isSeparator(c))
+ break;
+ else
+ buf.append((char)c);
+ }
+ }
+ catch (java.io.IOException e)
+ {
+ }
+ return buf.toString();
+ }
+}
+
+// A Fileset is a container for a set of files; it can be created
+// either from a string array or from an input stream, given a
+// separator character.
+class Fileset
+{
+ LinkedHashSet files = new LinkedHashSet();
+
+ Fileset (String[] s, int start, int end)
+ {
+ for (int i = start; i < end; i++)
+ {
+ files.add(new File(s[i]));
+ }
+ }
+
+ Fileset (InputStream is, char separator)
+ {
+ Reader r = new BufferedReader(new InputStreamReader(is));
+ Tokenizer st = new Tokenizer(r, separator);
+ String name;
+ while (! "".equals(name = st.nextToken()))
+ files.add(new File(name));
+ }
+
+ Iterator iterator()
+ {
+ return files.iterator();
+ }
+
+ int size()
+ {
+ return files.size();
+ }
+}