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 }