[Japi-cvs] SF.net SVN: japi: [525] libs/argparser/trunk/src
Status: Beta
                
                Brought to you by:
                
                    christianhujer
                    
                
            | 
     
      
      
      From: <chr...@us...> - 2007-07-09 20:54:34
      
     
   | 
Revision: 525
          http://svn.sourceforge.net/japi/?rev=525&view=rev
Author:   christianhujer
Date:     2007-07-09 13:54:31 -0700 (Mon, 09 Jul 2007)
Log Message:
-----------
[ 1750193 ] Partial read of command line arguments from a file
Modified Paths:
--------------
    libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java
    libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java
Added Paths:
-----------
    libs/argparser/trunk/src/net/sf/japi/io/args/TokenReader.java
    libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine
    libs/argparser/trunk/src/test/net/sf/japi/io/args/TokenReaderTest.java
Modified: libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java
===================================================================
--- libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java	2007-07-09 19:27:05 UTC (rev 524)
+++ libs/argparser/trunk/src/net/sf/japi/io/args/ArgParser.java	2007-07-09 20:54:31 UTC (rev 525)
@@ -30,6 +30,8 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import net.sf.japi.io.args.converter.ConverterRegistry;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -75,7 +77,7 @@
         this.command = command;
         commandClass = command.getClass();
         initMethods();
-        final List<String> argList = new ArrayList<String>(Arrays.asList(args));
+        final List<String> argList = getAllArguments(Arrays.asList(args));
         argIterator = argList.listIterator();
         parse();
         checkRequiredMethods();
@@ -92,6 +94,44 @@
     }
 
     /**
+     * Returns a list of all arguments after parsing arguments files.
+     */
+    public List<String> getAllArguments(@NotNull final List<String> args) {
+        final List<String> argList = new ArrayList<String>(args);
+        for (final ListIterator<String> iterator = argList.listIterator(); iterator.hasNext();) {
+            final String arg = iterator.next();
+            if (arg.equals("--")) {
+                break;
+            }
+            if (arg.startsWith("@")) {
+                iterator.remove();
+                for (final String insertArg : getAllArguments(readFromFile(arg.substring(1)))) {
+                    iterator.add(insertArg);
+                }
+            }
+        }
+        return argList;
+    }
+
+    /**
+     * Returns a tokenized unparsed list of arguments from an arguments file.
+     */
+    public List<String> readFromFile(@NotNull final String filename) {
+        final List<String> args = new ArrayList<String>();
+        final TokenReader in;
+        try {
+            in = new TokenReader(new FileInputStream(filename));
+        } catch (FileNotFoundException e) {
+            // TODO TODO TODO TODO TODO
+            return args;
+        }
+        for (final String token : in) {
+            args.add(token);
+        }
+        return args;
+    }
+
+    /**
      * Checks that all required methods have been invoked.
      * @throws RequiredOptionsMissingException in case a required command line argument was missing
      */
Added: libs/argparser/trunk/src/net/sf/japi/io/args/TokenReader.java
===================================================================
--- libs/argparser/trunk/src/net/sf/japi/io/args/TokenReader.java	                        (rev 0)
+++ libs/argparser/trunk/src/net/sf/japi/io/args/TokenReader.java	2007-07-09 20:54:31 UTC (rev 525)
@@ -0,0 +1,147 @@
+/*
+ * JAPI libs-argparser is a library for parsing command line arguments.
+ * Copyright (C) 2007  Christian Hujer.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+package net.sf.japi.io.args;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A TokenReader reads arguments from a file, non-recursive.
+ * That means the arguments are read regarding a certain argument syntax, but remain otherwise unparsed.
+ * @author <a href="mailto:ch...@ri...">Christian Hujer</a>
+ */
+public class TokenReader implements Closeable, Iterable<String>, Iterator<String> {
+
+    /** Reader to read from. */
+    @NotNull private Reader in;
+
+    /** The next token. */
+    @Nullable String next;
+
+    /** Creates a TokenReader.
+     * @param in InputStream to read from.
+     */
+    public TokenReader(@NotNull final InputStream in) {
+        this.in = new InputStreamReader(in);
+        next = readNextToken();
+    }
+
+    /** {@inheritDoc} */
+    public void close() throws IOException {
+        in.close();
+    }
+
+    /** {@inheritDoc} */
+    @NotNull public Iterator<String> iterator() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasNext() {
+        return next != null;
+    }
+
+    /** {@inheritDoc} */
+    @NotNull public String next() {
+        if (next == null) {
+            throw new NoSuchElementException();
+        }
+        try {
+            return next;
+        } finally {
+            next = readNextToken();
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** Reads the next token from the underlying reader.
+     * @return Next token read from the underlying reader or <code>null</code> if no more tokens are available.
+     */
+    @Nullable public String readNextToken() {
+        final StringBuilder nextToken = new StringBuilder();
+        boolean tokenValid = false;
+        Mode mode = Mode.WHITESPACE;
+        try {
+            for (int rc; (rc = in.read()) != -1;) {
+                final char c = (char) rc;
+                switch (mode) {
+                    case WHITESPACE:
+                        if (Character.isWhitespace(c)) {
+                        } else if (c == '"') {
+                            mode = Mode.STRING;
+                            tokenValid = true;
+                        } else {
+                            nextToken.append(c);
+                            mode = Mode.NORMAL;
+                            tokenValid = true;
+                        }
+                        break;
+                    case NORMAL:
+                        if (Character.isWhitespace(c)) {
+                            assert tokenValid;
+                            assert nextToken.length() != 0;
+                            return nextToken.toString();
+                        } else if (c == '"') {
+                            mode = Mode.STRING;
+                        } else {
+                            nextToken.append(c);
+                        }
+                        break;
+                    case STRING:
+                        if (c == '"') {
+                            mode = Mode.NORMAL;
+                        } else if (c == '\\') {
+                            mode = Mode.STRING_ESCAPE;
+                        } else {
+                            nextToken.append(c);
+                        }
+                        break;
+                    case STRING_ESCAPE:
+                        nextToken.append(c);
+                        mode = Mode.STRING;
+                        break;
+                }
+            }
+        } catch (final IOException ignore) {
+            // ignore
+        }
+        return tokenValid ? nextToken.toString() : null;
+    }
+
+    /** The mode of the tokenizer. */
+    private enum Mode {
+        WHITESPACE,
+        NORMAL,
+        STRING,
+        STRING_ESCAPE
+    }
+
+} // class TokenReader
Property changes on: libs/argparser/trunk/src/net/sf/japi/io/args/TokenReader.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + LF
Modified: libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java
===================================================================
--- libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java	2007-07-09 19:27:05 UTC (rev 524)
+++ libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest.java	2007-07-09 20:54:31 UTC (rev 525)
@@ -227,6 +227,25 @@
     }
 
     /**
+     * Tests whether reading options from a file works.
+     * @throws RequiredOptionsMissingException (unexpected)
+     * @throws TerminalException (unexpected)
+     * @throws UnknownOptionException (unexpected)
+     * @throws MissingArgumentException (unexpected)
+     */
+    @Test
+    public void testOptionsFromFileSingleLine() throws RequiredOptionsMissingException, MissingArgumentException, TerminalException, UnknownOptionException {
+        final MockCommand command = new MockCommand();
+        ArgParser.parseAndRun(command, "@src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine");
+        final List<String> args = command.getArgs();
+        Assert.assertEquals("Option value must be stored.", "fooInput", command.getInput());
+        Assert.assertTrue("Run must be called even with zero arguments.", command.isRunCalled());
+        Assert.assertEquals("Arguments must be stored.", 2, args.size());
+        Assert.assertEquals("Argument foo must be stored.", "foo", args.get(0));
+        Assert.assertEquals("Argument bar must be stored.", "bar", args.get(1));
+    }
+
+    /**
      * This MockCommand serves as a command for performing simple tests.
      * @author <a href="mailto:ch...@ri...">Christian Hujer</a>
      */
Added: libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine
===================================================================
--- libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine	                        (rev 0)
+++ libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine	2007-07-09 20:54:31 UTC (rev 525)
@@ -0,0 +1 @@
+-i fooInput foo bar
\ No newline at end of file
Property changes on: libs/argparser/trunk/src/test/net/sf/japi/io/args/ArgParserTest_OptionsFileSingleLine
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + LF
Added: libs/argparser/trunk/src/test/net/sf/japi/io/args/TokenReaderTest.java
===================================================================
--- libs/argparser/trunk/src/test/net/sf/japi/io/args/TokenReaderTest.java	                        (rev 0)
+++ libs/argparser/trunk/src/test/net/sf/japi/io/args/TokenReaderTest.java	2007-07-09 20:54:31 UTC (rev 525)
@@ -0,0 +1,162 @@
+/*
+ * JAPI libs-argparser is a library for parsing command line arguments.
+ * Copyright (C) 2007  Christian Hujer.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+package test.net.sf.japi.io.args;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.NoSuchElementException;
+import net.sf.japi.io.args.TokenReader;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.Assert;
+
+/**
+ * Test for {@link TokenReader}.
+ * @author <a href="mailto:ch...@ri...">Christian Hujer</a>
+ */
+public class TokenReaderTest {
+
+    /** Tests that a TokenReader on an empty file has no tokens. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenReaderEmpty() {
+        final TokenReader reader = new TokenReader(createStream(""));
+        Assert.assertFalse("On an empty file, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with whitespace only has no tokens. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenReaderWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("   \n    "));
+        Assert.assertFalse("On whitespace only, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with a single token returns that token. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenSimple() {
+        final TokenReader reader = new TokenReader(createStream("foo"));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        final String token = reader.next();
+        Assert.assertEquals("Token must be retrievable", "foo", token);
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with preceeding whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenWithPreceedingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("   foo"));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        final String token = reader.next();
+        Assert.assertEquals("Token must be retrievable", "foo", token);
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with trailing whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenWithTrailingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("foo   "));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        final String token = reader.next();
+        Assert.assertEquals("Token must be retrievable", "foo", token);
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with surrounding whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokenWithSurroundingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("   foo   "));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        final String token = reader.next();
+        Assert.assertEquals("Token must be retrievable", "foo", token);
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with preceeding whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokensWithPreceedingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("   foo  bar"));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "foo", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "bar", reader.next());
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with trailing whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokensWithTrailingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("foo  bar   "));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "foo", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "bar", reader.next());
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with surrounding whitespace returns the token without whitespace. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokensWithSurroundingWhitespace() {
+        final TokenReader reader = new TokenReader(createStream("   foo  bar   "));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "foo", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Token must be retrievable", "bar", reader.next());
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Tests that a TokenReader on a file with String tokens returns them. */
+    @Test(expected = NoSuchElementException.class)
+    public void testTokensComplex() {
+        final TokenReader reader = new TokenReader(createStream("   foo\nbar\nbuzz token\n\"  Multiline\n\\\"String  \"  anotherFoo  a\"n\"a"));
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "foo", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "bar", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "buzz", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "token", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "  Multiline\n\"String  ", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "anotherFoo", reader.next());
+        Assert.assertTrue("Before reading the last token, hasNext() must return true.", reader.hasNext());
+        Assert.assertEquals("Expecting token", "ana", reader.next());
+        Assert.assertFalse("After reading the last token, hasNext() must return false.", reader.hasNext());
+        reader.next();
+    }
+
+    /** Creates an InputStream for reading from a String.
+     * @param s String to read from.
+     * @return InputStream created from s.
+     */
+    @NotNull private static InputStream createStream(@NotNull final String s) {
+        return new ByteArrayInputStream(s.getBytes());
+    }
+
+} // class TokenReaderTest
Property changes on: libs/argparser/trunk/src/test/net/sf/japi/io/args/TokenReaderTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + LF
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
 |