Revision: 5295
          http://jnode.svn.sourceforge.net/jnode/?rev=5295&view=rev
Author:   chrisboertien
Date:     2009-04-16 21:26:19 +0000 (Thu, 16 Apr 2009)

Log Message:
-----------
More zip command implementation

Added support for -m -D -p -j -x -i
Added javadoc to Zip
Extrapolated strings from within code
Added 4 FileFilter implementations as nested classes in ADW

Signed-off-by: chrisboertien <chris.boert...@gmail.com>

Modified Paths:
--------------
    trunk/fs/descriptors/org.jnode.fs.command.archive.xml
    trunk/fs/src/fs/org/jnode/fs/command/AbstractDirectoryWalker.java
    trunk/fs/src/fs/org/jnode/fs/command/archive/ArchiveCommand.java
    trunk/fs/src/fs/org/jnode/fs/command/archive/Zip.java
    trunk/fs/src/fs/org/jnode/fs/command/archive/ZipCommand.java

Modified: trunk/fs/descriptors/org.jnode.fs.command.archive.xml
===================================================================
--- trunk/fs/descriptors/org.jnode.fs.command.archive.xml       2009-04-16 
20:37:00 UTC (rev 5294)
+++ trunk/fs/descriptors/org.jnode.fs.command.archive.xml       2009-04-16 
21:26:19 UTC (rev 5295)
@@ -15,6 +15,7 @@
   <runtime>
     <library name="jnode-fs.jar">
       <export name="org.jnode.fs.command.archive.*" />
+      <export name="org.jnode.fs.command.AbstractDirectoryWalker" />
     </library>
   </runtime>
   
@@ -244,7 +245,7 @@
           <option argLabel="recurse" shortName="r"/>
           <!--<option argLabel="recurse-cd" shortName="R"/>-->
           <option argLabel="newer" shortName="t"/>
-          <!--<option argLabel="older" shortName="tt"/>-->
+          <option argLabel="older" longName="tt"/> 
           <!-- Zip -->
           <option argLabel="no-path" shortName="j"/>
           <!-- Zip Operations -->
@@ -259,14 +260,12 @@
         </optionSet>
         <argument argLabel="archive"/>
         <repeat>
-          <argument argLabel="patterns"/>
+          <alternatives>
+            <option argLabel="exclude" shortName="x"/>
+            <option argLabel="include" shortName="i"/>
+            <argument argLabel="patterns"/>
+          </alternatives>
         </repeat>
-        <!-- TODO
-        <repeat>
-          <option argLabel="include" shortName="i"/>
-          <option argLabel="exclude" shortName="x"/>
-        </repeat>
-        -->
       </sequence>
     </syntax>
   </extension>

Modified: trunk/fs/src/fs/org/jnode/fs/command/AbstractDirectoryWalker.java
===================================================================
--- trunk/fs/src/fs/org/jnode/fs/command/AbstractDirectoryWalker.java   
2009-04-16 20:37:00 UTC (rev 5294)
+++ trunk/fs/src/fs/org/jnode/fs/command/AbstractDirectoryWalker.java   
2009-04-16 21:26:19 UTC (rev 5295)
@@ -28,6 +28,10 @@
 import java.util.Stack;
 import java.util.List;
 
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import org.jnode.shell.PathnamePattern;
 /**
  * <p>
  * <code>AbstractDirectoryWalker</code> - walk through a directory hierarchy
@@ -54,6 +58,66 @@
             this.depth = depth;
         }
     }
+    
+    public static class PathnamePatternFilter implements FileFilter {
+        
+        private Matcher matcher;
+        private boolean exclude;
+        
+        public PathnamePatternFilter(String pattern, boolean exclude) {
+            this.exclude = exclude;
+            this.matcher = PathnamePattern.compilePosixShellPattern(pattern, 
0).matcher("");
+        }
+        
+        public boolean accept(File file) {
+            return matcher.reset(file.getName()).matches() ^ exclude;
+        }
+    }
+    
+    public static class RegexPatternFilter implements FileFilter {
+        
+        private Matcher matcher;
+        private boolean exclude;
+        
+        public RegexPatternFilter(String pattern, boolean exclude) {
+            this.exclude = exclude;
+            this.matcher = Pattern.compile(pattern).matcher("");
+        }
+        
+        public boolean accept(File file) {
+            return matcher.reset(file.getName()).matches() ^ exclude;
+        }
+    }
+    
+    public static class ModTimeFilter implements FileFilter {
+        
+        private long modTime;
+        private boolean newer;
+        
+        public ModTimeFilter(long time, boolean newer) {
+            this.modTime = time;
+            this.newer = newer;
+        }
+        
+        public boolean accept(File file) {
+            return file.lastModified() == modTime || ((file.lastModified() < 
modTime) ^ newer);
+        }
+    }
+    
+    public static class SizeFilter implements FileFilter {
+        
+        private long size;
+        private boolean greater;
+        
+        public SizeFilter(long size, boolean greater) {
+            this.size = size;
+            this.greater = greater;
+        }
+        
+        public boolean accept(File file) {
+            return file.length() == size || ((file.length() < size) ^ greater);
+        }
+    }
 
     private final Stack<FileObject> stack = new Stack<FileObject>();
     private final Set<FileFilter> filters = new HashSet<FileFilter>();
@@ -87,7 +151,7 @@
     }
     
     public synchronized void walk(final List<File> dirs) throws IOException {
-        walk(dirs.toArray(new File[0]));
+        walk(dirs.toArray(new File[dirs.size() ]));
     }
     
     private void handle(final FileObject file) throws IOException {

Modified: trunk/fs/src/fs/org/jnode/fs/command/archive/ArchiveCommand.java
===================================================================
--- trunk/fs/src/fs/org/jnode/fs/command/archive/ArchiveCommand.java    
2009-04-16 20:37:00 UTC (rev 5294)
+++ trunk/fs/src/fs/org/jnode/fs/command/archive/ArchiveCommand.java    
2009-04-16 21:26:19 UTC (rev 5295)
@@ -24,6 +24,7 @@
 import org.jnode.shell.syntax.Argument;
 import org.jnode.shell.syntax.FlagArgument;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -35,6 +36,13 @@
 
 import java.util.ArrayList;
 
+import org.apache.tools.zip.ZipFile;
+
+/**
+ * This is a base class that holds some convenience methods for implementing 
archive commands.
+ *
+ * @author chris boertien
+ */
 public class ArchiveCommand extends AbstractCommand {
     
     private static final String help_verbose = "show the compression ratio for 
each file compressed";
@@ -76,6 +84,7 @@
     protected OutputStream stdout;
     
     protected String commandName;
+    protected int rc;
     protected boolean use_stdout;
     protected boolean force;
     protected boolean compress;
@@ -95,6 +104,7 @@
         stdin = getInput().getInputStream();
         stdout = getOutput().getOutputStream();
         
+        // FIXME get rid of this {
         if (command.equals("zcat") || command.equals("bzcat")) return;
         
         if (!command.equals("tar")) {
@@ -108,6 +118,7 @@
             if (Verbose.isSet()) outMode |= OUT_NOTICE;
             if (Debug.isSet()) outMode |= OUT_DEBUG;
         }
+        // }
     }
     
     protected void createStreamBuffer(int size) {
@@ -247,14 +258,45 @@
     }
     
     /**
+     * Convenience method for closing streams and writers.
+     */
+    protected void close(Closeable obj) {
+        if (obj != null) {
+            try {
+                obj.close();
+            } catch (IOException _) {
+                //ignore
+            }
+        }
+    }
+    
+    /**
+     * Convenience method for closing org.apache.tools.zip.ZipFile
+     */
+    protected void close(ZipFile zfile) {
+        if (zfile != null) {
+            try {
+                zfile.close();
+            } catch (IOException _) {
+                // ignore
+            }
+        }
+    }
+    
+    /**
      * Prompt the user with a question asking for a yes or no answer.
      *
+     * FIXME This is unsafe as it will trigger an endless loop if stdin
+     *       is not the terminal.
+     *
      * @param String the question to ask the user
      * @return true if the user said yes, false if the user said no
      */
     protected boolean prompt_yn(String s, boolean defaultY) {
         int choice;
-        for (;;) {
+        // put a cap on the looping to prevent non-terminal stdin 
+        // from an infinte loop
+        for (int i = 0; i < 10; i++) {
             stdoutWriter.print(s);
             try {
                 choice = stdinReader.read();
@@ -266,6 +308,8 @@
             if (choice == 'n') return false;
             if (choice == '\n') return defaultY;
         }
+        
+        return false;
     }
     
     protected void out(String s) {

Modified: trunk/fs/src/fs/org/jnode/fs/command/archive/Zip.java
===================================================================
--- trunk/fs/src/fs/org/jnode/fs/command/archive/Zip.java       2009-04-16 
20:37:00 UTC (rev 5294)
+++ trunk/fs/src/fs/org/jnode/fs/command/archive/Zip.java       2009-04-16 
21:26:19 UTC (rev 5295)
@@ -21,9 +21,11 @@
 package org.jnode.fs.command.archive;
 
 import java.io.File;
+import java.io.FileFilter;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.LineNumberReader;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -33,6 +35,9 @@
 import org.apache.tools.zip.ZipExtraField;
 import org.apache.tools.zip.ZipFile;
 import org.apache.tools.zip.ZipOutputStream;
+import org.jnode.fs.command.AbstractDirectoryWalker;
+import org.jnode.fs.command.AbstractDirectoryWalker.ModTimeFilter;
+import org.jnode.fs.command.AbstractDirectoryWalker.PathnamePatternFilter;
 import org.jnode.shell.PathnamePattern;
 import org.jnode.shell.syntax.Argument;
 import org.jnode.shell.syntax.FileArgument;
@@ -40,10 +45,17 @@
 import org.jnode.shell.syntax.StringArgument;
 
 /**
+ * TODO test return codes
+ * TODO make sure no archive is created if the creation fails
+ * TODO implement delete
+ * TODO implement update
+ * TODO implement freshen
  * @author chris boeriten
  */
 public class Zip extends ArchiveCommand {
 
+    private static final boolean DEBUG = true;
+    
     private static final String help_delete = "remove the list of entries from 
the archive";
     private static final String help_freshen = "[zip] Replaces entries in the 
archive with files from the file " +
                                                "system if they exist and are 
newer than the entry.\n[unzip] Replaces " +
@@ -60,6 +72,28 @@
     private static final String help_archive = "the zip archive to use";
     private static final String help_patterns = "file matching 
patterns(wildcards)";
     
+    private static final String fmt_extract  = "%11s: %s";
+    private static final String fmt_footer   = " %8d %8d                   %d 
files";
+    private static final String fmt_entry    = " %8d %8d                 %d 
%s";
+    private static final String fmt_warn_dup = "%s: %s: %s";
+    private static final String fatal_create_arch  = "Could not create 
archive: ";
+    private static final String fatal_req_arch     = "Archive required but not 
found: ";
+    private static final String fatal_create_zfile = "Unable to open archive 
as ZipFile: ";
+    private static final String fatal_inv_args     = "zip error: Invalid 
arguments (cannot repeat names in zip file)";
+    private static final String fatal_walking      = "Exception while 
walking.";
+    private static final String fatal_read_stdin   = "Exception while reading 
stdin.";
+    private static final String str_header_1    = "   Size    CSize     Date   
Time   M Name";
+    private static final String str_header_2    = " -------- -------- -------- 
-----  - ----";
+    private static final String str_footer      = " -------- --------          
         -------";
+    private static final String str_archive     = "Archive: ";
+    private static final String str_creating    = "creating";
+    private static final String str_inflating   = "inflating";
+    private static final String str_adding      = "adding";
+    private static final String str_zip_warn    = "zip warning";
+    private static final String str_fullname_1  = " first full name";
+    private static final String str_fullname_2  = "second full name";
+    private static final String str_name_repeat = "name in zip file repeated";
+    
     protected final StringArgument Patterns;
     protected final FileArgument Archive;
     protected final FlagArgument Delete;
@@ -82,9 +116,11 @@
     private static final int ZIP_INSERT   = ZIP_ADD | ZIP_MOVE;
     private static final int ZIP_REQ_ARCH = ZIP_ALL & ~ZIP_INSERT;
     
-    private List<Pattern> patterns;
-    private List<Pattern> includes;
-    private List<Pattern> excludes;
+    /* Populated in ZipCommand and UnzipCommand */
+    protected List<String> includes;
+    protected List<String> excludes;
+    protected List<String> excludeDirs;
+    
     private List<File> files;
     private List<ZipEntry> fileEntries;
     private List<ZipEntry> dirEntries;
@@ -94,13 +130,14 @@
     private File archive;
     private ZipFile zarchive;
     protected File tmpDir;
-    protected String noCompress;
+    protected String[] noCompress;
     protected int mode;
     protected boolean ignore_case;
     protected boolean keep;
     protected boolean overwrite;
     protected boolean backup;
     protected boolean noDirEntry;
+    protected boolean noPath;
     protected boolean recurse;
     protected boolean filesStdin;
     protected boolean useStdout;
@@ -123,8 +160,13 @@
         parseOptions(command);
         
         try {
-            if (mode == ZIP_ADD) {
+            if ((mode & ZIP_ADD) != 0) {
                 insert();
+                if ((mode & ZIP_MOVE) != 0) {
+                    for (File file : files) {
+                        file.delete();
+                    }
+                }
                 return;
             }
             
@@ -140,13 +182,7 @@
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
-            if (zarchive != null) {
-                try {
-                    zarchive.close();
-                } catch (IOException _) {
-                    // ignore
-                }
-            }
+            close(zarchive);
             exit(0);
         }
     }
@@ -157,11 +193,12 @@
         InputStream in;
         
         try {
-            zout = new ZipOutputStream(new FileOutputStream(archive));
+            zout = new ZipOutputStream(archive);
             for (File file : files) {
                 in = null;
+                entry = createEntry(file);
+                out(String.format(fmt_extract, str_adding, entry.getName()));
                 try {
-                    entry = createEntry(file);
                     if (!file.isDirectory()) {
                         if ((in = openFileRead(file)) == null) {
                             continue;
@@ -189,27 +226,29 @@
                 try {
                     zout.finish();
                 } catch (IOException e) {
-                    //
+                    // ignore
                 }
             }
         }
     }
     
+    @SuppressWarnings("unchecked")
     private void list() throws IOException {
         Enumeration<ZipEntry> entries;
-        ZipEntry entry;
         int size = 0;
         int csize = 0;
         int count = 0;
         
         printListHeader();
-        entries = zarchive.getEntries();
-        while (entries.hasMoreElements()) {
-            entry = entries.nextElement();
-            //debug(entry);
+        for (ZipEntry entry : dirEntries) {
             printListEntry(entry);
             count++;
-            size += entry.getSize();
+        }
+        
+        for (ZipEntry entry : fileEntries) {
+            printListEntry(entry);
+            count++;
+            size  += entry.getSize();
             csize += entry.getCompressedSize();
         }
         printListFooter(size, csize, count);
@@ -220,44 +259,47 @@
         OutputStream out = null;
         File file;
         
-        out("Archive: " + archive.getName());
+        out(str_archive + archive.getName());
+        
         for (ZipEntry entry : dirEntries) {
-            out(String.format("%11s: %s", "creating", entry.getName()));
+            out(String.format(fmt_extract, str_creating, entry.getName()));
             file = new File(entry.getName());
             file.mkdirs();
         }
         
         for (ZipEntry entry : fileEntries) {
-            out(String.format("%11s: %s", "inflating", entry.getName()));
+            out(String.format(fmt_extract, str_inflating, entry.getName()));
             file = new File(entry.getName());
             try {
+                File parent = file.getParentFile();
+                if (parent != null && !parent.exists()) {
+                    parent.mkdirs();
+                }
                 file.createNewFile();
                 in = zarchive.getInputStream(entry);
-                out = new FileOutputStream(file);
+                if ((out = openFileWrite(file, false, false)) == null) {
+                    continue;
+                }
                 processStream(in, out);
             } catch (IOException e) {
                 debug(e.getMessage());
             } finally {
-                if (in != null) {
-                    try {
-                        in.close();
-                        in = null;
-                    } catch (IOException _) {
-                        // ignore;
-                    }
-                }
-                if (out != null) {
-                    try {
-                        out.close();
-                        out = null;
-                    } catch (IOException _) {
-                        // ignore;
-                    }
-                }
+                close(in);
+                close(out);
             }
         }
     }
     
+    /**
+     * Creates a ZipEntry for the specified file.
+     *
+     * If the file is a directory it will have a trailing slash
+     * appended to its name. This is used to distinguish files
+     * from directories in the archive.
+     *
+     * If the -j option is given, then only the file name is stored,
+     * not its full pathname. Conflicts are dealt with in parseFiles()
+     */
     private ZipEntry createEntry(File file) {
         String name = file.getPath();
         ZipEntry entry;
@@ -267,37 +309,34 @@
             }
             entry = new ZipEntry(name);
             entry.setMethod(ZipEntry.STORED);
-            entry.setCrc(0);
-            entry.setSize(0);
         } else {
+            if (noPath) {
+                name = file.getName();
+            }
             entry = new ZipEntry(name);
             entry.setMethod(ZipEntry.DEFLATED);
+            if (noCompress != null && noCompress.length > 0) {
+                for (String suf : noCompress) {
+                    if (name.endsWith(suf)) {
+                        entry.setMethod(ZipEntry.STORED);
+                        break;
+                    }
+                }
+            }
         }
         return entry;
     }
     
-    private void printListHeader() {
-        out("   Size    CSize     Date   Time   Name");
-        out(" -------- -------- -------- -----  ----");
-    }
-    
-    private void printListEntry(ZipEntry entry) {
-        out(String.format(" %8d %8d                 %s", entry.getSize(), 
entry.getCompressedSize(), entry.getName()));
-    }
-    
-    private void printListFooter(int size, int csize, int numFiles) {
-        out(" -------- --------                 -------");
-        out(String.format(" %8d %8d                 %d files", size, csize, 
numFiles));
-    }
-    
-    private void printName(String s) {
-        if (outMode != 0) {
-            out(s);
+    private void parseOptions(String command) {
+        if (DEBUG || Debug.isSet()) {
+            outMode |= OUT_DEBUG;
         }
-    }
-    
-    private void parseOptions(String command) {
-        outMode |= OUT_DEBUG;
+        if (Verbose.isSet()) {
+            outMode |= OUT_NOTICE;
+        }
+        if (Quiet.isSet()) {
+            outMode = 0;
+        }
         if (command.equals("zip")) {
             if (Delete.isSet()) {
                 mode = ZIP_DELETE;
@@ -306,7 +345,7 @@
             } else if (Update.isSet()) {
                 mode = ZIP_UPDATE | ZIP_ADD;
             } else if (Move.isSet()) {
-                mode = ZIP_MOVE;
+                mode = ZIP_MOVE | ZIP_ADD;
             } else {
                 mode = ZIP_ADD;
             }
@@ -323,9 +362,10 @@
                 mode = ZIP_EXTRACT;
             }
         }
-        assert mode != 0 : "Invalid mode";
         
-        switch (mode) {
+        noPath = NoPath.isSet();
+        
+        switch (mode & (ZIP_ADD | ZIP_EXTRACT | ZIP_LIST)) {
             case ZIP_ADD :
                 parseFiles();
                 getArchive(true, false);
@@ -334,14 +374,26 @@
                 getArchive(false, true);
                 parseEntries();
                 break;
-            case ZIP_LIST : 
+            case ZIP_LIST :
                 getArchive(false, true);
+                parseEntries();
                 break;
             default :
                 throw new UnsupportedOperationException("This mode is not 
implemented.");
         }
     }
     
+    /**
+     * Instantiates the archive.
+     *
+     * If zipfile is true, than a ZipFile object for the archive is also 
created.
+     *
+     * This will exit with an error if:
+     * - The archive does not exist, create is true, but an exception was 
thrown on creation.
+     * - The archive does not exist, and create is false.
+     * - The archive exists and create is true. (FIXME)
+     * - A ZipFile was requested and there was an exception during 
instantiation.
+     */
     private void getArchive(boolean create, boolean zipfile) {
         archive = Archive.getValue();
         
@@ -354,10 +406,10 @@
                 try {
                     archive.createNewFile();
                 } catch (IOException e) {
-                    fatal("Could not create archive: " + archive, 1);
+                    fatal(fatal_create_arch + archive, 1);
                 }
             } else {
-                fatal("Archive required but not found: " + archive, 1);
+                fatal(fatal_req_arch + archive, 1);
             }
         } else {
             if (create) {
@@ -370,18 +422,41 @@
                 zarchive = new ZipFile(archive);
             } catch (IOException e) {
                 debug(e.getMessage());
-                fatal("Unable to open archive as ZipFile: " + archive, 1);
+                fatal(fatal_create_zfile + archive, 1);
             }
-            assert zarchive != null : "null zarchive";
         }
-        
-        assert archive != null : "null archive after getArchive()";
-        assert archive.exists() : "archive does not exist, or was not created";
     }
     
+    private class Walker extends AbstractDirectoryWalker {
+        @Override
+        public void handleFile(final File file) throws IOException {
+            addFile(file);
+        }
+        @Override
+        public void handleDir(final File file) throws IOException {
+            assert !(noDirEntry || noPath) : "handleDir called when noDirEntry 
|| noPath";
+            addFile(file);
+        }
+    }
+    
+    /**
+     * Creates a list of files based on the files and filename patterns given
+     * on the command line. If we're using recursion, then a directory walker
+     * is used with the given include/exclude filters if any are in use.
+     *
+     * The -D/-j options prevent directories from being listed.
+     * The -x/-i options are used to add exclude/include patterns.
+     * The -r option turns on recursion
+     *
+     * This will exit with an error if there was an exception while walking.
+     */
     private void parseFiles() {
         files = new ArrayList<File>();
+        List<File> dirs = new ArrayList<File>();
         
+        if (filesStdin) {
+            parseFilesStdin();
+        }
         if (Patterns.isSet()) {
             for (String pattern : Patterns.getValues()) {
                 if (!PathnamePattern.isPattern(pattern)) {
@@ -391,7 +466,7 @@
                         continue;
                     }
                     if (file.isDirectory()) {
-                        addDirectory(file);
+                        dirs.add(file);
                     } else {
                         addFile(file);
                     }
@@ -401,7 +476,7 @@
                     for (String name : list) {
                         File file = new File(name);
                         if (file.isDirectory()) {
-                            addDirectory(file);
+                            dirs.add(file);
                         } else {
                             addFile(file);
                         }
@@ -409,10 +484,90 @@
                 }
             }
         }
+        
+        if (recurse && dirs.size() > 0) {
+            Walker walker = new Walker();
+            if (noDirEntry || noPath) {
+                walker.addFilter(new FileFilter() {
+                    @Override
+                    public boolean accept(File file) {
+                        return !file.isDirectory();
+                    }
+                });
+            }
+            if (excludes != null && excludes.size() > 0) {
+                for (String pattern : excludes) {
+                    walker.addFilter(new PathnamePatternFilter(pattern, true));
+                }
+            }
+            if (includes != null && includes.size() > 0) {
+                for (String pattern : includes) {
+                    walker.addFilter(new PathnamePatternFilter(pattern, 
false));
+                }
+            }
+            if (newer > 0) {
+                walker.addFilter(new ModTimeFilter(newer, true));
+            }
+            if (older > 0) {
+                walker.addFilter(new ModTimeFilter(older, false));
+            }
+            try {
+                walker.walk(dirs);
+            } catch (IOException e) {
+                debug(e.getMessage());
+                fatal(fatal_walking, 1);
+            }
+        }
     }
     
+    /**
+     * Parses files from stdin, one file per line.
+     *
+     * If the file does not exist, it is ignored and omitted.
+     *
+     * This will exit with an error if there is an exception while reading 
stdin.
+     */
+    private void parseFilesStdin() {
+        LineNumberReader reader = new LineNumberReader(stdinReader);
+        String line;
+        File file;
+        
+        try {
+            while ((line = reader.readLine()) != null) {
+                file = new File(line);
+                if (file.exists()) {
+                    addFile(file);
+                }
+            }
+        } catch (IOException e) {
+            fatal(fatal_read_stdin, 1);
+        }
+    }
+    
+    /**
+     * Adds a file to the list of files.
+     *
+     * If the -j option is used, then the list is scanned for the file name.
+     * This is done because -j strips the path from the pathname, which can 
cause
+     * collisions if two files from separate directories with the same name 
are added.
+     */
+    private void addFile(File file) {
+        if (noPath) {
+            // this isn't effecient by any means, but this is not an often-used
+            // case, and when it is, its not likely that files.size() is going
+            // to grow very large.
+            for (File f : files) {
+                if (f.getName().equals(file.getName())) {
+                    printDuplicateError(file, f);
+                    fatal(fatal_inv_args, 1);
+                }
+            }
+        }
+        files.add(file);
+    }
+    
+    @SuppressWarnings("unchecked")
     private void parseEntries() {
-        assert zarchive != null : "null archive in parseEntries";
         int count = 0;
         
         ZipEntry entry;
@@ -429,30 +584,34 @@
                 fileEntries.add(entry);
             }
         }
-        
-        assert count == (fileEntries.size() + dirEntries.size());
     }
-        
-    private void addDirectory(File dir) {
-        if (!recurse) {
-            return;
-        }
-        files.add(dir);
-        
-        for (File file : dir.listFiles()) {
-            if (file.isDirectory()) {
-                addDirectory(file);
-            } else {
-
-                addFile(file);
-            }
-        }
+    
+    private void printListHeader() {
+        out(str_header_1);
+        out(str_header_2);
     }
     
-    private void addFile(File file) {
-        files.add(file);
+    private void printListEntry(ZipEntry entry) {
+        out(String.format(fmt_entry, entry.getSize(), 
entry.getCompressedSize(), entry.getMethod(), entry.getName()));
     }
     
+    private void printListFooter(int size, int csize, int numFiles) {
+        out(str_footer);
+        out(String.format(fmt_footer, size, csize, numFiles));
+    }
+    
+    private void printDuplicateError(File A, File B) {
+        error(String.format(fmt_warn_dup, str_zip_warn, str_fullname_1, 
A.getPath()));
+        error(String.format(fmt_warn_dup, str_zip_warn, str_fullname_2, 
B.getPath()));
+        error(String.format(fmt_warn_dup, str_zip_warn, str_name_repeat, 
A.getName()));
+    }
+    
+    private void printName(String s) {
+        if (outMode != 0) {
+            out(s);
+        }
+    }
+    
     private void debug(ZipEntry entry) {
         debug("Name: " + entry.getName());
         debug("Directory: " + entry.isDirectory());

Modified: trunk/fs/src/fs/org/jnode/fs/command/archive/ZipCommand.java
===================================================================
--- trunk/fs/src/fs/org/jnode/fs/command/archive/ZipCommand.java        
2009-04-16 20:37:00 UTC (rev 5294)
+++ trunk/fs/src/fs/org/jnode/fs/command/archive/ZipCommand.java        
2009-04-16 21:26:19 UTC (rev 5295)
@@ -20,6 +20,9 @@
 
 package org.jnode.fs.command.archive;
 
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
 import org.jnode.shell.syntax.Argument;
 import org.jnode.shell.syntax.FlagArgument;
 import org.jnode.shell.syntax.FileArgument;
@@ -37,7 +40,12 @@
     private static final String help_recurse     = "recurse into directories";
     private static final String help_newer_than  = "only include files newer 
than the specified time";
     private static final String help_older_than  = "only include files older 
than the specified time";
+    private static final String help_exclude     = "do not includes files 
matching a pattern";
+    private static final String help_include     = "only includes files 
matching a pattern";
     
+    private static final String fatal_bad_newer = "Invalid newer-than date: ";
+    private static final String fatal_bad_older = "Invalid older-than date: ";
+    
     private final FlagArgument FilesStdin;
     private final FlagArgument NoDirEntry;
     private final FlagArgument Recurse;
@@ -45,6 +53,8 @@
     private final StringArgument NoCompress;
     private final StringArgument NewerThan;
     private final StringArgument OlderThan;
+    private final StringArgument Exclude;
+    private final StringArgument Include;
     
     public ZipCommand() {
         super("compress files into a zip archive");
@@ -56,11 +66,13 @@
         FilesStdin   = new FlagArgument("files-stdin", Argument.OPTIONAL, 
help_files_stdin);
         NoDirEntry   = new FlagArgument("no-dirs", Argument.OPTIONAL, 
help_no_dir);
         Recurse      = new FlagArgument("recurse", Argument.OPTIONAL, 
help_recurse);
-        TmpDir       = new FileArgument("tmp-dir", Argument.OPTIONAL, 
help_tmpdir);
+        TmpDir       = new FileArgument("tmp-dir", Argument.OPTIONAL | 
Argument.EXISTING, help_tmpdir);
         NoCompress   = new StringArgument("no-compress", Argument.OPTIONAL, 
help_no_compress);
         NewerThan    = new StringArgument("newer", Argument.OPTIONAL, 
help_newer_than);
         OlderThan    = new StringArgument("older", Argument.OPTIONAL, 
help_older_than);
-        registerArguments(FilesStdin, TmpDir, NoDirEntry, NoCompress, Recurse, 
NewerThan, OlderThan);
+        Exclude      = new StringArgument("exclude", Argument.OPTIONAL | 
Argument.MULTIPLE, help_exclude);
+        Include      = new StringArgument("include", Argument.OPTIONAL | 
Argument.MULTIPLE, help_include);
+        registerArguments(FilesStdin, TmpDir, NoDirEntry, NoCompress, Recurse, 
NewerThan, OlderThan, Exclude, Include);
     }
     
     @Override
@@ -68,9 +80,40 @@
         recurse = Recurse.isSet();
         noDirEntry = NoDirEntry.isSet();
         filesStdin = FilesStdin.isSet();
-        if (NoCompress.isSet()) noCompress = NoCompress.getValue();
         if (TmpDir.isSet()) tmpDir = TmpDir.getValue();
-        
+        /* FIXME
+        if (NewerThan.isSet()) {
+            try {
+                newer = 
DateFormat.getInstance().parse(NewerThan.getValue()).getTime();
+            } catch (ParseException e) {
+                e.printStackTrace();
+                exit(1);
+            }
+        }
+        if (OlderThan.isSet()) {
+            try {
+                older = 
DateFormat.getInstance().parse(OlderThan.getValue()).getTime();
+            } catch (ParseException e) {
+                e.printStackTrace();
+                exit(1);
+            }
+        }
+        */
+        if (NoCompress.isSet()) {
+            noCompress = NoCompress.getValue().split(":");
+        }
+        if (Exclude.isSet()) {
+            excludes = new ArrayList<String>(Exclude.getValues().length);
+            for (String pattern : Exclude.getValues()) {
+                excludes.add(pattern);
+            }
+        }
+        if (Include.isSet()) {
+            includes = new ArrayList<String>(Include.getValues().length);
+            for (String pattern : Include.getValues()) {
+                includes.add(pattern);
+            }
+        }
         super.execute("zip");
     }
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Stay on top of everything new and different, both inside and 
around Java (TM) technology - register by April 22, and save
$200 on the JavaOne (SM) conference, June 2-5, 2009, San Francisco.
300 plus technical and hands-on sessions. Register today. 
Use priority code J9JMT32. http://p.sf.net/sfu/p
_______________________________________________
Jnode-svn-commits mailing list
Jnode-svn-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits

Reply via email to