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 }