Changeset 12422


Ignore:
Timestamp:
02/06/10 10:52:32 (12 years ago)
Author:
Mark Evenson
Message:

Extensively reworked new implementation for specifiying jar pathnames.

Pathname namestrings that have the form "jar:URL!/ENTRY" now construct
references to the ENTRY within a jar file that is located by URL. The
most common use is the "file:" form of URL
(e.g. 'jar:file:/home/me/foo.jar!/foo.lisp') although any valid syntax
accepted by the java.net.URL constructor should work (such as
'jar:http://abcl-dynamic-install.googlecode.com/files/baz.jar!/a/b/eek.lisp').

The internal structure of a jar pathname has changed. Previously a
pathname with a DEVICE that was itself a pathname referenced a jar.
This convention was not able to simultaneously represent bothjar
entries that were themselves jar files as occurs with packed FASLs
within JARs and devices which refer to drive letters under Windows.
Now, a pathname which refers to a jar has a DEVICE which is a proper
list of at most two entries. The first entry always references the
"outer jar", and the second entry (if it exists) references the "inner
jar". Casual users are encouraged not to manipulate the "internal
structure" of jar pathname by setting its DEVICE directly, but instead
rely on namestring <--> pathname conversions.

Jar pathnames are only currently valid for use with LOAD, TRUENAME,
PROBE-FILE and pathname translation related functions (such as
MERGE-PATHNAMES, TRANSLATE-PATHNAME, etc.) Passing one to OPEN
currently signals an error. Jar pathnames do not currently work
with DIRECTORY or PROBE-DIRECTORY.

Jar pathnames work for ASDF systems packaged within JARs. We override
ASDF:LOAD-OP to load ASDF from JAR Pathnames by bypassing compilation
if the output location would be in a JAR file. Interaction with
ASDF-BINARY-LOCATIONS is currently untested.

Pathname now used as the basis of ABCL's internal routines for loading
FASLs replacing the use of strings, which simplifies a lot of the
behavior in looking for things to LOAD.

Fixed nasty shared structure bug on MERGE-PATHNAMES by implementing
(and using) a copy constructor for Pathname.

Implemented SYS:PATHNAME-JAR-P predicate for jar pathnames.

Removed ZipCache? as it is no longer used now that we are using JVM's
implicit JAR caching.

WRITE-FILE-DATE works for jar pathnames, returning 0 for a
non-existent entry.

JAR-FILE tests now include loading FASLs from network location, which
means that these tests will fail if there is no network
connectivity. The tests initialization rewritten in Lisp, so it works
under Windows.

Allow of a top directory for creating hierarchially ZIPs with SYS:ZIP.
There is now a three argument version--PATHNAME PATHNAMES &OPTIONAL
TOPDIR--whereby all pathnames will be interpolated relative to topdir.

Implementation of SYS:UNZIP to unpack ZIP/JAR files.

JAR files always use '/' to name hierarchial entries. Pathname
translates '/' --> '\' under isPlatformWindows for all hierarchy
*except* reference to jar entries.

Pathname URL constructor under Windows to properly parses the
drive letter.

Ensure that *EXT:LISP-HOME* contains a directory.

Removed unused imports.

Converted Primitives to stack-trace friendly form where we touched the
source extensively anyways.

Location:
trunk/abcl
Files:
4 added
1 deleted
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/Autoload.java

    r12414 r12422  
    668668        autoload(PACKAGE_SYS, "single-float-bits", "FloatFunctions", true);
    669669        autoload(PACKAGE_SYS, "std-allocate-instance", "StandardObjectFunctions", true);
     670        autoload(PACKAGE_SYS, "unzip", "unzip", true);
    670671        autoload(PACKAGE_SYS, "zip", "zip", true);
    671672
  • trunk/abcl/src/org/armedbear/lisp/AutoloadedFunctionProxy.java

    r12381 r12422  
    247247    }
    248248
    249     // ### proxy-preloaded-function
    250     final private static Primitive PROXY_PRELOADED_FUNCTION
    251         = new Primitive("proxy-preloaded-function", PACKAGE_SYS, false,
    252                         "symbol name")
    253     {
    254       @Override
    255       final public LispObject execute(LispObject symbol, LispObject name) {
    256         LispThread thread = LispThread.currentThread();
    257         Symbol sym;
    258         Function fun;
    259         FunctionType fType = FunctionType.NORMAL;
    260 
    261         if (symbol instanceof Symbol)
    262             sym = (Symbol)symbol;
    263         else if (isValidSetfFunctionName(symbol)) {
    264             sym = (Symbol)symbol.cadr();
    265             fType = FunctionType.SETF;
    266         } else if (isValidMacroFunctionName(symbol)) {
    267             sym = (Symbol)symbol.cadr();
    268             fType = FunctionType.MACRO;
    269         } else {
    270             checkSymbol(symbol); // generate an error
    271             return null; // not reached
    272         }
    273 
    274         LispObject cache = AUTOLOADING_CACHE.symbolValue(thread);
    275         if (cache instanceof Nil)
    276             // during EVAL-WHEN :compile-toplevel, this function will
    277             // be called without a caching environment; we'll need to
    278             // forward to the compiled function loader
    279             return loadCompiledFunction(name.getStringValue());
    280         else {
    281             LispObject[] cachedSyms = new LispObject[symsToSave.length];
    282             for (int i = 0; i < symsToSave.length; i++)
    283                 cachedSyms[i] = symsToSave[i].symbolValue(thread);
    284 
    285             fun = new AutoloadedFunctionProxy(sym, name, cache,
    286                                               cachedSyms, fType);
    287             fun.setClassBytes((byte[])((Hashtable)cache.javaInstance())
    288                               .get(name.getStringValue()));
    289         }
    290 
    291         return fun;
    292       }
    293    };
    294 
    295   //  ### function-preload
    296   final private static Primitive FUNCTION_PRELOAD
    297     = new Primitive("function-preload", PACKAGE_SYS, false, "name")
    298   {
    299     @SuppressWarnings("unchecked")
    300     @Override
    301     final public LispObject execute(LispObject name) {
    302       String namestring = name.getStringValue();
    303       LispThread thread = LispThread.currentThread();
    304       Hashtable cache
    305           = (Hashtable)AUTOLOADING_CACHE.symbolValue(thread).javaInstance();
    306 
    307       byte[] bytes = readFunctionBytes(namestring);
    308       cache.put(namestring, bytes);
    309 
    310       return T;
    311     }
    312   };
    313 
     249    // ### proxy-preloaded-function symbol name => function
     250    final private static Primitive PROXY_PRELOADED_FUNCTION = new proxy_preloaded_function();
     251    final private static class proxy_preloaded_function extends Primitive {
     252        proxy_preloaded_function() {
     253            super("proxy-preloaded-function", PACKAGE_SYS, false,
     254                  "symbol name");
     255        }
     256        @Override
     257        final public LispObject execute(LispObject symbol, LispObject name) {
     258            LispThread thread = LispThread.currentThread();
     259            Symbol sym;
     260            Function fun;
     261            FunctionType fType = FunctionType.NORMAL;
     262
     263            if (symbol instanceof Symbol)
     264                sym = (Symbol)symbol;
     265            else if (isValidSetfFunctionName(symbol)) {
     266                sym = (Symbol)symbol.cadr();
     267                fType = FunctionType.SETF;
     268            } else if (isValidMacroFunctionName(symbol)) {
     269                sym = (Symbol)symbol.cadr();
     270                fType = FunctionType.MACRO;
     271            } else {
     272                checkSymbol(symbol); // generate an error
     273                return null; // not reached
     274            }
     275
     276            LispObject cache = AUTOLOADING_CACHE.symbolValue(thread);
     277            if (cache instanceof Nil)
     278                // during EVAL-WHEN :compile-toplevel, this function will
     279                // be called without a caching environment; we'll need to
     280                // forward to the compiled function loader
     281                return loadCompiledFunction(name.getStringValue());
     282            else {
     283                LispObject[] cachedSyms = new LispObject[symsToSave.length];
     284                for (int i = 0; i < symsToSave.length; i++)
     285                    cachedSyms[i] = symsToSave[i].symbolValue(thread);
     286
     287                fun = new AutoloadedFunctionProxy(sym, name, cache,
     288                                                  cachedSyms, fType);
     289                fun.setClassBytes((byte[])((Hashtable)cache.javaInstance())
     290                                  .get(name.getStringValue()));
     291            }
     292            return fun;
     293        }
     294    }
     295
     296    //  ### function-preload name => success
     297    final private static Primitive FUNCTION_PRELOAD = new function_preload();
     298    private static class function_preload extends Primitive {
     299        function_preload() {
     300            super("function-preload", PACKAGE_SYS, false, "name");
     301        }
     302        @SuppressWarnings("unchecked")
     303        @Override
     304        final public LispObject execute(LispObject name) {
     305            String namestring = name.getStringValue();
     306            LispThread thread = LispThread.currentThread();
     307            Hashtable cache
     308                = (Hashtable)AUTOLOADING_CACHE.symbolValue(thread).javaInstance();
     309
     310            Pathname pathname = new Pathname(namestring);
     311            byte[] bytes = readFunctionBytes(pathname);
     312            cache.put(namestring, bytes);
     313           
     314            return T;
     315        }
     316    }
    314317}
  • trunk/abcl/src/org/armedbear/lisp/FileStream.java

    r12362 r12422  
    281281        {
    282282            final Pathname pathname;
    283             if(first instanceof Pathname) {
     283            if (first instanceof Pathname) {
    284284                pathname = (Pathname) first;
    285285            }
     
    287287                return type_error(first, Symbol.PATHNAME);
    288288            }
     289            if (pathname.isJar()) {
     290                error(new FileError("Direct stream input/output on entries in JAR files no currently supported.",
     291                                    pathname));
     292            }
     293
    289294            final LispObject namestring = checkString(second);
    290295            LispObject elementType = third;
  • trunk/abcl/src/org/armedbear/lisp/Interpreter.java

    r12362 r12422  
    286286                        if (arg.equals("--load"))
    287287                            Load.load(new Pathname(args[i + 1]),
    288                                       args[i + 1],
    289288                                      false, false, true);
     289
    290290                        else
    291291                            Load.loadSystemFile(args[i + 1]);
  • trunk/abcl/src/org/armedbear/lisp/Lisp.java

    r12392 r12422  
    12021202  }
    12031203
     1204    @Deprecated
    12041205  public static final LispObject loadCompiledFunction(final String namestring)
    1205 
    1206   {
    1207       byte[] bytes = readFunctionBytes(namestring);
     1206  {
     1207      Pathname name = new Pathname(namestring);
     1208      byte[] bytes = readFunctionBytes(name);
    12081209      if (bytes != null)
    12091210        return loadClassBytes(bytes);
     
    12121213  }
    12131214
    1214   public static final byte[] readFunctionBytes(final String namestring)
    1215   {
    1216     final LispThread thread = LispThread.currentThread();
    1217     final boolean absolute = Utilities.isFilenameAbsolute(namestring);
    1218     LispObject device = NIL;
    1219     final Pathname defaultPathname;
    1220     if (absolute)
    1221       {
    1222         defaultPathname =
    1223           coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue(thread));
    1224       }
    1225     else
    1226       {
    1227         LispObject loadTruename = Symbol.LOAD_TRUENAME.symbolValue(thread);
    1228         if (loadTruename instanceof Pathname)
    1229           {
    1230             defaultPathname = (Pathname) loadTruename;
    1231             // We're loading a file.
    1232             device = ((Pathname)loadTruename).getDevice();
    1233           }
    1234         else
    1235           {
    1236             defaultPathname =
    1237               coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue(thread));
    1238           }
    1239       }
    1240     if (device instanceof Pathname) { //Loading from a jar
    1241   URL url = null;
    1242   String jar = ((Pathname)device).getNamestring();
    1243   if(jar.startsWith("jar:")) {
    1244       try {
    1245     url = new URL(jar + "!/" + namestring);
    1246       } catch (MalformedURLException ex) {
    1247     Debug.trace(ex);
    1248       }
    1249   } else {
    1250       url = Lisp.class.getResource(namestring);
    1251   }
    1252         if (url != null) {
    1253             try {
    1254     InputStream input = null;   
    1255     java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
    1256     try {
    1257         input = url.openStream();               
    1258         byte[] bytes = new byte[4096];
    1259         int n = 0;
    1260         while (n >= 0) {
    1261       n = input.read(bytes, 0, 4096);
    1262       if(n >= 0) {
    1263           baos.write(bytes, 0, n);
    1264       }
    1265         }
    1266         bytes = baos.toByteArray();
    1267         return bytes;
    1268     } finally {
    1269         baos.close();
    1270         if(input != null) {
    1271       input.close();
    1272         }
    1273     }
    1274       } catch (IOException e) {
    1275                 Debug.trace(e);
    1276       }
    1277   }
    1278         error(new LispError("Unable to load " + namestring));
    1279         return null; // not reached
    1280     }
    1281     Pathname pathname = new Pathname(namestring);
    1282     final File file = Utilities.getFile(pathname, defaultPathname);
    1283     if (file != null && file.isFile())
    1284       {
    1285         // The .cls file exists.
    1286         try
    1287           {
    1288             byte[] bytes = readFunctionBytes(new FileInputStream(file),
    1289                                              (int) file.length());
    1290             // FIXME close stream!
    1291             if (bytes != null)
    1292               return bytes;
    1293           }
    1294         catch (FileNotFoundException fnf) {
    1295             error(new LispError("Unable to load " + pathname.writeToString()
    1296                                 + ": " + fnf.getMessage()));
    1297             return null; // not reached
    1298         }
    1299         return null; // not reached
    1300       }
    1301     try
    1302       {
    1303         LispObject loadTruename = Symbol.LOAD_TRUENAME.symbolValue(thread);
    1304         String zipFileName = ((Pathname)loadTruename).getNamestring();
    1305         ZipFile zipFile = ZipCache.getZip(zipFileName);
    1306         try
    1307           {
    1308             ZipEntry entry = zipFile.getEntry(namestring);
    1309             if (entry != null)
    1310               {
    1311                 byte[] bytes = readFunctionBytes(zipFile.getInputStream(entry),
    1312                                                  (int) entry.getSize());
    1313                 if (bytes != null)
    1314                   return bytes;
    1315                 Debug.trace("Unable to load " + namestring);
    1316                 error(new LispError("Unable to load " + namestring));
    1317                 return null; // not reached
    1318               }
    1319           }
    1320         finally
    1321           {
    1322             ZipCache.removeZip(zipFile.getName());
    1323           }
    1324       }
    1325     catch (IOException t)
    1326       {
    1327         Debug.trace(t);
    1328       }
    1329     error(new FileError("File not found: " + namestring,
    1330                         new Pathname(namestring)));
    1331     return null; // not reached
     1215  public static final byte[] readFunctionBytes(final Pathname name) {
     1216      final LispThread thread = LispThread.currentThread();
     1217      Pathname load = null;
     1218      LispObject truenameFasl = Symbol.LOAD_TRUENAME_FASL.symbolValue(thread);
     1219      LispObject truename = Symbol.LOAD_TRUENAME.symbolValue(thread);
     1220      Pathname fasl = null;
     1221      if (truenameFasl instanceof Pathname) {
     1222          load = Pathname.mergePathnames(name, (Pathname)truenameFasl, Keyword.NEWEST);
     1223      } else if (truename instanceof Pathname) {
     1224          load = Pathname.mergePathnames(name, (Pathname) truename, Keyword.NEWEST);
     1225      } else {
     1226          load = name;
     1227      }
     1228      InputStream input = load.getInputStream();
     1229      byte[] bytes = new byte[4096];
     1230      try {
     1231          if (input == null) {
     1232              Debug.trace("Pathname: " + name);
     1233              Debug.trace("LOAD_TRUENAME_FASL: " + truenameFasl);
     1234              Debug.trace("LOAD_TRUENAME: " + truename);
     1235              Debug.assertTrue(input != null);
     1236          }
     1237
     1238          int n = 0;
     1239          java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
     1240          try {
     1241              while (n >= 0) {
     1242                  n = input.read(bytes, 0, 4096);
     1243                if (n >= 0) {
     1244                    baos.write(bytes, 0, n);
     1245                }
     1246            }
     1247          } catch (IOException e) {
     1248              Debug.trace("Failed to read bytes from "
     1249                          + "'" + name.getNamestring() + "'");
     1250              return null;
     1251          }
     1252          bytes = baos.toByteArray();
     1253      } finally {
     1254          try {
     1255              input.close();
     1256          } catch (IOException e) {
     1257              Debug.trace("Failed to close InputStream: " + e);
     1258          }
     1259      }
     1260      return bytes;
    13321261  }
    13331262
     
    23962325    Symbol.LOAD_PATHNAME.initializeSpecial(NIL);
    23972326    Symbol.LOAD_TRUENAME.initializeSpecial(NIL);
     2327    Symbol.LOAD_TRUENAME_FASL.initializeSpecial(NIL);
    23982328    Symbol.COMPILE_VERBOSE.initializeSpecial(T);
    23992329    Symbol.COMPILE_PRINT.initializeSpecial(T);
  • trunk/abcl/src/org/armedbear/lisp/Load.java

    r12362 r12422  
    3636import static org.armedbear.lisp.Lisp.*;
    3737
    38 import java.io.ByteArrayInputStream;
    39 import java.io.ByteArrayOutputStream;
    40 import java.io.File;
    41 import java.io.FileInputStream;
    42 import java.io.FileNotFoundException;
    4338import java.io.IOException;
    4439import java.io.InputStream;
    4540import java.net.URL;
    46 import java.net.URLDecoder;
    47 import java.util.Hashtable;
    48 import java.util.zip.ZipEntry;
    49 import java.util.zip.ZipException;
    50 import java.util.zip.ZipFile;
    51 import java.util.zip.ZipInputStream;
    5241
    5342/* This file holds ABCL's (FASL and non-FASL) loading behaviours.
     
    6251 *   from the special variable and continues loading from there.
    6352 *
    64  *   Note: In order to prevent re-opening the ZIP file again and again,
    65  *    ABCL keeps a cache of opened zip files, which are retrieved to load
    66  *    .cls (compiled-function files) from the ZIP while loading the main
    67  *    ._ file with FASL loading instructions.
    6853 */
    69 
    7054public final class Load
    7155{
    7256    public static final LispObject load(String filename)
    73 
    7457    {
    7558        final LispThread thread = LispThread.currentThread();
    7659        return load(new Pathname(filename),
    77                     filename,
    7860                    Symbol.LOAD_VERBOSE.symbolValue(thread) != NIL,
    7961                    Symbol.LOAD_PRINT.symbolValue(thread) != NIL,
    8062                    true);
    8163    }
    82 
    83     private static final File findLoadableFile(final String filename,
    84                                                final String dir)
    85     {
    86         File file = new File(dir, filename);
    87         if (!file.isFile()) {
    88             String extension = getExtension(filename);
    89             if (extension == null) {
    90                 // No extension specified. Try appending ".lisp" or ".abcl".
    91                 File lispFile = new File(dir, filename.concat(".lisp"));
    92                 File abclFile = new File(dir, filename.concat(".abcl"));
    93                 if (lispFile.isFile() && abclFile.isFile()) {
    94                     if (abclFile.lastModified() > lispFile.lastModified()) {
    95                         return abclFile;
    96                     } else {
    97                         return lispFile;
    98                     }
    99                 } else if (abclFile.isFile()) {
    100                     return abclFile;
    101                 } else if (lispFile.isFile()) {
    102                     return lispFile;
    103                 }
    104             }
    105         } else
    106             return file; // the file exists
    107         return null; // this is the error case: the file does not exist
    108                      // no need to check again at the caller
     64 
     65    /** @return Pathname of loadable file based on NAME, or null if
     66     * none can be determined. */
     67    private static final Pathname findLoadableFile(Pathname name) {
     68        LispObject truename  = Pathname.truename(name, false);
     69        if (truename instanceof Pathname) {
     70            Pathname t = (Pathname)truename;
     71            if (t.name != NIL
     72                && t.name != null) {
     73                return t;
     74            }
     75        }
     76        if (name.type == NIL
     77            && (name.name != NIL || name.name != null)) {
     78            Pathname lispPathname = new Pathname(name);
     79            lispPathname.type = new SimpleString("lisp");
     80            lispPathname.invalidateNamestring();
     81            LispObject lisp = Pathname.truename(lispPathname, false);
     82            Pathname abclPathname = new Pathname(name);
     83            abclPathname.type = new SimpleString("abcl");
     84            abclPathname.invalidateNamestring();
     85            LispObject abcl = Pathname.truename(abclPathname, false);
     86            if (lisp instanceof Pathname && abcl instanceof Pathname) {
     87                lispPathname = (Pathname)lisp;
     88                abclPathname = (Pathname)abcl;
     89                long lispLastModified = lispPathname.getLastModified();
     90                long abclLastModified = abclPathname.getLastModified();
     91              if (abclLastModified > lispLastModified) {
     92                  return lispPathname;
     93              } else {
     94                  return abclPathname;
     95              }
     96            } else if (abcl instanceof Pathname) {
     97                return (Pathname) abcl;
     98            } else if (lisp instanceof Pathname) {
     99                return (Pathname) lisp;
     100            }
     101        }
     102        if (name.isJar()) {
     103            if (name.type.equals(NIL)) {
     104                name.type = COMPILE_FILE_INIT_FASL_TYPE;
     105                name.invalidateNamestring();
     106                Pathname result = findLoadableFile(name);
     107                if (result != null) {
     108                    return result;
     109                }
     110                name.type = new SimpleString(COMPILE_FILE_TYPE);
     111                name.invalidateNamestring();
     112                result = findLoadableFile(name);
     113                if (result != null) {
     114                    return result;
     115                }
     116            }
     117        }
     118        return null;
    109119    }
    110120 
    111121    public static final LispObject load(Pathname pathname,
    112                                         String filename,
    113122                                        boolean verbose,
    114123                                        boolean print,
    115124                                        boolean ifDoesNotExist)
    116125    {
    117         return load(pathname, filename, verbose, print, ifDoesNotExist, false);
    118     }
    119 
    120     public static final LispObject load(Pathname pathname,
    121                                         String filename,
     126        return load(pathname, verbose, print, ifDoesNotExist, false);
     127    }
     128
     129    public static final LispObject load(final Pathname pathname,
    122130                                        boolean verbose,
    123131                                        boolean print,
     
    126134
    127135    {
    128         String dir = null;
    129         if (!Utilities.isFilenameAbsolute(filename)) {
    130             dir = coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS
    131                                    .symbolValue()).getNamestring();
    132         }
    133 
    134         String zipFileName = null;
    135         String zipEntryName = null;
    136         if (filename.startsWith("jar:file:")) {
    137             String s = new String(filename);
    138             s = s.substring(9);
    139             int index = s.lastIndexOf('!');
    140             if (index >= 0) {
    141                 zipFileName = s.substring(0, index);
    142                 zipEntryName = s.substring(index + 1);
    143                 if (zipEntryName.length() > 0 && zipEntryName.charAt(0) == '/')
    144                     zipEntryName = zipEntryName.substring(1);
    145                 if (Utilities.isPlatformWindows) {
    146                     if (zipFileName.length() > 0 && zipFileName.charAt(0) == '/')
    147                         zipFileName = zipFileName.substring(1);
    148                 }
    149             }
    150         }
    151 
    152         File file = findLoadableFile(filename, dir);
    153         if (null == file && null == zipFileName) {
    154             if (ifDoesNotExist)
    155                 return error(new FileError("File not found: " + filename, pathname));
    156             else
     136        Pathname mergedPathname = null;
     137        if (!pathname.isAbsolute() && !pathname.isJar()) {
     138            Pathname pathnameDefaults
     139                = coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue());
     140            mergedPathname = Pathname.mergePathnames(pathname, pathnameDefaults);
     141        }
     142
     143        Pathname truename = findLoadableFile(mergedPathname != null ? mergedPathname : pathname);
     144
     145        if (truename == null || truename.equals(NIL)) {
     146            if (ifDoesNotExist) {
     147                return error(new FileError("File not found: " + pathname));
     148            } else {
     149                Debug.trace("Failed to load " + pathname.getNamestring());
    157150                return NIL;
    158         }
    159 
    160         if (checkZipFile(file)) {
    161             // Either we are loading a packed FASL (i.e. ZIP with suffix ".abcl")
    162             // Or we are loading from a JAR archive
    163             if (".abcl".equals(getExtension(file.getPath()))) {
    164                 // So we adjust the value passed to
    165                 // loadFileFromStream() to get any further loading
    166                 // within this invocation of LOAD to work properly.
    167                 filename = file.getPath();
    168             }
    169             zipFileName = file.getPath();
    170             zipEntryName = file.getName();
    171         }
     151            }
     152        }
     153
     154        if (truename.type.getStringValue().equals(COMPILE_FILE_TYPE)
     155            && Utilities.checkZipFile(truename))
     156            {
     157                String n = truename.getNamestring();
     158                if (n.startsWith("jar:")) {
     159                    n = "jar:" + n + "!/" + truename.name.getStringValue() + "."
     160                      + COMPILE_FILE_INIT_FASL_TYPE;
     161                } else {
     162                    n = "jar:file:" + n + "!/" + truename.name.getStringValue() + "."
     163                      + COMPILE_FILE_INIT_FASL_TYPE;
     164                }
     165                mergedPathname = new Pathname(n);
     166                LispObject initTruename = Pathname.truename(mergedPathname);
     167                if (initTruename == null || initTruename.equals(NIL)) {
     168                    String errorMessage
     169                        = "Loadable FASL not found for"
     170                          + "'" + pathname + "'"
     171                          + " in "
     172                          + "'" + mergedPathname + "'";
     173                    if (ifDoesNotExist) {
     174                        return error(new FileError(errorMessage, mergedPathname));
     175                    } else {
     176                        Debug.trace(errorMessage);
     177                        return NIL;
     178                    }
     179                }
     180                truename = (Pathname)initTruename;
     181            }
    172182       
    173         String truename = filename;
    174         ZipFile zipfile = null;
    175 
    176         boolean packedFASL = false;
    177 
    178         InputStream in = null;
    179         if (zipFileName != null) {
    180             try {
    181                 zipfile = ZipCache.getZip(zipFileName);
    182             }
    183             catch (IOException e) {
    184                 return error (new FileError("Zip file not found: " + filename, pathname));
    185             }
    186             ZipEntry entry = zipfile.getEntry(zipEntryName);
    187             if (null == entry) {
    188                 // try appending "._" to base filename
    189                 int index = zipEntryName.lastIndexOf('.');
    190                 if (-1 == index) index = zipEntryName.length();
    191                 zipEntryName = zipEntryName.substring(0, index).concat("._");
    192                 entry = zipfile.getEntry(zipEntryName);
    193             }
    194             if (null == entry) {
    195                 // try appending ".abcl" to base filename
    196                 int index = zipEntryName.lastIndexOf('.');
    197                 if (index == -1)
    198                   index = zipEntryName.length();
    199                 zipEntryName = zipEntryName.substring(0, index).concat(".abcl");
    200                 entry = zipfile.getEntry(zipEntryName);
    201                 if (entry != null)
    202                   packedFASL = true;
    203             }
    204             if (null == entry) {
    205                 // Try looking for ".lisp"
    206                 int i = zipEntryName.lastIndexOf('.');
    207                 if (i == -1) {
    208                     i = zipEntryName.length();
    209                 }
    210                 zipEntryName = zipEntryName.substring(0, i).concat(".lisp");
    211                 entry = zipfile.getEntry(zipEntryName);
    212                 if (entry == null) {
    213                   return error(new LispError("Failed to find " + zipEntryName + " in "
    214                                              + zipFileName + "."));
    215                 }
    216             }
    217 
    218             if (null == entry) {
    219                 return error(new FileError("Can't find zip file entry "
    220                                            + zipEntryName, pathname));
    221             }
    222             if (".abcl".equals(getExtension(zipEntryName))) {
    223                 packedFASL = true;
    224             }
    225             if (packedFASL) {
    226                 // If we are loading a packed FASL from the JAR we
    227                 // have to decompress it first, and seek for the '._'
    228                 // init FASL.
    229                 int i = zipEntryName.lastIndexOf('.');
    230     int j = zipEntryName.lastIndexOf('/');
    231     if(j >= i) {
    232         return error(new LispError("Invalid zip entry name: " + zipEntryName));
    233     }
    234                 String subZipEntryName = zipEntryName.substring(j + 1, i).concat("._");
    235                 in = Utilities.getZippedZipEntryAsInputStream(zipfile,
    236                                                               zipEntryName,
    237                                                               subZipEntryName);
    238             } else {
    239                 try {
    240                     in = zipfile.getInputStream(entry);
    241                 }
    242                 catch (IOException e) {
    243                     return error(new LispError(e.getMessage()));
    244                 }
    245             }
    246         } else {
    247             try {
    248                 in = new FileInputStream(file);
    249                 truename = file.getCanonicalPath();
    250             }
    251             catch (FileNotFoundException e) {
    252                 if (ifDoesNotExist)
    253                     return error(new FileError("File not found: " + filename,
    254                                                 pathname));
    255                 else
    256                     return NIL;
    257             }
    258             catch (IOException e) {
    259                 return error(new LispError(e.getMessage()));
    260             }
    261         }
     183        InputStream in = truename.getInputStream();
     184        Debug.assertTrue(in != null);
     185   
    262186        try {
    263 
    264           return loadFileFromStream(null, truename,
    265                                     new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER),
    266                                     verbose, print, false, returnLastResult);
     187            return loadFileFromStream(pathname, truename,
     188                                      new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER),
     189                                      verbose, print, false, returnLastResult);
    267190        }
    268191        catch (FaslVersionMismatch e) {
     
    276199                try {
    277200                   in.close();
    278                 }
    279                 catch (IOException e) {
    280                     return error(new LispError(e.getMessage()));
    281                 }
    282             }
    283             if (zipfile != null) {
    284                 try {
    285                     ZipCache.removeZip(zipfile.getName());
    286201                }
    287202                catch (IOException e) {
     
    328243    }
    329244
     245    static final LispObject COMPILE_FILE_INIT_FASL_TYPE = new SimpleString("_");
     246
    330247    public static final LispObject loadSystemFile(final String filename,
    331248                                                  boolean verbose,
     
    334251
    335252    {
    336         final int ARRAY_SIZE = 2;
    337         String[] candidates = new String[ARRAY_SIZE];
    338         final String extension = getExtension(filename);
    339         if (extension == null) {
    340             // No extension specified.
    341             candidates[0] = filename + '.' + COMPILE_FILE_TYPE;
    342             candidates[1] = filename.concat(".lisp");
    343         } else if (extension.equals(".abcl")) {
    344             candidates[0] = filename;
    345             candidates[1] =
    346                 filename.substring(0, filename.length() - 5).concat(".lisp");
    347         } else
    348             candidates[0] = filename;
    349253        InputStream in = null;
    350254        Pathname pathname = null;
    351         String truename = null;
    352         for (int i = 0; i < ARRAY_SIZE; i++) {
    353             String s = candidates[i];
    354             if (s == null)
    355                 break;
    356             ZipFile zipfile = null;
    357             final String dir = Site.getLispHome();
     255        Pathname truename = null;
     256        pathname = new Pathname(filename);
     257        Pathname mergedPathname = Pathname.mergePathnames(pathname, Site.getLispHome());
     258        truename = findLoadableFile(mergedPathname);
     259        if (truename == null || truename.equals(NIL)) {
     260            // Make an attempt to use the boot classpath
     261            String path = pathname.asEntryPath();
     262            URL url = Lisp.class.getResource(path);
     263            if (url == null || url.toString().endsWith("/")) {
     264                url = Lisp.class.getResource(path + ".abcl");
     265                if (url == null) {
     266                    url = Lisp.class.getResource(path + ".lisp");
     267                }
     268            }
     269            if (url == null) {
     270                return error(new LispError("Failed to find loadable system file "
     271                                           + "'" + path + "'"
     272                                           + " in boot classpath."));
     273            }               
     274            Pathname urlPathname = new Pathname(url);
     275            truename = findLoadableFile(urlPathname);
     276            if (truename == null) {
     277                return error(new LispError("Failed to find loadable system file in boot classpath "
     278                                           + "'" + url + "'"));
     279            }
     280        }
     281
     282        // Look for a init FASL inside a packed FASL
     283        if (truename.type.writeToString().equals(COMPILE_FILE_TYPE) && Utilities.checkZipFile(truename))  {
     284            Pathname init = new Pathname(truename.getNamestring());
     285            init.type = COMPILE_FILE_INIT_FASL_TYPE;
     286            LispObject t = Pathname.truename(init);
     287            if (t instanceof Pathname) {
     288                truename = (Pathname)t;
     289            } else {
     290                return error (new LispError("Failed to find loadable init FASL in "
     291                                            + "'" + init.getNamestring() + "'"));
     292            }
     293        }
     294
     295        in = truename.getInputStream();
     296
     297        if (in != null) {
     298            final LispThread thread = LispThread.currentThread();
     299            final SpecialBindingsMark mark = thread.markSpecialBindings();
     300            thread.bindSpecial(_WARN_ON_REDEFINITION_, NIL);
    358301            try {
    359                 if (dir != null) {
    360                     File file = new File(dir, s);
    361                     if (file.isFile()) {
    362                         // File exists. For system files, we know the extension
    363                         // will be .abcl if it is a compiled file.
    364                         String ext = getExtension(s);
    365                         if (ext.equalsIgnoreCase(".abcl")) {
    366                             try {
    367                                 zipfile = ZipCache.getZip(file.getPath());
    368                                 String name = file.getName();
    369                                 int index = name.lastIndexOf('.');
    370                                 Debug.assertTrue(index >= 0);
    371                                 name = name.substring(0, index).concat("._");
    372                                 ZipEntry entry = zipfile.getEntry(name);
    373                                 if (entry != null) {
    374                                     in = zipfile.getInputStream(entry);
    375                                     truename = file.getCanonicalPath();
    376                                 }
    377                             }
    378                             catch (ZipException e) {
    379                                 // Fall through.
    380                             }
    381                             catch (IOException e) {
    382                                 // fall through
    383                             }
    384                         }
    385                         if (in == null) {
    386                             try {
    387                                 in = new FileInputStream(file);
    388                                 truename = file.getCanonicalPath();
    389                             }
    390                             catch (IOException e) {
    391                                 in = null;
    392                             }
    393                         }
    394                     }
    395                 } else {
    396                     URL url = Lisp.class.getResource(s);
    397                     if (url != null) {
    398                         try {
    399                             in = url.openStream();
    400                             if ("jar".equals(url.getProtocol()) &&
    401         url.getPath().startsWith("file:"))
    402                                 pathname = new Pathname(url);
    403                             truename = getPath(url);
    404                         }
    405                         catch (IOException e) {
    406                             in = null;
    407                         }
    408                     }
    409                 }
    410                 if (in != null) {
    411                     final LispThread thread = LispThread.currentThread();
    412                     final SpecialBindingsMark mark = thread.markSpecialBindings();
    413                     thread.bindSpecial(_WARN_ON_REDEFINITION_, NIL);
    414                     try {
    415                         return loadFileFromStream(pathname, truename,
    416                                                   new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER),
    417                                                   verbose, print, auto);
    418                     }
    419                     catch (FaslVersionMismatch e) {
    420                         FastStringBuffer sb =
    421                             new FastStringBuffer("; Incorrect fasl version: ");
    422                         sb.append(truename);
    423                         System.err.println(sb.toString());
    424                     }
    425                     finally {
    426                         thread.resetSpecialBindings(mark);
    427                         try {
    428                             in.close();
    429                         }
    430                         catch (IOException e) {
    431                             return error(new LispError(e.getMessage()));
    432                         }
    433                     }
    434                 }
    435             }
    436             finally {
    437                 if (zipfile != null) {
    438                     try {
    439                         ZipCache.removeZip(zipfile.getName());
    440                     }
    441                     catch (IOException e) {
    442                         return error(new LispError(e.getMessage()));
    443                     }
    444                 }
    445             }
    446         }
    447         return error(new LispError("File not found: " + filename));
     302                Stream stream = new Stream(Symbol.SYSTEM_STREAM, in, Symbol.CHARACTER);
     303                return loadFileFromStream(pathname, truename, stream,
     304                                          verbose, print, auto);
     305            } catch (FaslVersionMismatch e) {
     306                FastStringBuffer sb =
     307                    new FastStringBuffer("; Incorrect fasl version: ");
     308                sb.append(truename);
     309                System.err.println(sb.toString());
     310            } finally {
     311                thread.resetSpecialBindings(mark);
     312                try {
     313                    in.close();
     314                }
     315                catch (IOException e) {
     316                    return error(new LispError(e.getMessage()));
     317                }
     318            }
     319        }
     320        return error(new FileError("Failed to load system file: "
     321                                   + "'" + filename + "'"
     322                                   + " resolved as "
     323                                   + "'" + mergedPathname + "'" ,
     324                                   truename));
    448325    }
    449326
     
    469346        internSpecial("*FASL-ANONYMOUS-PACKAGE*", PACKAGE_SYS, NIL);
    470347
    471     // ### init-fasl
    472     private static final Primitive INIT_FASL =
    473         new Primitive("init-fasl", PACKAGE_SYS, true, "&key version")
    474     {
     348    // ### init-fasl &key version
     349    private static final Primitive INIT_FASL = new init_fasl();
     350    private static class init_fasl extends Primitive {
     351        init_fasl() {
     352            super("init-fasl", PACKAGE_SYS, true, "&key version");
     353        }
    475354        @Override
    476355        public LispObject execute(LispObject first, LispObject second)
     
    488367            throw new FaslVersionMismatch(second);
    489368        }
    490     };
    491 
    492     private static final LispObject loadFileFromStream(LispObject pathname,
    493                                                        String truename,
     369    }
     370
     371    private static final LispObject loadFileFromStream(Pathname pathname,
     372                                                       Pathname truename,
    494373                                                       Stream in,
    495374                                                       boolean verbose,
     
    500379    }
    501380
     381    // A nil TRUENAME signals a load from stream which has no possible path
    502382    private static final LispObject loadFileFromStream(LispObject pathname,
    503                                                        String truename,
     383                                                       LispObject truename,
    504384                                                       Stream in,
    505385                                                       boolean verbose,
     
    526406        final String prefix = getLoadVerbosePrefix(loadDepth);
    527407        try {
    528             if (pathname == null && truename != null)
    529                 pathname = Pathname.parseNamestring(truename);
    530             thread.bindSpecial(Symbol.LOAD_PATHNAME,
    531                                pathname != null ? pathname : NIL);
    532             thread.bindSpecial(Symbol.LOAD_TRUENAME,
    533                                pathname != null ? pathname : NIL);
     408            thread.bindSpecial(Symbol.LOAD_PATHNAME, pathname);
     409            Pathname truePathname = new Pathname(((Pathname)truename).getNamestring());
     410            String type = truePathname.type.getStringValue();
     411            if (type.equals(COMPILE_FILE_TYPE)
     412                || type.equals(COMPILE_FILE_INIT_FASL_TYPE.toString())) {
     413                thread.bindSpecial(Symbol.LOAD_TRUENAME_FASL, truePathname);
     414            }
     415            if (truePathname.type.getStringValue().equals(COMPILE_FILE_INIT_FASL_TYPE.getStringValue())
     416                && truePathname.isJar()) {
     417                if (truePathname.device.cdr() != NIL ) {
     418                    // set truename to the enclosing JAR
     419                    truePathname.host = NIL;
     420                    truePathname.directory = NIL;
     421                    truePathname.name = NIL;
     422                    truePathname.type = NIL;
     423                    truePathname.invalidateNamestring();
     424                } else {
     425                    // XXX There is something fishy in the asymmetry
     426                    // between the "jar:jar:http:" and "jar:jar:file:"
     427                    // cases but this currently passes the tests.
     428                    if (!(truePathname.device.car() instanceof AbstractString)) {
     429                         truePathname = (Pathname)truePathname.device.car();
     430                         truePathname.invalidateNamestring();
     431                    }
     432               }
     433                thread.bindSpecial(Symbol.LOAD_TRUENAME, truePathname);
     434            } else {
     435                thread.bindSpecial(Symbol.LOAD_TRUENAME, truename);
     436            }
    534437            thread.bindSpecial(_SOURCE_,
    535438                               pathname != null ? pathname : NIL);
     
    539442                out._writeString(prefix);
    540443                out._writeString(auto ? " Autoloading " : " Loading ");
    541                 out._writeString(truename != null ? truename : "stream");
     444                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
    542445                out._writeLine(" ...");
    543446                out._finishOutput();
     
    547450                out._writeString(prefix);
    548451                out._writeString(auto ? " Autoloaded " : " Loaded ");
    549                 out._writeString(truename != null ? truename : "stream");
     452                out._writeString(!truename.equals(NIL) ? truePathname.writeToString() : "stream");
    550453                out._writeString(" (");
    551454                out._writeString(String.valueOf(((float)elapsed)/1000));
     
    611514
    612515    private static final LispObject faslLoadStream(LispThread thread)
    613 
    614516    {
    615517        Stream in = (Stream) _LOAD_STREAM_.symbolValue(thread);
     
    639541    }
    640542
    641     // Returns extension including leading '.'
    642     private static final String getExtension(String filename)
    643     {
    644         int index = filename.lastIndexOf('.');
    645         if (index < 0)
    646             return null;
    647         if (index < filename.lastIndexOf(File.separatorChar))
    648             return null; // Last dot was in path part of filename.
    649         return filename.substring(index);
    650     }
    651 
    652     private static final String getPath(URL url)
    653     {
    654         if (url != null) {
    655             String path;
    656             try {
    657                 path = URLDecoder.decode(url.getPath(),"UTF-8");
    658             }
    659             catch (java.io.UnsupportedEncodingException uee) {
    660                 // Can't happen: every Java is supposed to support
    661                 // at least UTF-8 encoding
    662                 path = null;
    663             }
    664             if (path != null) {
    665                 if (Utilities.isPlatformWindows) {
    666                     if (path.length() > 0 && path.charAt(0) == '/')
    667                         path = path.substring(1);
    668                 }
    669                 return path;
    670             }
    671         }
    672         return null;
    673     }
    674 
    675     private static final boolean checkZipFile(File file)
    676     {
    677         InputStream in = null;
    678         try {
    679             in = new FileInputStream(file);
    680             byte[] bytes = new byte[4];
    681             int bytesRead = in.read(bytes);
    682             return (bytesRead == 4
    683                     && bytes[0] == 0x50
    684                     && bytes[1] == 0x4b
    685                     && bytes[2] == 0x03
    686                     && bytes[3] == 0x04);
    687         }
    688         catch (Throwable t) { // any error probably means 'no'
    689             return false;
    690         }
    691         finally {
    692             if (in != null) {
    693                 try {
    694                     in.close();
    695                 }
    696                 catch (IOException e) {} // ignore exceptions
    697             }
    698         }
    699     }
    700543
    701544    // ### %load filespec verbose print if-does-not-exist => generalized-boolean
    702     private static final Primitive _LOAD =
    703         new Primitive("%load", PACKAGE_SYS, false,
    704                       "filespec verbose print if-does-not-exist")
    705     {
     545    private static final Primitive _LOAD = new _load();
     546    private static class _load extends Primitive {
     547        _load() {
     548            super("%load", PACKAGE_SYS, false,
     549                  "filespec verbose print if-does-not-exist");
     550        }
    706551        @Override
    707552        public LispObject execute(LispObject filespec, LispObject verbose,
    708553                                  LispObject print, LispObject ifDoesNotExist)
    709             {
     554        {
    710555            return load(filespec, verbose, print, ifDoesNotExist, NIL);
    711556        }
    712     };
     557    }
    713558
    714559    // ### %load-returning-last-result filespec verbose print if-does-not-exist => object
    715     private static final Primitive _LOAD_RETURNING_LAST_RESULT =
    716         new Primitive("%load-returning-last-result", PACKAGE_SYS, false,
    717                       "filespec verbose print if-does-not-exist")
    718     {
     560    private static final Primitive _LOAD_RETURNING_LAST_RESULT = new _load_returning_last_result();
     561    private static class _load_returning_last_result extends Primitive {
     562        _load_returning_last_result() {
     563            super("%load-returning-last-result", PACKAGE_SYS, false,
     564                  "filespec verbose print if-does-not-exist");
     565        }
    719566        @Override
    720567        public LispObject execute(LispObject filespec, LispObject verbose,
     
    723570            return load(filespec, verbose, print, ifDoesNotExist, T);
    724571        }
    725     };
     572    }
    726573
    727574    private static final LispObject load(LispObject filespec,
     
    738585                else
    739586                    pathname = NIL;
    740                 String truename;
     587                LispObject truename;
    741588                if (pathname instanceof Pathname)
    742                     truename = ((Pathname)pathname).getNamestring();
     589                    truename = pathname;
    743590                else
    744                     truename = null;
     591                    truename = NIL;
    745592                return loadFileFromStream(pathname,
    746593                                          truename,
     
    757604            pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
    758605        return load(pathname,
    759                     pathname.getNamestring(),
    760606                    verbose != NIL,
    761607                    print != NIL,
     
    765611
    766612    // ### load-system-file
    767     private static final Primitive LOAD_SYSTEM_FILE =
    768         new Primitive("load-system-file", PACKAGE_SYS, true)
    769     {
     613    private static final Primitive LOAD_SYSTEM_FILE = new load_system_file();
     614    private static class load_system_file extends Primitive {
     615        load_system_file () {
     616            super("load-system-file", PACKAGE_SYS, true);
     617        }
    770618        @Override
    771619        public LispObject execute(LispObject arg)
     
    777625                                  false);
    778626        }
    779     };
     627    }
    780628
    781629    private static class FaslVersionMismatch extends Error
  • trunk/abcl/src/org/armedbear/lisp/LogicalPathname.java

    r12288 r12422  
    4646    private static final HashMap map = new HashMap();
    4747
    48     public LogicalPathname()
    49     {
     48    protected LogicalPathname()
     49    {
     50    }
     51
     52    protected LogicalPathname(Pathname p) {
     53        super(p);
    5054    }
    5155
     
    279283
    280284    // ### canonicalize-logical-host host => canonical-host
    281     private static final Primitive CANONICALIZE_LOGICAL_HOST =
    282         new Primitive("canonicalize-logical-host", PACKAGE_SYS, true, "host")
    283     {
     285    private static final Primitive CANONICALIZE_LOGICAL_HOST = new canonicalize_logical_host();
     286    private static class canonicalize_logical_host extends Primitive {
     287        canonicalize_logical_host() {
     288            super("canonicalize-logical-host", PACKAGE_SYS, true, "host");
     289        }
    284290        @Override
    285291        public LispObject execute(LispObject arg)
    286 
    287292        {
    288                 AbstractString s = checkString(arg);
    289                 if (s.length() == 0) {
    290                     // "The null string, "", is not a valid value for any
    291                     // component of a logical pathname." 19.3.2.2
    292                     return error(new LispError("Invalid logical host name: \"" +
    293                                                 s.getStringValue() + '"'));
    294                 }
    295                 return canonicalizeStringComponent(s);
    296         }
    297     };
     293            AbstractString s = checkString(arg);
     294            if (s.length() == 0) {
     295                // "The null string, "", is not a valid value for any
     296                // component of a logical pathname." 19.3.2.2
     297                return error(new LispError("Invalid logical host name: \"" +
     298                                           s.getStringValue() + '"'));
     299            }
     300            return canonicalizeStringComponent(s);
     301        }
     302    }
    298303
    299304    // ### %make-logical-pathname namestring => logical-pathname
    300     private static final Primitive _MAKE_LOGICAL_PATHNAME =
    301         new Primitive("%make-logical-pathname", PACKAGE_SYS, true, "namestring")
    302     {
     305    private static final Primitive _MAKE_LOGICAL_PATHNAME = new _make_logical_pathname();
     306    private static class _make_logical_pathname extends Primitive {
     307        _make_logical_pathname() {
     308            super("%make-logical-pathname", PACKAGE_SYS, true, "namestring");
     309        }
    303310        @Override
    304311        public LispObject execute(LispObject arg)
     
    322329            return error(new TypeError("Logical namestring does not specify a host: \"" + s + '"'));
    323330        }
    324     };
     331    }
    325332}
  • trunk/abcl/src/org/armedbear/lisp/Pathname.java

    r12298 r12422  
    3131 * exception statement from your version.
    3232 */
    33 
    3433package org.armedbear.lisp;
    3534
     
    3837import java.io.File;
    3938import java.io.IOException;
     39import java.io.InputStream;
     40import java.io.FileInputStream;
     41import java.net.JarURLConnection;
     42import java.net.MalformedURLException;
    4043import java.net.URL;
     44import java.net.URLConnection;
    4145import java.net.URLDecoder;
    4246import java.util.StringTokenizer;
    43 
    44 public class Pathname extends LispObject
    45 {
     47import java.util.jar.JarEntry;
     48import java.util.jar.JarFile;
     49import java.util.zip.ZipEntry;
     50import java.util.zip.ZipInputStream;
     51
     52public class Pathname extends LispObject {
     53
    4654    protected LispObject host = NIL;
    4755    protected LispObject device = NIL;
    4856    protected LispObject directory = NIL;
    4957    protected LispObject name = NIL;
    50 
    5158    // A string, NIL, :WILD or :UNSPECIFIC.
    5259    protected LispObject type = NIL;
    53 
    5460    // A positive integer, or NIL, :WILD, :UNSPECIFIC, or :NEWEST.
    5561    protected LispObject version = NIL;
     
    5763    private String namestring;
    5864
    59     protected Pathname()
    60     {
    61     }
    62 
    63     public Pathname(String s)
    64     {
     65    /** The protocol for changing any instance field (i.e. 'host', 'type', etc.)
     66     *  is to call this method after changing the field to recompute the namestring.
     67     *  We could do this with setter/getters, but that choose not to in order to avoid the
     68     *  performance indirection penalty.
     69     */
     70    public void invalidateNamestring() {
     71        namestring = null;
     72    }
     73
     74    protected Pathname() {}
     75
     76    /** Copy constructor which shares no structure with the original. */
     77    protected Pathname(Pathname p) {
     78        if (p.host != NIL) {
     79            if (p.host instanceof SimpleString) {
     80                host = new SimpleString(((SimpleString)p.host).getStringValue());
     81            } else  if (p.host instanceof Symbol) {
     82                host = p.host;
     83            } else {
     84                Debug.assertTrue(false);
     85            }
     86        }
     87        if (p.device != NIL) {
     88            if (p.device instanceof SimpleString) {
     89                device = new SimpleString(((SimpleString)p.device).getStringValue());
     90            } else if (p.device instanceof Cons) {
     91                Cons jars = (Cons)p.device;
     92                device = new Cons(NIL, NIL);
     93                LispObject first = jars.car();
     94                if (first instanceof SimpleString) {
     95                    ((Cons)device).car = new SimpleString(((SimpleString)first).getStringValue());
     96                } else if (first instanceof Pathname) {
     97                    ((Cons)device).car = new Pathname((Pathname)first);
     98                } else {
     99                    Debug.assertTrue(false);
     100                }
     101                if (!jars.cdr().equals(NIL)) {
     102                    if (jars.cdr() instanceof Cons) {
     103                        ((Cons)device).cdr = new Cons(new Pathname((Pathname)jars.cdr().car()), NIL);
     104                    } else {
     105                        Debug.assertTrue(false);
     106                    }
     107                }
     108            } else if (p.device instanceof Symbol) {
     109                device = p.device;
     110            } else {
     111                Debug.assertTrue(false);
     112            }               
     113        }
     114        if (p.directory != NIL) {
     115            if (p.directory instanceof Cons) {
     116                directory = NIL;
     117                for (LispObject list = p.directory; list != NIL; list = list.cdr()) {
     118                    LispObject o = list.car();
     119                    if (o instanceof Symbol) {
     120                        directory = directory.push(o);
     121                    } else if (o instanceof SimpleString) {
     122                        directory = directory.push(new SimpleString(((SimpleString)o).getStringValue()));
     123                    } else {
     124                        Debug.assertTrue(false);
     125                    }
     126                }
     127                directory.nreverse();
     128            } else {
     129                Debug.assertTrue(false);
     130            }
     131        }
     132        if (p.name != NIL) {
     133            if (p.name instanceof SimpleString) {
     134                name = new SimpleString(((SimpleString)p.name).getStringValue());
     135            } else if (p.name instanceof Symbol) {
     136                name = p.name;
     137            } else {
     138                Debug.assertTrue(false);
     139            }
     140        }
     141        if (p.type != NIL) {
     142            if (p.type instanceof SimpleString) {
     143                type = new SimpleString(((SimpleString)p.type).getStringValue());
     144            } else if (p.type instanceof Symbol) {
     145                type = p.type;
     146            } else {
     147                Debug.assertTrue(false);
     148            }
     149        }
     150    }
     151
     152    public Pathname(String s) {
    65153        init(s);
    66154    }
    67155
    68     public Pathname(URL url)
    69     {
     156    public Pathname(URL url) {
    70157        String protocol = url.getProtocol();
    71158        if ("jar".equals(protocol)) {
     159            init(url.toString());
     160            return;
     161        } else if ("file".equals(protocol)) {
    72162            String s;
    73163            try {
    74                 s = URLDecoder.decode(url.getPath(),"UTF-8");
    75             }
    76             catch (java.io.UnsupportedEncodingException uee) {
     164                s = URLDecoder.decode(url.getPath(), "UTF-8");
     165            } catch (java.io.UnsupportedEncodingException uee) {
    77166                // Can't happen: every Java is supposed to support
    78167                // at least UTF-8 encoding
     168                Debug.assertTrue(false);
    79169                s = null;
    80170            }
    81             if (s.startsWith("file:")) {
    82                 int index = s.indexOf("!/");
    83                 String container = s.substring(5, index);
    84                 if (Utilities.isPlatformWindows) {
    85                     if (container.length() > 0 && container.charAt(0) == '/')
    86                         container = container.substring(1);
    87                 }
    88                 device = new Pathname(container);
    89                 s = s.substring(index + 1);
    90                 Pathname p = new Pathname(s);
     171            if (s != null) {
     172    if (Utilities.isPlatformWindows) {
     173        //  Workaround for Java's idea of URLs
     174        //  new (URL"file:///c:/a/b").getPath() --> "/c:/a/b"
     175                    //  whereas we need "c" to be the DEVICE.
     176        if (s.length() > 2
     177      && s.charAt(0) == '/'
     178      && s.charAt(2) == ':') {
     179      s = s.substring(1);
     180        }
     181    }
     182                init(s);
     183                return;
     184            }
     185        }
     186        error(new LispError("Unsupported URL: '" + url.toString() + "'"));
     187    }
     188
     189    static final private String jarSeparator = "!/";
     190    private final void init(String s) {
     191        if (s == null) {
     192            return;
     193        }
     194        if (s.equals(".") || s.equals("./")
     195          || (Utilities.isPlatformWindows && s.equals(".\\"))) {
     196            directory = new Cons(Keyword.RELATIVE);
     197            return;
     198        }
     199        if (s.equals("..") || s.equals("../")) {
     200            directory = list(Keyword.RELATIVE, Keyword.UP);
     201            return;
     202        }
     203        if (Utilities.isPlatformWindows) {
     204            if (s.startsWith("\\\\")) {
     205                //UNC path support
     206                // match \\<server>\<share>\[directories-and-files]
     207
     208                int shareIndex = s.indexOf('\\', 2);
     209                int dirIndex = s.indexOf('\\', shareIndex + 1);
     210
     211                if (shareIndex == -1 || dirIndex == -1) {
     212                    error(new LispError("Unsupported UNC path format: \"" + s + '"'));
     213                }
     214
     215                host = new SimpleString(s.substring(2, shareIndex));
     216                device = new SimpleString(s.substring(shareIndex + 1, dirIndex));
     217
     218                Pathname p = new Pathname(s.substring(dirIndex));
    91219                directory = p.directory;
    92220                name = p.name;
    93221                type = p.type;
     222                version = p.version;
    94223                return;
    95224            }
    96         } else if ("file".equals(protocol)) {
    97             String s;
    98             try {
    99                 s = URLDecoder.decode(url.getPath(),"UTF-8");
    100             }
    101             catch (java.io.UnsupportedEncodingException uee) {
    102                 // Can't happen: every Java is supposed to support
    103                 // at least UTF-8 encoding
    104                 s = null;
    105             }
    106             if (s != null && s.startsWith("file:")) {
    107                 init(s.substring(5));
    108                 return;
    109             }
    110         }
    111         error(new LispError("Unsupported URL: \"" + url.toString() + '"'));
    112     }
    113 
    114     private final void init(String s)
    115     {
    116         if (s == null)
     225        }
     226
     227        // A JAR file
     228        if (s.startsWith("jar:") && s.endsWith(jarSeparator)) {
     229            LispObject jars = NIL;
     230            int i = s.lastIndexOf(jarSeparator, s.length() - jarSeparator.length() - 1);
     231            String jar = null;
     232            if (i == -1) {
     233                jar = s;
     234            } else {
     235                // There can be no more than two jar references and the
     236                // inner one must be a file reference within the outer.
     237                jar = "jar:file:" + s.substring(i + jarSeparator.length());
     238                s = s.substring("jar:".length(), i + jarSeparator.length());
     239                Pathname p = new Pathname(s);
     240                LispObject first = ((Cons) p.device).car();
     241                if (first instanceof AbstractString) {
     242                    jars = jars.push(first);
     243                } else {
     244                    jars = jars.push(p.device.car());
     245                }
     246            }
     247            if (jar.startsWith("jar:file:")) {
     248                String jarString = jar.substring("jar:".length(),
     249                  jar.length() - jarSeparator.length());
     250                // Use URL constructor to normalize Windows' use of device
     251                URL url = null;
     252                try {
     253                    url = new URL(jarString);
     254                } catch (MalformedURLException e) {
     255                    error(new LispError("Failed to parse '" + jarString + "'"
     256                            + " as URL:"
     257                            + e.getMessage()));
     258                }
     259                Pathname jarPathname = new Pathname(url);
     260                if (jarString.endsWith(jarSeparator)) {
     261                    jars = jars.push(jarPathname.device);
     262                } else {
     263                    jars = jars.push(jarPathname);
     264                }
     265            } else {
     266                URL url = null;
     267                try {
     268                    url = new URL(jar.substring("jar:".length(), jar.length() - 2));
     269                    jars = jars.push(new SimpleString(url.toString()));
     270                } catch (MalformedURLException e) {
     271                    error(new LispError("Failed to parse url '" + url + "'"
     272                      + e.getMessage()));
     273                }
     274            }
     275            jars = jars.nreverse();
     276            device = jars;
    117277            return;
    118         if (s.equals(".") || s.equals("./") ||
    119             (Utilities.isPlatformWindows && s.equals(".\\"))) {
    120             directory = new Cons(Keyword.RELATIVE);
     278        }
     279
     280        // An entry in a JAR file
     281        final int separatorIndex = s.lastIndexOf(jarSeparator);
     282        if (separatorIndex > 0 && s.startsWith("jar:")) {
     283            final String jarURL = s.substring(0, separatorIndex + jarSeparator.length());
     284            Pathname d = new Pathname(jarURL);
     285            if (device instanceof Cons) {
     286                LispObject[] jars = d.copyToArray();
     287                //  XXX Is this ever reached?  If so, need to append lists
     288                Debug.assertTrue(false);
     289            } else {
     290                device = d.device;
     291            }
     292            s = s.substring(separatorIndex + jarSeparator.length());
     293            Pathname p = new Pathname(s);
     294            directory = p.directory;
     295            name = p.name;
     296            type = p.type;
     297            version = p.version;
    121298            return;
    122299        }
    123         if (s.equals("..") || s.equals("../")) {
    124             directory = list(Keyword.RELATIVE, Keyword.UP);
    125             return;
    126         }
     300
    127301        if (Utilities.isPlatformWindows) {
    128             if (s.startsWith("\\\\")) {
    129                //UNC path support
    130                // match \\<server>\<share>\[directories-and-files]
    131 
    132                int shareIndex = s.indexOf('\\', 2);
    133                int dirIndex = s.indexOf('\\', shareIndex + 1);
    134 
    135                if (shareIndex == -1 || dirIndex == -1)
    136                   error(new LispError("Unsupported UNC path format: \"" + s + '"'));
    137 
    138                host = new SimpleString(s.substring(2, shareIndex));
    139                device = new SimpleString(s.substring(shareIndex + 1, dirIndex));
    140 
    141                Pathname p = new Pathname(s.substring(dirIndex));
    142                directory = p.directory;
    143                name = p.name;
    144                type = p.type;
    145                version = p.version;
    146                return;
    147             }
    148 
    149             s = s.replace('/', '\\');
    150         }
    151         // Jar file support.
    152         int bang = s.indexOf("!/");
    153         if (bang >= 0) {
    154             Pathname container = new Pathname(s.substring(0, bang));
    155             LispObject containerType = container.type;
    156             if (containerType instanceof AbstractString) {
    157                 if (containerType.getStringValue().equalsIgnoreCase("jar")) {
    158                     device = container;
    159                     s = s.substring(bang + 1);
    160                     Pathname p = new Pathname(s);
    161                     directory = p.directory;
    162                     name = p.name;
    163                     type = p.type;
    164                     return;
    165                 }
    166             }
    167         }
     302            if (!s.contains(jarSeparator)) {
     303                s = s.replace("/", "\\");
     304            } else {
     305              StringBuilder result = new StringBuilder();
     306              for (int i = 0; i < s.length(); i++) {
     307                  char c = s.charAt(i);
     308                  if ( c != '/') {
     309                      result.append(c);
     310                  } else {
     311                      if (i != 0 && s.charAt(i-1) != '!') {
     312                          result.append("\\");
     313                      } else {
     314                          result.append(c);
     315                      }
     316                  }
     317              }
     318              s = result.toString();
     319            }
     320        }
     321
     322        // Expand user home directories
    168323        if (Utilities.isPlatformUnix) {
    169             if (s.equals("~"))
     324            if (s.equals("~")) {
    170325                s = System.getProperty("user.home").concat("/");
    171             else if (s.startsWith("~/"))
     326            } else if (s.startsWith("~/")) {
    172327                s = System.getProperty("user.home").concat(s.substring(1));
     328            }
    173329        }
    174330        namestring = s;
     
    216372            n = s.substring(0, index);
    217373            t = s.substring(index + 1);
    218         } else if (s.length() > 0)
     374        } else if (s.length() > 0) {
    219375            n = s;
     376        }
    220377        if (n != null) {
    221             if (n.equals("*"))
     378            if (n.equals("*")) {
    222379                name = Keyword.WILD;
    223             else
     380            } else {
    224381                name = new SimpleString(n);
     382            }
    225383        }
    226384        if (t != null) {
    227             if (t.equals("*"))
     385            if (t.equals("*")) {
    228386                type = Keyword.WILD;
    229             else
     387            } else {
    230388                type = new SimpleString(t);
    231         }
    232     }
    233 
    234     private static final LispObject parseDirectory(String d)
    235 
    236     {
    237         if (d.equals("/") || (Utilities.isPlatformWindows && d.equals("\\")))
     389            }
     390        }
     391    }
     392
     393    private static final LispObject parseDirectory(String d) {
     394        if (d.equals("/") || (Utilities.isPlatformWindows && d.equals("\\"))) {
    238395            return new Cons(Keyword.ABSOLUTE);
     396        }
    239397        LispObject result;
    240         if (d.startsWith("/") || (Utilities.isPlatformWindows && d.startsWith("\\")))
     398        if (d.startsWith("/") || (Utilities.isPlatformWindows && d.startsWith("\\"))) {
    241399            result = new Cons(Keyword.ABSOLUTE);
    242         else
     400        } else {
    243401            result = new Cons(Keyword.RELATIVE);
     402        }
    244403        StringTokenizer st = new StringTokenizer(d, "/\\");
    245404        while (st.hasMoreTokens()) {
    246405            String token = st.nextToken();
    247406            LispObject obj;
    248             if (token.equals("*"))
     407            if (token.equals("*")) {
    249408                obj = Keyword.WILD;
    250             else if (token.equals("**"))
     409            } else if (token.equals("**")) {
    251410                obj = Keyword.WILD_INFERIORS;
    252             else if (token.equals("..")) {
     411            } else if (token.equals("..")) {
    253412                if (result.car() instanceof AbstractString) {
    254413                    result = result.cdr();
    255414                    continue;
    256415                }
    257                 obj= Keyword.UP;
    258             } else
     416                obj = Keyword.UP;
     417            } else {
    259418                obj = new SimpleString(token);
     419            }
    260420            result = new Cons(obj, result);
    261421        }
     
    264424
    265425    @Override
    266     public LispObject getParts()
    267     {
     426    public LispObject getParts() {
    268427        LispObject parts = NIL;
    269428        parts = parts.push(new Cons("HOST", host));
     
    277436
    278437    @Override
    279     public LispObject typeOf()
    280     {
     438    public LispObject typeOf() {
    281439        return Symbol.PATHNAME;
    282440    }
    283441
    284442    @Override
    285     public LispObject classOf()
    286     {
     443    public LispObject classOf() {
    287444        return BuiltInClass.PATHNAME;
    288445    }
    289446
    290447    @Override
    291     public LispObject typep(LispObject type)
    292     {
    293         if (type == Symbol.PATHNAME)
     448    public LispObject typep(LispObject type) {
     449        if (type == Symbol.PATHNAME) {
    294450            return T;
    295         if (type == BuiltInClass.PATHNAME)
     451        }
     452        if (type == BuiltInClass.PATHNAME) {
    296453            return T;
     454        }
    297455        return super.typep(type);
    298456    }
    299457
    300     public final LispObject getDevice()
    301     {
     458    public final LispObject getDevice() {
    302459        return device;
    303460    }
    304461
    305     public String getNamestring()
    306     {
    307         if (namestring != null)
     462    public String getNamestring() {
     463        if (namestring != null) {
    308464            return namestring;
     465        }
    309466        if (name == NIL && type != NIL) {
    310467            Debug.assertTrue(namestring == null);
    311468            return null;
    312469        }
    313         if (directory instanceof AbstractString)
     470        if (directory instanceof AbstractString) {
    314471            Debug.assertTrue(false);
     472        }
    315473        FastStringBuffer sb = new FastStringBuffer();
    316474        // "If a pathname is converted to a namestring, the symbols NIL and
     
    320478        if (host != NIL) {
    321479            Debug.assertTrue(host instanceof AbstractString);
    322             if (! (this instanceof LogicalPathname))
    323                sb.append("\\\\"); //UNC file support; if there's a host, it's a UNC path.
     480            if (!(this instanceof LogicalPathname)) {
     481                sb.append("\\\\"); //UNC file support; if there's a host, it's a UNC path.
     482            }
    324483            sb.append(host.getStringValue());
    325             if (this instanceof LogicalPathname)
    326               sb.append(':');
    327             else
    328               sb.append(File.separatorChar);
     484            if (this instanceof LogicalPathname) {
     485                sb.append(':');
     486            } else {
     487                sb.append(File.separatorChar);
     488            }
    329489        }
    330490        if (device == NIL) {
    331491        } else if (device == Keyword.UNSPECIFIC) {
     492        } else if (device instanceof Cons) {
     493            LispObject[] jars = ((Cons) device).copyToArray();
     494            int i = 0;
     495            if (jars[0] instanceof AbstractString) {
     496                sb.append("jar:");
     497                sb.append(((AbstractString) jars[0]).getStringValue());
     498                sb.append("!/");
     499                i = 1;
     500            }
     501            FastStringBuffer prefix = new FastStringBuffer();
     502            for (; i < jars.length; i++) {
     503                prefix.append("jar:");
     504                if (i == 0) {
     505                    sb.append("file:");
     506                }
     507                if (jars[i] instanceof Pathname) {
     508                    sb.append(((Pathname) jars[i]).getNamestring());
     509                }
     510                sb.append("!/");
     511            }
     512            sb = prefix.append(sb);
     513        } else if (device instanceof AbstractString
     514          && device.getStringValue().startsWith("jar:")) {
     515            sb.append(device.getStringValue());
    332516        } else if (device instanceof AbstractString) {
    333517            sb.append(device.getStringValue());
    334518            if (this instanceof LogicalPathname
    335                 || host == NIL)
    336               sb.append(':'); // non-UNC paths
    337         } else if (device instanceof Pathname) {
    338             sb.append(((Pathname)device).getNamestring());
    339             sb.append("!");
    340         } else
     519              || host == NIL) {
     520                sb.append(':'); // non-UNC paths
     521            }
     522        } else {
    341523            Debug.assertTrue(false);
     524        }
    342525        sb.append(getDirectoryNamestring());
    343526        if (name instanceof AbstractString) {
     
    348531            }
    349532            sb.append(n);
    350         } else if (name == Keyword.WILD)
     533        } else if (name == Keyword.WILD) {
    351534            sb.append('*');
     535        }
    352536        if (type != NIL) {
    353537            sb.append('.');
     
    359543                }
    360544                sb.append(t);
    361             } else if (type == Keyword.WILD)
     545            } else if (type == Keyword.WILD) {
    362546                sb.append('*');
    363             else
     547            } else {
    364548                Debug.assertTrue(false);
     549            }
    365550        }
    366551        if (this instanceof LogicalPathname) {
     
    368553                sb.append('.');
    369554                int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue());
    370                 if (version instanceof Fixnum)
    371                     sb.append(Integer.toString(((Fixnum)version).value, base).toUpperCase());
    372                 else if (version instanceof Bignum)
    373                     sb.append(((Bignum)version).value.toString(base).toUpperCase());
     555                if (version instanceof Fixnum) {
     556                    sb.append(Integer.toString(((Fixnum) version).value, base).toUpperCase());
     557                } else if (version instanceof Bignum) {
     558                    sb.append(((Bignum) version).value.toString(base).toUpperCase());
     559                }
    374560            } else if (version == Keyword.WILD) {
    375561                sb.append(".*");
     
    381567    }
    382568
    383     protected String getDirectoryNamestring()
    384     {
     569    protected String getDirectoryNamestring() {
    385570        validateDirectory(true);
    386571        FastStringBuffer sb = new FastStringBuffer();
     
    391576        if (directory != NIL) {
    392577            final char separatorChar;
    393             if (device instanceof Pathname)
     578            if (device instanceof Cons) {
    394579                separatorChar = '/'; // Jar file.
    395             else
     580            } else {
    396581                separatorChar = File.separatorChar;
     582            }
    397583            LispObject temp = directory;
    398584            LispObject part = temp.car();
     
    408594                // else: Nothing to do.
    409595            } else {
    410                 error(new FileError("Unsupported directory component " +
    411                                     part.writeToString() + ".",
    412                                     this));
     596                error(new FileError("Unsupported directory component "
     597                  + part.writeToString() + ".",
     598                  this));
    413599            }
    414600            while (temp != NIL) {
    415601                part = temp.car();
    416                 if (part instanceof AbstractString)
     602                if (part instanceof AbstractString) {
    417603                    sb.append(part.getStringValue());
    418                 else if (part == Keyword.WILD)
     604                } else if (part == Keyword.WILD) {
    419605                    sb.append('*');
    420                 else if (part == Keyword.WILD_INFERIORS)
     606                } else if (part == Keyword.WILD_INFERIORS) {
    421607                    sb.append("**");
    422                 else if (part == Keyword.UP)
     608                } else if (part == Keyword.UP) {
    423609                    sb.append("..");
    424                 else
     610                } else {
    425611                    error(new FileError("Unsupported directory component " + part.writeToString() + ".",
    426                                         this));
     612                      this));
     613                }
    427614                sb.append(separatorChar);
    428615                temp = temp.cdr();
     
    432619    }
    433620
     621    /** @return The representation of this pathname suitable for referencing an entry in a Zip/JAR file */
     622    protected String asEntryPath() {
     623        Pathname p = new Pathname();
     624        p.directory = directory;
     625        p.name = name;
     626        p.type = type;
     627        String path = p.getNamestring();
     628        if (Utilities.isPlatformWindows) {
     629      StringBuilder result = new StringBuilder();
     630      for (int i = 0; i < path.length(); i++) {
     631    char c = path.charAt(i);
     632    if (c == '\\') {
     633        result.append('/');
     634    } else {
     635        result.append(c);
     636    }
     637      }
     638      return result.toString();
     639        }
     640        return path;
     641    }
     642
    434643    @Override
    435     public boolean equal(LispObject obj)
    436     {
    437         if (this == obj)
     644    public boolean equal(LispObject obj) {
     645        if (this == obj) {
    438646            return true;
     647        }
    439648        if (obj instanceof Pathname) {
    440649            Pathname p = (Pathname) obj;
    441650            if (Utilities.isPlatformWindows) {
    442                 if (!host.equalp(p.host))
     651                if (!host.equalp(p.host)) {
    443652                    return false;
    444                 if (!device.equalp(p.device))
     653                }
     654                if (!device.equalp(p.device)) {
    445655                    return false;
    446                 if (!directory.equalp(p.directory))
     656                }
     657                if (!directory.equalp(p.directory)) {
    447658                    return false;
    448                 if (!name.equalp(p.name))
     659                }
     660                if (!name.equalp(p.name)) {
    449661                    return false;
    450                 if (!type.equalp(p.type))
     662                }
     663                if (!type.equalp(p.type)) {
    451664                    return false;
     665                }
    452666                // Ignore version component.
    453667                //if (!version.equalp(p.version))
     
    455669            } else {
    456670                // Unix.
    457                 if (!host.equal(p.host))
     671                if (!host.equal(p.host)) {
    458672                    return false;
    459                 if (!device.equal(p.device))
     673                }
     674                if (!device.equal(p.device)) {
    460675                    return false;
    461                 if (!directory.equal(p.directory))
     676                }
     677                if (!directory.equal(p.directory)) {
    462678                    return false;
    463                 if (!name.equal(p.name))
     679                }
     680                if (!name.equal(p.name)) {
    464681                    return false;
    465                 if (!type.equal(p.type))
     682                }
     683                if (!type.equal(p.type)) {
    466684                    return false;
     685                }
    467686                // Ignore version component.
    468687                //if (!version.equal(p.version))
     
    475694
    476695    @Override
    477     public boolean equalp(LispObject obj)
    478     {
     696    public boolean equalp(LispObject obj) {
    479697        return equal(obj);
    480698    }
    481699
    482700    @Override
    483     public int sxhash()
    484     {
    485         return ((host.sxhash() ^
    486                  device.sxhash() ^
    487                  directory.sxhash() ^
    488                  name.sxhash() ^
    489                  type.sxhash()) & 0x7fffffff);
     701    public int sxhash() {
     702        return ((host.sxhash()
     703          ^ device.sxhash()
     704          ^ directory.sxhash()
     705          ^ name.sxhash()
     706          ^ type.sxhash()) & 0x7fffffff);
    490707    }
    491708
    492709    @Override
    493     public String writeToString()
    494     {
     710    public String writeToString() {
    495711        final LispThread thread = LispThread.currentThread();
    496712        boolean printReadably = (Symbol.PRINT_READABLY.symbolValue(thread) != NIL);
     
    508724                } else if (name instanceof AbstractString) {
    509725                    String n = name.getStringValue();
    510                     if (n.equals(".") || n.equals(".."))
     726                    if (n.equals(".") || n.equals("..")) {
    511727                        useNamestring = false;
    512                     else if (n.indexOf(File.separatorChar) >= 0)
     728                    } else if (n.indexOf(File.separatorChar) >= 0) {
    513729                        useNamestring = false;
    514                 }
    515             }
    516         } else
    517            useNamestring = false;
     730                    }
     731                }
     732            }
     733        } else {
     734            useNamestring = false;
     735        }
    518736        FastStringBuffer sb = new FastStringBuffer();
    519737        if (useNamestring) {
    520             if (printReadably || printEscape)
     738            if (printReadably || printEscape) {
    521739                sb.append("#P\"");
     740            }
    522741            final int limit = s.length();
    523742            for (int i = 0; i < limit; i++) {
    524743                char c = s.charAt(i);
    525744                if (printReadably || printEscape) {
    526                     if (c == '\"' || c == '\\')
     745                    if (c == '\"' || c == '\\') {
    527746                        sb.append('\\');
     747                    }
    528748                }
    529749                sb.append(c);
    530750            }
    531             if (printReadably || printEscape)
     751            if (printReadably || printEscape) {
    532752                sb.append('"');
     753            }
    533754        } else {
    534755            sb.append("#P(");
     
    537758                sb.append(host.writeToString());
    538759                sb.append(' ');
    539            }
    540            if (device != NIL) {
    541                sb.append(":DEVICE ");
    542                sb.append(device.writeToString());
    543                sb.append(' ');
     760            }
     761            if (device != NIL) {
     762                sb.append(":DEVICE ");
     763                sb.append(device.writeToString());
     764                sb.append(' ');
    544765            }
    545766            if (directory != NIL) {
     
    548769                sb.append(" ");
    549770            }
    550            if (name != NIL) {
     771            if (name != NIL) {
    551772                sb.append(":NAME ");
    552773                sb.append(name.writeToString());
     
    563784                sb.append(' ');
    564785            }
    565             if (sb.charAt(sb.length() - 1) == ' ')
     786            if (sb.charAt(sb.length() - 1) == ' ') {
    566787                sb.setLength(sb.length() - 1);
     788            }
    567789            sb.append(')');
    568          }
    569          return sb.toString();
    570     }
    571 
     790        }
     791        return sb.toString();
     792    }
    572793    // A logical host is represented as the string that names it.
    573794    // (defvar *logical-pathname-translations* (make-hash-table :test 'equal))
    574795    public static EqualHashTable LOGICAL_PATHNAME_TRANSLATIONS =
    575         new EqualHashTable(64, NIL, NIL);
    576 
     796      new EqualHashTable(64, NIL, NIL);
    577797    private static final Symbol _LOGICAL_PATHNAME_TRANSLATIONS_ =
    578         exportSpecial("*LOGICAL-PATHNAME-TRANSLATIONS*", PACKAGE_SYS,
    579                       LOGICAL_PATHNAME_TRANSLATIONS);
    580 
    581     public static Pathname parseNamestring(String s)
    582 
    583     {
     798      exportSpecial("*LOGICAL-PATHNAME-TRANSLATIONS*", PACKAGE_SYS,
     799      LOGICAL_PATHNAME_TRANSLATIONS);
     800
     801    public static Pathname parseNamestring(String s) {
    584802        return new Pathname(s);
    585803    }
    586804
    587     public static Pathname parseNamestring(AbstractString namestring)
    588 
    589     {
     805    public static Pathname parseNamestring(AbstractString namestring) {
    590806        // Check for a logical pathname host.
    591807        String s = namestring.getStringValue();
     
    599815
    600816    public static Pathname parseNamestring(AbstractString namestring,
    601                                            AbstractString host)
    602 
    603     {
     817      AbstractString host) {
    604818        // Look for a logical pathname host in the namestring.
    605819        String s = namestring.getStringValue();
     
    607821        if (h != null) {
    608822            if (!h.equals(host.getStringValue())) {
    609                 error(new LispError("Host in " + s +
    610                                     " does not match requested host " +
    611                                     host.getStringValue()));
     823                error(new LispError("Host in " + s
     824                  + " does not match requested host "
     825                  + host.getStringValue()));
    612826                // Not reached.
    613827                return null;
     
    626840
    627841    // "one or more uppercase letters, digits, and hyphens"
    628     protected static String getHostString(String s)
    629     {
     842    protected static String getHostString(String s) {
    630843        int colon = s.indexOf(':');
    631         if (colon >= 0)
     844        if (colon >= 0) {
    632845            return s.substring(0, colon).toUpperCase();
    633         else
     846        } else {
    634847            return null;
    635     }
    636 
    637     private static final void checkCaseArgument(LispObject arg)
    638 
    639     {
    640         if (arg != Keyword.COMMON && arg != Keyword.LOCAL)
     848        }
     849    }
     850
     851    private static final void checkCaseArgument(LispObject arg) {
     852        if (arg != Keyword.COMMON && arg != Keyword.LOCAL) {
    641853            type_error(arg, list(Symbol.MEMBER, Keyword.COMMON,
    642                                        Keyword.LOCAL));
    643     }
    644 
     854              Keyword.LOCAL));
     855        }
     856    }
    645857    // ### %pathname-host
    646     private static final Primitive _PATHNAME_HOST =
    647         new Primitive("%pathname-host", PACKAGE_SYS, false)
    648     {
     858    private static final Primitive _PATHNAME_HOST = new _pathname_host();
     859    private static class _pathname_host extends Primitive {
     860        _pathname_host() {
     861            super("%pathname-host", PACKAGE_SYS, false);
     862        }
    649863        @Override
    650         public LispObject execute(LispObject first, LispObject second)
    651 
    652         {
     864        public LispObject execute(LispObject first, LispObject second) {
    653865            checkCaseArgument(second);
    654866            return coerceToPathname(first).host;
    655867        }
    656     };
    657 
     868    }
    658869    // ### %pathname-device
    659     private static final Primitive _PATHNAME_DEVICE =
    660         new Primitive("%pathname-device", PACKAGE_SYS, false)
    661     {
     870    private static final Primitive _PATHNAME_DEVICE = new _pathname_device();
     871    private static class _pathname_device extends Primitive {
     872        _pathname_device() {
     873            super("%pathname-device", PACKAGE_SYS, false);
     874        }
    662875        @Override
    663         public LispObject execute(LispObject first, LispObject second)
    664 
    665         {
     876        public LispObject execute(LispObject first, LispObject second) {
    666877            checkCaseArgument(second);
    667878            return coerceToPathname(first).device;
    668879        }
    669     };
    670 
     880    }
    671881    // ### %pathname-directory
    672     private static final Primitive _PATHNAME_DIRECTORY =
    673         new Primitive("%pathname-directory", PACKAGE_SYS, false)
    674     {
     882    private static final Primitive _PATHNAME_DIRECTORY = new _pathname_directory();
     883    private static class _pathname_directory extends Primitive {
     884        _pathname_directory() {
     885            super("%pathname-directory", PACKAGE_SYS, false);
     886        }
    675887        @Override
    676         public LispObject execute(LispObject first, LispObject second)
    677 
    678         {
     888        public LispObject execute(LispObject first, LispObject second) {
    679889            checkCaseArgument(second);
    680890            return coerceToPathname(first).directory;
    681891        }
    682     };
    683 
     892    }
    684893    // ### %pathname-name
    685     private static final Primitive _PATHNAME_NAME =
    686         new Primitive("%pathname-name", PACKAGE_SYS, false)
    687     {
     894    private static final Primitive _PATHNAME_NAME = new _pathname_name();
     895    private static class  _pathname_name extends Primitive {
     896        _pathname_name() {
     897            super ("%pathname-name", PACKAGE_SYS, false);
     898        }
    688899        @Override
    689         public LispObject execute(LispObject first, LispObject second)
    690 
    691         {
     900        public LispObject execute(LispObject first, LispObject second) {
    692901            checkCaseArgument(second);
    693902            return coerceToPathname(first).name;
    694903        }
    695     };
    696 
     904    }
    697905    // ### %pathname-type
    698     private static final Primitive _PATHNAME_TYPE =
    699         new Primitive("%pathname-type", PACKAGE_SYS, false)
    700     {
     906    private static final Primitive _PATHNAME_TYPE = new _pathname_type();
     907    private static class _pathname_type extends Primitive {
     908        _pathname_type() {
     909            super("%pathname-type", PACKAGE_SYS, false);
     910        }
    701911        @Override
    702         public LispObject execute(LispObject first, LispObject second)
    703 
    704         {
     912        public LispObject execute(LispObject first, LispObject second) {
    705913            checkCaseArgument(second);
    706914            return coerceToPathname(first).type;
    707915        }
    708     };
    709 
     916    }
    710917    // ### pathname-version
    711     private static final Primitive PATHNAME_VERSION =
    712         new Primitive("pathname-version", "pathname")
    713     {
     918    private static final Primitive PATHNAME_VERSION = new pathname_version();
     919    private static class pathname_version extends Primitive {
     920        pathname_version() {
     921            super("pathname-version", "pathname");
     922        }
    714923        @Override
    715         public LispObject execute(LispObject arg)
    716         {
     924        public LispObject execute(LispObject arg) {
    717925            return coerceToPathname(arg).version;
    718926        }
    719     };
    720 
     927    }
    721928    // ### namestring
    722929    // namestring pathname => namestring
    723     private static final Primitive NAMESTRING =
    724         new Primitive("namestring", "pathname")
    725     {
     930    private static final Primitive NAMESTRING = new namestring();
     931    private static class namestring extends Primitive {
     932        namestring() {
     933            super("namestring", "pathname");
     934        }
    726935        @Override
    727         public LispObject execute(LispObject arg)
    728         {
     936        public LispObject execute(LispObject arg) {
    729937            Pathname pathname = coerceToPathname(arg);
    730938            String namestring = pathname.getNamestring();
    731             if (namestring == null)
    732                 error(new SimpleError("Pathname has no namestring: " +
    733                                       pathname.writeToString()));
     939            if (namestring == null) {
     940                error(new SimpleError("Pathname has no namestring: "
     941                                      + pathname.writeToString()));
     942            }
    734943            return new SimpleString(namestring);
    735944        }
    736     };
    737 
     945    }
    738946    // ### directory-namestring
    739947    // directory-namestring pathname => namestring
    740     private static final Primitive DIRECTORY_NAMESTRING =
    741         new Primitive("directory-namestring", "pathname")
    742     {
     948    private static final Primitive DIRECTORY_NAMESTRING = new directory_namestring();
     949    private static class directory_namestring extends Primitive {
     950        directory_namestring() {
     951            super("directory-namestring", "pathname");
     952        }
    743953        @Override
    744         public LispObject execute(LispObject arg)
    745         {
     954        public LispObject execute(LispObject arg) {
    746955            return new SimpleString(coerceToPathname(arg).getDirectoryNamestring());
    747956        }
    748     };
    749 
     957    }
    750958    // ### pathname pathspec => pathname
    751     private static final Primitive PATHNAME =
    752         new Primitive("pathname", "pathspec")
    753     {
     959    private static final Primitive PATHNAME = new pathname();
     960    private static class pathname extends Primitive {
     961        pathname() {
     962            super("pathname", "pathspec");
     963        }
    754964        @Override
    755         public LispObject execute(LispObject arg)
    756         {
     965        public LispObject execute(LispObject arg) {
    757966            return coerceToPathname(arg);
    758967        }
    759     };
    760 
     968    }
    761969    // ### %parse-namestring string host default-pathname => pathname, position
    762     private static final Primitive _PARSE_NAMESTRING =
    763         new Primitive("%parse-namestring", PACKAGE_SYS, false,
    764                       "namestring host default-pathname")
    765     {
     970    private static final Primitive _PARSE_NAMESTRING = new _parse_namestring();
     971    private static class _parse_namestring extends Primitive {
     972        _parse_namestring() {
     973            super("%parse-namestring", PACKAGE_SYS, false,
     974                  "namestring host default-pathname");
     975        }
    766976        @Override
    767         public LispObject execute(LispObject first, LispObject second,
    768                                   LispObject third)
    769 
    770         {
     977        public LispObject execute(LispObject first, LispObject second, LispObject third) {
    771978            final LispThread thread = LispThread.currentThread();
    772979            final AbstractString namestring = checkString(first);
     
    779986                // of DEFAULT-PATHNAME."
    780987                third = coerceToPathname(third);
    781                 if (third instanceof LogicalPathname)
    782                     second = ((LogicalPathname)third).host;
    783                 else
     988                if (third instanceof LogicalPathname) {
     989                    second = ((LogicalPathname) third).host;
     990                } else {
    784991                    return thread.setValues(parseNamestring(namestring),
    785992                                            namestring.LENGTH());
     993                }
    786994            }
    787995            Debug.assertTrue(second != NIL);
     
    790998                                    namestring.LENGTH());
    791999        }
    792     };
    793 
     1000    }
    7941001    // ### make-pathname
    795     private static final Primitive MAKE_PATHNAME =
    796         new Primitive("make-pathname",
    797                       "&key host device directory name type version defaults case")
    798     {
     1002    private static final Primitive MAKE_PATHNAME = new make_pathname();
     1003    private static class make_pathname extends Primitive {
     1004        make_pathname() {
     1005            super("make-pathname",
     1006                  "&key host device directory name type version defaults case");
     1007        }
    7991008        @Override
    800         public LispObject execute(LispObject[] args)
    801 
    802         {
     1009        public LispObject execute(LispObject[] args) {
    8031010            return _makePathname(args);
    8041011        }
    805     };
     1012    }
    8061013
    8071014    // Used by the #p reader.
    808     public static final Pathname makePathname(LispObject args)
    809 
    810     {
     1015    public static final Pathname makePathname(LispObject args) {
    8111016        return _makePathname(args.copyToArray());
    8121017    }
    8131018
    814     private static final Pathname _makePathname(LispObject[] args)
    815 
    816     {
    817         if (args.length % 2 != 0)
     1019    public static final Pathname makePathname(File file) {
     1020        String namestring = null;
     1021        try {
     1022            namestring = file.getCanonicalPath();
     1023        } catch (IOException e) {
     1024            Debug.trace("Failed to make a Pathname from "
     1025              + "." + file + "'");
     1026            return null;
     1027        }
     1028        return new Pathname(namestring);
     1029    }
     1030
     1031    private static final Pathname _makePathname(LispObject[] args) {
     1032        if (args.length % 2 != 0) {
    8181033            error(new ProgramError("Odd number of keyword arguments."));
     1034        }
    8191035        LispObject host = NIL;
    8201036        LispObject device = NIL;
     
    8291045        for (int i = 0; i < args.length; i += 2) {
    8301046            LispObject key = args[i];
    831             LispObject value = args[i+1];
     1047            LispObject value = args[i + 1];
    8321048            if (key == Keyword.HOST) {
    8331049                host = value;
     
    8361052                deviceSupplied = true;
    8371053            } else if (key == Keyword.DIRECTORY) {
    838                 if (value instanceof AbstractString)
     1054                if (value instanceof AbstractString) {
    8391055                    directory = list(Keyword.ABSOLUTE, value);
    840                 else if (value == Keyword.WILD)
     1056                } else if (value == Keyword.WILD) {
    8411057                    directory = list(Keyword.ABSOLUTE, Keyword.WILD);
    842                 else
     1058                } else {
    8431059                    directory = value;
     1060                }
    8441061            } else if (key == Keyword.NAME) {
    8451062                name = value;
     
    8531070                defaults = coerceToPathname(value);
    8541071            } else if (key == Keyword.CASE) {
    855                   // Ignored.
     1072                // Ignored.
    8561073            }
    8571074        }
    8581075        if (defaults != null) {
    859             if (host == NIL)
     1076            if (host == NIL) {
    8601077                host = defaults.host;
     1078            }
    8611079            directory = mergeDirectories(directory, defaults.directory);
    862             if (!deviceSupplied)
     1080            if (!deviceSupplied) {
    8631081                device = defaults.device;
    864             if (!nameSupplied)
     1082            }
     1083            if (!nameSupplied) {
    8651084                name = defaults.name;
    866             if (!typeSupplied)
     1085            }
     1086            if (!typeSupplied) {
    8671087                type = defaults.type;
     1088            }
    8681089        }
    8691090        final Pathname p;
    8701091        final boolean logical;
    8711092        if (host != NIL) {
    872             if (host instanceof AbstractString)
    873                 host = LogicalPathname.canonicalizeStringComponent((AbstractString)host);
     1093            if (host instanceof AbstractString) {
     1094                host = LogicalPathname.canonicalizeStringComponent((AbstractString) host);
     1095            }
    8741096            if (LOGICAL_PATHNAME_TRANSLATIONS.get(host) == null) {
    8751097                // Not a defined logical pathname host.
     
    8871109            if (logical) {
    8881110                // "The device component of a logical pathname is always :UNSPECIFIC."
    889                 if (device != Keyword.UNSPECIFIC)
     1111                if (device != Keyword.UNSPECIFIC) {
    8901112                    error(new LispError("The device component of a logical pathname must be :UNSPECIFIC."));
    891             } else
     1113                }
     1114            } else {
    8921115                p.device = device;
     1116            }
    8931117        }
    8941118        if (directory != NIL) {
     
    8981122                    while (directory != NIL) {
    8991123                        LispObject component = directory.car();
    900                         if (component instanceof AbstractString)
    901                             d = d.push(LogicalPathname.canonicalizeStringComponent((AbstractString)component));
    902                         else
     1124                        if (component instanceof AbstractString) {
     1125                            d = d.push(LogicalPathname.canonicalizeStringComponent((AbstractString) component));
     1126                        } else {
    9031127                            d = d.push(component);
     1128                        }
    9041129                        directory = directory.cdr();
    9051130                    }
    9061131                    p.directory = d.nreverse();
    907                 } else if (directory == Keyword.WILD || directory == Keyword.WILD_INFERIORS)
     1132                } else if (directory == Keyword.WILD || directory == Keyword.WILD_INFERIORS) {
    9081133                    p.directory = directory;
    909                 else
     1134                } else {
    9101135                    error(new LispError("Invalid directory component for logical pathname: " + directory.writeToString()));
    911             } else
     1136                }
     1137            } else {
    9121138                p.directory = directory;
     1139            }
    9131140        }
    9141141        if (name != NIL) {
    915             if (logical && name instanceof AbstractString)
    916                 p.name = LogicalPathname.canonicalizeStringComponent((AbstractString)name);
    917             else if (name instanceof AbstractString)
    918                 p.name = validateStringComponent((AbstractString)name);
    919             else
     1142            if (logical && name instanceof AbstractString) {
     1143                p.name = LogicalPathname.canonicalizeStringComponent((AbstractString) name);
     1144            } else if (name instanceof AbstractString) {
     1145                p.name = validateStringComponent((AbstractString) name);
     1146            } else {
    9201147                p.name = name;
     1148            }
    9211149        }
    9221150        if (type != NIL) {
    923             if (logical && type instanceof AbstractString)
    924                 p.type = LogicalPathname.canonicalizeStringComponent((AbstractString)type);
    925             else
     1151            if (logical && type instanceof AbstractString) {
     1152                p.type = LogicalPathname.canonicalizeStringComponent((AbstractString) type);
     1153            } else {
    9261154                p.type = type;
     1155            }
    9271156        }
    9281157        p.version = version;
     
    9301159    }
    9311160
    932     private static final AbstractString validateStringComponent(AbstractString s)
    933 
    934     {
     1161    private static final AbstractString validateStringComponent(AbstractString s) {
    9351162        final int limit = s.length();
    9361163        for (int i = 0; i < limit; i++) {
    9371164            char c = s.charAt(i);
    9381165            if (c == '/' || c == '\\' && Utilities.isPlatformWindows) {
    939                 error(new LispError("Invalid character #\\" + c +
    940                                     " in pathname component \"" + s +
    941                                     '"'));
     1166                error(new LispError("Invalid character #\\" + c
     1167                  + " in pathname component \"" + s
     1168                  + '"'));
    9421169                // Not reached.
    9431170                return null;
     
    9471174    }
    9481175
    949     private final boolean validateDirectory(boolean signalError)
    950 
    951     {
     1176    private final boolean validateDirectory(boolean signalError) {
    9521177        LispObject temp = directory;
    9531178        while (temp != NIL) {
     
    9711196        return true;
    9721197    }
    973 
    9741198    // ### pathnamep
    975     private static final Primitive PATHNAMEP =
    976         new Primitive("pathnamep", "object")
    977     {
     1199    private static final Primitive PATHNAMEP = new pathnamep();
     1200    private static class pathnamep extends Primitive  {
     1201        pathnamep() {
     1202            super("pathnamep", "object");
     1203        }
    9781204        @Override
    979         public LispObject execute(LispObject arg)
    980         {
     1205        public LispObject execute(LispObject arg) {
    9811206            return arg instanceof Pathname ? T : NIL;
    9821207        }
    983     };
    984 
     1208    }
    9851209    // ### logical-pathname-p
    986     private static final Primitive LOGICAL_PATHNAME_P =
    987         new Primitive("logical-pathname-p", PACKAGE_SYS, true, "object")
    988     {
     1210    private static final Primitive LOGICAL_PATHNAME_P = new logical_pathname_p();
     1211    private static class logical_pathname_p extends Primitive {
     1212        logical_pathname_p() {
     1213            super("logical-pathname-p", PACKAGE_SYS, true, "object");
     1214        }
    9891215        @Override
    990         public LispObject execute(LispObject arg)
    991         {
     1216        public LispObject execute(LispObject arg) {
    9921217            return arg instanceof LogicalPathname ? T : NIL;
    9931218        }
    994     };
    995 
     1219    }
    9961220    // ### user-homedir-pathname &optional host => pathname
    997     private static final Primitive USER_HOMEDIR_PATHNAME =
    998         new Primitive("user-homedir-pathname", "&optional host")
    999     {
     1221    private static final Primitive USER_HOMEDIR_PATHNAME = new user_homedir_pathname();
     1222    private static class user_homedir_pathname extends Primitive {
     1223        user_homedir_pathname() {
     1224            super("user-homedir-pathname", "&optional host");
     1225        }
    10001226        @Override
    1001         public LispObject execute(LispObject[] args)
    1002         {
     1227        public LispObject execute(LispObject[] args) {
    10031228            switch (args.length) {
    1004                 case 0: {
    1005                     String s = System.getProperty("user.home");
    1006                     if (!s.endsWith(File.separator))
    1007                         s = s.concat(File.separator);
    1008                     return new Pathname(s);
    1009                 }
    1010                 case 1:
    1011                     return NIL;
    1012                 default:
    1013                     return error(new WrongNumberOfArgumentsException(this));
    1014             }
    1015         }
    1016     };
    1017 
    1018     // ### list-directory
    1019     private static final Primitive LIST_DIRECTORY =
    1020         new Primitive("list-directory", PACKAGE_SYS, true)
    1021     {
     1229            case 0: {
     1230                String s = System.getProperty("user.home");
     1231                if (!s.endsWith(File.separator)) {
     1232                    s = s.concat(File.separator);
     1233                }
     1234                return new Pathname(s);
     1235            }
     1236            case 1:
     1237                return NIL; // ??? huh? -- ME 20100206
     1238            default:
     1239                return error(new WrongNumberOfArgumentsException(this));
     1240            }
     1241        }
     1242    }
     1243    // ### list-directory directory
     1244    private static final Primitive LIST_DIRECTORY = new list_directory();
     1245    private static class list_directory extends Primitive {
     1246        list_directory() {
     1247            super("list-directory", PACKAGE_SYS, true, "directory");
     1248        }
    10221249        @Override
    1023         public LispObject execute(LispObject arg)
    1024         {
     1250        public LispObject execute(LispObject arg) {
    10251251            Pathname pathname = coerceToPathname(arg);
    1026             if (pathname instanceof LogicalPathname)
    1027                 pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
     1252            if (pathname instanceof LogicalPathname) {
     1253                pathname = LogicalPathname.translateLogicalPathname((LogicalPathname) pathname);
     1254            }
     1255            if (pathname.isJar()) {
     1256                return error(new FileError("Unimplemented directory listing of JAR files.", pathname));
     1257            }
    10281258            LispObject result = NIL;
    10291259            String s = pathname.getNamestring();
     
    10321262                if (f.isDirectory()) {
    10331263                    try {
    1034       File[] files = f.listFiles();
     1264                        File[] files = f.listFiles();
    10351265                        for (int i = files.length; i-- > 0;) {
    10361266                            File file = files[i];
    10371267                            Pathname p;
    1038                             if (file.isDirectory())
     1268                            if (file.isDirectory()) {
    10391269                                p = Utilities.getDirectoryPathname(file);
    1040                             else
     1270                            } else {
    10411271                                p = new Pathname(file.getCanonicalPath());
     1272                            }
    10421273                            result = new Cons(p, result);
    10431274                        }
    1044                     }
    1045                     catch (IOException e) {
     1275                    } catch (IOException e) {
    10461276                        return error(new FileError("Unable to list directory " + pathname.writeToString() + ".",
    10471277                                                   pathname));
     1278                    } catch (SecurityException e) {
     1279                        Debug.trace(e);
     1280                    } catch (NullPointerException e) {
     1281                        Debug.trace(e);
    10481282                    }
    1049                     catch (SecurityException e) {
    1050                     }
    1051                     catch (NullPointerException e) {
    1052                     }
    10531283                }
    10541284            }
    10551285            return result;
    10561286        }
    1057     };
    1058 
    1059     public boolean isWild()
    1060     {
    1061         if (host == Keyword.WILD || host == Keyword.WILD_INFERIORS)
     1287    }
     1288
     1289    public boolean isAbsolute()  {
     1290        if (!directory.equals(NIL) || !(directory == null)) {
     1291            if (directory instanceof Cons) {
     1292                if (((Cons)directory).car().equals(Keyword.ABSOLUTE)) {
     1293                    return true;
     1294                }
     1295            }
     1296        }
     1297        return false;
     1298    }
     1299
     1300    // ### PATHNAME-JAR-P
     1301    private static final Primitive PATHNAME_JAR_P = new pathname_jar_p();
     1302    private static class pathname_jar_p extends Primitive {
     1303        pathname_jar_p() {
     1304            super("pathname-jar-p", PACKAGE_SYS, true, "pathname",
     1305                  "Predicate for whether PATHNAME references a JAR.");
     1306        }
     1307        @Override
     1308        public LispObject execute(LispObject arg) {
     1309            Pathname p = coerceToPathname(arg);
     1310            return p.isJar() ? T : NIL;
     1311        }
     1312    }
     1313
     1314    public boolean isJar() {
     1315        if (device instanceof Cons) {
    10621316            return true;
    1063         if (device == Keyword.WILD || device == Keyword.WILD_INFERIORS)
     1317        }
     1318        return false;
     1319    }
     1320
     1321    public boolean isWild() {
     1322        if (host == Keyword.WILD || host == Keyword.WILD_INFERIORS) {
    10641323            return true;
     1324        }
     1325        if (device == Keyword.WILD || device == Keyword.WILD_INFERIORS) {
     1326            return true;
     1327        }
    10651328        if (directory instanceof Cons) {
    1066             if (memq(Keyword.WILD, directory))
     1329            if (memq(Keyword.WILD, directory)) {
    10671330                return true;
    1068             if (memq(Keyword.WILD_INFERIORS, directory))
     1331            }
     1332            if (memq(Keyword.WILD_INFERIORS, directory)) {
    10691333                return true;
    1070         }
    1071         if (name == Keyword.WILD || name == Keyword.WILD_INFERIORS)
     1334            }
     1335        }
     1336        if (name == Keyword.WILD || name == Keyword.WILD_INFERIORS) {
    10721337            return true;
    1073         if (type == Keyword.WILD || type == Keyword.WILD_INFERIORS)
     1338        }
     1339        if (type == Keyword.WILD || type == Keyword.WILD_INFERIORS) {
    10741340            return true;
    1075         if (version == Keyword.WILD || version == Keyword.WILD_INFERIORS)
     1341        }
     1342        if (version == Keyword.WILD || version == Keyword.WILD_INFERIORS) {
    10761343            return true;
     1344        }
    10771345        return false;
    10781346    }
    1079 
    10801347    // ### %wild-pathname-p
    10811348    private static final Primitive _WILD_PATHNAME_P =
    1082         new Primitive("%wild-pathname-p", PACKAGE_SYS, true)
    1083     {
    1084         @Override
    1085         public LispObject execute(LispObject first, LispObject second)
    1086 
    1087         {
    1088             Pathname pathname = coerceToPathname(first);
    1089             if (second == NIL)
    1090                 return pathname.isWild() ? T : NIL;
    1091             if (second == Keyword.DIRECTORY) {
    1092                 if (pathname.directory instanceof Cons) {
    1093                     if (memq(Keyword.WILD, pathname.directory))
    1094                         return T;
    1095                     if (memq(Keyword.WILD_INFERIORS, pathname.directory))
    1096                         return T;
    1097                 }
    1098                 return NIL;
    1099             }
    1100             LispObject value;
    1101             if (second == Keyword.HOST)
    1102                 value = pathname.host;
    1103             else if (second == Keyword.DEVICE)
    1104                 value = pathname.device;
    1105             else if (second == Keyword.NAME)
    1106                 value = pathname.name;
    1107             else if (second == Keyword.TYPE)
    1108                 value = pathname.type;
    1109             else if (second == Keyword.VERSION)
    1110                 value = pathname.version;
    1111             else
    1112                 return error(new ProgramError("Unrecognized keyword " +
    1113                                               second.writeToString() + "."));
    1114             if (value == Keyword.WILD || value == Keyword.WILD_INFERIORS)
    1115                 return T;
    1116             else
    1117                 return NIL;
    1118         }
    1119     };
    1120 
     1349      new Primitive("%wild-pathname-p", PACKAGE_SYS, true) {
     1350
     1351          @Override
     1352          public LispObject execute(LispObject first, LispObject second) {
     1353              Pathname pathname = coerceToPathname(first);
     1354              if (second == NIL) {
     1355                  return pathname.isWild() ? T : NIL;
     1356              }
     1357              if (second == Keyword.DIRECTORY) {
     1358                  if (pathname.directory instanceof Cons) {
     1359                      if (memq(Keyword.WILD, pathname.directory)) {
     1360                          return T;
     1361                      }
     1362                      if (memq(Keyword.WILD_INFERIORS, pathname.directory)) {
     1363                          return T;
     1364                      }
     1365                  }
     1366                  return NIL;
     1367              }
     1368              LispObject value;
     1369              if (second == Keyword.HOST) {
     1370                  value = pathname.host;
     1371              } else if (second == Keyword.DEVICE) {
     1372                  value = pathname.device;
     1373              } else if (second == Keyword.NAME) {
     1374                  value = pathname.name;
     1375              } else if (second == Keyword.TYPE) {
     1376                  value = pathname.type;
     1377              } else if (second == Keyword.VERSION) {
     1378                  value = pathname.version;
     1379              } else {
     1380                  return error(new ProgramError("Unrecognized keyword "
     1381                    + second.writeToString() + "."));
     1382              }
     1383              if (value == Keyword.WILD || value == Keyword.WILD_INFERIORS) {
     1384                  return T;
     1385              } else {
     1386                  return NIL;
     1387              }
     1388          }
     1389      };
    11211390    // ### merge-pathnames
    11221391    private static final Primitive MERGE_PATHNAMES =
    1123         new Primitive("merge-pathnames",
    1124                       "pathname &optional default-pathname default-version")
     1392      new Primitive("merge-pathnames",
     1393      "pathname &optional default-pathname default-version") {
     1394
     1395          @Override
     1396          public LispObject execute(LispObject arg) {
     1397              Pathname pathname = coerceToPathname(arg);
     1398              Pathname defaultPathname =
     1399                coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue());
     1400              LispObject defaultVersion = Keyword.NEWEST;
     1401              return mergePathnames(pathname, defaultPathname, defaultVersion);
     1402          }
     1403
     1404          @Override
     1405          public LispObject execute(LispObject first, LispObject second) {
     1406              Pathname pathname = coerceToPathname(first);
     1407              Pathname defaultPathname =
     1408                coerceToPathname(second);
     1409              LispObject defaultVersion = Keyword.NEWEST;
     1410              return mergePathnames(pathname, defaultPathname, defaultVersion);
     1411          }
     1412
     1413          @Override
     1414          public LispObject execute(LispObject first, LispObject second,
     1415            LispObject third) {
     1416              Pathname pathname = coerceToPathname(first);
     1417              Pathname defaultPathname =
     1418                coerceToPathname(second);
     1419              LispObject defaultVersion = third;
     1420              return mergePathnames(pathname, defaultPathname, defaultVersion);
     1421          }
     1422      };
     1423
     1424    public static final Pathname mergePathnames(Pathname pathname, Pathname defaultPathname) {
     1425        return mergePathnames(pathname, defaultPathname, Keyword.NEWEST);
     1426    }
     1427
     1428    public static final Pathname mergePathnames(final Pathname pathname,
     1429                                                final Pathname defaultPathname,
     1430                                                final LispObject defaultVersion)
    11251431    {
    1126         @Override
    1127         public LispObject execute(LispObject arg)
    1128         {
    1129             Pathname pathname = coerceToPathname(arg);
    1130             Pathname defaultPathname =
    1131                 coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue());
    1132             LispObject defaultVersion = Keyword.NEWEST;
    1133             return mergePathnames(pathname, defaultPathname, defaultVersion);
    1134         }
    1135         @Override
    1136         public LispObject execute(LispObject first, LispObject second)
    1137 
    1138         {
    1139             Pathname pathname = coerceToPathname(first);
    1140             Pathname defaultPathname =
    1141                 coerceToPathname(second);
    1142             LispObject defaultVersion = Keyword.NEWEST;
    1143             return mergePathnames(pathname, defaultPathname, defaultVersion);
    1144         }
    1145         @Override
    1146         public LispObject execute(LispObject first, LispObject second,
    1147                                   LispObject third)
    1148 
    1149         {
    1150             Pathname pathname = coerceToPathname(first);
    1151             Pathname defaultPathname =
    1152                 coerceToPathname(second);
    1153             LispObject defaultVersion = third;
    1154             return mergePathnames(pathname, defaultPathname, defaultVersion);
    1155         }
    1156     };
    1157 
    1158     public static final Pathname mergePathnames(Pathname pathname,
    1159                                                 Pathname defaultPathname,
    1160                                                 LispObject defaultVersion)
    1161 
    1162     {
    1163         Pathname p;
    1164         if (pathname instanceof LogicalPathname)
    1165             p = new LogicalPathname();
    1166         else {
    1167             p = new Pathname();
    1168             if (defaultPathname instanceof LogicalPathname)
    1169                 defaultPathname = LogicalPathname.translateLogicalPathname((LogicalPathname)defaultPathname);
    1170         }
    1171         if (pathname.host != NIL)
    1172             p.host = pathname.host;
    1173         else
    1174             p.host = defaultPathname.host;
    1175         if (pathname.device != NIL)
    1176             p.device = pathname.device;
    1177         else
    1178             p.device = defaultPathname.device;
    1179         p.directory =
    1180             mergeDirectories(pathname.directory, defaultPathname.directory);
    1181         if (pathname.name != NIL)
    1182             p.name = pathname.name;
    1183         else
    1184             p.name = defaultPathname.name;
    1185         if (pathname.type != NIL)
    1186             p.type = pathname.type;
    1187         else
    1188             p.type = defaultPathname.type;
    1189         if (pathname.version != NIL)
    1190             p.version = pathname.version;
    1191         else if (pathname.name instanceof AbstractString)
    1192             p.version = defaultVersion;
    1193         else if (defaultPathname.version != NIL)
    1194             p.version = defaultPathname.version;
    1195         else
    1196             p.version = defaultVersion;
    1197         if (p instanceof LogicalPathname) {
     1432        Pathname result;
     1433        Pathname p = new Pathname(pathname);
     1434        Pathname d;
     1435
     1436        if (pathname instanceof LogicalPathname) {
     1437            result = new LogicalPathname();
     1438            d = new Pathname(defaultPathname);
     1439        } else {
     1440            result = new Pathname();
     1441            if (defaultPathname instanceof LogicalPathname) {
     1442                d = LogicalPathname.translateLogicalPathname((LogicalPathname) defaultPathname);
     1443            } else {
     1444                d = new Pathname(defaultPathname);
     1445            }
     1446        }
     1447        if (pathname.host != NIL) {
     1448            result.host = p.host;
     1449        } else {
     1450            result.host = d.host;
     1451        }
     1452
     1453        if (pathname.device != NIL) { // XXX if device represent JARs we want to merge
     1454            result.device = p.device;
     1455        } else {
     1456            result.device = d.device;
     1457        }
     1458
     1459        if (pathname.isJar()) {
     1460            Cons jars = (Cons)result.device;
     1461            LispObject jar = jars.car;
     1462            if (jar instanceof Pathname) {
     1463                Pathname defaults = new Pathname(d);
     1464                if (defaults.isJar()) {
     1465                    defaults.device = NIL;
     1466                }
     1467                Pathname o = mergePathnames((Pathname)jar, defaults);
     1468                if (o.directory instanceof Cons
     1469                    && ((Cons)o.directory).length() == 1) { // i.e. (:ABSOLUTE) or (:RELATIVE)
     1470                    o.directory = NIL;
     1471                }
     1472                ((Cons)result.device).car = o;
     1473            }
     1474        } else {
     1475            result.directory = mergeDirectories(p.directory, d.directory);
     1476        }
     1477
     1478        // A JAR always has relative directories
     1479        if (result.isJar()
     1480            && result.directory instanceof Cons
     1481            && result.directory.car().equals(Keyword.ABSOLUTE)) {
     1482            if (result.directory.cdr().equals(NIL)) {
     1483                result.directory = NIL;
     1484            } else {
     1485                ((Cons)result.directory).car = Keyword.RELATIVE;
     1486            }
     1487        }
     1488
     1489        if (pathname.name != NIL) {
     1490            result.name = p.name;
     1491        } else {
     1492            result.name = d.name;
     1493        }
     1494        if (pathname.type != NIL) {
     1495            result.type = p.type;
     1496        } else {
     1497            result.type = d.type;
     1498        }
     1499        if (pathname.version != NIL) {
     1500            result.version = pathname.version;
     1501        } else if (pathname.name instanceof AbstractString) {
     1502            result.version = defaultVersion;
     1503        } else if (defaultPathname.version != NIL) {
     1504            result.version = defaultPathname.version;
     1505        } else {
     1506            result.version = defaultVersion;
     1507        }
     1508        if (pathname instanceof LogicalPathname) {
    11981509            // When we're returning a logical
    1199             p.device = Keyword.UNSPECIFIC;
    1200             if (p.directory.listp()) {
    1201                 LispObject original = p.directory;
     1510            result.device = Keyword.UNSPECIFIC;
     1511            if (result.directory.listp()) {
     1512                LispObject original = result.directory;
    12021513                LispObject canonical = NIL;
    12031514                while (original != NIL) {
    12041515                    LispObject component = original.car();
    1205                     if (component instanceof AbstractString)
    1206                         component = LogicalPathname.canonicalizeStringComponent((AbstractString)component);
     1516                    if (component instanceof AbstractString) {
     1517                        component = LogicalPathname.canonicalizeStringComponent((AbstractString) component);
     1518                    }
    12071519                    canonical = canonical.push(component);
    12081520                    original = original.cdr();
    12091521                }
    1210                 p.directory = canonical.nreverse();
    1211             }
    1212             if (p.name instanceof AbstractString)
    1213                 p.name = LogicalPathname.canonicalizeStringComponent((AbstractString)p.name);
    1214             if (p.type instanceof AbstractString)
    1215                 p.type = LogicalPathname.canonicalizeStringComponent((AbstractString)p.type);
    1216         }
    1217         return p;
     1522                result.directory = canonical.nreverse();
     1523            }
     1524            if (result.name instanceof AbstractString) {
     1525                result.name = LogicalPathname.canonicalizeStringComponent((AbstractString) result.name);
     1526            }
     1527            if (result.type instanceof AbstractString) {
     1528                result.type = LogicalPathname.canonicalizeStringComponent((AbstractString) result.type);
     1529            }
     1530        }
     1531        result.invalidateNamestring();
     1532        return result;
    12181533    }
    12191534
    12201535    private static final LispObject mergeDirectories(LispObject dir,
    1221                                                      LispObject defaultDir)
    1222 
    1223     {
    1224         if (dir == NIL)
     1536                                                     LispObject defaultDir) {
     1537        if (dir == NIL) {
    12251538            return defaultDir;
     1539        }
    12261540        if (dir.car() == Keyword.RELATIVE && defaultDir != NIL) {
    12271541            LispObject result = NIL;
     
    12381552            for (int i = 0; i < array.length - 1; i++) {
    12391553                if (array[i] == Keyword.BACK) {
    1240                     if (array[i+1] instanceof AbstractString || array[i+1] == Keyword.WILD) {
     1554                    if (array[i + 1] instanceof AbstractString || array[i + 1] == Keyword.WILD) {
    12411555                        array[i] = null;
    1242                         array[i+1] = null;
     1556                        array[i + 1] = null;
    12431557                    }
    12441558                }
     
    12461560            result = NIL;
    12471561            for (int i = 0; i < array.length; i++) {
    1248                 if (array[i] != null)
     1562                if (array[i] != null) {
    12491563                    result = new Cons(array[i], result);
     1564                }
    12501565            }
    12511566            return result;
     
    12541569    }
    12551570
    1256     public static final LispObject truename(LispObject arg,
    1257                                             boolean errorIfDoesNotExist)
    1258 
     1571    public static final LispObject truename(Pathname pathname) {
     1572        return truename(pathname, false);
     1573    }
     1574
     1575    public static final LispObject truename(LispObject arg) {
     1576        return truename(arg, false);
     1577    }
     1578
     1579    public static final LispObject truename(LispObject arg, boolean errorIfDoesNotExist) {
     1580        final Pathname pathname = coerceToPathname(arg);
     1581        return truename(pathname, errorIfDoesNotExist);
     1582    }
     1583
     1584    /** @return The canonical TRUENAME as a Pathname if the pathname
     1585     * exists, otherwise returns NIL or possibly a subtype of
     1586     * LispError if there are logical problems with the input.
     1587     */
     1588    public static final LispObject truename(Pathname pathname,
     1589                                            boolean errorIfDoesNotExist)
    12591590    {
    1260         Pathname pathname = coerceToPathname(arg);
    1261         if (pathname instanceof LogicalPathname)
    1262             pathname = LogicalPathname.translateLogicalPathname((LogicalPathname)pathname);
    1263         if (pathname.isWild())
     1591        if (pathname instanceof LogicalPathname) {
     1592            pathname = LogicalPathname.translateLogicalPathname((LogicalPathname) pathname);
     1593        }
     1594        if (pathname.isWild()) {
    12641595            return error(new FileError("Bad place for a wild pathname.",
    1265                                        pathname));
    1266         final Pathname defaultedPathname =
    1267             mergePathnames(pathname,
    1268                            coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()),
    1269                            NIL);
    1270         final String namestring = defaultedPathname.getNamestring();
    1271         if (namestring == null)
    1272             return error(new FileError("Pathname has no namestring: " + defaultedPathname.writeToString(),
    1273                                        defaultedPathname));
    1274         final File file = new File(namestring);
    1275         if (file.isDirectory())
    1276             return Utilities.getDirectoryPathname(file);
    1277         if (file.exists()) {
    1278             try {
    1279                 return new Pathname(file.getCanonicalPath());
    1280             }
    1281             catch (IOException e) {
    1282                 return error(new LispError(e.getMessage()));
    1283             }
    1284         }
     1596              pathname));
     1597        }
     1598        if (!(pathname.device instanceof Cons)) {
     1599            pathname
     1600                = mergePathnames(pathname,
     1601                                 coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()),
     1602                                 NIL);
     1603            final String namestring = pathname.getNamestring();
     1604            if (namestring == null) {
     1605                return error(new FileError("Pathname has no namestring: "
     1606                                           + pathname.writeToString(),
     1607                                           pathname));
     1608            }
     1609           
     1610            final File file = new File(namestring);
     1611            if (file.isDirectory()) {
     1612                return Utilities.getDirectoryPathname(file);
     1613            }
     1614            if (file.exists()) {
     1615                try {
     1616                    return new Pathname(file.getCanonicalPath());
     1617                } catch (IOException e) {
     1618                    return error(new FileError(e.getMessage(), pathname));
     1619                }
     1620            }
     1621        } else
     1622        jarfile: {
     1623            // Possibly canonicalize jar file directory
     1624            Cons jars = (Cons) pathname.device;
     1625            LispObject o = jars.car();
     1626            if (o instanceof Pathname) {
     1627                LispObject truename = Pathname.truename((Pathname)o, errorIfDoesNotExist);
     1628                if (truename != null
     1629                    && truename instanceof Pathname) {
     1630                    jars.car = (Pathname)truename;
     1631                } else {
     1632                    break jarfile;
     1633                }
     1634            }
     1635
     1636            // Check for existence of a JAR file and/or JarEntry
     1637            //
     1638            // Cases:
     1639            // 1.  JAR
     1640            // 2.  JAR in JAR
     1641            // 3.  JAR with Entry
     1642            // 4.  JAR in JAR with Entry
     1643            JarFile jarFile = getJarFile(jars.car());
     1644            String entryPath = pathname.asEntryPath();
     1645            if (jarFile != null) {
     1646                if (jars.cdr() instanceof Cons) {
     1647                  Pathname inner = (Pathname) jars.cdr().car();
     1648                  InputStream inputStream = Utilities.getInputStream(jarFile, inner);
     1649                  if (inputStream != null) {
     1650                      if (entryPath.length() == 0) {
     1651                          return pathname; // Case 2
     1652                      } else {
     1653                          ZipInputStream zipInputStream
     1654                              = new ZipInputStream(inputStream);
     1655                          ZipEntry entry = Utilities.getEntry(zipInputStream,
     1656                                                              entryPath,
     1657                                                              false);
     1658                          if (entry != null) {
     1659                              // XXX this could possibly be a directory?
     1660                              return pathname; // Case 4
     1661                         }
     1662                      }
     1663                  }
     1664                } else {
     1665                    if (entryPath.length() == 0) {
     1666                        return pathname; // Case 1
     1667                    } else {
     1668                        ZipEntry entry = jarFile.getEntry(entryPath);
     1669                        if (entry != null) {
     1670                            // ensure this isn't a directory
     1671                            try {
     1672                                InputStream input = jarFile.getInputStream(entry);
     1673                                if (input != null) {
     1674                                    return pathname; // Case 3
     1675                                }
     1676                            } catch (IOException e) {
     1677                                break jarfile;
     1678                            }
     1679                        }
     1680                    }
     1681                }
     1682            }
     1683        }
     1684        error:
    12851685        if (errorIfDoesNotExist) {
    12861686            FastStringBuffer sb = new FastStringBuffer("The file ");
    1287             sb.append(defaultedPathname.writeToString());
     1687            sb.append(pathname.writeToString());
    12881688            sb.append(" does not exist.");
    1289             return error(new FileError(sb.toString(), defaultedPathname));
     1689            return error(new FileError(sb.toString(), pathname));
    12901690        }
    12911691        return NIL;
     1692    }
     1693
     1694
     1695    /** Make a JarURL from a Pathname that references a file */
     1696    private static URL makeJarURL(Pathname p) {
     1697        String jarURL = "jar:file:" + p.getNamestring() + "!/";
     1698        URL result = null;
     1699        try {
     1700            result = new URL(jarURL);
     1701        } catch (MalformedURLException ex) {
     1702            // XXX
     1703            Debug.trace("Could not form URL from pathname "
     1704              + "'" + jarURL + "'"
     1705              + " because " + ex);
     1706        }
     1707        return result;
     1708    }
     1709
     1710    /** Make a JarURL from a generic URL reference. */
     1711    private static URL makeJarURL(String url) {
     1712        String jarURL = "jar:" + url + "!/";
     1713        URL result = null;
     1714        try {
     1715            result = new URL(jarURL);
     1716        } catch (MalformedURLException ex) {
     1717            // XXX
     1718            Debug.trace("Could not form jar URL from  "
     1719              + "'" + jarURL + "'"
     1720              + " because " + ex);
     1721        }
     1722        return result;
     1723    }
     1724 
     1725    private static JarFile getJarFile(LispObject device) {
     1726        URL url = null;
     1727        if (device instanceof SimpleString) {
     1728            url = makeJarURL(((SimpleString) device).getStringValue());
     1729        } else {
     1730            url = makeJarURL((Pathname) device);
     1731        }
     1732        if (url == null) {
     1733            return null;
     1734        }
     1735        URLConnection connection;
     1736        try {
     1737            connection = url.openConnection();
     1738        } catch (IOException ex) {
     1739            Debug.trace("Failed to open "
     1740              + "'" + url + "'");
     1741            return null;
     1742        }
     1743        if (!(connection instanceof JarURLConnection)) {
     1744            // XXX
     1745            Debug.trace("Could not get a URLConnection from " + url);
     1746            return null;
     1747        }
     1748        JarURLConnection jarURLConnection = (JarURLConnection) connection;
     1749
     1750        JarFile result;
     1751        try {
     1752            result = jarURLConnection.getJarFile();
     1753        } catch (IOException ex) {
     1754            Debug.trace("Could not get a JarURLConnection from "
     1755              + "'" + jarURLConnection + "'");
     1756            return null;
     1757        }
     1758        return result;
     1759    }
     1760
     1761    public InputStream getInputStream() {
     1762        InputStream result = null;
     1763        if (isJar()) {
     1764            String entryPath = asEntryPath();
     1765            // XXX We only return the bytes of an entry in a JAR
     1766            Debug.assertTrue(entryPath != null);
     1767            JarFile jarFile = Pathname.getJarFile(device.car());
     1768            Debug.assertTrue(jarFile != null);
     1769            // Is this a JAR within a JAR?
     1770            if (device.cdr() instanceof Cons) {
     1771                Pathname inner = (Pathname) device.cdr().car();
     1772                InputStream input = Utilities.getInputStream(jarFile, inner);
     1773                ZipInputStream zipInputStream = new ZipInputStream(input);
     1774                result =  Utilities.getEntryAsInputStream(zipInputStream, entryPath);
     1775            } else {
     1776                ZipEntry entry = jarFile.getEntry(entryPath);
     1777    if (entry == null) {
     1778        Debug.trace("Failed to get InputStream for "   
     1779        + "'" + getNamestring() + "'");
     1780
     1781        Debug.assertTrue(false);
     1782    }
     1783                try {
     1784                    result = jarFile.getInputStream(entry);
     1785                } catch (IOException e) {
     1786                    Debug.trace("Failed to get InputStream from "
     1787                                + "'" + getNamestring() + "'"
     1788                                + ": " + e);
     1789                }
     1790            }
     1791        } else {
     1792            File file = Utilities.getFile(this);
     1793            try {
     1794                result = new FileInputStream(file);
     1795            } catch (IOException e) {
     1796                Debug.trace("Failed to get InputStream for read from "
     1797                                + "'" + getNamestring() + "'"
     1798                                + ": " + e);
     1799            }
     1800        }
     1801        return result;
     1802    }
     1803
     1804    // ### last-modified pathname => time-in-milliseconds
     1805    public static final Primitive LAST_MODIFIED
     1806        = new Primitive("LAST-MODIFIED", PACKAGE_EXT, true, "pathname",
     1807                        "If PATHNAME exists, returns the last modified time in miliseconds since the UNIX epoch.") 
     1808            {
     1809                @Override
     1810                public LispObject execute(LispObject arg) {
     1811                    final Pathname p = coerceToPathname(arg);
     1812                    if (p.isWild()) {
     1813                        error(new FileError("Bad place for a wild pathname.", p));
     1814                    }
     1815                    long time = p.getLastModified();
     1816                    return LispInteger.getInstance(time);
     1817                }
     1818            };
     1819
     1820    /** @return Time in milliseconds since the UNIX epoch at which the
     1821     * resource was last modified, or 0 if the time is unknown.
     1822     */
     1823    public long getLastModified() {
     1824        if (!(device instanceof Cons)) {
     1825            File f = Utilities.getFile(this);
     1826            return f.lastModified();
     1827        }
     1828        // JAR cases
     1829        // 0.  JAR from URL
     1830        // 1.  JAR
     1831        // 2.  JAR in JAR
     1832        // 3.  Entry in JAR
     1833        // 4.  Entry in JAR in JAR
     1834        String entryPath = asEntryPath();
     1835        Cons d = (Cons)device;
     1836        if (d.cdr().equals(NIL)) {
     1837            if (entryPath.length() == 0) {
     1838                LispObject o = d.car();
     1839                if (o instanceof SimpleString) {
     1840                    // 0. JAR from URL
     1841                    URL u = makeJarURL(o.getStringValue());
     1842                    URLConnection c = null;
     1843                    try {
     1844                      c = u.openConnection();
     1845                    } catch(IOException e) {
     1846                      Debug.trace("Failed to open Connection for URL "
     1847                                  + "'" + u + "'");
     1848                      return 0;
     1849                    }
     1850                    c.getLastModified();
     1851                } else  { 
     1852                    // 1. JAR
     1853                    return ((Pathname)o).getLastModified();
     1854                }
     1855            } else {
     1856                // 3. Entry in JAR
     1857                final JarEntry entry = getJarFile(device.car()).getJarEntry(entryPath);
     1858                if (entry == null) {
     1859                    return 0;
     1860                }
     1861                final long time = entry.getTime();
     1862                if (time == -1) {
     1863                    return 0;
     1864                }
     1865                return time;
     1866            }
     1867        } else {
     1868            JarFile outerJar = getJarFile(d.car());
     1869            if (entryPath.length() == 0) {
     1870                // 4.  JAR in JAR
     1871                String jarPath = ((Pathname)d.cdr()).asEntryPath();
     1872                final JarEntry entry = outerJar.getJarEntry(jarPath);
     1873                final long time = entry.getTime();
     1874                if (time == -1) {
     1875                    return 0;
     1876                }
     1877                return time;
     1878            } else {
     1879                // 5. Entry in JAR in JAR
     1880                String innerJarPath = ((Pathname)d.cdr()).asEntryPath();
     1881                ZipEntry entry = outerJar.getEntry(entryPath);
     1882                ZipInputStream innerJarInputStream
     1883                    = Utilities.getZipInputStream(outerJar, innerJarPath);
     1884                ZipEntry innerEntry = Utilities.getEntry(innerJarInputStream,
     1885                                                         entryPath);
     1886                long time = innerEntry.getTime();
     1887                if (time == -1) {
     1888                    return 0;
     1889                }
     1890                return time;
     1891            }
     1892        }
     1893        return 0;
    12921894    }
    12931895
    12941896    // ### mkdir
    12951897    private static final Primitive MKDIR =
    1296         new Primitive("mkdir", PACKAGE_SYS, false)
    1297     {
    1298         @Override
    1299         public LispObject execute(LispObject arg)
    1300         {
    1301             final Pathname pathname = coerceToPathname(arg);
    1302             if (pathname.isWild())
    1303                 error(new FileError("Bad place for a wild pathname.", pathname));
    1304             Pathname defaultedPathname =
     1898      new Primitive("mkdir", PACKAGE_SYS, false) {
     1899
     1900          @Override
     1901          public LispObject execute(LispObject arg) {
     1902              final Pathname pathname = coerceToPathname(arg);
     1903              if (pathname.isWild()) {
     1904                  error(new FileError("Bad place for a wild pathname.", pathname));
     1905              }
     1906              Pathname defaultedPathname =
    13051907                mergePathnames(pathname,
    1306                                coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()),
    1307                                NIL);
    1308             File file = Utilities.getFile(defaultedPathname);
    1309             return file.mkdir() ? T : NIL;
    1310         }
    1311     };
    1312 
     1908                coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()),
     1909                NIL);
     1910              File file = Utilities.getFile(defaultedPathname);
     1911              return file.mkdir() ? T : NIL;
     1912          }
     1913      };
    13131914    // ### rename-file filespec new-name => defaulted-new-name, old-truename, new-truename
    13141915    public static final Primitive RENAME_FILE =
    1315         new Primitive("rename-file", "filespec new-name")
    1316     {
    1317         @Override
    1318         public LispObject execute(LispObject first, LispObject second)
    1319 
    1320         {
    1321             final Pathname original = (Pathname) truename(first, true);
    1322             final String originalNamestring = original.getNamestring();
    1323             Pathname newName = coerceToPathname(second);
    1324             if (newName.isWild())
    1325                 error(new FileError("Bad place for a wild pathname.", newName));
    1326             newName = mergePathnames(newName, original, NIL);
    1327             final String newNamestring;
    1328             if (newName instanceof LogicalPathname)
    1329                 newNamestring = LogicalPathname.translateLogicalPathname((LogicalPathname)newName).getNamestring();
    1330             else
    1331                 newNamestring = newName.getNamestring();
    1332             if (originalNamestring != null && newNamestring != null) {
    1333                 final File source = new File(originalNamestring);
    1334                 final File destination = new File(newNamestring);
    1335                 if (Utilities.isPlatformWindows) {
    1336                     if (destination.isFile())
    1337                         destination.delete();
    1338                 }
    1339                 if (source.renameTo(destination))
    1340                     // Success!
    1341                     return LispThread.currentThread().setValues(newName, original,
    1342                                                                 truename(newName, true));
    1343             }
    1344             return error(new FileError("Unable to rename " +
    1345                                        original.writeToString() +
    1346                                        " to " + newName.writeToString() +
    1347                                        "."));
    1348         }
    1349     };
    1350 
     1916      new Primitive("rename-file", "filespec new-name") {
     1917
     1918          @Override
     1919          public LispObject execute(LispObject first, LispObject second) {
     1920              final Pathname original = (Pathname) truename(first, true);
     1921              final String originalNamestring = original.getNamestring();
     1922              Pathname newName = coerceToPathname(second);
     1923              if (newName.isWild()) {
     1924                  error(new FileError("Bad place for a wild pathname.", newName));
     1925              }
     1926              newName = mergePathnames(newName, original, NIL);
     1927              final String newNamestring;
     1928              if (newName instanceof LogicalPathname) {
     1929                  newNamestring = LogicalPathname.translateLogicalPathname((LogicalPathname) newName).getNamestring();
     1930              } else {
     1931                  newNamestring = newName.getNamestring();
     1932              }
     1933              if (originalNamestring != null && newNamestring != null) {
     1934                  final File source = new File(originalNamestring);
     1935                  final File destination = new File(newNamestring);
     1936                  if (Utilities.isPlatformWindows) {
     1937                      if (destination.isFile()) {
     1938                          destination.delete();
     1939                      }
     1940                  }
     1941                  if (source.renameTo(destination)) // Success!
     1942                  {
     1943                      return LispThread.currentThread().setValues(newName, original,
     1944                        truename(newName, true));
     1945                  }
     1946              }
     1947              return error(new FileError("Unable to rename "
     1948                + original.writeToString()
     1949                + " to " + newName.writeToString()
     1950                + "."));
     1951          }
     1952      };
    13511953    // ### file-namestring pathname => namestring
    13521954    private static final Primitive FILE_NAMESTRING =
    1353         new Primitive("file-namestring", "pathname")
    1354     {
    1355         @Override
    1356         public LispObject execute(LispObject arg)
    1357         {
    1358             Pathname p = coerceToPathname(arg);
    1359             FastStringBuffer sb = new FastStringBuffer();
    1360             if (p.name instanceof AbstractString)
    1361                 sb.append(p.name.getStringValue());
    1362             else if (p.name == Keyword.WILD)
    1363                 sb.append('*');
    1364             else
    1365                 return NIL;
    1366             if (p.type instanceof AbstractString) {
    1367                 sb.append('.');
    1368                 sb.append(p.type.getStringValue());
    1369             } else if (p.type == Keyword.WILD)
    1370                 sb.append(".*");
    1371             return new SimpleString(sb);
    1372         }
    1373     };
    1374 
     1955      new Primitive("file-namestring", "pathname") {
     1956
     1957          @Override
     1958          public LispObject execute(LispObject arg) {
     1959              Pathname p = coerceToPathname(arg);
     1960              FastStringBuffer sb = new FastStringBuffer();
     1961              if (p.name instanceof AbstractString) {
     1962                  sb.append(p.name.getStringValue());
     1963              } else if (p.name == Keyword.WILD) {
     1964                  sb.append('*');
     1965              } else {
     1966                  return NIL;
     1967              }
     1968              if (p.type instanceof AbstractString) {
     1969                  sb.append('.');
     1970                  sb.append(p.type.getStringValue());
     1971              } else if (p.type == Keyword.WILD) {
     1972                  sb.append(".*");
     1973              }
     1974              return new SimpleString(sb);
     1975          }
     1976      };
    13751977    // ### host-namestring pathname => namestring
    13761978    private static final Primitive HOST_NAMESTRING =
    1377         new Primitive("host-namestring", "pathname")
    1378     {
    1379         @Override
    1380         public LispObject execute(LispObject arg)
    1381         {
    1382             return coerceToPathname(arg).host;
    1383         }
    1384     };
     1979      new Primitive("host-namestring", "pathname") {
     1980
     1981          @Override
     1982          public LispObject execute(LispObject arg) {
     1983              return coerceToPathname(arg).host;
     1984          }
     1985      };
     1986   
     1987    public String toString() {
     1988        return getNamestring();
     1989    }
    13851990
    13861991    static {
     
    13891994    }
    13901995}
     1996
  • trunk/abcl/src/org/armedbear/lisp/Site.java

    r12298 r12422  
    4343public final class Site
    4444{
    45     private static final String LISP_HOME;
     45    private static Pathname LISP_HOME;
    4646
    47     static {
    48         String lispHome = System.getProperty("abcl.home");
    49         if (lispHome == null) {
    50             URL url = Lisp.class.getResource("boot.lisp");
    51             if (url != null) {
    52                 String protocol = url.getProtocol();
    53                 if (protocol != null && protocol.equals("file")) {
    54                     String path = url.getPath();
    55                     try {
    56                         path = URLDecoder.decode(path, "UTF-8");
    57                     }
    58                     catch (java.io.UnsupportedEncodingException uee) {
    59                         // can't happen: Java implementations are required to
    60                         // support UTF-8
    61                     }
    62                     int index = path.lastIndexOf('/');
    63                     if (index >= 0) {
    64                         lispHome = path.substring(0, index + 1);
    65                         if (Utilities.isPlatformWindows) {
    66                             if (lispHome.length() > 0 && lispHome.charAt(0) == '/')
    67                                 lispHome = lispHome.substring(1);
    68                         }
    69                     }
    70                 }
     47    private static void init() {
     48        String s = System.getProperty("abcl.home");
     49        if (s != null) {
     50            String fileSeparator = System.getProperty("file.separator");
     51            if (!s.endsWith(fileSeparator)) {
     52                s += fileSeparator;;
    7153            }
     54            LISP_HOME = new Pathname(s);
     55            return;
    7256        }
    73         LISP_HOME = lispHome;
     57        URL url = Lisp.class.getResource("boot.lisp");
     58        if (url != null) {
     59            LISP_HOME = new Pathname(url);
     60            LISP_HOME.name = NIL;
     61            LISP_HOME.type = NIL;
     62            LISP_HOME.invalidateNamestring();
     63            return;
     64        }
     65        Debug.trace("Unable to determine LISP_HOME.");
    7466    }
    7567
    76     public static final String getLispHome()
     68
     69    public static final Pathname getLispHome()
    7770    {
    78         return LISP_HOME;
     71      if (LISP_HOME == null) {
     72        init();
     73      }
     74      return LISP_HOME;
    7975    }
    8076
     
    8480
    8581    static {
    86         String s = Site.getLispHome();
    87         if (s != null)
    88             _LISP_HOME_.setSymbolValue(new Pathname(s));
     82        Pathname p = Site.getLispHome();
     83        if (p != null)
     84            _LISP_HOME_.setSymbolValue(p);
    8985    }
    9086}
  • trunk/abcl/src/org/armedbear/lisp/Stream.java

    r12397 r12422  
    395395    {
    396396        LispObject result = readPreservingWhitespace(eofError, eofValue,
    397                             recursive, thread);
     397                                                     recursive, thread);
    398398        if (result != eofValue && !recursive) {
    399399            try {
     
    423423
    424424    public LispObject readPreservingWhitespace(boolean eofError,
    425             LispObject eofValue,
    426             boolean recursive,
    427             LispThread thread)
     425                                               LispObject eofValue,
     426                                               boolean recursive,
     427                                               LispThread thread)
    428428
    429429    {
     
    435435                    n = _readChar();
    436436                } catch (IOException e) {
     437                    Debug.trace(e);
    437438                    error(new StreamError(this, e));
    438439                }
  • trunk/abcl/src/org/armedbear/lisp/Symbol.java

    r12375 r12422  
    29102910  public static final Symbol MACROEXPAND_ALL =
    29112911    PACKAGE_EXT.addExternalSymbol("MACROEXPAND-ALL");
     2912  public static final Symbol LOAD_TRUENAME_FASL =
     2913    PACKAGE_EXT.addExternalSymbol("*LOAD-TRUENAME-FASL*");
    29122914
    29132915  // MOP.
  • trunk/abcl/src/org/armedbear/lisp/Utilities.java

    r12290 r12422  
    4141import java.io.IOException;
    4242import java.io.InputStream;
     43import java.util.jar.JarFile;
    4344import java.util.zip.ZipEntry;
    4445import java.util.zip.ZipFile;
     
    125126        }
    126127    }
    127    
    128     public static byte[] getZippedZipEntryAsByteArray(ZipFile zipfile,
    129                                                       String entryName,
    130                                                       String subEntryName)
    131 
    132   {
    133       ZipEntry entry = zipfile.getEntry(entryName);
    134      
    135       ZipInputStream stream = null;
    136       try {
    137           stream = new ZipInputStream(zipfile.getInputStream(entry));
    138       }
    139       catch (IOException e) {
     128
     129    public static ZipInputStream getZipInputStream(ZipFile zipfile,
     130                                                   String entryName) {
     131        return Utilities.getZipInputStream(zipfile, entryName, false);
     132    }
     133
     134  public static ZipInputStream getZipInputStream(ZipFile zipfile,
     135                                                 String entryName,
     136                                                 boolean errorOnFailure) {
     137    ZipEntry zipEntry = zipfile.getEntry(entryName);
     138    ZipInputStream stream = null;
     139    try {
     140      stream = new ZipInputStream(zipfile.getInputStream(zipEntry));
     141    } catch (IOException e) {
     142      if (errorOnFailure) {
    140143          Lisp.error(new FileError("Failed to open '" + entryName + "' in zipfile '"
    141144                                   + zipfile + "': " + e.getMessage()));
    142145      }
    143       //  XXX Cache the zipEntries somehow
    144       do {
    145           try {
    146               entry = stream.getNextEntry();
    147           } catch (IOException e){
    148               Lisp.error(new FileError("Failed to seek for '" + subEntryName
    149                                        + "' in '"
    150                                        + zipfile.getName() + ":" + entryName + ".:"
    151                                        + e.getMessage()));
    152           }
    153       } while (!entry.getName().equals(subEntryName));
    154      
    155       ByteArrayOutputStream buffer = new ByteArrayOutputStream();
     146      return null;
     147    }
     148    return stream;
     149  }
     150
     151  public static InputStream getEntryAsInputStream(ZipInputStream zipInputStream,
     152                                                    String entryName)
     153    {
     154        ZipEntry entry = getEntry(zipInputStream, entryName);
     155        ByteArrayOutputStream bytes = readEntry(zipInputStream);
     156        return new ByteArrayInputStream(bytes.toByteArray());
     157
     158    }
     159
     160    public static ByteArrayOutputStream readEntry(ZipInputStream stream) {
     161        ByteArrayOutputStream result = new ByteArrayOutputStream();
    156162        int count;
    157163        byte buf[] = new byte[1024];
    158164        try {
    159165            while ((count = stream.read(buf, 0, buf.length)) != -1) {
    160                 buffer.write(buf, 0, count);
     166                result.write(buf, 0, count);
    161167            }
    162168        } catch (java.io.IOException e) {
    163           Lisp.error(new FileError("Failed to read compressed '"
    164                                    + subEntryName
    165                                    + "' in '"
    166                                    + zipfile.getName() + ":" + entryName + ":"
    167                                    + e.getMessage()));
    168         }
    169         return buffer.toByteArray();
    170     }
     169            Debug.trace("Failed to read entry from "
     170                        + stream
     171                        + ": " + e);
     172            return null;
     173        }
     174        return result;
     175    }
     176
     177    public static ZipEntry getEntry(ZipInputStream zipInputStream, String entryName) {
     178        return Utilities.getEntry(zipInputStream, entryName, false);
     179    }
     180
     181  public static ZipEntry getEntry(ZipInputStream zipInputStream,
     182                                  String entryName,
     183                                  boolean errorOnFailure)
     184  {
     185    ZipEntry entry = null;
     186    do {
     187      try {
     188        entry = zipInputStream.getNextEntry();
     189      } catch (IOException e) {
     190        if (errorOnFailure) {
     191          Lisp.error(new FileError("Failed to seek for "
     192            + "'" + entryName + "'"
     193            + " in " + zipInputStream.toString()));
     194        }
     195        return null;
     196      }
     197    } while (entry != null && !entry.getName().equals(entryName));
     198    if (entry != null) {
     199      return entry;
     200    }
     201    if (errorOnFailure) {
     202      Lisp.error(new FileError("Failed to find "
     203        + "'" + entryName + "'"
     204        + " in " + zipInputStream.toString()));
     205    }
     206    return null;
     207
     208  }
    171209   
    172     public static InputStream getZippedZipEntryAsInputStream(ZipFile zipfile,
    173                                                              String entryName,
    174                                                              String subEntryName)
    175 
    176   {
    177         return
    178             new ByteArrayInputStream(Utilities
    179                                      .getZippedZipEntryAsByteArray(zipfile, entryName,
    180                                                                    subEntryName));
    181   }
     210    public static final boolean checkZipFile(Pathname name) {
     211        InputStream input = name.getInputStream();
     212        try {
     213            byte[] bytes = new byte[4];
     214            int bytesRead = input.read(bytes);
     215            return (bytesRead == 4
     216                    && bytes[0] == 0x50
     217                    && bytes[1] == 0x4b
     218                    && bytes[2] == 0x03
     219                    && bytes[3] == 0x04);
     220        } catch (Throwable t) { // any error probably means 'no'
     221            return false;
     222        } finally {
     223            if (input != null) {
     224                try {
     225                    input.close();
     226                }
     227                catch (IOException e) {} // ignore exceptions
     228            }
     229        }
     230    }
     231
     232    static InputStream getInputStream(JarFile jarFile, Pathname inner) {
     233        String entryPath = inner.asEntryPath();
     234        ZipEntry entry = jarFile.getEntry(entryPath);
     235        if (entry == null) {
     236            Debug.trace("Failed to find entry "
     237                    + "'" + entryPath + "'"
     238                    + " in "
     239                    + "'" + jarFile.getName() + "'");
     240            return null;
     241        }
     242        InputStream result = null;
     243        try {
     244            result = jarFile.getInputStream(entry);
     245        } catch (IOException e) {
     246            Debug.trace("Failed to open InputStream for "
     247              + "'" + entryPath + "'"
     248              + " in "
     249              + "'" + jarFile.getName() + "'");
     250            return null;
     251        }
     252        return result;
     253    }
     254
     255
     256
    182257}
    183 
  • trunk/abcl/src/org/armedbear/lisp/asdf.lisp

    r11365 r12422  
    11741174  (pushnew 'contrib-sysdef-search *system-definition-search-functions*))
    11751175
     1176(require 'asdf-abcl)
    11761177(provide 'asdf)
  • trunk/abcl/src/org/armedbear/lisp/compile-system.lisp

    r12216 r12422  
    122122      (load (do-compile "ldb.lisp"))
    123123      (load (do-compile "destructuring-bind.lisp"))
     124      (load (do-compile "asdf.lisp"))
    124125      ;; But not for these.
    125126      (mapc #'do-compile '("adjoin.lisp"
     
    127128                           "apropos.lisp"
    128129                           "arrays.lisp"
    129                            "asdf.lisp"
     130                           "asdf-abcl.lisp"
    130131                           "assert.lisp"
    131132                           "assoc.lisp"
     
    212213                           "parse-integer.lisp"
    213214                           "parse-lambda-list.lisp"
     215                           "package.lisp"
    214216                           "pathnames.lisp"
    215                            "package.lisp"
    216217                           "print-object.lisp"
    217218                           "print-unreadable-object.lisp"
  • trunk/abcl/src/org/armedbear/lisp/file_write_date.java

    r12288 r12422  
    5252        if (pathname.isWild())
    5353            error(new FileError("Bad place for a wild pathname.", pathname));
    54         File file = Utilities.getFile(pathname);
    55         long lastModified = file.lastModified();
     54        long lastModified = pathname.getLastModified();
    5655        if (lastModified == 0)
    5756            return NIL;
Note: See TracChangeset for help on using the changeset viewer.