KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > Main


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 /* The commandline interface to jbet */
32
33 package jbet;
34 import java.io.*;
35 import java.util.*;
36
37 public class Main
38 {
39     static Hashtable commands;
40     static Vector lexers = new Vector();
41     static boolean writeDirty = true;
42     public static boolean verboseErrors = false;
43     static Vector javaclasspath = new Vector();
44     static Vector cmdpath = new Vector();
45     public static ClassPathElement JbetCPE = null;
46
47     static char[] _spaces;
48     static String JavaDoc jbethelp = "Use 'jbet help <topic>' for help.\n'jbet help' gives a list of commands and other help topics.";
49     static HashSet helpcmds;
50
51     static {
52
53     /* Initialize the class loader */
54     Jbet.loader = new ClassInfoLoader();
55     String JavaDoc prop = System.getProperty("java.class.path");
56     Jbet.loader.parseClassPath(prop);
57
58     for (int i = 0; i < Jbet.loader.classPath.size(); i++) {
59         try {
60         ClassPathElement cpe = Jbet.loader.getCPElement (i);
61         javaclasspath.addElement (cpe);
62
63         if (cpe.get ("jbet/Main.class") != null) {
64             JbetCPE = cpe;
65             cmdpath.addElement ("jbet.cmd");
66         }
67         } catch (IOException e) { }
68     }
69
70     if (cmdpath.size() == 0) {
71         System.err.println ("java.class.path property does not contain an entry with jbet/Main.");
72         System.exit (1);
73     }
74
75     /* make a string with 30 spaces for aligning the help text */
76     _spaces = new char[31];
77     for (int i = 0; i <= 30; i++) _spaces[i] = ' ';
78
79     /* Initialize the command list */
80     commands = new Hashtable();
81     commands.put ("diagecho", new Command() {
82         public int helplevel() { return 5; }
83         public String JavaDoc shorthelp() { return "echoes a string if verbosity is >= info"; }
84         public String JavaDoc longhelp() {
85             return "jbet diagecho <string> echoes <string> if verbosity is >= info\n";
86         }
87         public void run(Lexer lexer) throws Exception JavaDoc {
88             lexer.match(Token.END_OF_OPTS);
89             String JavaDoc s = lexer.parse_string();
90             lexer.term();
91             Jbet.info.println(s);
92         }
93         });
94     commands.put ("echo", new Command() {
95         public int helplevel() { return 5; }
96         public String JavaDoc shorthelp() { return "echoes a string"; }
97         public String JavaDoc longhelp() {
98             return "jbet echo <string> echoes a string\n";
99         }
100         public void run(Lexer lexer) throws Exception JavaDoc {
101             lexer.match(Token.END_OF_OPTS);
102             String JavaDoc s = lexer.parse_string();
103             lexer.term();
104             Jbet.output.println(s);
105         }
106         });
107     commands.put ("getclasses", new Command() {
108         public int helplevel() { return 5; }
109         public String JavaDoc shorthelp() { return "getclasseses"; }
110         public String JavaDoc longhelp() {
111             return "jbet getclasses\n";
112         }
113         public void run(Lexer lexer) throws Exception JavaDoc {
114             lexer.match(Token.END_OF_OPTS);
115             ClassInfo [] classes = lexer.getClasses();
116             lexer.term();
117             for (int i = 0; i < classes.length; i++)
118             Jbet.output.println(classes[i].name());
119         }
120         });
121
122     commands.put ("makezip", new Command() {
123         public int helplevel() { return 5; }
124         public String JavaDoc shorthelp() { return "makezip"; }
125         public String JavaDoc longhelp() {
126             return "jbet makezip\n";
127         }
128         public void run(Lexer lexer) throws Exception JavaDoc {
129             lexer.match(Token.END_OF_OPTS);
130             Vector v = new Vector();
131             lexer.getClasses(v);
132             lexer.term();
133             Util.writeZip("zipfile.zip", v.iterator());
134         }
135         });
136
137         
138
139     commands.put ("classpath", new Command() {
140         public int helplevel() { return 5; }
141         public String JavaDoc shorthelp() { return "sets the classpath"; }
142         public String JavaDoc longhelp() {
143             return "jbet classpath <string> sets the classpath\n";
144         }
145         public void run(Lexer lexer) throws Exception JavaDoc {
146             lexer.match(Token.END_OF_OPTS);
147             String JavaDoc s = lexer.parse_string();
148             lexer.term();
149             Jbet.loader.clearPath();
150             Jbet.loader.parseClassPath(s);
151         }
152         });
153     commands.put ("classpathadd", new Command() {
154         public int helplevel() { return 5; }
155         public String JavaDoc shorthelp() { return ""; }
156         public String JavaDoc longhelp() {
157             return "jbet classpathadd <string> adds to the classpath\n";
158         }
159         public void run(Lexer lexer) throws Exception JavaDoc {
160             lexer.match(Token.END_OF_OPTS);
161             String JavaDoc s = lexer.parse_string();
162             lexer.term();
163             Jbet.loader.parseClassPath(s);
164         }
165         });
166     commands.put ("printpath", new Command() {
167         public int helplevel() { return 5; }
168         public String JavaDoc shorthelp() { return ""; }
169         public String JavaDoc longhelp() {
170             return "jbet printpath prints the current classpath\n";
171         }
172         public void run(Lexer lexer) throws Exception JavaDoc {
173             lexer.match(Token.END_OF_OPTS);
174             lexer.term();
175             Jbet.loader.print(Jbet.output);
176         }
177         });
178     commands.put ("resolve_constants", new Command() {
179         public int helplevel() { return 5; };
180         public String JavaDoc shorthelp() { return "call resolve constants"; }
181         public String JavaDoc longhelp() { return "jbet resolve_constants thing\n";}
182         public void run(Lexer lexer) throws Exception JavaDoc {
183             lexer.match(Token.END_OF_OPTS);
184             Object JavaDoc thing = lexer.getThing(Jbet.default_class);
185             lexer.term();
186             if (thing instanceof ClassInfo) {
187             ((ClassInfo)thing).resolveConstants();
188             Jbet.info.println("resolve_constants " +
189                       ((ClassInfo)thing).thisClass);
190             } else if (thing instanceof MethodInfo) {
191             ((MethodInfo)thing).resolveConstants();
192             Jbet.info.println("resolve_constants " +
193                       ((MethodInfo)thing).qualifiedName());
194             } else if (thing instanceof FieldInfo) {
195             ((FieldInfo)thing).resolveConstants();
196             Jbet.info.println("resolve_constants " +
197                       ((FieldInfo)thing).qualifiedName());
198             }
199         }
200         });
201     commands.put ("listmethods", new Command() {
202         public int helplevel() { return 5; };
203         public String JavaDoc shorthelp() { return "list methods of a class"; }
204         public String JavaDoc longhelp() { return "jbet listmethods <class>\n";}
205         public void run(Lexer lexer) throws Exception JavaDoc {
206             lexer.match(Token.END_OF_OPTS);
207             ClassInfo cr = lexer.getClass(Jbet.default_class);
208             lexer.term();
209             for (int i = 0; i < cr.methods.size(); i++) {
210             MethodInfo mi = cr.methodAt(i);
211             Jbet.output.println(cr.name() + "." + mi.name + ":" +
212                         mi.descriptor);
213             }
214         }
215         });
216
217     commands.put ("inners", new Command() {
218         public int helplevel() { return 5; };
219         public String JavaDoc shorthelp() { return "inners"; }
220         public String JavaDoc longhelp() { return "inners\n";}
221         public void run(Lexer lexer) throws Exception JavaDoc {
222             lexer.match(Token.END_OF_OPTS);
223             ClassInfo cr = lexer.getClass(Jbet.default_class);
224             lexer.term();
225             HashSet s = Util.findInnerClasses(cr.name());
226             for (Iterator i = s.iterator(); i.hasNext();) {
227             Jbet.output.println(i.next());
228             }
229         }
230         });
231
232     commands.put ("setvar", new Command() {
233         public int helplevel() { return 5; };
234         public String JavaDoc shorthelp() { return "set a variable"; }
235         public String JavaDoc longhelp() { return "set <varname> <varvalue>\n";}
236         public void run(Lexer lexer) throws Exception JavaDoc {
237             lexer.match(Token.END_OF_OPTS);
238             lexer.push(Lexer.ST_STRING);
239             String JavaDoc name = lexer.parse_string();
240             String JavaDoc val = lexer.parse_string();
241             Jbet.lexerVars.put(name, val);
242             lexer.pop();
243         }
244         });
245
246     helpcmds = new HashSet();
247     helpcmds.add ("print");
248     helpcmds.add ("printclass");
249     helpcmds.add ("disassemble");
250     helpcmds.add ("assemble");
251     helpcmds.add ("listbbs");
252     helpcmds.add ("listdags");
253     helpcmds.add ("listmethods");
254     helpcmds.add ("set");
255     helpcmds.add ("verify");
256     helpcmds.add ("verifyall");
257     helpcmds.add ("findclasses");
258     }
259
260     static Command getCommand (String JavaDoc name) throws Exception JavaDoc
261     {
262     Exception JavaDoc lastex = null;
263     Object JavaDoc o = commands.get(name);
264     if (o != null)
265         return (Command) o;
266
267     for (int i = 0; i < cmdpath.size(); i++)
268         try {
269         String JavaDoc cp = cmdpath.elementAt(i).toString();
270
271         Class JavaDoc cls = Class.forName (cp + "." + name);
272         Command cmd = (Command) cls.newInstance();
273         cmd.hashCode();
274         commands.put (name, cmd);
275         return cmd;
276         } catch (Exception JavaDoc e) { lastex = e; }
277
278     if (lastex != null)
279         throw lastex;
280     else
281         throw new IllegalStateException JavaDoc ("something bad happened");
282     }
283
284     // same as getCommand, but return null instead of throwing an exception
285
static Command getCommand2 (String JavaDoc name)
286     {
287     try {
288         return getCommand (name);
289     } catch (Exception JavaDoc e) {
290         return null;
291     }
292     }
293
294     /** Print out the one line help for each command.
295        @param helplevel Include only commands with helplevel less than this.
296     */

297     public static void usage (int helplevel)
298     {
299     Jbet.output.println ("Usage: jbet <options> <command> <arguments>\nCommands:");
300
301     for (Iterator i = helpcmds.iterator(); i.hasNext(); ) {
302         String JavaDoc cname = i.next().toString();
303         Command co = getCommand2 (cname);
304
305         if (co != null) {
306             String JavaDoc spaces = new String JavaDoc (_spaces, 0, 17 - cname.length());
307             Jbet.output.println (cname + spaces + co.shorthelp());
308         }
309     }
310
311     Jbet.output.println ("help <command> extended help on <command>");
312     Jbet.output.println ("help options show help on commandline options");
313     Jbet.output.println ("help syntax show help on argument syntax");
314     }
315
316     /** Print the one line help for all commands.
317      */

318     public static void usage ()
319     {
320     usage (3);
321     }
322
323     public static void usage (String JavaDoc text)
324     {
325     if (text.equals ("all")) {
326         usage (99);
327         return;
328     }
329     else if (text.equals ("options")) {
330         optionhelp ();
331         return;
332     }
333
334     else if (text.equals ("syntax")) {
335         Jbet.output.println
336         ("Class names:\n" +
337          " Use slashes in the names, such as java/lang/Object.\n" +
338          " The package name is always required.\n" +
339          "Method specification:\n" +
340          " Use <class>.<method> or <class>.<method>:<descriptor>.\n" +
341          " The descriptor is required only if there is more than one method\n" +
342          " with the same name.\n" +
343          "Method descriptors:\n" +
344          " Use the JNI descriptor syntax, which is (<arguments>)<return type>.\n" +
345          " Each type is one of the following:\n" +
346          " int I\n" +
347          " long J\n" +
348          " float F\n" +
349          " double D\n" +
350          " short S\n" +
351          " byte B\n" +
352          " char C\n" +
353          " boolean Z\n" +
354          " reference L<class-name>;\n" +
355          " So a method declared as int foo (String, long, Object) would be\n" +
356          " (Ljava/lang/String;JLjava/lang/Object;)I\n"
357          );
358         return;
359     }
360
361     Command cmd = getCommand2 (text);
362
363     if (cmd == null)
364         Jbet.output.println ("invalid command " + text);
365     else {
366         Jbet.output.print (cmd.longhelp());
367     }
368     }
369
370     /** Read a command name from the lexer, and pass the remaining lexer to the
371      * command object's run method. Show a warning if there is no command.
372      * Called from the main loop for each input command.
373      * @param lexer the lexer to read
374      */

375     static void doCommands (Lexer lexer) throws Exception JavaDoc
376     {
377     lexer.varFunction = Jbet.lexerVarFunction;
378
379     while (true) {
380         lexer.state = Lexer.ST_TAG;
381
382         Token tok;
383         do { tok = lexer.read(); } while ( tok.type == ';' );
384         
385         if (tok.type == Token.EOF) break;
386         if (tok.type != Token.TAG) lexer.unexpected(tok);
387
388         Command cmd = getCommand (tok.text);
389         
390         if (cmd == null)
391         throw new ParseException ("invalid command " + tok.text + "; type 'jbet help' for a list");
392
393         Jbet.debug.println ("executing command " + tok.text);
394         cmd.run (lexer);
395     }
396     }
397
398     static void doCommands (String JavaDoc s) throws Exception JavaDoc
399     {
400     doCommands (new Lexer (new StringReader (s), "cmdline"));
401     }
402
403     /** Write out a ClassInfo and a comment saying where written.
404      * Called from main for each dirty class.
405      *
406      * @param cr the ClassInfo to write out
407      * @param recursive feature not used
408      */

409     static void write (ClassInfo cr) throws Exception JavaDoc {
410     cr.write();
411     }
412
413     /** Main program.
414      * Sets up loader, reads args, executes commands, writes out modified classes.
415      * The loader keeps a list of classes that have been read in.
416      * Args from command line and the jbet.init property.
417      * @param args Array of strings from the environment.
418      */

419     public static void main (String JavaDoc[] args) {
420     int exitStatus = 0;
421
422     if (args.length == 0)
423         {
424         Jbet.output.println (jbethelp);
425         return;
426         }
427
428     try {
429
430         parseArgs (args); //parse user arguements
431

432         if (lexers.size() == 0) {
433         Jbet.output.println (jbethelp);
434         return;
435         }
436
437         for (int i = 0; i < lexers.size(); i++)
438         doCommands((Lexer) lexers.elementAt(i));
439
440         if (writeDirty) {
441         /* Write out all modified classes */
442         Enumeration classes = Jbet.loader.getClasses();
443         ClassInfo cr;
444         while (classes.hasMoreElements()) {
445             cr = (ClassInfo) classes.nextElement();
446             if (cr.dirty)
447             write(cr);
448         }
449         }
450         
451     } catch (Throwable JavaDoc e) {
452         exitStatus = 1;
453         if (verboseErrors) {
454         Jbet.fatal.print("\n\n");
455         e.printStackTrace(Jbet.fatal);
456         } else
457         if (e instanceof GlobalException || e instanceof ParseException || e instanceof ClassFileException)
458             Jbet.fatal.println( e.getMessage() );
459         else
460             Jbet.fatal.println(e.getClass().getName() + ": " + e.getMessage() );
461     }
462     System.exit(exitStatus);
463     }
464
465     static MyGetopt g;
466
467     /** Parse the argument string.
468      *
469      * @param args Array of strings from the environment.
470      */

471     static void parseArgs (String JavaDoc [] args) throws Exception JavaDoc {
472     MyLongOpt [] longs = new MyLongOpt[9];
473     longs[0] = new MyLongOpt("classpath", MyGetopt.REQUIRED_ARG, 'p');
474     longs[1] = new MyLongOpt("cmdpath", MyGetopt.REQUIRED_ARG, 'C');
475     longs[2] = new MyLongOpt("nowrite", MyGetopt.NO_ARG, 'W');
476     longs[3] = new MyLongOpt("pluspath", MyGetopt.REQUIRED_ARG, 'P');
477     longs[4] = new MyLongOpt("outputdir", MyGetopt.REQUIRED_ARG, 'o');
478     longs[5] = new MyLongOpt("verbosity", MyGetopt.REQUIRED_ARG, 'l');
479     longs[6] = new MyLongOpt("comment", MyGetopt.NO_ARG, 'q');
480     longs[7] = new MyLongOpt("default", MyGetopt.REQUIRED_ARG, 'd');
481     longs[8] = new MyLongOpt("facility", MyGetopt.REQUIRED_ARG, 'F');
482
483     if (g == null)
484         g = new MyGetopt (":c:vVeEjJvqWro:C:d:f:p:P:l:F:", args, longs);
485     int opt;
486     while ( (opt = g.getopt()) != -1 ) {
487         switch (opt) {
488         case 1:
489         /* All remaining command line arguments are commands: create a lexer for them */
490         StringBuffer JavaDoc output = new StringBuffer JavaDoc();
491         for (int i = g.optind - 1; i < args.length; i++) {
492             output.append (args[i]);
493             output.append (" ");
494         }
495         lexers.addElement (new Lexer (new StringReader (output.toString()), "cmdline"));
496         return;
497
498         /* Command path */
499         case 'C':
500         cmdpath.addElement(ClassInfoLoader.directory (g.optarg));
501         break;
502
503         /* Output message options */
504         case 'v':
505         Jbet.logger.setLevel(Logger.INFO);
506         break;
507         case 'l':
508         int level = Logger.str2level(g.optarg);
509         if (level == -1)
510             throw new ParseException("bad verbosity level: " + g.optarg);
511         Jbet.logger.setLevel(level);
512         break;
513         case 'R':
514         Jbet.logger.setOut(System.err);
515         break;
516         case 'F':
517         Jbet.logger.addFacility (g.optarg);
518         break;
519         case 'V':
520         Jbet.logger.setLevel(Logger.WARN);
521         break;
522         case 'e':
523         verboseErrors = true;
524         break;
525         case 'E':
526         verboseErrors = false;
527         break;
528
529         /* Output file options */
530         case 'W':
531         writeDirty = false;
532         break;
533         case 'o':
534         Jbet.outputdir = g.optarg;
535         if (!Jbet.outputdir.endsWith("/"))
536             Jbet.outputdir = Jbet.outputdir + "/";
537         break;
538         case 'q':
539         Jbet.compact = false;
540         break;
541
542         case 'd':
543         Jbet.setDefault(g.optarg);
544         break;
545
546         /* alternate command entry */
547             case 'c':
548         doCommands(new Lexer(new StringReader(g.optarg), "-c"));
549                 break;
550
551         case 'f':
552         if (g.optarg.equals("-"))
553             lexers.addElement( new Lexer(System.in, "stdin"));
554         else {
555             FileInputStream fp = new FileInputStream(g.optarg);
556             lexers.addElement (new Lexer (fp, g.optarg));
557         }
558         break;
559
560         /* class path */
561         case 'p':
562         Jbet.loader.clearPath();
563         //fall through
564
case 'P':
565         Jbet.loader.parseClassPath(g.optarg);
566         break;
567         case 'j':
568         Jbet.loader.clearPath();
569         case 'J':
570         {
571             Vector cp = getSystemClassPath();
572             for (Iterator i = cp.iterator(); i.hasNext(); )
573             Jbet.loader.parseClassPath (i.next().toString(), false);
574         }
575         break;
576
577         case '?':
578         case ':':
579         throw new ParseException (g.error);
580         }
581     }
582
583     return;
584     }
585
586     /** Print out a list of command options.
587      */

588     static void optionhelp ()
589     {
590     Jbet.output.println (
591         " -p \t specify a classpath \n" +
592         " -P \t specify elemetns to add to the current classpath \n" +
593         " -j \t set classpath to Java system classpath\n" +
594         " -J \t append Java system classpath to classpath\n" +
595         " -v \t print a message for each action taken (same as -l info)\n"+
596         " -e \t verbose errors \n"+
597         " -W \t inhibit automatic writing of modified classes \n"+
598         " -f \t specify a file to read commands from \n"+
599         " -d \t specify a default class \n" +
600         " -R \t use stderr for log and error messages \n" +
601         " -l \t set log level (all, debug, info, warn, error, fatal) \n"+
602         " -f \t show all messages from specified facility\n"+
603         " -o \t specify an output directory"
604         );
605     }
606
607     static Vector getSystemClassPath () {
608     try {
609         java.lang.reflect.Method JavaDoc jcl = ClassLoader JavaDoc.class.getDeclaredMethod ("getBootstrapClassPath", new Class JavaDoc[0]);
610         jcl.setAccessible (true);
611         sun.misc.URLClassPath cp = (sun.misc.URLClassPath) jcl.invoke (null, new Object JavaDoc[0]);
612
613         java.net.URL JavaDoc[] cps = cp.getURLs();
614
615         Vector out = new Vector();
616         for (int i = 0; i < cps.length; i++)
617         if (cps[i].getProtocol().equals ("file"))
618             out.addElement (java.net.URLDecoder.decode (cps[i].getPath()));
619         return out;
620     } catch (Exception JavaDoc e) {
621         throw new IllegalStateException JavaDoc (e.toString());
622     }
623     }
624 }
625
Popular Tags