001    /* Copyright 2000, 2001, Compaq Computer Corporation */
002    
003    package javafe.filespace;
004    
005    
006    import java.io.*;
007    import java.util.Properties;
008    import java.util.Enumeration;
009    
010    import javafe.genericfile.*;
011    
012    
013    /**
014     * Functions for dealing with classpaths.
015     */
016    
017    public class ClassPath {
018    
019        /************************************************************
020         *                                                          *
021         * Accessing our current classpath:                         *
022         *                                                          *
023         ***********************************************************/
024    
025        /**
026         * Return our current classpath; if the Java system property
027         * <code>java.class.path.skip</code> is set to <var>n</var>, we
028         * ignore the first <var>n</var> components of the path. <p>
029         *
030         * This makes it easier to write Java applications that use the
031         * classpath because we can append the path component containing
032         * the application binaries to the start of the classpath then
033         * remove them here, making it look like the classpath was not
034         * disturbed.  (In particular, the automatic addition of the system
035         * libraries is not disturbed.)
036         */
037        //@ ensures \result != null;
038        public static String current() {
039            String arg = System.getProperty("java.class.path.skip", "0");
040            int skip = 0;
041            try {
042                skip = new Integer(arg).intValue();
043            } catch (NumberFormatException e) {}
044    
045            String path = System.getProperty("java.class.path", ".");
046    
047            for (int i=0; i<skip; i++) {
048                int sep = path.indexOf(File.pathSeparatorChar);
049                if (sep == -1 || sep == path.length()-1)
050                    return ".";
051                path = path.substring(sep + 1);
052            }
053    
054            return path;
055        }
056    
057        /**
058         * Set our current classpath by changing the property
059         * <code>java.class.path</code>.<p>
060         *
061         */
062        //@ requires newClassPath != null;
063        public static void set(String newClassPath) {
064            Properties P = System.getProperties();
065            P.put("java.class.path", newClassPath);
066            System.setProperties(P);
067        }
068    
069    
070        /************************************************************
071         *                                                          *
072         * Obtaining the namespace associated with a classpath:     *
073         *                                                          *
074         ***********************************************************/
075    
076        /**
077         * Get the filtered filespace (cf {@link PathComponent})
078         * specified by a classpath.  (Filtering is performed using
079         * {@link PkgTree} on each of the path components before they are
080         * union'ed together).<p>
081         *
082         * All {@link PkgTree} accessors and enumerators can be used on
083         * the resulting filespace.<p>
084         *
085         * May throw an {@link IOException} if errors occur.<p>
086         *
087         * Iff complain is set, we throw {@link IOException}s if
088         * non-existent or ill-formed path components are present in the
089         * classpath.<p>
090         *
091         */
092        //@ requires classpath != null;
093        //@ ensures \result != null;
094        public static Tree open(String classpath, boolean complain)
095                                    throws IOException {
096            if (classpath.length()==0) {
097                throw new IOException("Empty classpath");
098            }
099    
100            String[] pathnames = StringUtil.parseList(classpath,
101                                                      File.pathSeparatorChar);
102    
103            Tree[] components = new Tree[pathnames.length];
104            for (int i=0; i<components.length; i++) {
105                components[i] = new PkgTree(PathComponent.open(pathnames[i],
106                                                               complain));
107            }
108    
109            return new UnionTree(components);
110        }
111    
112    
113        /**
114         * Get the namespace specified by the current classpath using open;
115         * this is a convenience function.<p>
116         *
117         * Iff complain is set, we throw {@link IOException}s if
118         * non-existent or ill-formed path components are present in the
119         * classpath.<p>
120         */
121        //@ ensures \result != null;
122        public static Tree open(boolean complain) throws IOException {
123            return open(current(), complain);
124        }
125    
126    
127        /***************************************************
128         *                                                 *
129         * Debugging functions:                            *
130         *                                                 *
131         **************************************************/
132    
133        /**
134         * A nicer, formatted version of print.<p>
135         *
136         * @param P must be a filespace filtered via {@link PkgTree};
137         * moreover <code>PkgTree.isPackage(P)</code> should be true.<p>
138         */
139        //@ requires P != null;
140        public static void displayPackage(Tree P) {
141            // Enumerate P's subpackages:
142            for (Enumeration E = PkgTree.packages(P); E.hasMoreElements();) {
143                Tree SP = (Tree)E.nextElement();
144    
145                // Display the current package's full name:
146                System.out.println(PkgTree.getPackageName(SP) + ":");
147    
148                // List the sources of the current subpackage:
149                Enumeration S = PkgTree.components(SP, ".java");
150                while (S.hasMoreElements())
151                    System.out.println("  S> "
152                            + ((Tree)S.nextElement()).getSimpleName());
153    
154                // List the binaries of the current subpackage:
155                S = PkgTree.components(SP, ".class");
156                while (S.hasMoreElements())
157                    System.out.println("  B> "
158                            + ((Tree)S.nextElement()).getSimpleName());
159            }
160        }
161    
162    
163        /** A simple test driver */
164        //@ requires args != null;
165        /*@ requires (\forall int i; (0<=i && i<args.length)
166                    ==> args[i] != null); */
167        public static void main(String[] args) throws IOException {
168            /*
169             * Parse command arguments:
170             */
171            if (args.length>2) {
172                System.out.println("ClassPath: usage "
173                    + "[<package name> [<class or interface name>]]");
174                return;
175            }
176            String packageName = (args.length>0 ? args[0] : "");
177            String typeName   = (args.length>1 ? args[1] : null);
178    
179    //      set("Tmp2/new.zip");
180    //      set("");
181    
182            System.out.println("classpath=" + current());
183    
184            // Get the indicated package:
185            Tree P = open(false).getQualifiedChild(packageName, '.');
186            if (P==null) {
187                System.out.println("No such package: " + packageName);
188                return;
189            }
190    
191            // If no type given, just display the indicated package and exit:
192            if (typeName==null) {
193                displayPackage(P);
194                return;
195            }
196    
197            // Get the indicated source:
198            Tree source = P.getChild(typeName+".java");
199            if (source == null) {
200                System.out.println("No source is available for type "
201                            + PkgTree.getPackageName(P) + "." + typeName);
202                return;
203            }
204            
205            // Dump the source in question to standard out:
206            GenericFile sourceFile = (GenericFile)source.data;      //@ nowarn Cast;
207            //@ assume sourceFile != null;
208            InputStream I = sourceFile.getInputStream();
209            System.out.println(sourceFile.getHumanName() + ":");
210            System.out.println("------------------------------ " +
211                typeName + ".java: ------------------------------ ");
212    
213            for (int next=I.read(); next>=0; next=I.read())
214                System.out.write(next);
215        }
216    }