OSDN Git Service

Add NIOS2 support. Code from SourceyG++.
[pf3gnuchains/gcc-fork.git] / libjava / gnu / gcj / tools / gcj_dbtool / Main.java
1 /* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
2    Free Software Foundation
3
4    This file is part of libgcj.
5
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
8 details.  */
9
10 package gnu.gcj.tools.gcj_dbtool;
11
12
13 import gnu.gcj.runtime.PersistentByteMap;
14 import java.io.*;
15 import java.nio.channels.*;
16 import java.util.*;
17 import java.util.jar.*;
18 import java.security.MessageDigest;
19
20 public class Main
21 {
22   static private boolean verbose = false;
23
24   public static void main (String[] s)
25   {
26     boolean fileListFromStdin = false;
27     char filenameSeparator = ' ';
28
29     insist (s.length >= 1);
30
31     if (s[0].equals("-") ||
32         s[0].equals("-0"))
33       {
34         if (s[0].equals("-0"))
35           filenameSeparator = (char)0;
36         fileListFromStdin = true;
37         String[] newArgs = new String[s.length - 1];
38         System.arraycopy(s, 1, newArgs, 0, s.length - 1);
39         s = newArgs;
40       }
41
42     if (s[0].equals("-v") || s[0].equals("--version"))
43       {
44         insist (s.length == 1);
45         System.out.println("gcj-dbtool ("
46                            + System.getProperty("java.vm.name")
47                            + ") "
48                            + System.getProperty("java.vm.version"));
49         System.out.println();
50         System.out.println("Copyright 2010 Free Software Foundation, Inc.");
51         System.out.println("This is free software; see the source for copying conditions.  There is NO");
52         System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
53         return;
54       }
55     if (s[0].equals("--help"))
56       {
57         usage(System.out);
58         return;
59       }
60
61     if (s[0].equals("-n"))
62       {
63         // Create a new database.
64         insist (s.length >= 2 && s.length <= 3);
65
66         int capacity = 32749;
67
68         if (s.length == 3)
69           {         
70             capacity = Integer.parseInt(s[2]);
71
72             if (capacity <= 2)
73               {
74                 usage(System.err);
75                 System.exit(1);
76               }
77           }
78             
79         try
80           {
81             PersistentByteMap b 
82               = PersistentByteMap.emptyPersistentByteMap(new File(s[1]), 
83                                                          capacity, capacity*32);
84           }
85         catch (Exception e)
86           {
87             System.err.println ("error: could not create " 
88                                 + s[1] + ": " + e.toString());
89             System.exit(2);
90           }
91         return;
92       }
93
94     if (s[0].equals("-a") || s[0].equals("-f"))
95       {
96         // Add a jar file to a database, creating it if necessary.
97         // Copies the database, adds the jar file to the copy, and
98         // then renames the new database over the old.
99         try
100           {
101             insist (s.length == 4);
102             File database = new File(s[1]);
103             database = database.getAbsoluteFile();
104             File jar = new File(s[2]);  
105             PersistentByteMap map; 
106             if (database.isFile())
107               map = new PersistentByteMap(database, 
108                                           PersistentByteMap.AccessMode.READ_ONLY);
109             else
110               map = PersistentByteMap.emptyPersistentByteMap(database, 
111                                                              100, 100*32);
112             File soFile = new File(s[3]);
113             if (! s[0].equals("-f") && ! soFile.isFile())
114               throw new IllegalArgumentException(s[3] + " is not a file");
115             map = addJar(jar, map, soFile);
116           }
117         catch (Exception e)
118           {
119             System.err.println ("error: could not update " + s[1] 
120                                 + ": " + e.toString());
121             System.exit(2);
122           }
123         return;
124       }
125
126     if (s[0].equals("-t"))
127       {
128         // Test
129         try
130           {
131             insist (s.length == 2);
132             PersistentByteMap b 
133               = new PersistentByteMap(new File(s[1]),
134                                       PersistentByteMap.AccessMode.READ_ONLY);
135             Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
136         
137             while (iterator.hasNext())
138               {
139                 PersistentByteMap.MapEntry entry 
140                   = (PersistentByteMap.MapEntry)iterator.next();
141                 byte[] key = (byte[])entry.getKey();
142                 byte[] value = (byte[])b.get(key);
143                 if (! Arrays.equals (value, (byte[])entry.getValue()))
144                   {
145                     String err 
146                       = ("Key " + bytesToString(key) + " at bucket " 
147                          + entry.getBucket());
148                   
149                     throw new RuntimeException(err);
150                   }
151               }
152           }
153         catch (Exception e)
154           {
155             e.printStackTrace();
156             System.exit(3);
157           }
158         return;
159       }
160          
161     if (s[0].equals("-m"))
162       {
163         // Merge databases.
164         insist (s.length >= 3
165                 || fileListFromStdin && s.length == 2);
166         try
167           {
168             File database = new File(s[1]);
169             database = database.getAbsoluteFile();
170             File temp = File.createTempFile(database.getName(), "", 
171                                             database.getParentFile());
172                 
173             int newSize = 0;
174             int newStringTableSize = 0;
175             Fileset files = getFiles(s, 2, fileListFromStdin, 
176                                      filenameSeparator);
177             PersistentByteMap[] sourceMaps 
178               = new PersistentByteMap[files.size()];
179
180             // Scan all the input files, calculating worst case string
181             // table and hash table use.
182             {
183               Iterator it = files.iterator();
184               int i = 0;
185               while (it.hasNext())
186                 {
187                   PersistentByteMap b 
188                     = new PersistentByteMap((File)it.next(),
189                                             PersistentByteMap.AccessMode.READ_ONLY);
190                   newSize += b.size();
191                   newStringTableSize += b.stringTableSize();
192                   sourceMaps[i++] = b;
193                 }
194             }
195             
196             newSize *= 1.5; // Scaling the new size by 1.5 results in
197                             // fewer collisions.
198             PersistentByteMap map 
199               = PersistentByteMap.emptyPersistentByteMap
200               (temp, newSize, newStringTableSize);
201
202             for (int i = 0; i < sourceMaps.length; i++)
203               {
204                 if (verbose)
205                   System.err.println("adding " + sourceMaps[i].size() 
206                                      + " elements from "
207                                      + sourceMaps[i].getFile());
208                 map.putAll(sourceMaps[i]);
209               }
210             map.close();
211             temp.renameTo(database);
212           }
213         catch (Exception e)
214           {
215             e.printStackTrace();
216             System.exit(3);
217           }
218         return;
219       }
220
221     if (s[0].equals("-l"))
222       {
223         // List a database.
224         insist (s.length == 2);
225         try
226           {
227             PersistentByteMap b 
228               = new PersistentByteMap(new File(s[1]),
229                                       PersistentByteMap.AccessMode.READ_ONLY);
230
231             System.out.println ("Capacity: " + b.capacity());
232             System.out.println ("Size: " + b.size());
233             System.out.println ();
234
235             System.out.println ("Elements: ");
236             Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
237     
238             while (iterator.hasNext())
239               {
240                 PersistentByteMap.MapEntry entry 
241                   = (PersistentByteMap.MapEntry)iterator.next();
242                 byte[] digest = (byte[])entry.getKey();
243                 System.out.print ("[" + entry.getBucket() + "] " 
244                                   + bytesToString(digest)
245                                   + " -> ");
246                 System.out.println (new String((byte[])entry.getValue()));
247               }
248           }
249         catch (Exception e)
250           {
251             System.err.println ("error: could not list " 
252                                 + s[1] + ": " + e.toString());
253             System.exit(2);
254           }
255         return;
256       }
257
258     if (s[0].equals("-d"))
259       {
260         // For testing only: fill the byte map with random data.
261         insist (s.length == 2);
262         try
263           {    
264             MessageDigest md = MessageDigest.getInstance("MD5");
265             PersistentByteMap b 
266               = new PersistentByteMap(new File(s[1]), 
267                                       PersistentByteMap.AccessMode.READ_WRITE);
268             int N = b.capacity();
269             byte[] bytes = new byte[1];
270             byte digest[] = md.digest(bytes);
271             for (int i = 0; i < N; i++)
272               {
273                 digest = md.digest(digest);
274                 b.put(digest, digest);
275               }
276           }
277         catch (Exception e)
278           {
279             e.printStackTrace();
280             System.exit(3);
281           }         
282         return;
283       }
284
285     if (s[0].equals("-p"))
286       {
287         insist (s.length == 1 || s.length == 2);
288         String result;
289         
290         if (s.length == 1)
291           result = System.getProperty("gnu.gcj.precompiled.db.path", "");
292         else 
293           result = (s[1] 
294                     + (s[1].endsWith(File.separator) ? "" : File.separator)
295                     + getDbPathTail ());
296
297         System.out.println (result);
298         return;
299       }
300
301     usage(System.err);
302     System.exit(1);         
303   }
304
305   private static native String getDbPathTail ();
306     
307   private static void insist(boolean ok)
308   {
309     if (! ok)
310       {
311         usage(System.err);
312         System.exit(1);
313       }     
314   }
315
316   private static void usage(PrintStream out)
317   {
318     out.println
319       ("gcj-dbtool: Manipulate gcj map database files\n"
320        + "\n"
321        + "  Usage: \n"
322        + "    gcj-dbtool -n file.gcjdb [size]     - Create a new gcj map database\n"
323        + "    gcj-dbtool -a file.gcjdb file.jar file.so\n"
324        + "            - Add the contents of file.jar to a gcj map database\n"
325        + "    gcj-dbtool -f file.gcjdb file.jar file.so\n"
326        + "            - Add the contents of file.jar to a gcj map database\n"
327        + "    gcj-dbtool -t file.gcjdb            - Test a gcj map database\n"
328        + "    gcj-dbtool -l file.gcjdb            - List a gcj map database\n"
329        + "    gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
330        + "            - Merge gcj map databases into dest\n"
331        + "              Replaces dest\n"
332        + "              To add to dest, include dest in the list of sources\n"
333        + "              If the first arg is -, read the list from stdin\n"
334        + "              If the first arg is -0, filenames separated by nul\n"
335        + "    gcj-dbtool -p [LIBDIR]              - Print default database name"
336        );
337   }
338
339   // Add a jar to a map.  This copies the map first and returns a
340   // different map that contains the data.  The original map is
341   // closed.
342
343   private static PersistentByteMap 
344   addJar(File f, PersistentByteMap b, File soFile)
345     throws Exception
346   {
347     MessageDigest md = MessageDigest.getInstance("MD5");
348
349     JarFile jar = new JarFile (f);
350
351     int count = 0;
352     {
353       Enumeration entries = jar.entries();      
354       while (entries.hasMoreElements())
355         {
356           JarEntry classfile = (JarEntry)entries.nextElement();
357           if (classfile.getName().endsWith(".class"))
358             count++;
359         }
360     }
361
362     if (verbose)
363       System.err.println("adding " + count + " elements from "
364                          + f + " to " + b.getFile());
365     
366     // Maybe resize the destination map.  We're allowing plenty of
367     // extra space by using a loadFactor of 2.  
368     b = resizeMap(b, (b.size() + count) * 2, true);
369
370     Enumeration entries = jar.entries();
371
372     byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
373     while (entries.hasMoreElements())
374       {
375         JarEntry classfile = (JarEntry)entries.nextElement();
376         if (classfile.getName().endsWith(".class"))
377           {
378             InputStream str = jar.getInputStream(classfile);
379             int length = (int) classfile.getSize();
380             if (length == -1)
381               throw new EOFException();
382
383             byte[] data = new byte[length];
384             int pos = 0;
385             while (length - pos > 0)
386               {
387                 int len = str.read(data, pos, length - pos);
388                 if (len == -1)
389                   throw new EOFException("Not enough data reading from: "
390                                          + classfile.getName());
391                 pos += len;
392               }
393             b.put(md.digest(data), soFileName);
394           }
395       }
396     return b;
397   }    
398
399   // Resize a map by creating a new one with the same data and
400   // renaming it.  If close is true, close the original map.
401
402   static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
403     throws IOException, IllegalAccessException
404   {
405     newCapacity = Math.max(m.capacity(), newCapacity);
406     File name = m.getFile();
407     File copy = File.createTempFile(name.getName(), "", name.getParentFile());
408     try
409       {
410         PersistentByteMap dest 
411           = PersistentByteMap.emptyPersistentByteMap
412           (copy, newCapacity, newCapacity*32);
413         dest.putAll(m);
414         dest.force();
415         if (close)
416           m.close();
417         copy.renameTo(name);
418         return dest;
419       }
420     catch (Exception e)
421       {
422         copy.delete();
423       }
424     return null;
425   }
426     
427          
428   static String bytesToString(byte[] b)
429   {
430     StringBuffer hexBytes = new StringBuffer();
431     int length = b.length;
432     for (int i = 0; i < length; ++i)
433       {
434         int v = b[i] & 0xff;
435         if (v < 16)
436           hexBytes.append('0');
437         hexBytes.append(Integer.toHexString(v));
438       }
439     return hexBytes.toString();
440   }
441
442
443   // Return a Fileset, either from a String array or from System.in,
444   // depending on fileListFromStdin.
445   private static final Fileset getFiles(String[] s, int startPos,
446                                         boolean fileListFromStdin,
447                                         char separator)
448   {
449     if (fileListFromStdin)
450       return new Fileset(System.in, separator);
451     else
452       return new Fileset(s, startPos, s.length);
453   }
454 }
455
456 // Parse a stream into tokens.  The separator can be any char, and
457 // space is equivalent to any whitepace character.
458 class Tokenizer
459 {
460   final Reader r;
461   final char separator;
462
463   Tokenizer(Reader r, char separator)
464   {
465     this.r = r;
466     this.separator = separator;
467   }
468
469   boolean isSeparator(int c)
470   {
471     if (Character.isWhitespace(separator))
472       return Character.isWhitespace((char)c);
473     else
474       return c == separator;
475   }
476
477   // Parse a token from the input stream.  Return the empty string
478   // when the stream is exhausted.
479   String nextToken ()
480   {
481     StringBuffer buf = new StringBuffer();
482     int c;
483     try
484       {
485         while ((c = r.read()) != -1)
486           {
487             if (! isSeparator(c))
488               {
489                 buf.append((char)c);
490                 break;
491               }
492           }
493         while ((c = r.read()) != -1)
494           {
495             if (isSeparator(c))
496               break;
497             else
498               buf.append((char)c);
499           }
500       }
501     catch (java.io.IOException e)
502       {
503       }
504     return buf.toString();
505   }
506 }
507
508 // A Fileset is a container for a set of files; it can be created
509 // either from a string array or from an input stream, given a
510 // separator character.
511 class Fileset
512 {
513   LinkedHashSet files = new LinkedHashSet();
514   
515   Fileset (String[] s, int start, int end)
516   {
517     for (int i = start; i < end; i++)
518       {
519         files.add(new File(s[i]));
520       }
521   }
522
523   Fileset (InputStream is, char separator)
524   {
525     Reader r = new BufferedReader(new InputStreamReader(is));
526     Tokenizer st = new Tokenizer(r, separator);
527     String name;
528     while (! "".equals(name = st.nextToken()))
529       files.add(new File(name));
530   }
531
532   Iterator iterator()
533   {
534     return files.iterator();
535   }
536
537   int size()
538   {
539     return files.size();
540   }
541 }