    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    }