|
From: <cr...@us...> - 2009-02-16 13:47:37
|
Revision: 5032
http://jnode.svn.sourceforge.net/jnode/?rev=5032&view=rev
Author: crawley
Date: 2009-02-16 13:47:27 +0000 (Mon, 16 Feb 2009)
Log Message:
-----------
Add support for input and output files to the black-box test harness
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
trunk/shell/src/test/org/jnode/test/shell/harness/ClassTestRunner.java
trunk/shell/src/test/org/jnode/test/shell/harness/CommandTestRunner.java
trunk/shell/src/test/org/jnode/test/shell/harness/ScriptTestRunner.java
trunk/shell/src/test/org/jnode/test/shell/harness/TestHarness.java
trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnable.java
trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecification.java
trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecificationParser.java
Added Paths:
-----------
trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java
Removed Paths:
-------------
trunk/shell/src/test/org/jnode/test/shell/harness/JNodeTestRunnerBase.java
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -39,6 +39,7 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -913,7 +914,7 @@
map.put(var.name, var.value);
}
}
- return map;
+ return Collections.unmodifiableMap(map);
}
PrintStream resolvePrintStream(CommandIO commandIOIF) {
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-02-16 13:47:27 UTC (rev 5032)
@@ -588,9 +588,9 @@
echo 'a b'
echo "a b"
echo $*
- echo $@
+ echo $@@
echo "$*"
- echo "$@"
+ echo "$@@"
</script>
<arg>arg1</arg>
<arg>arg2</arg>
@@ -611,4 +611,11 @@
+ echo arg1 arg2
</error>
</testSpec>
+ <testSpec title="redirection" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ echo > @TEMP_DIR@/blablah Hi mum
+ </script>
+ <file name="blablah" input="false">Hi mum
+</file>
+ </testSpec>
</testSet>
\ No newline at end of file
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/ClassTestRunner.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/ClassTestRunner.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/ClassTestRunner.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -20,9 +20,7 @@
package org.jnode.test.shell.harness;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
+import java.io.IOException;
import java.lang.reflect.Method;
/**
@@ -31,17 +29,10 @@
*
* @author cr...@jn...
*/
-class ClassTestRunner implements TestRunnable {
+class ClassTestRunner extends TestRunnerBase implements TestRunnable {
- private ByteArrayOutputStream outBucket;
- private ByteArrayOutputStream errBucket;
-
- private final TestSpecification spec;
- private final TestHarness harness;
-
public ClassTestRunner(TestSpecification spec, TestHarness harness) {
- this.spec = spec;
- this.harness = harness;
+ super(spec, harness);
}
@Override
@@ -53,24 +44,11 @@
return check() ? 0 : 1;
}
- private boolean check() {
+ private boolean check() throws IOException {
// When a class is run this way we cannot capture the RC.
return
harness.expect(outBucket.toString(), spec.getOutputContent(), "output content") &
- harness.expect(errBucket.toString(), spec.getErrorContent(), "err content");
+ harness.expect(errBucket.toString(), spec.getErrorContent(), "err content") &
+ checkFiles();
}
-
- @Override
- public void cleanup() {
- }
-
- @Override
- public void setup() {
- System.setIn(new ByteArrayInputStream(spec.getInputContent().toString().getBytes()));
- outBucket = new ByteArrayOutputStream();
- errBucket = new ByteArrayOutputStream();
- System.setOut(new PrintStream(outBucket));
- System.setErr(new PrintStream(errBucket));
- }
-
}
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/CommandTestRunner.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/CommandTestRunner.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/CommandTestRunner.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -20,9 +20,7 @@
package org.jnode.test.shell.harness;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
+import java.io.IOException;
import org.jnode.shell.CommandShell;
@@ -33,12 +31,8 @@
*
* @author cr...@jn...
*/
-class CommandTestRunner extends JNodeTestRunnerBase implements TestRunnable {
+class CommandTestRunner extends TestRunnerBase implements TestRunnable {
- private ByteArrayOutputStream outBucket;
- private ByteArrayOutputStream errBucket;
-
-
public CommandTestRunner(TestSpecification spec, TestHarness harness) {
super(spec, harness);
}
@@ -55,24 +49,11 @@
return check(rc) ? 0 : 1;
}
- private boolean check(int rc) {
+ private boolean check(int rc) throws IOException {
return
harness.expect(rc, spec.getRc(), "return code") &
harness.expect(outBucket.toString(), spec.getOutputContent(), "output content") &
- harness.expect(errBucket.toString(), spec.getErrorContent(), "err content");
+ harness.expect(errBucket.toString(), spec.getErrorContent(), "err content") &
+ checkFiles();
}
-
- @Override
- public void cleanup() {
- }
-
- @Override
- public void setup() {
- System.setIn(new ByteArrayInputStream(spec.getInputContent().toString().getBytes()));
- outBucket = new ByteArrayOutputStream();
- errBucket = new ByteArrayOutputStream();
- System.setOut(new PrintStream(outBucket));
- System.setErr(new PrintStream(errBucket));
- }
-
}
Deleted: trunk/shell/src/test/org/jnode/test/shell/harness/JNodeTestRunnerBase.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/JNodeTestRunnerBase.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/JNodeTestRunnerBase.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -1,144 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2003-2009 JNode.org
- *
- * 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 org.jnode.test.shell.harness;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import org.jnode.naming.InitialNaming;
-import org.jnode.plugin.PluginManager;
-import org.jnode.shell.CommandShell;
-import org.jnode.shell.ShellException;
-
-/**
- * This base class supplies functions for getting hold of "the shell" for
- * testing commands, configuring required plugins and setting up the
- * System streams for a command.
- *
- * @author cr...@jn...
- */
-public abstract class JNodeTestRunnerBase implements TestRunnable {
-
- private class TeeStream extends FilterOutputStream {
- private OutputStream out2;
-
- public TeeStream(OutputStream out, OutputStream out2) {
- super(out);
- this.out2 = out2;
- }
-
- @Override
- public void close() throws IOException {
- super.close();
- out2.close();
- }
-
- @Override
- public void flush() throws IOException {
- super.flush();
- out2.flush();
- }
-
- @Override
- public void write(int b) throws IOException {
- super.write(b);
- out2.write(b);
- }
- }
-
- protected ByteArrayOutputStream outBucket;
- protected ByteArrayOutputStream errBucket;
-
- protected final TestSpecification spec;
- protected final TestHarness harness;
-
- protected final boolean usingEmu;
-
- public JNodeTestRunnerBase(TestSpecification spec, TestHarness harness) {
- super();
- this.spec = spec;
- this.harness = harness;
- this.usingEmu = TestEmu.initEmu(harness.getRoot());
- }
-
- public CommandShell getShell() throws ShellException {
- CommandShell shell = TestEmu.getShell();
- if (shell == null) {
- shell = new TestCommandShell(System.in, System.out, System.err);
- shell.configureShell();
- }
- return shell;
- }
-
- @Override
- public void cleanup() {
- }
-
- @Override
- public void setup() {
- ensurePluginsLoaded(spec.getTestSet());
- for (PluginSpecification plugin : spec.getPlugins()) {
- ensurePluginLoaded(plugin);
- }
- System.setIn(new ByteArrayInputStream(spec.getInputContent().toString().getBytes()));
- outBucket = new ByteArrayOutputStream();
- errBucket = new ByteArrayOutputStream();
- if (harness.isDebug()) {
- System.setOut(new PrintStream(new TeeStream(outBucket, System.out)));
- System.setErr(new PrintStream(new TeeStream(errBucket, System.err)));
- } else {
- System.setOut(new PrintStream(outBucket));
- System.setErr(new PrintStream(errBucket));
- }
- }
-
- private void ensurePluginsLoaded(TestSetSpecification testSet) {
- if (testSet == null) {
- return;
- }
- ensurePluginsLoaded(testSet.getParentSet());
- for (PluginSpecification plugin : spec.getTestSet().getPlugins()) {
- ensurePluginLoaded(plugin);
- }
- }
-
- protected void ensurePluginLoaded(PluginSpecification plugin) {
- if (usingEmu) {
- TestEmu.loadPseudoPlugin(plugin.getPluginId(), plugin.getClassName());
- } else {
- // TODO - I'm not sure about this. A simpler alternative is to assume
- // that all required plugins have already been loaded by JNode.
- String ver = (plugin.getPluginVersion().length() == 0) ?
- System.getProperty("os.version") : plugin.getPluginVersion();
- try {
- PluginManager mgr = InitialNaming.lookup(PluginManager.NAME);
- mgr.getRegistry().loadPlugin(mgr.getLoaderManager(), plugin.getPluginId(), ver);
- } catch (Exception ex) {
- throw new RuntimeException(
- "Cannot load plugin '" + plugin.getPluginId() + "/" + ver + "'");
- }
- }
- }
-}
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/ScriptTestRunner.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/ScriptTestRunner.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/ScriptTestRunner.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -20,9 +20,13 @@
package org.jnode.test.shell.harness;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
-import java.io.Writer;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Properties;
/**
@@ -31,7 +35,7 @@
*
* @author cr...@jn...
*/
-class ScriptTestRunner extends JNodeTestRunnerBase implements TestRunnable {
+class ScriptTestRunner extends TestRunnerBase implements TestRunnable {
private File tempScriptFile;
@@ -41,25 +45,28 @@
@Override
public int run() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("TEMP_DIR", System.getProperty("java.io.tmpdir"));
tempScriptFile = new File(System.getProperty("java.io.tmpdir"), spec.getCommand());
- Writer w = null;
+ BufferedWriter bw = null;
try {
- w = new FileWriter(tempScriptFile);
- w.write(spec.getScriptContent().toString());
- w.write('\n');
+ bw = new BufferedWriter(new FileWriter(tempScriptFile));
+ expand(props, spec.getScriptContent().toString(), bw, '@');
+ bw.write('\n');
} finally {
- w.close();
+ bw.close();
}
int rc = getShell().runCommandFile(tempScriptFile,
spec.getCommand(), spec.getArgs().toArray(new String[0]));
return check(rc) ? 0 : 1;
}
- private boolean check(int rc) {
+ private boolean check(int rc) throws IOException {
return
harness.expect(rc, spec.getRc(), "return code") &
harness.expect(outBucket.toString(), spec.getOutputContent(), "output content") &
- harness.expect(errBucket.toString(), spec.getErrorContent(), "err content");
+ harness.expect(errBucket.toString(), spec.getErrorContent(), "err content") &
+ checkFiles();
}
@Override
@@ -69,5 +76,56 @@
}
super.cleanup();
}
-
+
+ /**
+ * Expand a '@...@' sequences in a template, writing the result to an
+ * Writer. A sequence '@@' turns into a single '@'. A sequence
+ * '@name@' expands to the value of the named property if it is defined in
+ * the property set, or the sequence '@name@' if it does not. A CR, NL or
+ * EOF in an '@...@' sequence is an error.
+ *
+ * @param props the properties to be expanded
+ * @param template is the template string
+ * @param w the sink for the expanded template
+ * @param marker the sequence marker character(defaults to '@')
+ * @throws IOException
+ * @throws TestSpecificationException
+ */
+ private void expand(Properties props, String template, BufferedWriter w, char marker)
+ throws IOException, TestSpecificationException {
+ int ch;
+ Reader r = new StringReader(template);
+ while ((ch = r.read()) != -1) {
+ if (ch == marker) {
+ StringBuffer sb = new StringBuffer(20);
+ while ((ch = r.read()) != marker) {
+ switch (ch) {
+ case -1:
+ throw new TestSpecificationException("Encountered EOF in a " + marker +
+ "..." + marker + " sequence in script template");
+ case '\n':
+ throw new TestSpecificationException("Encountered newline in a " +
+ marker + "..." + marker + " sequence in script template");
+ default:
+ sb.append((char) ch);
+ }
+ }
+ if (sb.length() == 0) {
+ w.write(marker);
+ } else {
+ String name = sb.toString();
+ String value = props.getProperty(name);
+ if (value == null) {
+ w.write(marker);
+ w.write(sb.toString().toCharArray());
+ w.write(marker);
+ } else {
+ w.write(value.toCharArray());
+ }
+ }
+ } else {
+ w.write((char) ch);
+ }
+ }
+ }
}
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/TestHarness.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestHarness.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestHarness.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -279,4 +279,13 @@
public boolean isDebug() {
return debug;
}
+
+ public File tempFile(File file) {
+ return new File(System.getProperty("java.io.tmpdir"), file.toString());
+ }
+
+ public boolean fail(String msg) {
+ report("Incorrect test result in test " + asString(spec.getTitle()) + ": " + msg);
+ return false;
+ }
}
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnable.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnable.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnable.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -20,6 +20,7 @@
package org.jnode.test.shell.harness;
+
/**
* This is the API implemented by the command test runners. We cannot
* use / extend Runnable because we need to propagate any exceptions
@@ -31,7 +32,7 @@
public int run() throws Exception;
- public void setup();
+ public void setup() throws Exception;
public void cleanup();
Added: trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java (rev 0)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -0,0 +1,196 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * 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 org.jnode.test.shell.harness;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.jnode.naming.InitialNaming;
+import org.jnode.plugin.PluginManager;
+import org.jnode.shell.CommandShell;
+import org.jnode.shell.ShellException;
+import org.jnode.test.shell.harness.TestSpecification.FileSpecification;
+
+/**
+ * This base class supplies functions for getting hold of "the shell" for
+ * testing commands, configuring required plugins and setting up the
+ * System streams for a command.
+ *
+ * @author cr...@jn...
+ */
+public abstract class TestRunnerBase implements TestRunnable {
+
+ private class TeeStream extends FilterOutputStream {
+ private OutputStream out2;
+
+ public TeeStream(OutputStream out, OutputStream out2) {
+ super(out);
+ this.out2 = out2;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ out2.close();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ out2.flush();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ super.write(b);
+ out2.write(b);
+ }
+ }
+
+ protected ByteArrayOutputStream outBucket;
+ protected ByteArrayOutputStream errBucket;
+
+ protected final TestSpecification spec;
+ protected final TestHarness harness;
+
+ protected final boolean usingEmu;
+
+ public TestRunnerBase(TestSpecification spec, TestHarness harness) {
+ super();
+ this.spec = spec;
+ this.harness = harness;
+ this.usingEmu = TestEmu.initEmu(harness.getRoot());
+ }
+
+ public CommandShell getShell() throws ShellException {
+ CommandShell shell = TestEmu.getShell();
+ if (shell == null) {
+ shell = new TestCommandShell(System.in, System.out, System.err);
+ shell.configureShell();
+ }
+ return shell;
+ }
+
+ @Override
+ public void cleanup() {
+ if (!harness.isDebug()) {
+ for (FileSpecification fs : spec.getFiles()) {
+ if (fs.isInput()) {
+ File tempFile = harness.tempFile(fs.getFile());
+ tempFile.delete();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setup() throws IOException {
+ ensurePluginsLoaded(spec.getTestSet());
+ for (PluginSpecification plugin : spec.getPlugins()) {
+ ensurePluginLoaded(plugin);
+ }
+ System.setIn(new ByteArrayInputStream(spec.getInputContent().toString().getBytes()));
+ outBucket = new ByteArrayOutputStream();
+ errBucket = new ByteArrayOutputStream();
+ if (harness.isDebug()) {
+ System.setOut(new PrintStream(new TeeStream(outBucket, System.out)));
+ System.setErr(new PrintStream(new TeeStream(errBucket, System.err)));
+ } else {
+ System.setOut(new PrintStream(outBucket));
+ System.setErr(new PrintStream(errBucket));
+ }
+ for (FileSpecification fs : spec.getFiles()) {
+ File tempFile = harness.tempFile(fs.getFile());
+ if (fs.isInput()) {
+ OutputStream os = new FileOutputStream(tempFile);
+ try {
+ byte[] bytes = fs.getFileContent().getBytes();
+ os.write(bytes);
+ } finally {
+ os.close();
+ }
+ } else {
+ tempFile.delete();
+ }
+ }
+ }
+
+ protected boolean checkFiles() throws IOException {
+ boolean ok = true;
+ for (FileSpecification fs : spec.getFiles()) {
+ File tempFile = harness.tempFile(fs.getFile());
+ if (!fs.isInput()) {
+ if (!tempFile.exists()) {
+ harness.fail("file not created: '" + tempFile + "'");
+ ok = false;
+ } else {
+ int fileLength = (int) tempFile.length();
+ byte[] bytes = new byte[fileLength];
+ InputStream is = new FileInputStream(tempFile);
+ try {
+ is.read(bytes);
+ } finally {
+ is.close();
+ }
+ String content = new String(bytes);
+ ok = ok & harness.expect(content, fs.getFileContent(), "file content (" + tempFile + ")");
+ }
+ }
+ }
+ return ok;
+ }
+
+ private void ensurePluginsLoaded(TestSetSpecification testSet) {
+ if (testSet == null) {
+ return;
+ }
+ ensurePluginsLoaded(testSet.getParentSet());
+ for (PluginSpecification plugin : spec.getTestSet().getPlugins()) {
+ ensurePluginLoaded(plugin);
+ }
+ }
+
+ protected void ensurePluginLoaded(PluginSpecification plugin) {
+ if (usingEmu) {
+ TestEmu.loadPseudoPlugin(plugin.getPluginId(), plugin.getClassName());
+ } else {
+ // TODO - I'm not sure about this. A simpler alternative is to assume
+ // that all required plugins have already been loaded by JNode.
+ String ver = (plugin.getPluginVersion().length() == 0) ?
+ System.getProperty("os.version") : plugin.getPluginVersion();
+ try {
+ PluginManager mgr = InitialNaming.lookup(PluginManager.NAME);
+ mgr.getRegistry().loadPlugin(mgr.getLoaderManager(), plugin.getPluginId(), ver);
+ } catch (Exception ex) {
+ throw new RuntimeException(
+ "Cannot load plugin '" + plugin.getPluginId() + "/" + ver + "'");
+ }
+ }
+ }
+}
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecification.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecification.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecification.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -22,9 +22,7 @@
import java.io.File;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* This represents a command test specification for a command or script.
@@ -39,6 +37,31 @@
AS_ALIAS
}
+ public static class FileSpecification {
+ private final File file;
+ private final boolean input;
+ private final String fileContent;
+
+ public FileSpecification(File file, boolean input,
+ String fileContent) {
+ this.file = file;
+ this.input = input;
+ this.fileContent = fileContent;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public boolean isInput() {
+ return input;
+ }
+
+ public String getFileContent() {
+ return fileContent;
+ }
+ }
+
private final RunMode runMode;
private final String command;
private final List<String> args = new ArrayList<String>();
@@ -49,19 +72,19 @@
private final String title;
private final List<PluginSpecification> plugins = new ArrayList<PluginSpecification>();
private final int rc;
- private final Map<File, String> fileMap = new HashMap<File, String>();
+ private final List<FileSpecification> files = new ArrayList<FileSpecification>();
private TestSetSpecification testSet;
- public TestSpecification(RunMode runMode, String command, String scriptContent2,
- String inputContent2, String outputContent2, String errorContent2,
+ public TestSpecification(RunMode runMode, String command, String scriptContent,
+ String inputContent, String outputContent, String errorContent,
String title, int rc) {
super();
this.runMode = runMode;
this.command = command;
- this.scriptContent = scriptContent2;
- this.inputContent = inputContent2;
- this.outputContent = outputContent2;
- this.errorContent = errorContent2;
+ this.scriptContent = scriptContent;
+ this.inputContent = inputContent;
+ this.outputContent = outputContent;
+ this.errorContent = errorContent;
this.title = title;
this.rc = rc;
}
@@ -86,12 +109,12 @@
plugins.add(plugin);
}
- public void addFile(File file, String content) {
- fileMap.put(file, content);
+ public void addFile(FileSpecification file) {
+ files.add(file);
}
- public Map<File, String> getFileMap() {
- return fileMap;
+ public List<FileSpecification> getFiles() {
+ return files;
}
public RunMode getRunMode() {
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecificationParser.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecificationParser.java 2009-02-15 22:30:50 UTC (rev 5031)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestSpecificationParser.java 2009-02-16 13:47:27 UTC (rev 5032)
@@ -113,13 +113,19 @@
private void parseFile(IXMLElement elem, TestSpecification res)
throws TestSpecificationException {
String fileName = extractAttribute(elem, "name");
- String content = extractElementValue(elem, "content", "");
- res.addFile(new File(fileName), content);
+ boolean isInput = extractAttribute(elem, "input", "false").equals("true");
+ String content = extractElementValue(elem, null, "");
+ File file = new File(fileName);
+ if (file.isAbsolute()) {
+ throw new TestSpecificationException(
+ "A '" + elem.getName() + "' element must have a relative 'name''");
+ }
+ res.addFile(new TestSpecification.FileSpecification(file...
[truncated message content] |
|
From: <cr...@us...> - 2009-02-24 15:28:40
|
Revision: 5063
http://jnode.svn.sourceforge.net/jnode/?rev=5063&view=rev
Author: crawley
Date: 2009-02-24 15:28:36 +0000 (Tue, 24 Feb 2009)
Log Message:
-----------
Implement '( <cmd> ; ... ) > file '
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/ListCommandNode.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-02-24 13:33:41 UTC (rev 5062)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-02-24 15:28:36 UTC (rev 5063)
@@ -942,6 +942,12 @@
holders[index].setStream(stream, mine);
}
}
+
+ void closeStreams() {
+ for (StreamHolder holder : holders) {
+ holder.close();
+ }
+ }
void performAssignments(BjorneToken[] assignments) throws ShellException {
if (assignments != null) {
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/ListCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/ListCommandNode.java 2009-02-24 13:33:41 UTC (rev 5062)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/ListCommandNode.java 2009-02-24 15:28:36 UTC (rev 5063)
@@ -71,44 +71,55 @@
@Override
public int execute(BjorneContext context) throws ShellException {
+ int listFlags = getFlags();
int rc = 0;
- if (getNodeType() == BjorneInterpreter.CMD_SUBSHELL) {
- // This simulates creating a 'subshell'.
- context = new BjorneContext(context);
- }
- int listFlags = getFlags();
- if ((listFlags & BjorneInterpreter.FLAG_PIPE) != 0) {
- PipelineStage[] stages = assemblePipeline(context);
- boolean done = false;
- try {
- rc = runPipeline(stages);
- done = true;
- } finally {
- if (!done) {
- // If we are propagating an exception, all streams that
- // were opened by 'assemblePipeline' must be closed.
- for (PipelineStage stage : stages) {
- for (StreamHolder holder : stage.holders) {
- holder.close();
- }
- }
+ try {
+ if (getNodeType() == BjorneInterpreter.CMD_SUBSHELL) {
+ // This simulates creating a 'subshell'.
+ context = new BjorneContext(context);
+ StreamHolder[] holders = context.evaluateRedirections(getRedirects());
+ for (int i = 0; i < holders.length; i++) {
+ CommandIO stream = holders[i].getStream();
+ context.setStream(i, stream, holders[i].isMine());
}
}
- } else {
- for (CommandNode command : commands) {
- int commandFlags = command.getFlags();
- if ((commandFlags & BjorneInterpreter.FLAG_AND_IF) != 0) {
- if (context.getLastReturnCode() != 0) {
- break;
+ if ((listFlags & BjorneInterpreter.FLAG_PIPE) != 0) {
+ PipelineStage[] stages = assemblePipeline(context);
+ boolean done = false;
+ try {
+ rc = runPipeline(stages);
+ done = true;
+ } finally {
+ if (!done) {
+ // If we are propagating an exception, all streams that
+ // were opened by 'assemblePipeline' must be closed.
+ for (PipelineStage stage : stages) {
+ for (StreamHolder holder : stage.holders) {
+ holder.close();
+ }
+ }
}
}
- if ((commandFlags & BjorneInterpreter.FLAG_OR_IF) != 0) {
- if (context.getLastReturnCode() == 0) {
- break;
+ } else {
+ for (CommandNode command : commands) {
+ int commandFlags = command.getFlags();
+ if ((commandFlags & BjorneInterpreter.FLAG_AND_IF) != 0) {
+ if (context.getLastReturnCode() != 0) {
+ break;
+ }
}
+ if ((commandFlags & BjorneInterpreter.FLAG_OR_IF) != 0) {
+ if (context.getLastReturnCode() == 0) {
+ break;
+ }
+ }
+ rc = command.execute(context);
}
- rc = command.execute(context);
}
+ } finally {
+ if (getNodeType() == BjorneInterpreter.CMD_SUBSHELL) {
+ context.closeStreams();
+ }
}
if ((listFlags & BjorneInterpreter.FLAG_BANG) != 0) {
rc = (rc == 0) ? -1 : 0;
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-02-24 13:33:41 UTC (rev 5062)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-02-24 15:28:36 UTC (rev 5063)
@@ -629,4 +629,45 @@
<error>Hello mother again
</error>
</testSpec>
+ <testSpec title="pipeline" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ echo > @TEMP_DIR@/1 Hi mum
+ echo > @TEMP_DIR@/2 Hi mum again
+ cat @TEMP_DIR@/1 @TEMP_DIR@/2 @TEMP_DIR@/1 @TEMP_DIR@/2 | cat
+ cat @TEMP_DIR@/1 @TEMP_DIR@/2 @TEMP_DIR@/1 @TEMP_DIR@/2 | cat > @TEMP_DIR@/3
+ </script>
+ <file name="1" input="false">Hi mum
+</file>
+ <file name="2" input="false">Hi mum again
+</file>
+ <file name="3" input="false">Hi mum
+Hi mum again
+Hi mum
+Hi mum again
+</file>
+ <output>Hi mum
+Hi mum again
+Hi mum
+Hi mum again
+</output>
+ </testSpec>
+ <testSpec title="subshell" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ echo > @TEMP_DIR@/1 Hi mum
+ echo > @TEMP_DIR@/2 Hi mum again
+ ( cat @TEMP_DIR@/1 ; cat @TEMP_DIR@/2 )
+ ( cat @TEMP_DIR@/1 ; cat @TEMP_DIR@/2 ) > @TEMP_DIR@/3
+ </script>
+ <file name="1" input="false">Hi mum
+</file>
+ <file name="2" input="false">Hi mum again
+</file>
+ <file name="3" input="false">Hi mum
+Hi mum again
+</file>
+ <output>Hi mum
+Hi mum again
+</output>
+ </testSpec>
+
</testSet>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-10 14:34:47
|
Revision: 5095
http://jnode.svn.sourceforge.net/jnode/?rev=5095&view=rev
Author: crawley
Date: 2009-03-10 14:34:35 +0000 (Tue, 10 Mar 2009)
Log Message:
-----------
New classes to be used in a reworked pipeline implementation for Bjorne.
(Unfortunately, the classic PipedInput/Output won't work when there are
potentially multiple threads reading or writing the same pipe.)
Added Paths:
-----------
trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java
trunk/shell/src/shell/org/jnode/shell/io/PipelineInputStream.java
trunk/shell/src/shell/org/jnode/shell/io/PipelineOutputStream.java
trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java
Added: trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java 2009-03-10 14:34:35 UTC (rev 5095)
@@ -0,0 +1,220 @@
+package org.jnode.shell.io;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides a buffered byte-stream pipeline implementation that
+ * supports multiple sources and sinks. The pipeline has a finite buffer,
+ * so a thread that reads and writes to the same pipeline risks deadlock.
+ * <p>
+ * Unlike the standard Piped* classes,
+ * Pipeline and its related classes do not try to detect dead pipes based
+ * on exit of threads. Instead, a pipeline shuts down when the sources
+ * are closed, or when {@link #shutdown()} method called.
+ * <p>
+ * The intended lifecycle of a Pipeline is as follows:
+ * <ol>
+ * <li>A Pipeline object is instantiated.</li>
+ * <li>One or more sources and sinks are created using {@link #createSource()}
+ * and {@link #createSink()}.
+ * <li>The Pipeline is activated by calling {@link #activate()}.
+ * <li>Data is written to the pipeline sources and read from the sinks.
+ * <li>The pipeline sources are closed, causing the pipeline to shut down cleanly.
+ * Read calls on the sinks will return any remaining buffered data and then
+ * signal EOF in the normal way.
+ * <li>The sinks are closed, and the Pipeline is shutdown.
+ * </ol>
+ *
+ * @author cr...@jn...
+ */
+public class Pipeline {
+ // FIXME This first-cut implementation unnecessarily double-copies data when
+ // a reader is waiting for it. Also, it doesn't fill/empty the buffer in a
+ // circular fashion. Finally, it doesn't implement atomic writes / reads or
+ // detect situations where behavior is non-deterministic.
+
+ private List<PipelineInputStream> sinks =
+ new ArrayList<PipelineInputStream>();
+ private List<PipelineOutputStream> sources =
+ new ArrayList<PipelineOutputStream>();
+
+ private byte[] buffer = new byte[1024];
+ private int pos = 0;
+ private int lim = 0;
+ private boolean activated;
+
+ /**
+ * Create a pipeline, in 'inactive' state.
+ */
+ public Pipeline() {
+ }
+
+ /**
+ * Create a sink for a inactive pipeline.
+ * @return the sink.
+ * @throws IOException This is thrown if the pipeline is 'active' or 'shut down'.
+ */
+ public synchronized PipelineInputStream createSink() throws IOException {
+ if (activated) {
+ throw new IOException("pipeline state wrong");
+ }
+ PipelineInputStream is = new PipelineInputStream(this);
+ sinks.add(is);
+ return is;
+ }
+
+ /**
+ * Create a source for a inactive pipeline.
+ * @return the source.
+ * @throws IOException This is thrown if the pipeline is 'active' or 'shut down'.
+ */
+ public synchronized PipelineOutputStream createSource() throws IOException {
+ if (activated) {
+ throw new IOException("pipeline state wrong");
+ }
+ PipelineOutputStream os = new PipelineOutputStream(this);
+ sources.add(os);
+ return os;
+ }
+
+ /**
+ * Put the pipeline into the 'active' state.
+ * @throws IOException This is thrown if the pipeline is 'shut down', or
+ * if it is 'inactive' but there are no sources or sinks.
+ */
+ public synchronized void activate() throws IOException {
+ if (buffer == null) {
+ throw new IOException("pipeline state wrong");
+ }
+ if (sinks.isEmpty() || sources.isEmpty()) {
+ throw new IOException("pipeline has no inputs and/or outputs");
+ }
+ activated = true;
+ }
+
+ /**
+ * Test if the pipeline is in the 'active' state.
+ * @return
+ */
+ public synchronized boolean isActive() {
+ return activated && buffer != null;
+ }
+
+ /**
+ * Test if the pipeline is in the 'shut down' state.
+ * @return
+ */
+ public synchronized boolean isShutdown() {
+ return activated && buffer == null;
+ }
+
+ /**
+ * Forcibly shut down the pipeline. This will cause any threads
+ * currently blocked on sources or sinks to get an IOException.
+ */
+ public synchronized void shutdown() {
+ buffer = null;
+ this.notifyAll();
+ }
+
+ synchronized int available() {
+ return lim - pos;
+ }
+
+ synchronized void closeInput(PipelineInputStream input) {
+ sinks.remove(input);
+ if (sinks.isEmpty()) {
+ buffer = null;
+ this.notifyAll();
+ }
+ }
+
+ synchronized void closeOutput(PipelineOutputStream output) {
+ sources.remove(output);
+ if (sources.isEmpty()) {
+ buffer = null;
+ this.notifyAll();
+ }
+ }
+
+ synchronized int read(byte[] b, int off, int len) throws IOException {
+ if (buffer == null) {
+ throw new IOException("pipeline state wrong");
+ }
+ int startOff = off;
+ while (off < len && !sources.isEmpty()) {
+ while (pos == lim) {
+ try {
+ this.wait();
+ } catch (InterruptedException ex) {
+ throw new InterruptedIOException();
+ }
+ }
+ while (off < len && pos != lim) {
+ b[off++] = buffer[pos++];
+ }
+ if (pos == lim) {
+ pos = 0;
+ lim = 0;
+ }
+ this.notify();
+ }
+ return (off == startOff) ? -1 : (off - startOff);
+ }
+
+ synchronized long skip(long n) throws IOException {
+ if (buffer == null) {
+ throw new IOException("pipeline state wrong");
+ }
+ long off = 0;
+ while (off < n && !sources.isEmpty()) {
+ while (pos == lim) {
+ try {
+ this.wait();
+ } catch (InterruptedException ex) {
+ throw new InterruptedIOException();
+ }
+ }
+ long count = Math.min(lim - pos, n - off);
+ pos += count;
+ if (pos == lim) {
+ pos = 0;
+ lim = 0;
+ }
+ this.notify();
+ }
+ return off == 0 ? -1 : off;
+ }
+
+ synchronized void flush() throws IOException {
+ if (buffer == null) {
+ throw new IOException("pipeline state wrong");
+ }
+ this.notifyAll();
+ }
+
+ synchronized void write(byte[] b, int off, int len) throws IOException {
+ if (buffer == null) {
+ throw new IOException("pipeline state wrong");
+ }
+ while (off < len) {
+ while (lim == buffer.length) {
+ if (sinks.isEmpty()) {
+ throw new IOException("pipeline broken");
+ }
+ try {
+ this.wait();
+ } catch (InterruptedException ex) {
+ throw new InterruptedIOException();
+ }
+ }
+ while (off < len && lim < buffer.length) {
+ buffer[lim++] = b[off++];
+ }
+ this.notify();
+ }
+ }
+}
Added: trunk/shell/src/shell/org/jnode/shell/io/PipelineInputStream.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/io/PipelineInputStream.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/io/PipelineInputStream.java 2009-03-10 14:34:35 UTC (rev 5095)
@@ -0,0 +1,95 @@
+package org.jnode.shell.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class provides the input side of a JNode shell pipeline.
+ * Unlike the standard PipedInputStream, this one is designed to
+ * support a pipeline with multiple readers and writers.
+ *
+ * @author cr...@jn...
+ */
+public final class PipelineInputStream extends InputStream {
+
+ private Pipeline pipeline;
+
+ /**
+ * This is not a public constructor. Use {@link Pipeline#createSink()}
+ * to create a PipelineInputStream instance.
+ *
+ * @param pipeline the parent pipeline.
+ */
+ PipelineInputStream(Pipeline pipeline) {
+ this.pipeline = pipeline;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ byte[] buffer = new byte[1];
+ int got = pipeline.read(buffer, 0, 1);
+ if (got == 1) {
+ return buffer[0];
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ return pipeline.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (pipeline != null) {
+ pipeline.closeInput(this);
+ pipeline = null;
+ }
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ // ignore
+ }
+
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ return pipeline.read(b, off, len);
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ return pipeline.read(b, 0, b.length);
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ throw new IOException("reset not supported");
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ return pipeline.skip(n);
+ }
+}
Added: trunk/shell/src/shell/org/jnode/shell/io/PipelineOutputStream.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/io/PipelineOutputStream.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/io/PipelineOutputStream.java 2009-03-10 14:34:35 UTC (rev 5095)
@@ -0,0 +1,68 @@
+package org.jnode.shell.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class provides the output side of a JNode shell pipeline.
+ * Unlike the standard PipedInputStream, this one is designed to
+ * support a pipeline with multiple readers and writers.
+ *
+ * @author cr...@jn...
+ */
+public final class PipelineOutputStream extends OutputStream {
+
+ private Pipeline pipeline;
+
+ /**
+ * This is not a public constructor. Use {@link Pipeline#createSource()}
+ * to create a PipelineOutputStream instance.
+ *
+ * @param pipeline the parent pipeline.
+ */
+ PipelineOutputStream(Pipeline pipeline) {
+ this.pipeline = pipeline;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (pipeline != null) {
+ pipeline.closeOutput(this);
+ pipeline = null;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ pipeline.flush();
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ pipeline.write(b, off, len);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ pipeline.write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if (pipeline == null) {
+ throw new IOException("pipeline closed");
+ }
+ byte[] buffer = new byte[]{(byte) b};
+ pipeline.write(buffer, 0, 1);
+ }
+
+}
Added: trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java (rev 0)
+++ trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java 2009-03-10 14:34:35 UTC (rev 5095)
@@ -0,0 +1,100 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * 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 org.jnode.test.shell.io;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import junit.framework.TestCase;
+
+import org.jnode.shell.io.Pipeline;
+
+public class PipelineTest extends TestCase {
+
+ public void testConstructor() {
+ new Pipeline();
+ }
+
+ public void testLifecycle() throws IOException {
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ assertFalse(p.isActive());
+ assertFalse(p.isShutdown());
+ p.activate();
+ assertTrue(p.isActive());
+ assertFalse(p.isShutdown());
+ is.close();
+ os.close();
+ assertFalse(p.isActive());
+ assertTrue(p.isShutdown());
+ }
+
+ public void testLifecycle2() throws IOException {
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ assertFalse(p.isActive());
+ assertFalse(p.isShutdown());
+ p.activate();
+ assertTrue(p.isActive());
+ assertFalse(p.isShutdown());
+ p.shutdown();
+ assertFalse(p.isActive());
+ assertTrue(p.isShutdown());
+ try {
+ is.read();
+ fail("no exception on read()");
+ } catch (IOException ex) {
+ // expected ...
+ }
+ try {
+ os.write('X');
+ fail("no exception on write()");
+ } catch (IOException ex) {
+ // expected ...
+ }
+ }
+
+ public void testOneOne() throws IOException {
+ // This should work ... despite the source and sink being operated from
+ // the same thread ... because we are reading/writing less than a buffer full.
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ p.activate();
+ assertEquals(0, is.available());
+ os.write('A');
+ assertEquals(1, is.available());
+ assertEquals('A', is.read());
+ os.write('B');
+ assertEquals('B', is.read());
+ assertEquals(0, is.available());
+ os.write("the quick brown fox".getBytes());
+ int len = "the quick brown fox".length();
+ assertEquals(len, is.available());
+ byte[] buffer = new byte[100];
+ assertEquals(len, is.read(buffer, 0, len));
+ assertEquals("the quick brown fox", new String(buffer, 0, len));
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-13 11:25:06
|
Revision: 5096
http://jnode.svn.sourceforge.net/jnode/?rev=5096&view=rev
Author: crawley
Date: 2009-03-13 11:24:46 +0000 (Fri, 13 Mar 2009)
Log Message:
-----------
Fixed bugs and expanded unit test for Pipeline et al.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java
trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java 2009-03-10 14:34:35 UTC (rev 5095)
+++ trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java 2009-03-13 11:24:46 UTC (rev 5096)
@@ -32,49 +32,77 @@
*/
public class Pipeline {
// FIXME This first-cut implementation unnecessarily double-copies data when
- // a reader is waiting for it. Also, it doesn't fill/empty the buffer in a
- // circular fashion. Finally, it doesn't implement atomic writes / reads or
- // detect situations where behavior is non-deterministic.
+ // a reader is waiting for it. It doesn't fill/empty the buffer in a
+ // circular fashion. If there are multiple active readers or writers,
+ // too many threads get woken up. Finally, this class doesn't implement
+ // atomic writes / reads or detect cases where behavior is non-deterministic.
private List<PipelineInputStream> sinks =
new ArrayList<PipelineInputStream>();
private List<PipelineOutputStream> sources =
new ArrayList<PipelineOutputStream>();
- private byte[] buffer = new byte[1024];
+ private byte[] buffer;
private int pos = 0;
private int lim = 0;
- private boolean activated;
+ private int state = INITIAL;
+ private static final int INITIAL = 1;
+ private static final int ACTIVE = 2;
+ private static final int CLOSED = 4;
+ private static final int SHUTDOWN = 8;
+
+ private static final String[] STATE_NAMES = new String[] {
+ null, "INITIAL", "ACTIVE", null, "CLOSED",
+ null, null, null, "SHUTDOWN"
+ };
+
/**
- * Create a pipeline, in 'inactive' state.
+ * The default Pipeline buffer size.
*/
+ public static final int DEFAULT_BUFFER_SIZE = 1024;
+
+ /**
+ * Create a pipeline, in 'inactive' state with the default buffer size;
+ */
public Pipeline() {
+ buffer = new byte[DEFAULT_BUFFER_SIZE];
}
/**
+ * Create a pipeline, in 'inactive' state.
+ * @param bufferSize the pipeline's buffer size.
+ */
+ public Pipeline(int bufferSize) {
+ buffer = new byte[bufferSize];
+ }
+
+ /**
* Create a sink for a inactive pipeline.
* @return the sink.
* @throws IOException This is thrown if the pipeline is 'active' or 'shut down'.
*/
public synchronized PipelineInputStream createSink() throws IOException {
- if (activated) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(INITIAL, "create");
PipelineInputStream is = new PipelineInputStream(this);
sinks.add(is);
return is;
}
+ private void checkState(int allowedStates, String action) throws IOException {
+ if ((state & allowedStates) == 0) {
+ String stateName = STATE_NAMES[state];
+ throw new IOException(action + " not allowed in state " + stateName);
+ }
+ }
+
/**
* Create a source for a inactive pipeline.
* @return the source.
* @throws IOException This is thrown if the pipeline is 'active' or 'shut down'.
*/
public synchronized PipelineOutputStream createSource() throws IOException {
- if (activated) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(INITIAL, "create");
PipelineOutputStream os = new PipelineOutputStream(this);
sources.add(os);
return os;
@@ -86,13 +114,11 @@
* if it is 'inactive' but there are no sources or sinks.
*/
public synchronized void activate() throws IOException {
- if (buffer == null) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(INITIAL, "activate");
if (sinks.isEmpty() || sources.isEmpty()) {
throw new IOException("pipeline has no inputs and/or outputs");
}
- activated = true;
+ state = ACTIVE;
}
/**
@@ -100,15 +126,23 @@
* @return
*/
public synchronized boolean isActive() {
- return activated && buffer != null;
+ return state == ACTIVE;
}
/**
+ * Test if the pipeline is in the 'closed' state.
+ * @return
+ */
+ public synchronized boolean isClosed() {
+ return state == CLOSED;
+ }
+
+ /**
* Test if the pipeline is in the 'shut down' state.
* @return
*/
public synchronized boolean isShutdown() {
- return activated && buffer == null;
+ return state == SHUTDOWN;
}
/**
@@ -116,97 +150,98 @@
* currently blocked on sources or sinks to get an IOException.
*/
public synchronized void shutdown() {
- buffer = null;
+ state = SHUTDOWN;
this.notifyAll();
}
- synchronized int available() {
+ synchronized int available() throws IOException {
+ checkState(ACTIVE, "available");
return lim - pos;
}
synchronized void closeInput(PipelineInputStream input) {
sinks.remove(input);
if (sinks.isEmpty()) {
- buffer = null;
- this.notifyAll();
+ if (state < CLOSED) {
+ state = CLOSED;
+ this.notifyAll();
+ }
}
}
synchronized void closeOutput(PipelineOutputStream output) {
sources.remove(output);
if (sources.isEmpty()) {
- buffer = null;
- this.notifyAll();
+ if (state < CLOSED) {
+ state = CLOSED;
+ this.notifyAll();
+ }
}
}
synchronized int read(byte[] b, int off, int len) throws IOException {
- if (buffer == null) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(ACTIVE | CLOSED | SHUTDOWN, "read");
int startOff = off;
- while (off < len && !sources.isEmpty()) {
- while (pos == lim) {
+ while (off < len && state <= CLOSED) {
+ while (pos == lim && state == ACTIVE) {
try {
this.wait();
} catch (InterruptedException ex) {
throw new InterruptedIOException();
}
}
- while (off < len && pos != lim) {
+ if (pos == lim) {
+ break;
+ }
+ while (off < len && pos < lim) {
b[off++] = buffer[pos++];
}
if (pos == lim) {
pos = 0;
lim = 0;
}
- this.notify();
+ this.notifyAll();
}
return (off == startOff) ? -1 : (off - startOff);
}
synchronized long skip(long n) throws IOException {
- if (buffer == null) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(ACTIVE | CLOSED | SHUTDOWN, "skip");
long off = 0;
- while (off < n && !sources.isEmpty()) {
- while (pos == lim) {
+ while (off < n && state <= CLOSED) {
+ while (pos == lim && state == ACTIVE) {
try {
this.wait();
} catch (InterruptedException ex) {
throw new InterruptedIOException();
}
}
+ if (pos == lim) {
+ break;
+ }
long count = Math.min(lim - pos, n - off);
pos += count;
if (pos == lim) {
pos = 0;
lim = 0;
}
- this.notify();
+ this.notifyAll();
}
return off == 0 ? -1 : off;
}
synchronized void flush() throws IOException {
- if (buffer == null) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(ACTIVE | CLOSED, "flush");
this.notifyAll();
}
synchronized void write(byte[] b, int off, int len) throws IOException {
- if (buffer == null) {
- throw new IOException("pipeline state wrong");
- }
+ checkState(ACTIVE, "write");
while (off < len) {
while (lim == buffer.length) {
- if (sinks.isEmpty()) {
- throw new IOException("pipeline broken");
- }
try {
this.wait();
+ checkState(ACTIVE, "write");
} catch (InterruptedException ex) {
throw new InterruptedIOException();
}
@@ -214,7 +249,7 @@
while (off < len && lim < buffer.length) {
buffer[lim++] = b[off++];
}
- this.notify();
+ this.notifyAll();
}
}
}
Modified: trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java 2009-03-10 14:34:35 UTC (rev 5095)
+++ trunk/shell/src/test/org/jnode/test/shell/io/PipelineTest.java 2009-03-13 11:24:46 UTC (rev 5096)
@@ -17,13 +17,17 @@
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
package org.jnode.test.shell.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
import junit.framework.TestCase;
@@ -40,14 +44,17 @@
InputStream is = p.createSink();
OutputStream os = p.createSource();
assertFalse(p.isActive());
+ assertFalse(p.isClosed());
assertFalse(p.isShutdown());
p.activate();
assertTrue(p.isActive());
+ assertFalse(p.isClosed());
assertFalse(p.isShutdown());
is.close();
os.close();
assertFalse(p.isActive());
- assertTrue(p.isShutdown());
+ assertTrue(p.isClosed());
+ assertFalse(p.isShutdown());
}
public void testLifecycle2() throws IOException {
@@ -62,13 +69,8 @@
p.shutdown();
assertFalse(p.isActive());
assertTrue(p.isShutdown());
+ assertEquals(-1, is.read());
try {
- is.read();
- fail("no exception on read()");
- } catch (IOException ex) {
- // expected ...
- }
- try {
os.write('X');
fail("no exception on write()");
} catch (IOException ex) {
@@ -97,4 +99,244 @@
assertEquals(len, is.read(buffer, 0, len));
assertEquals("the quick brown fox", new String(buffer, 0, len));
}
+
+ public void testTwo1_One1() throws Throwable {
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ OutputStream os2 = p.createSource();
+ p.activate();
+
+ Source source = new Source("1".getBytes(), 10000, -1, os);
+ Source source2 = new Source("2".getBytes(), 10000, -1, os2);
+ Sink sink = new Sink(20000, 1, -1, is);
+
+ List<Throwable> exceptions = runInThreads(new Runnable[] {source, source2, sink});
+ if (exceptions.size() > 0) {
+ throw exceptions.get(0);
+ }
+ assertEquals(10000, sink.getCount((byte) '1'));
+ assertEquals(10000, sink.getCount((byte) '2'));
+ }
+
+ public void testTwo10_One10() throws Throwable {
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ OutputStream os2 = p.createSource();
+ p.activate();
+
+ Source source = new Source("1111111111".getBytes(), 1000, -1, os);
+ Source source2 = new Source("2222222222".getBytes(), 1000, -1, os2);
+ Sink sink = new Sink(20000, 10, -1, is);
+
+ List<Throwable> exceptions = runInThreads(new Runnable[] {source, source2, sink});
+ if (exceptions.size() > 0) {
+ throw exceptions.get(0);
+ }
+ assertEquals(10000, sink.getCount((byte) '1'));
+ assertEquals(10000, sink.getCount((byte) '2'));
+ }
+
+ public void testTwo100_One100() throws Throwable {
+ Pipeline p = new Pipeline();
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ OutputStream os2 = p.createSource();
+ p.activate();
+
+ byte[] buff1 = new byte[100];
+ Arrays.fill(buff1, (byte) '1');
+ Source source = new Source(buff1, 100, -1, os);
+ byte[] buff2 = new byte[100];
+ Arrays.fill(buff2, (byte) '2');
+ Source source2 = new Source(buff2, 100, -1, os2);
+ Sink sink = new Sink(20000, 100, -1, is);
+
+ List<Throwable> exceptions = runInThreads(new Runnable[] {source, source2, sink});
+ if (exceptions.size() > 0) {
+ throw exceptions.get(0);
+ }
+ assertEquals(10000, sink.getCount((byte) '1'));
+ assertEquals(10000, sink.getCount((byte) '2'));
+ }
+
+ public void testTwo100_One100_SmallBuffer() throws Throwable {
+ Pipeline p = new Pipeline(100);
+ InputStream is = p.createSink();
+ OutputStream os = p.createSource();
+ OutputStream os2 = p.createSource();
+ p.activate();
+
+ byte[] buff1 = new byte[100];
+ Arrays.fill(buff1, (byte) '1');
+ Source source = new Source(buff1, 100, -1, os);
+ byte[] buff2 = new byte[100];
+ Arrays.fill(buff2, (byte) '2');
+ Source source2 = new Source(buff2, 100, -1, os2);
+ Sink sink = new Sink(20000, 100, -1, is);
+
+ List<Throwable> exceptions = runInThreads(new Runnable[] {source, source2, sink});
+ if (exceptions.size() > 0) {
+ throw exceptions.get(0);
+ }
+ assertEquals(10000, sink.getCount((byte) '1'));
+ assertEquals(10000, sink.getCount((byte) '2'));
+ }
+
+ /**
+ * Create Threads for each runnable (with an exception handler), start them,
+ * join them and return any exceptions
+ * @param runnables the test runnables
+ * @return any exceptions caught.
+ */
+ private List<Throwable> runInThreads(Runnable[] runnables) {
+ final List<Throwable> exceptions = new ArrayList<Throwable>();
+ Thread[] threads = new Thread[runnables.length];
+ for (int i = 0; i < threads.length; i++) {
+ System.err.println("create");
+ threads[i] = new Thread(runnables[i]);
+ threads[i].setUncaughtExceptionHandler(
+ new UncaughtExceptionHandler() {
+ public void uncaughtException(Thread thr, Throwable exc) {
+ System.err.println("handled exception " + exc);
+ exc.printStackTrace();
+ exceptions.add(exc);
+ }
+ });
+ }
+ for (Thread thread : threads) {
+ System.err.println("start");
+ thread.start();
+ }
+ for (Thread thread : threads) {
+ try {
+ System.err.println("join");
+ thread.join();
+ } catch (InterruptedException ex) {
+ exceptions.add(ex);
+ }
+ }
+ System.err.println("done");
+ return exceptions;
+ }
+
+ private static class Source implements Runnable {
+ private byte[] b;
+ private int count;
+ private int sleep;
+ private OutputStream os;
+
+ /**
+ * Create a test source.
+ * @param b the buffer to be written
+ * @param count the number of times
+ * @param sleep sleep this number of milliseconds between writes; -1 means no sleep.
+ * @param os write bytes here.
+ */
+ Source(byte[] b, int count, int sleep, OutputStream os) {
+ this.b = b;
+ this.count = count;
+ this.os = os;
+ this.sleep = sleep;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < count; i++) {
+ os.write(b);
+ if (sleep != -1) {
+ Thread.sleep(sleep);
+ }
+ }
+ os.close();
+ os = null;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ System.err.println("wrote " + count);
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ private static class Sink implements Runnable {
+ private HashMap<Byte, Integer> counters = new HashMap<Byte, Integer>();
+ private InputStream is;
+ private int max;
+ private int sleep;
+ private int len;
+
+ /**
+ * Create a test Sink.
+ * @param max if we read more than this number of bytes, throw an exception
+ * @param len the read buffer size.
+ * @param sleep sleep this number of milliseconds between reads; -1 means no sleep.
+ * @param is read bytes from here.
+ */
+ Sink(int max, int len, int sleep, InputStream is) {
+ this.is = is;
+ this.max = max;
+ this.sleep = sleep;
+ this.len = len;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int counter = 0;
+ byte[] buffer = new byte[len];
+ int nosRead = is.read(buffer);
+ while (nosRead != -1) {
+ for (int i = 0; i < nosRead; i++) {
+ Byte bb = new Byte((byte) buffer[i]);
+ Integer cc = counters.get(bb);
+ int c = (cc == null) ? 1 : (cc.intValue() + 1);
+ counters.put(bb, new Integer(c));
+ if (++counter > max) {
+ throw new RuntimeException("too many (" + counter + ")");
+ }
+ }
+ if (sleep != -1) {
+ Thread.sleep(sleep);
+ }
+ nosRead = is.read(buffer);
+ }
+ System.err.println("read " + counter);
+ is.close();
+ is = null;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ try {
+ if (is != null) {
+ is.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Get the number of bytes read for a given byte value.
+ * @param b the key byte
+ * @return the number instances of the 'key' byte read.
+ */
+ public int getCount(byte b) {
+ Integer cc = counters.get(b);
+ return (cc == null) ? 0 : cc.intValue();
+ }
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-15 06:00:02
|
Revision: 5108
http://jnode.svn.sourceforge.net/jnode/?rev=5108&view=rev
Author: crawley
Date: 2009-03-15 05:59:57 +0000 (Sun, 15 Mar 2009)
Log Message:
-----------
Lots of changes aimed at getting Bjorne pipelines to work.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/AbstractCommand.java
trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/CommandRunnable.java
trunk/shell/src/shell/org/jnode/shell/CommandRunner.java
trunk/shell/src/shell/org/jnode/shell/CommandShell.java
trunk/shell/src/shell/org/jnode/shell/CommandThreadImpl.java
trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneBuiltin.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/CaseCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/ColonBuiltin.java
trunk/shell/src/shell/org/jnode/shell/bjorne/CommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/ForCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/FunctionDefinitionNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/IfCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/ListCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/LoopCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
trunk/shell/src/shell/org/jnode/shell/io/BaseCommandIO.java
trunk/shell/src/shell/org/jnode/shell/io/CommandIO.java
trunk/shell/src/shell/org/jnode/shell/io/CommandIOMarker.java
trunk/shell/src/shell/org/jnode/shell/io/CommandInput.java
trunk/shell/src/shell/org/jnode/shell/io/CommandInputOutput.java
trunk/shell/src/shell/org/jnode/shell/io/CommandOutput.java
trunk/shell/src/shell/org/jnode/shell/io/Pipeline.java
trunk/shell/src/shell/org/jnode/shell/io/PipelineOutputStream.java
trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/isolate/IsolateCommandThreadImpl.java
trunk/shell/src/shell/org/jnode/shell/proclet/ProcletCommandInvoker.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneContextTests.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
trunk/shell/src/test/org/jnode/test/shell/harness/TestEmu.java
Added Paths:
-----------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneSubshellRunner.java
trunk/shell/src/shell/org/jnode/shell/io/CommandIOHolder.java
Removed Paths:
-------------
trunk/shell/src/shell/org/jnode/shell/bjorne/StreamHolder.java
Modified: trunk/shell/src/shell/org/jnode/shell/AbstractCommand.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/AbstractCommand.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/AbstractCommand.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -94,7 +94,7 @@
CommandIO[] myIOs = new CommandIO[] {
new CommandInput(System.in),
new CommandOutput(System.out),
- new CommandOutput(System.err),
+ new CommandOutput(System.err)
};
command.initialize(new CommandLine(args), myIOs);
command.execute();
Modified: trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/AsyncCommandInvoker.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -107,9 +107,8 @@
CommandRunner cr = null;
CommandIO[] ios = cmdLine.getStreams();
- CommandIO[] resolvedIOs;
try {
- resolvedIOs = commandShell.resolveStreams(ios);
+ commandShell.resolveStreams(ios);
} catch (ClassCastException ex) {
throw new ShellFailureException("streams array broken", ex);
}
@@ -120,7 +119,7 @@
throw new ShellInvocationException("Problem while creating command instance", ex);
}
if (command != null) {
- cr = new CommandRunner(this, cmdInfo, cmdLine, resolvedIOs, sysProps, env);
+ cr = new CommandRunner(this, cmdInfo, cmdLine, ios, sysProps, env);
} else {
try {
method = cmdInfo.getCommandClass().getMethod(MAIN_METHOD, MAIN_ARG_TYPES);
@@ -140,7 +139,7 @@
method.setAccessible(true);
cr = new CommandRunner(
this, cmdInfo, cmdInfo.getCommandClass(), method,
- new Object[] {cmdLine.getArguments()}, resolvedIOs, sysProps, env);
+ new Object[] {cmdLine.getArguments()}, ios, sysProps, env);
} catch (NoSuchMethodException e) {
// continue;
}
@@ -149,9 +148,6 @@
"No entry point method found for " + cmdInfo.getCommandClass());
}
}
-
- // These are now the real streams ...
- cmdLine.setStreams(resolvedIOs);
return cr;
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandRunnable.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandRunnable.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/CommandRunnable.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -4,4 +4,6 @@
void flushStreams();
+ int getRC();
+
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandRunner.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandRunner.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/CommandRunner.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -93,7 +93,6 @@
public void run() {
try {
- boolean ok = false;
try {
if (method != null) {
try {
@@ -121,10 +120,9 @@
// bounce us to the older execute(CommandLine, InputStream, PrintStream,
// PrintStream) method.
Command cmd = cmdInfo.createCommandInstance();
- cmd.initialize(commandLine, getIos());
+ cmd.initialize(commandLine, getIOs());
cmd.execute();
}
- ok = true;
} catch (PrivilegedActionException ex) {
Exception ex2 = ex.getException();
if (ex2 instanceof InvocationTargetException) {
@@ -132,26 +130,7 @@
} else {
throw ex2;
}
- } finally {
- IOException savedEx = null;
- // Make sure that we try to flush all IOs, even if some of the flushes
- // result in IOExceptions.
- for (CommandIO io : getIos()) {
- try {
- io.flush();
- } catch (IOException ex) {
- shellErr.println("Failed to flush output: " + ex.getMessage());
- if (ok) {
- savedEx = ex;
- }
- }
- }
- if (savedEx != null) {
- // If we weren't already propagating an exception, and the flush failed,
- // propagate one of the IOExceptions.
- throw savedEx;
- }
- }
+ }
} catch (SyntaxErrorException ex) {
try {
HelpFactory.getHelpFactory().getHelp(commandLine.getCommandName(), cmdInfo).usage(shellErr);
@@ -197,7 +176,7 @@
return args;
}
- public CommandIO[] getIos() {
+ public CommandIO[] getIOs() {
return ios;
}
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -979,12 +979,10 @@
}
}
- public CommandIO[] resolveStreams(CommandIO[] ios) {
- CommandIO[] res = new CommandIO[ios.length];
- for (int i = 0; i < res.length; i++) {
- res[i] = resolveStream(ios[i]);
+ public void resolveStreams(CommandIO[] ios) {
+ for (int i = 0; i < ios.length; i++) {
+ ios[i] = resolveStream(ios[i]);
}
- return res;
}
public PrintStream resolvePrintStream(CommandIO io) {
Modified: trunk/shell/src/shell/org/jnode/shell/CommandThreadImpl.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandThreadImpl.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/CommandThreadImpl.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -83,11 +83,7 @@
}
public int getReturnCode() {
- if (this.runner instanceof CommandRunner) {
- return ((CommandRunner) this.runner).getRC();
- } else {
- return 0;
- }
+ return this.runner.getRC();
}
@SuppressWarnings("deprecation")
Modified: trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -86,9 +86,9 @@
}
try {
final CommandIO[] ios = cmdLine.getStreams();
- if (ios[0] != CommandLine.DEFAULT_STDIN
- || ios[1] != CommandLine.DEFAULT_STDOUT
- || ios[2] != CommandLine.DEFAULT_STDERR) {
+ if (ios[0] != CommandLine.DEFAULT_STDIN ||
+ ios[1] != CommandLine.DEFAULT_STDOUT ||
+ ios[2] != CommandLine.DEFAULT_STDERR) {
err.println("Warning: redirections ignored by the '"
+ getName() + "' invoker");
}
Modified: trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/RedirectingInterpreter.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -332,7 +332,6 @@
// squash
}
prevIOs[Command.STD_OUT] = CommandLine.DEVNULL;
- prev.commandLine.setStreams(prevIOs);
}
} else {
// the previous stage has explicitly redirected stdout
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneBuiltin.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneBuiltin.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneBuiltin.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -30,7 +30,7 @@
BjorneContext context) throws ShellException;
void error(String msg, BjorneContext context) {
- context.resolvePrintStream(context.getStream(Command.STD_ERR)).println(msg);
+ context.resolvePrintStream(context.getIO(Command.STD_ERR)).println(msg);
}
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -49,15 +49,15 @@
import org.jnode.shell.Command;
import org.jnode.shell.CommandLine;
-import org.jnode.shell.CommandThread;
+import org.jnode.shell.CommandShell;
import org.jnode.shell.PathnamePattern;
import org.jnode.shell.ShellException;
import org.jnode.shell.ShellFailureException;
import org.jnode.shell.ShellSyntaxException;
import org.jnode.shell.io.CommandIO;
-import org.jnode.shell.io.CommandIOMarker;
import org.jnode.shell.io.CommandInput;
import org.jnode.shell.io.CommandOutput;
+import org.jnode.shell.io.CommandIOHolder;
/**
* This class holds the shell variable and stream state for a bjorne shell
@@ -70,10 +70,6 @@
*/
public class BjorneContext {
- public static final CommandIOMarker PIPE_IN = new CommandIOMarker("PIPEIN");
-
- public static final CommandIOMarker PIPE_OUT = new CommandIOMarker("PIPEOUT");
-
private static final int NONE = 0;
private static final int PREHASH = 1;
@@ -122,13 +118,13 @@
private String options = "";
- private StreamHolder[] holders;
+ private CommandIOHolder[] holders;
private boolean echoExpansions;
private BjorneContext parent;
- public BjorneContext(BjorneInterpreter interpreter, StreamHolder[] holders) {
+ public BjorneContext(BjorneInterpreter interpreter, CommandIOHolder[] holders) {
this.interpreter = interpreter;
this.holders = holders;
this.variables = new HashMap<String, VariableSlot>();
@@ -138,12 +134,12 @@
this(interpreter, defaultStreamHolders());
}
- private static StreamHolder[] defaultStreamHolders() {
- StreamHolder[] res = new StreamHolder[4];
- res[Command.STD_IN] = new StreamHolder(CommandLine.DEFAULT_STDIN, false);
- res[Command.STD_OUT] = new StreamHolder(CommandLine.DEFAULT_STDOUT, false);
- res[Command.STD_ERR] = new StreamHolder(CommandLine.DEFAULT_STDERR, false);
- res[Command.SHELL_ERR] = new StreamHolder(CommandLine.DEFAULT_STDERR, false);
+ private static CommandIOHolder[] defaultStreamHolders() {
+ CommandIOHolder[] res = new CommandIOHolder[4];
+ res[Command.STD_IN] = new CommandIOHolder(CommandLine.DEFAULT_STDIN, false);
+ res[Command.STD_OUT] = new CommandIOHolder(CommandLine.DEFAULT_STDOUT, false);
+ res[Command.STD_ERR] = new CommandIOHolder(CommandLine.DEFAULT_STDERR, false);
+ res[Command.SHELL_ERR] = new CommandIOHolder(CommandLine.DEFAULT_STDERR, false);
return res;
}
@@ -227,18 +223,22 @@
/**
* Create a copy of some stream holders without passing ownership.
*/
- public static StreamHolder[] copyStreamHolders(StreamHolder[] holders) {
- StreamHolder[] res = new StreamHolder[holders.length];
+ public static CommandIOHolder[] copyStreamHolders(CommandIOHolder[] holders) {
+ CommandIOHolder[] res = new CommandIOHolder[holders.length];
for (int i = 0; i < res.length; i++) {
- res[i] = new StreamHolder(holders[i]);
+ res[i] = new CommandIOHolder(holders[i]);
}
return res;
}
- StreamHolder[] getCopyOfHolders() {
+ CommandIOHolder[] getCopyOfHolders() {
return copyStreamHolders(holders);
}
+ CommandIOHolder[] getHolders() {
+ return holders;
+ }
+
void setArgs(String[] args) {
this.args = Arrays.asList(args.clone());
}
@@ -749,7 +749,7 @@
case QUERY:
if (value == null) {
String msg = word.length() > 0 ? word : (parameter + " is unset");
- resolvePrintStream(getStream(Command.STD_ERR)).println(msg);
+ resolvePrintStream(getIO(Command.STD_ERR)).println(msg);
throw new BjorneControlException(BjorneInterpreter.BRANCH_EXIT, 1);
} else {
return value;
@@ -757,7 +757,7 @@
case COLONQUERY:
if (value == null || value.length() == 0) {
String msg = word.length() > 0 ? word : (parameter + " is unset or null");
- resolvePrintStream(getStream(Command.STD_ERR)).println(msg);
+ resolvePrintStream(getIO(Command.STD_ERR)).println(msg);
throw new BjorneControlException(BjorneInterpreter.BRANCH_EXIT, 1);
} else {
return value;
@@ -925,30 +925,54 @@
return interpreter.resolveInputStream(stream);
}
- CommandIO getStream(int index) {
+ CommandIO getIO(int index) {
if (index < 0) {
throw new ShellFailureException("negative stream index");
} else if (index < holders.length) {
- return holders[index].stream;
+ return holders[index].getIO();
} else {
return null;
}
}
- void setStream(int index, CommandIO stream, boolean mine) {
+ void setIO(int index, CommandIO io, boolean mine) {
if (index < 0 || index >= holders.length) {
- throw new ShellFailureException("negative stream index");
+ throw new ShellFailureException("bad stream index");
} else {
- holders[index].setStream(stream, mine);
+ holders[index].setIO(io, mine);
}
}
- void closeStreams() {
- for (StreamHolder holder : holders) {
+ void setIO(int index, CommandIOHolder holder) {
+ if (index < 0 || index >= holders.length) {
+ throw new ShellFailureException("bad stream index");
+ } else {
+ holders[index].setIO(holder);
+ }
+ }
+
+ void closeIOs() {
+ for (CommandIOHolder holder : holders) {
holder.close();
}
}
+
+ void flushIOs() {
+ for (CommandIOHolder holder : holders) {
+ holder.flush();
+ }
+ }
+
+ CommandIO[] getIOs() {
+ CommandIO[] io = new CommandIO[holders.length];
+ int i = 0;
+ for (CommandIOHolder holder : holders) {
+ io[i++] = (holder == null) ? null : holder.getIO();
+ }
+ return io;
+ }
+
void performAssignments(BjorneToken[] assignments) throws ShellException {
if (assignments != null) {
for (int i = 0; i < assignments.length; i++) {
@@ -972,8 +996,10 @@
* input/outputStreamTuple streams for this command.
* @throws ShellException
*/
- StreamHolder[] evaluateRedirections(RedirectionNode[] redirects) throws ShellException {
- return evaluateRedirections(redirects, copyStreamHolders(holders));
+ CommandIOHolder[] evaluateRedirections(RedirectionNode[] redirects) throws ShellException {
+ CommandIOHolder[] res = copyStreamHolders(holders);
+ evaluateRedirections(redirects, res);
+ return res;
}
/**
@@ -984,10 +1010,10 @@
* @return the stream state after redirections
* @throws ShellException
*/
- StreamHolder[] evaluateRedirections(
- RedirectionNode[] redirects, StreamHolder[] holders) throws ShellException {
+ void evaluateRedirections(
+ RedirectionNode[] redirects, CommandIOHolder[] holders) throws ShellException {
if (redirects == null) {
- return holders;
+ return;
}
boolean ok = false;
try {
@@ -1018,12 +1044,12 @@
}
// If necessary, grow the fd table.
if (fd >= holders.length) {
- StreamHolder[] tmp = new StreamHolder[fd + 1];
+ CommandIOHolder[] tmp = new CommandIOHolder[fd + 1];
System.arraycopy(holders, 0, tmp, 0, fd + 1);
holders = tmp;
}
- StreamHolder stream;
+ CommandIOHolder stream;
switch (redir.getRedirectionType()) {
case REDIR_DLESS:
throw new UnsupportedOperationException("<<");
@@ -1037,9 +1063,9 @@
throw new ShellException("File already exists");
}
CommandOutput tmp = new CommandOutput(new FileOutputStream(file));
- stream = new StreamHolder(tmp, true);
+ stream = new CommandIOHolder(tmp, true);
} catch (IOException ex) {
- throw new ShellException("Cannot open input file", ex);
+ throw new ShellException("Cannot open output file", ex);
}
break;
@@ -1048,9 +1074,9 @@
try {
FileOutputStream tmp = new FileOutputStream(redir.getArg().getText(),
redir.getRedirectionType() == REDIR_DGREAT);
- stream = new StreamHolder(new CommandOutput(tmp), true);
+ stream = new CommandIOHolder(new CommandOutput(tmp), true);
} catch (IOException ex) {
- throw new ShellException("Cannot open input file", ex);
+ throw new ShellException("Cannot open output file", ex);
}
break;
@@ -1058,7 +1084,7 @@
try {
File file = new File(redir.getArg().getText());
CommandInput tmp = new CommandInput(new FileInputStream(file));
- stream = new StreamHolder(tmp, true);
+ stream = new CommandIOHolder(tmp, true);
} catch (IOException ex) {
throw new ShellException("Cannot open input file", ex);
}
@@ -1067,7 +1093,7 @@
case REDIR_LESSAND:
try {
int fromFd = Integer.parseInt(redir.getArg().getText());
- stream = (fromFd >= holders.length) ? null : new StreamHolder(holders[fromFd]);
+ stream = (fromFd >= holders.length) ? null : new CommandIOHolder(holders[fromFd]);
} catch (NumberFormatException ex) {
throw new ShellException("Invalid fd after >&");
}
@@ -1076,7 +1102,7 @@
case REDIR_GREATAND:
try {
int fromFd = Integer.parseInt(redir.getArg().getText());
- stream = (fromFd >= holders.length) ? null : new StreamHolder(holders[fromFd]);
+ stream = (fromFd >= holders.length) ? null : new CommandIOHolder(holders[fromFd]);
} catch (NumberFormatException ex) {
throw new ShellException("Invalid fd after >&");
}
@@ -1092,18 +1118,13 @@
ok = true;
} finally {
if (!ok) {
- for (StreamHolder holder : holders) {
+ for (CommandIOHolder holder : holders) {
holder.close();
}
}
}
- return holders;
}
- public CommandThread fork(CommandLine command, CommandIO[] ios) throws ShellException {
- return interpreter.fork(command, ios);
- }
-
public boolean patternMatch(CharSequence text, CharSequence pat) {
int flags = PathnamePattern.EAGER | PathnamePattern.DEFAULT_FLAGS;
Pattern regex = PathnamePattern.compilePosixShellPattern(pat, flags);
@@ -1117,4 +1138,13 @@
public int nosArgs() {
return args.size();
}
+
+ public CommandShell getShell() {
+ return interpreter.getShell();
+ }
+
+ public String getName() {
+ return interpreter.getUniqueName();
+ }
+
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-15 05:55:22 UTC (rev 5107)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -49,7 +49,6 @@
import org.jnode.shell.CommandInterpreter;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandShell;
-import org.jnode.shell.CommandThread;
import org.jnode.shell.Completable;
import org.jnode.shell.IncompleteCommandException;
import org.jnode.shell.ShellException;
@@ -137,6 +136,8 @@
new HashMap<String, BjorneBuiltin>();
private static boolean DEBUG = false;
+
+ private static long subshellCount;
static {
BUILTINS.put("break", new BreakBuiltin());
@@ -235,7 +236,7 @@
myContext = this.context;
} else {
myContext = new BjorneContext(this);
- myContext.setStream(1, new CommandOutput(capture), true);
+ myContext.setIO(1, new CommandOutput(capture), true);
}
BjorneTokenizer tokens = new BjorneTokenizer(command);
CommandNode tree = new BjorneParser(tokens, "> ").parse();
@@ -363,11 +364,12 @@
public InputStream resolveInputStream(CommandIO stream) {
return shell.resolveInputStream(stream);
}
+
+ private static synchronized long getSubshellNumber() {
+ return subshellCount++;
+ }
- public CommandThread fork(CommandLine command, CommandIO[] streams)
- throws ShellException {
- command.setStreams(streams);
- CommandInfo cmdInfo = command.parseCommandLine(shell);
- return shell.invokeAsynchronous(command, cmdInfo);
+ public String getUniqueName() {
+ return getName() + "-" + getSubshellNumber();
}
}
Added: trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java 2009-03-15 05:59:57 UTC (rev 5108)
@@ -0,0 +1,224 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * 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 org.jnode.shell.bjorne;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jnode.shell.Command;
+import org.jnode.shell.CommandShell;
+import org.jnode.shell.CommandThread;
+import org.jnode.shell.ShellException;
+import org.jnode.shell.ShellFailureException;
+import org.jnode.shell.ThreadExitListener;
+import org.jnode.shell.io.CommandIO;
+import org.jnode.shell.io.CommandIOHolder;
+import org.jnode.shell.io.CommandIOMarker;
+import org.jnode.shell.io.CommandInput;
+import org.jnode.shell.io.CommandOutput;
+import org.jnode.shell.io.Pipeline;
+
+/**
+ * This class deals with construction and running of multi-command
+ * pipelines for the Bjorne shell.
+ *
+ * @author cr...@jn...
+ */
+class BjornePipeline {
+ private static class PipelineStage {
+ private String stageName;
+ private CommandNode command;
+ private BjorneContext context;
+ private CommandThread thread;
+ private CommandIOHolder[] holders;
+ private BjornePipeline nestedPipeline;
+ }
+
+ private int stageCount = 0;
+ private int nextStage = 0;
+ private final PipelineStage[] stages;
+ private final BjornePipeline parent;
+ private final Map<String, Pipeline> pipes;
+ private int activeStageCount;
+
+
+ BjornePipeline(int len) {
+ this.stages = new PipelineStage[len];
+ this.parent = null;
+ this.pipes = new HashMap<String, Pipeline>();
+ }
+
+ BjornePipeline(BjornePipeline parent, int len) {
+ this.stages = new PipelineStage[len];
+ this.parent = parent;
+ this.pipes = null;
+ }
+
+ void closeStreams() {
+ for (PipelineStage stage : stages) {
+ if (stage != null) {
+ for (CommandIOHolder holder : stage.holders) {
+ holder.close();
+ }
+ if (stage.nestedPipeline != null) {
+ stage.nestedPipeline.closeStreams();
+ }
+ }
+ }
+ }
+
+ void wire() throws ShellException {
+ evaluateRedirections();
+ createPipes();
+ activatePipes();
+ }
+
+ private void evaluateRedirections() throws ShellException {
+ for (PipelineStage stage : stages) {
+ RedirectionNode[] redirects = stage.command.getRedirects();
+ stage.context.evaluateRedirections(redirects, stage.holders);
+ }
+ }
+
+ private void createPipes() throws ShellFailureException {
+ try {
+ for (PipelineStage stage : stages) {
+ for (CommandIOHolder holder : stage.holders) {
+ CommandIO io = holder.getIO();
+ ...
[truncated message content] |
|
From: <cr...@us...> - 2009-03-16 14:17:38
|
Revision: 5110
http://jnode.svn.sourceforge.net/jnode/?rev=5110&view=rev
Author: crawley
Date: 2009-03-16 14:17:28 +0000 (Mon, 16 Mar 2009)
Log Message:
-----------
Fix for bug that caused bjorne to try to open '>' files twice.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java 2009-03-15 14:34:32 UTC (rev 5109)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjornePipeline.java 2009-03-16 14:17:28 UTC (rev 5110)
@@ -86,18 +86,10 @@
}
void wire() throws ShellException {
- evaluateRedirections();
createPipes();
activatePipes();
}
- private void evaluateRedirections() throws ShellException {
- for (PipelineStage stage : stages) {
- RedirectionNode[] redirects = stage.command.getRedirects();
- stage.context.evaluateRedirections(redirects, stage.holders);
- }
- }
-
private void createPipes() throws ShellFailureException {
try {
for (PipelineStage stage : stages) {
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-15 14:34:32 UTC (rev 5109)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-16 14:17:28 UTC (rev 5110)
@@ -703,5 +703,13 @@
Hi mum again
</file>
</testSpec>
+ <testSpec title="subshell 4" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ ( echo Hi mum ; echo Hi mum again ) | cat > @TEMP_DIR@/1
+ </script>
+ <file name="1" input="false">Hi mum
+Hi mum again
+</file>
+ </testSpec>
</testSet>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-20 13:26:48
|
Revision: 5126
http://jnode.svn.sourceforge.net/jnode/?rev=5126&view=rev
Author: crawley
Date: 2009-03-20 13:26:45 +0000 (Fri, 20 Mar 2009)
Log Message:
-----------
Implementation of HERE documents ... expansion done yet.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java
trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-20 12:58:04 UTC (rev 5125)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-20 13:26:45 UTC (rev 5126)
@@ -36,6 +36,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
+import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1050,11 +1051,15 @@
}
CommandIOHolder stream;
+ CommandInput in;
+ CommandOutput out;
switch (redir.getRedirectionType()) {
case REDIR_DLESS:
- throw new UnsupportedOperationException("<<");
case REDIR_DLESSDASH:
- throw new UnsupportedOperationException("<<-");
+ // FIXME do expansion
+ in = new CommandInput(new StringReader(redir.getHereDocument()));
+ stream = new CommandIOHolder(in, true);
+ break;
case REDIR_GREAT:
try {
@@ -1062,8 +1067,8 @@
if (isNoClobber() && file.exists()) {
throw new ShellException("File already exists");
}
- CommandOutput tmp = new CommandOutput(new FileOutputStream(file));
- stream = new CommandIOHolder(tmp, true);
+ out = new CommandOutput(new FileOutputStream(file));
+ stream = new CommandIOHolder(out, true);
} catch (IOException ex) {
throw new ShellException("Cannot open output file", ex);
}
@@ -1083,8 +1088,8 @@
case REDIR_LESS:
try {
File file = new File(redir.getArg().getText());
- CommandInput tmp = new CommandInput(new FileInputStream(file));
- stream = new CommandIOHolder(tmp, true);
+ in = new CommandInput(new FileInputStream(file));
+ stream = new CommandIOHolder(in, true);
} catch (IOException ex) {
throw new ShellException("Cannot open input file", ex);
}
@@ -1093,16 +1098,18 @@
case REDIR_LESSAND:
try {
int fromFd = Integer.parseInt(redir.getArg().getText());
- stream = (fromFd >= holders.length) ? null : new CommandIOHolder(holders[fromFd]);
+ stream = (fromFd >= holders.length) ? null :
+ new CommandIOHolder(holders[fromFd]);
} catch (NumberFormatException ex) {
- throw new ShellException("Invalid fd after >&");
+ throw new ShellException("Invalid fd after <&");
}
break;
case REDIR_GREATAND:
try {
int fromFd = Integer.parseInt(redir.getArg().getText());
- stream = (fromFd >= holders.length) ? null : new CommandIOHolder(holders[fromFd]);
+ stream = (fromFd >= holders.length) ? null :
+ new CommandIOHolder(holders[fromFd]);
} catch (NumberFormatException ex) {
throw new ShellException("Invalid fd after >&");
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-03-20 12:58:04 UTC (rev 5125)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-03-20 13:26:45 UTC (rev 5126)
@@ -79,6 +79,7 @@
import static org.jnode.shell.bjorne.BjorneToken.TOK_WHILE;
import static org.jnode.shell.bjorne.BjorneToken.TOK_WORD;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -90,6 +91,9 @@
private final BjorneTokenizer tokens;
private final String continuationPrompt;
+
+ private final List<RedirectionNode> hereRedirections =
+ new ArrayList<RedirectionNode>();
public BjorneParser(BjorneTokenizer tokens, String continuationPrompt) {
this.tokens = tokens;
@@ -103,13 +107,14 @@
* @throws ShellSyntaxException
*/
public CommandNode parse() throws ShellSyntaxException {
+ hereRedirections.clear();
List<CommandNode> commands = new LinkedList<CommandNode>();
while (tokens.peek().getTokenType() != TOK_END_OF_STREAM) {
CommandNode command = parseList();
commands.add(command);
- tokens.next();
- skipLineBreaks();
+ processLineBreaks();
}
+ captureHereDocuments();
return listToNode(commands);
}
@@ -172,13 +177,13 @@
}
commands.add(command);
tokens.next();
- skipLineBreaks();
+ processLineBreaks();
}
return listToNode(commands);
}
private CommandNode parseOptAndOr() throws ShellSyntaxException {
- skipLineBreaks();
+ processLineBreaks();
switch (tokens.peek(RULE_1_CONTEXT).getTokenType()) {
case TOK_LBRACE:
case TOK_LPAREN:
@@ -230,7 +235,7 @@
commands.add(parseCommand());
while (tokens.peek().getTokenType() == TOK_BAR) {
tokens.next();
- skipLineBreaks();
+ processLineBreaks();
commands.add(parseCommand());
}
boolean pipe = commands.size() > 1;
@@ -359,7 +364,7 @@
if (tt != TOK_RPAREN) {
syntaxError("expected matching ')' in function_definition", tt);
}
- skipLineBreaks();
+ processLineBreaks();
return new FunctionDefinitionNode(fname, parseFunctionBody());
}
@@ -432,7 +437,9 @@
if (tt2 != TOK_WORD) {
syntaxError("expected a filename after " + token, tt2);
}
- break;
+ // (The corresponding token type and redirection type values are the
+ // same ...)
+ return new RedirectionNode(tt, io, arg);
case TOK_DLESS:
case TOK_DLESSDASH:
arg = tokens.next();
@@ -440,14 +447,14 @@
if (tt3 != TOK_WORD) {
syntaxError("expected a here-end marker " + token, tt3);
}
- // TODO ... need to grab the HERE document ...
- break;
+ RedirectionNode res = new RedirectionNode(tt, io, arg);
+ // (The HERE document will be captured when we reach the next
+ // real (i.e. not '\' escaped) line break ... see processLineBreaks())
+ hereRedirections.add(res);
+ return res;
default:
throw new ShellSyntaxException("expected a redirection token");
}
- // (The corresponding token type and redirection type values are the
- // same ...)
- return new RedirectionNode(tt, io, arg);
}
private RedirectionNode[] parseOptRedirects() throws ShellSyntaxException {
@@ -490,23 +497,25 @@
private CommandNode parseCompoundList() throws ShellSyntaxException {
List<CommandNode> commands = new LinkedList<CommandNode>();
- skipLineBreaks();
+ processLineBreaks();
CommandNode command = parseAndOr();
LOOP:
while (command != null) {
commands.add(command);
switch (tokens.peek().getTokenType()) {
case TOK_SEMI:
+ tokens.next();
break;
case TOK_END_OF_LINE:
break;
case TOK_AMP:
command.setFlag(FLAG_ASYNC);
+ tokens.next();
break;
default:
break LOOP;
}
- tokens.next();
+ processLineBreaks();
command = parseOptAndOr();
}
return listToNode(commands);
@@ -527,21 +536,21 @@
tokens.next();
BjorneToken word = tokens.next();
List<CaseItemNode> caseItems = new LinkedList<CaseItemNode>();
- skipLineBreaks();
+ processLineBreaks();
int tt = tokens.next(RULE_6_CONTEXT).getTokenType();
if (tt != TOK_IN) {
syntaxError("expected 'in' in case_clause", tt);
}
- skipLineBreaks();
+ processLineBreaks();
BjorneToken token = tokens.peek(RULE_1_CONTEXT);
while (token.getTokenType() != TOK_ESAC) {
caseItems.add(parseCaseItem());
- skipLineBreaks();
+ processLineBreaks();
token = tokens.peek(RULE_1_CONTEXT);
tt = token.getTokenType();
if (tt == TOK_DSEMI) {
tokens.next();
- skipLineBreaks();
+ processLineBreaks();
token = tokens.peek(RULE_1_CONTEXT);
} else if (tt != TOK_ESAC) {
syntaxError("expected ';;' or 'esac' after case_item", tt);
@@ -566,12 +575,12 @@
syntaxError("expected ')' after pattern in case_item", tt);
}
CommandNode body = null;
- skipLineBreaks();
+ processLineBreaks();
token = tokens.peek(RULE_1_CONTEXT);
if (token.getTokenType() != TOK_DSEMI
&& token.getTokenType() != TOK_ESAC) {
body = parseCompoundList();
- skipLineBreaks();
+ processLineBreaks();
}
return new CaseItemNode(pattern, body);
@@ -601,7 +610,7 @@
if (tt != TOK_NAME) {
syntaxError("expected a NAME following 'for'", tt);
}
- skipLineBreaks();
+ processLineBreaks();
List<BjorneToken> words = new LinkedList<BjorneToken>();
if (tokens.peek(RULE_6_CONTEXT).getTokenType() == TOK_IN) {
tokens.next();
@@ -618,10 +627,10 @@
switch (tt) {
case TOK_SEMI:
tokens.next();
- skipLineBreaks();
+ processLineBreaks();
break;
case TOK_END_OF_LINE:
- skipLineBreaks();
+ processLineBreaks();
break;
default:
syntaxError("expected a ';' following wordlist", tt);
@@ -632,13 +641,13 @@
}
private CommandNode parseDoGroup() throws ShellSyntaxException {
- skipLineBreaks();
+ processLineBreaks();
int tt = tokens.next(RULE_1_CONTEXT).getTokenType();
if (tt != TOK_DO) {
syntaxError("expected the 'do' of a do_group", tt);
}
CommandNode body = parseCompoundList();
- skipLineBreaks();
+ processLineBreaks();
tt = tokens.next(RULE_1_CONTEXT).getTokenType();
if (tt != TOK_DONE) {
syntaxError("expected a command or 'done'", tt);
@@ -663,14 +672,14 @@
private IfCommandNode parseIfCommand() throws ShellSyntaxException {
tokens.next();
CommandNode cond = parseCompoundList();
- skipLineBreaks();
+ processLineBreaks();
int tt = tokens.next(RULE_1_CONTEXT).getTokenType();
if (tt != TOK_THEN) {
syntaxError("expected a 'then' in if_clause", tt);
}
CommandNode thenPart = parseCompoundList();
CommandNode elsePart = parseOptElsePart();
- skipLineBreaks();
+ processLineBreaks();
tt = tokens.next(RULE_1_CONTEXT).getTokenType();
if (tt != TOK_FI) {
syntaxError("expected an 'elif', 'else' or 'fi'", tt);
@@ -679,11 +688,11 @@
}
private CommandNode parseOptElsePart() throws ShellSyntaxException {
- skipLineBreaks();
+ processLineBreaks();
switch (tokens.next(RULE_1_CONTEXT).getTokenType()) {
case TOK_ELIF:
CommandNode cond = parseCompoundList();
- skipLineBreaks();
+ processLineBreaks();
int tt = tokens.next(RULE_1_CONTEXT).getTokenType();
if (tt != TOK_THEN) {
syntaxError("expected a 'then' in else_part", tt);
@@ -707,12 +716,37 @@
}
}
- private void skipLineBreaks() {
- while (tokens.peek().getTokenType() == TOK_END_OF_LINE) {
+ private void processLineBreaks() throws IncompleteCommandException {
+ if (tokens.peek().getTokenType() == TOK_END_OF_LINE) {
tokens.next();
+ captureHereDocuments();
+ while (tokens.peek().getTokenType() == TOK_END_OF_LINE) {
+ tokens.next();
+ }
}
}
+ private void captureHereDocuments() throws IncompleteCommandException {
+ for (RedirectionNode redirection : hereRedirections) {
+ StringBuilder sb = new StringBuilder();
+ String marker = redirection.getArg().getText();
+ boolean trimTabs = redirection.getRedirectionType() == TOK_DLESSDASH;
+ while (true) {
+ String line = tokens.readHereLine(trimTabs);
+ if (line == null) {
+ throw new IncompleteCommandException("EOF reached while looking for '" +
+ marker + "' to end a HERE document", continuationPrompt);
+ }
+ if (line.equals(marker)) {
+ break;
+ }
+ sb.append(line).append('\n');
+ }
+ redirection.setHereDocument(sb.toString());
+ }
+ hereRedirections.clear();
+ }
+
private CommandNode listToNode(List<? extends CommandNode> commands) {
int len = commands.size();
if (len == 0) {
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java 2009-03-20 12:58:04 UTC (rev 5125)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java 2009-03-20 13:26:45 UTC (rev 5126)
@@ -113,6 +113,9 @@
* @throws IncompleteCommandException
*/
private char[] foldContinuations(String text) throws IncompleteCommandException {
+ // FIXME this is wrong ... if we are going to imitate the documented behaviour
+ // of bash. (In bash, if the the MARKER is quoted, '\<newline>' is apparently
+ // not interpreted as a continuation.)
if (text.indexOf('\\') == -1) {
return text.toCharArray();
}
@@ -248,6 +251,26 @@
public void remove() {
throw new UnsupportedOperationException("remove not supported");
}
+
+ public String readHereLine(boolean trimTabs) {
+ StringBuilder sb = new StringBuilder(40);
+ while (true) {
+ int ch = nextCh();
+ switch (ch) {
+ case '\n':
+ return sb.toString();
+ case EOS:
+ return (sb.length() > 0) ? sb.toString() : null;
+ case '\t':
+ if (!trimTabs || sb.length() > 0) {
+ sb.append('\t');
+ }
+ break;
+ default:
+ sb.append((char) ch);
+ }
+ }
+ }
/**
* Parse and return the next token
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java 2009-03-20 12:58:04 UTC (rev 5125)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java 2009-03-20 13:26:45 UTC (rev 5126)
@@ -21,11 +21,13 @@
package org.jnode.shell.bjorne;
public class RedirectionNode {
- public final int redirectionType;
+ private final int redirectionType;
- public final BjorneToken io;
+ private final BjorneToken io;
- public final BjorneToken arg;
+ private final BjorneToken arg;
+
+ private String hereDocument;
public RedirectionNode(final int redirectionType, BjorneToken io,
BjorneToken arg) {
@@ -47,6 +49,14 @@
return redirectionType;
}
+ public void setHereDocument(String hereDocument) {
+ this.hereDocument = hereDocument;
+ }
+
+ public String getHereDocument() {
+ return hereDocument;
+ }
+
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Redirect{");
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-20 12:58:04 UTC (rev 5125)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-20 13:26:45 UTC (rev 5126)
@@ -628,6 +628,16 @@
</output>
<error>Hello mother again
</error>
+ </testSpec><testSpec title="here" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ cat <<EOF > @TEMP_DIR@/1
+Hi mum
+Hi mum again
+EOF
+ </script>
+ <file name="1" input="false">Hi mum
+Hi mum again
+</file>
</testSpec>
<testSpec title="pipeline" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-21 01:13:55
|
Revision: 5134
http://jnode.svn.sourceforge.net/jnode/?rev=5134&view=rev
Author: crawley
Date: 2009-03-21 01:13:41 +0000 (Sat, 21 Mar 2009)
Log Message:
-----------
Implemented expansion of HERE documents.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java
trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-20 20:42:48 UTC (rev 5133)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-21 01:13:41 UTC (rev 5134)
@@ -1056,8 +1056,11 @@
switch (redir.getRedirectionType()) {
case REDIR_DLESS:
case REDIR_DLESSDASH:
- // FIXME do expansion
- in = new CommandInput(new StringReader(redir.getHereDocument()));
+ String here = redir.getHereDocument();
+ if (redir.isHereDocumentExpandable()) {
+ here = expand(here).toString();
+ }
+ in = new CommandInput(new StringReader(here));
stream = new CommandIOHolder(in, true);
break;
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java 2009-03-20 20:42:48 UTC (rev 5133)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneTokenizer.java 2009-03-21 01:13:41 UTC (rev 5134)
@@ -252,6 +252,14 @@
throw new UnsupportedOperationException("remove not supported");
}
+ /**
+ * This method bypasses normal tokenization and reads a raw line of
+ * text up to the next NL (or the end of stream).
+ *
+ * @param trimTabs if {@code true}, trim any leading TABs from the line
+ * @return the line read without the terminating NL. If we got an
+ * end of stream immediately, return {@code null}.
+ */
public String readHereLine(boolean trimTabs) {
StringBuilder sb = new StringBuilder(40);
while (true) {
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java 2009-03-20 20:42:48 UTC (rev 5133)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/RedirectionNode.java 2009-03-21 01:13:41 UTC (rev 5134)
@@ -26,8 +26,10 @@
private final BjorneToken io;
private final BjorneToken arg;
+
+ private String hereDocument;
- private String hereDocument;
+ private boolean expandable = true;
public RedirectionNode(final int redirectionType, BjorneToken io,
BjorneToken arg) {
@@ -50,6 +52,8 @@
}
public void setHereDocument(String hereDocument) {
+ // FIXME ... should analyze the document and set 'expandable'
+ // if there anything that requires expansion.
this.hereDocument = hereDocument;
}
@@ -70,4 +74,8 @@
sb.append("}");
return sb.toString();
}
+
+ public boolean isHereDocumentExpandable() {
+ return expandable;
+ }
}
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-20 20:42:48 UTC (rev 5133)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-21 01:13:41 UTC (rev 5134)
@@ -639,6 +639,32 @@
Hi mum again
</file>
</testSpec>
+ <testSpec title="here 2" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ for i in 1 2 3 4 5 ; do cat <<EOF ; done
+Hi mum $i
+EOF
+ </script>
+ <output>Hi mum 1
+Hi mum 2
+Hi mum 3
+Hi mum 4
+Hi mum 5
+</output>
+ </testSpec>
+ <testSpec title="here 3" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ for i in 1 2 3 4 5 ; do cat <<EOF ; done
+Hi mum `echo $i`
+EOF
+ </script>
+ <output>Hi mum 1
+Hi mum 2
+Hi mum 3
+Hi mum 4
+Hi mum 5
+</output>
+ </testSpec>
<testSpec title="pipeline" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
echo > @TEMP_DIR@/1 Hi mum
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-29 04:20:42
|
Revision: 5174
http://jnode.svn.sourceforge.net/jnode/?rev=5174&view=rev
Author: crawley
Date: 2009-03-29 04:20:40 +0000 (Sun, 29 Mar 2009)
Log Message:
-----------
Bug fix: an empty line in a script would clear $?. Also added a partly
implemented / partly tested version of the 'alias' builtin.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Added Paths:
-----------
trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java
Added: trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java 2009-03-29 04:20:40 UTC (rev 5174)
@@ -0,0 +1,90 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * 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 org.jnode.shell.bjorne;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.jnode.shell.Command;
+import org.jnode.shell.CommandLine;
+import org.jnode.shell.ShellException;
+
+/**
+ * This class implements the 'alias' built-in.
+ *
+ * @author cr...@jn...
+ */
+final class AliasBuiltin extends BjorneBuiltin {
+ @SuppressWarnings("deprecation")
+ public int invoke(CommandLine command, BjorneInterpreter interpreter,
+ BjorneContext context) throws ShellException {
+ Iterator<String> args = command.iterator();
+ context = context.getParent();
+ PrintStream ps = context.resolvePrintStream(context.getIO(Command.STD_ERR));
+ int rc = 0;
+ if (!args.hasNext()) {
+ printAliases(ps, context.getAliases());
+ } else {
+ while (args.hasNext()) {
+ String arg = args.next();
+ int pos = arg.indexOf('=');
+ String aliasName;
+ String alias;
+ if (pos <= 0) {
+ aliasName = arg;
+ alias = null;
+ } else {
+ aliasName = arg.substring(0, pos);
+ alias = arg.substring(pos + 1);
+ }
+ if (alias == null) {
+ alias = context.getAlias(aliasName);
+ if (alias == null) {
+ error("alias: " + aliasName + " not found", context);
+ rc = 1;
+ } else {
+ printAlias(ps, aliasName, alias);
+ }
+ } else {
+ if (!BjorneToken.isName(aliasName)) {
+ error("alias: " + aliasName + ": not a valid alias name", context);
+ }
+ context.defineAlias(aliasName, alias);
+ }
+ }
+ }
+ return rc;
+ }
+
+ private void printAliases(PrintStream ps, TreeMap<String, String> aliases) {
+ for (Map.Entry<String, String> entry : aliases.entrySet()) {
+ printAlias(ps, entry.getKey(), entry.getValue());
+ }
+ }
+
+ private void printAlias(PrintStream ps, String aliasName, String alias) {
+ ps.println(aliasName + "=" + alias);
+ }
+
+
+}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-29 03:11:28 UTC (rev 5173)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-29 04:20:40 UTC (rev 5174)
@@ -45,6 +45,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -102,6 +103,8 @@
private final BjorneInterpreter interpreter;
private Map<String, VariableSlot> variables;
+
+ private TreeMap<String, String> aliases;
private String command = "";
@@ -129,6 +132,7 @@
this.interpreter = interpreter;
this.holders = holders;
this.variables = new HashMap<String, VariableSlot>();
+ this.aliases = new TreeMap<String, String>();
}
public BjorneContext(BjorneInterpreter interpreter) {
@@ -299,8 +303,42 @@
var.exported = exported;
}
}
+
+ /**
+ * Get the complete alias map.
+ * @return the alias map
+ */
+ TreeMap<String, String> getAliases() {
+ return aliases;
+ }
+
+ /**
+ * Lookup an alias
+ * @param aliasName the (possible) alias name
+ * @return the alias string or {@code null}
+ */
+ String getAlias(String aliasName) {
+ return aliases.get(aliasName);
+ }
+
+ /**
+ * Define an alias
+ * @param aliasName the alias name
+ * @param alias the alias.
+ */
+ void defineAlias(String aliasName, String alias) {
+ aliases.put(aliasName, alias);
+ }
/**
+ * Undefine an alias
+ * @param aliasName the alias name
+ */
+ void undefineAlias(String aliasName) {
+ aliases.remove(aliasName);
+ }
+
+ /**
* Perform expand-and-split processing on a list of word tokens. The resulting
* wordTokens are assembled into a CommandLine.
*
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-29 03:11:28 UTC (rev 5173)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-29 04:20:40 UTC (rev 5174)
@@ -140,6 +140,7 @@
private static long subshellCount;
static {
+ BUILTINS.put("alias", new AliasBuiltin());
BUILTINS.put("break", new BreakBuiltin());
BUILTINS.put("continue", new ContinueBuiltin());
BUILTINS.put("exit", new ExitBuiltin());
@@ -242,7 +243,7 @@
CommandNode tree = new BjorneParser(tokens, "> ").parse();
if (tree == null) {
// An empty command line
- return 0;
+ return myContext.getLastReturnCode();
}
if (DEBUG) {
System.err.println(tree);
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 03:11:28 UTC (rev 5173)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 04:20:40 UTC (rev 5174)
@@ -3,12 +3,25 @@
<plugin id="org.jnode.shell.command.posix"/>
<testSpec title="exit 0" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
-exit 0
+ exit 0
</script>
</testSpec>
- <testSpec title="exit 99" command="test" runMode="AS_SCRIPT" rc="99">
+ <testSpec title="exit 99" runMode="AS_SCRIPT" rc="99">
<script>#!bjorne
-exit 99
+ exit 99
</script>
</testSpec>
+ <testSpec title="alias" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ alias > @TEMP_DIR@/1
+ </script>
+ <file name="1" input="false"></file>
+ </testSpec>
+ <testSpec title="alias 2" command="test" runMode="AS_SCRIPT" rc="1">
+ <script>#!bjorne
+ alias fred
+ </script>
+ <error>alias: fred not found
+</error>
+ </testSpec>
</testSet>
\ No newline at end of file
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-29 03:11:28 UTC (rev 5173)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-03-29 04:20:40 UTC (rev 5174)
@@ -22,9 +22,17 @@
echo $?
false
echo $?
+false
+
+echo $?
+false
+# no comment
+echo $?
</script>
<output>0
1
+1
+1
</output>
</testSpec>
<testSpec title="``" command="test" runMode="AS_SCRIPT" rc="0">
@@ -164,7 +172,7 @@
A is 1
</output>
</testSpec>
- <testSpec title="while ... do ... done" command="test" runMode="AS_SCRIPT" rc="0">
+ <testSpec title="while ... do ... done" command="test" runMode="AS_SCRIPT" rc="1">
<script>#!bjorne
A=5
while expr $A != 0 ; do echo A is $A ; A=`expr $A - 1`; done
@@ -182,7 +190,7 @@
0
</output>
</testSpec>
- <testSpec title="while ... do ... done multi-line" command="test" runMode="AS_SCRIPT" rc="0">
+ <testSpec title="while ... do ... done multi-line" command="test" runMode="AS_SCRIPT" rc="1">
<script>#!bjorne
A=5
while expr $A != 0 ;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-29 07:24:25
|
Revision: 5175
http://jnode.svn.sourceforge.net/jnode/?rev=5175&view=rev
Author: crawley
Date: 2009-03-29 07:24:21 +0000 (Sun, 29 Mar 2009)
Log Message:
-----------
Added 'unalias' and fixed bugs in 'alias'.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
Added Paths:
-----------
trunk/shell/src/shell/org/jnode/shell/bjorne/UnaliasBuiltin.java
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java 2009-03-29 04:20:40 UTC (rev 5174)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/AliasBuiltin.java 2009-03-29 07:24:21 UTC (rev 5175)
@@ -40,10 +40,11 @@
BjorneContext context) throws ShellException {
Iterator<String> args = command.iterator();
context = context.getParent();
- PrintStream ps = context.resolvePrintStream(context.getIO(Command.STD_ERR));
+ PrintStream out = context.resolvePrintStream(context.getIO(Command.STD_OUT));
+ PrintStream err = context.resolvePrintStream(context.getIO(Command.STD_ERR));
int rc = 0;
if (!args.hasNext()) {
- printAliases(ps, context.getAliases());
+ printAliases(out, context.getAliases());
} else {
while (args.hasNext()) {
String arg = args.next();
@@ -60,14 +61,14 @@
if (alias == null) {
alias = context.getAlias(aliasName);
if (alias == null) {
- error("alias: " + aliasName + " not found", context);
+ err.println("alias: " + aliasName + " not found");
rc = 1;
} else {
- printAlias(ps, aliasName, alias);
+ printAlias(out, aliasName, alias);
}
} else {
if (!BjorneToken.isName(aliasName)) {
- error("alias: " + aliasName + ": not a valid alias name", context);
+ err.println("alias: " + aliasName + ": not a valid alias name");
}
context.defineAlias(aliasName, alias);
}
@@ -83,7 +84,7 @@
}
private void printAlias(PrintStream ps, String aliasName, String alias) {
- ps.println(aliasName + "=" + alias);
+ ps.println(aliasName + "='" + alias + "'");
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-29 04:20:40 UTC (rev 5174)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-03-29 07:24:21 UTC (rev 5175)
@@ -148,8 +148,9 @@
BUILTINS.put("return", new ReturnBuiltin());
BUILTINS.put("set", new SetBuiltin());
BUILTINS.put("shift", new ShiftBuiltin());
+ BUILTINS.put("source", new SourceBuiltin());
+ BUILTINS.put("unalias", new UnaliasBuiltin());
BUILTINS.put(".", new SourceBuiltin());
- BUILTINS.put("source", new SourceBuiltin());
BUILTINS.put(":", new ColonBuiltin());
}
Added: trunk/shell/src/shell/org/jnode/shell/bjorne/UnaliasBuiltin.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/UnaliasBuiltin.java (rev 0)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/UnaliasBuiltin.java 2009-03-29 07:24:21 UTC (rev 5175)
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * 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 org.jnode.shell.bjorne;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+
+import org.jnode.shell.Command;
+import org.jnode.shell.CommandLine;
+import org.jnode.shell.ShellException;
+
+/**
+ * This class implements the 'unalias' built-in.
+ *
+ * @author cr...@jn...
+ */
+final class UnaliasBuiltin extends BjorneBuiltin {
+ @SuppressWarnings("deprecation")
+ public int invoke(CommandLine command, BjorneInterpreter interpreter,
+ BjorneContext context) throws ShellException {
+ Iterator<String> args = command.iterator();
+ context = context.getParent();
+ PrintStream err = context.resolvePrintStream(context.getIO(Command.STD_ERR));
+ int rc = 0;
+ while (args.hasNext()) {
+ String arg = args.next();
+ if (arg.equals("-a")) {
+ context.getAliases().clear();
+ break;
+ } else {
+ String alias = context.getAlias(arg);
+ if (alias == null) {
+ err.println("alias: " + arg + " not found");
+ rc = 1;
+ } else {
+ context.undefineAlias(arg);
+ }
+ }
+ }
+ return rc;
+ }
+}
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 04:20:40 UTC (rev 5174)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 07:24:21 UTC (rev 5175)
@@ -24,4 +24,30 @@
<error>alias: fred not found
</error>
</testSpec>
+ <testSpec title="alias 3" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ alias fred=ls
+ alias fred
+ alias jim="echo hi"
+ alias jim
+ alias
+ </script>
+ <output>fred='ls'
+jim='echo hi'
+fred='ls'
+jim='echo hi'
+</output>
+ </testSpec>
+ <testSpec title="unalias" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ alias fred=ls
+ alias jim="echo hi"
+ unalias jim
+ alias
+ unalias -a
+ alias
+ </script>
+ <output>fred='ls'
+</output>
+ </testSpec>
</testSet>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-03-29 13:08:23
|
Revision: 5180
http://jnode.svn.sourceforge.net/jnode/?rev=5180&view=rev
Author: crawley
Date: 2009-03-29 13:08:19 +0000 (Sun, 29 Mar 2009)
Log Message:
-----------
Bjorne shell aliases should now work
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-29 10:53:16 UTC (rev 5179)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-03-29 13:08:19 UTC (rev 5180)
@@ -52,6 +52,7 @@
import org.jnode.shell.Command;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandShell;
+import org.jnode.shell.IncompleteCommandException;
import org.jnode.shell.PathnamePattern;
import org.jnode.shell.ShellException;
import org.jnode.shell.ShellFailureException;
@@ -159,6 +160,7 @@
this.interpreter = parent.interpreter;
this.holders = copyStreamHolders(parent.holders);
this.variables = copyVariables(parent.variables);
+ this.aliases = new TreeMap<String, String>(parent.aliases);
this.globbing = parent.globbing;
this.tildeExpansion = parent.tildeExpansion;
this.echoExpansions = parent.echoExpansions;
@@ -1238,4 +1240,39 @@
return interpreter.getUniqueName();
}
+ public BjorneToken[] substituteAliases(BjorneToken[] words)
+ throws IncompleteCommandException {
+ String alias = aliases.get(words[0].getText());
+ if (alias == null) {
+ return words;
+ }
+ List<BjorneToken> list = new LinkedList<BjorneToken>(Arrays.asList(words));
+ substituteAliases(list, 0, 0);
+ return list.toArray(new BjorneToken[list.size()]);
+ }
+
+ private void substituteAliases(List<BjorneToken> list, int pos, int depth)
+ throws IncompleteCommandException {
+ if (depth > 10) {
+ throw new ShellFailureException("probable cycle detected in alias expansion");
+ }
+ String aliasName = list.get(pos).getText();
+ String alias = aliases.get(aliasName);
+ if (alias == null) {
+ return;
+ }
+ BjorneTokenizer tokens = new BjorneTokenizer(alias);
+ list.remove(pos);
+ int i = 0;
+ while (tokens.hasNext()) {
+ list.add(pos + i, tokens.next());
+ if (i == 0 && !aliasName.equals(list.get(pos + i).getText())) {
+ substituteAliases(list, pos + i, depth + 1);
+ }
+ i++;
+ }
+ if (alias.endsWith(" ") && pos + i < list.size()) {
+ substituteAliases(list, pos + i, depth + 1);
+ }
+ }
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-03-29 10:53:16 UTC (rev 5179)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-03-29 13:08:19 UTC (rev 5180)
@@ -83,6 +83,9 @@
childContext.evaluateRedirections(getRedirects());
rc = 0;
} else {
+ // FIXME ... strictly speaking, alias substitution should be performed
+ // before "applying the grammatical rules" (i.e. parsing).
+ words = context.substituteAliases(words);
CommandLine command = context.expandAndSplit(words);
// Assignments and redirections are done in the command's context
BjorneContext childContext = new BjorneContext(context);
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 10:53:16 UTC (rev 5179)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-03-29 13:08:19 UTC (rev 5180)
@@ -38,6 +38,30 @@
jim='echo hi'
</output>
</testSpec>
+ <testSpec title="alias 4" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ alias fred="echo hi"
+ fred
+ fred ho
+ fred fred
+ </script>
+ <output>hi
+hi ho
+hi fred
+</output>
+ </testSpec>
+ <testSpec title="alias 5" command="test" runMode="AS_SCRIPT" rc="0">
+ <script>#!bjorne
+ alias fred="echo hi "
+ fred
+ fred ho
+ fred fred
+ </script>
+ <output>hi
+hi ho
+hi echo hi
+</output>
+ </testSpec>
<testSpec title="unalias" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
alias fred=ls
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-13 10:06:06
|
Revision: 5260
http://jnode.svn.sourceforge.net/jnode/?rev=5260&view=rev
Author: crawley
Date: 2009-04-13 10:06:04 +0000 (Mon, 13 Apr 2009)
Log Message:
-----------
Fix bug found by cluster - globbing is now suppressed by quotes (modulo some
other bugs in PathnamePattern that I'm working on.)
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneToken.java
trunk/shell/src/shell/org/jnode/shell/bjorne/CaseCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/ForCommandNode.java
trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneContextTests.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -117,43 +117,51 @@
* match "a'c"; i.e. a filename containing a single-quote character.
*/
public static final int SINGLE_QUOTE_ESCAPES = 0x10;
+
+ /**
+ * When set, this flag causes characters inside matching double-quote
+ * characters to be match literal characters in the pathname. Only a '\' is
+ * unaffected. Thus ""a*c"" will match the file "a*c", but ""a\"c"" will
+ * match "a"c"; i.e. a filename containing a double-quote character.
+ */
+ public static final int DOUBLE_QUOTE_ESCAPES = 0x20;
/**
* When set, this flag causes the [...] character class syntax to be
* recognized.
*/
- public static final int CHARACTER_CLASSES = 0x20;
+ public static final int CHARACTER_CLASSES = 0x40;
/**
* When set, the pattern is anchored to the left of the string to be searched.
* This is set implicitly by the pathname matching methods.
*/
- public static final int ANCHOR_LEFT = 0x40;
+ public static final int ANCHOR_LEFT = 0x80;
/**
* When set, the pattern is anchored to the right of the string to be searched.
* This is set implicitly by the pathname matching methods.
*/
- public static final int ANCHOR_RIGHT = 0x80;
+ public static final int ANCHOR_RIGHT = 0x100;
/**
* When set, '*' is eager, matching as many characters as possible.
* This is set implicitly by the pathname matching methods.
* matching is always eager.
*/
- public static final int EAGER = 0x100;
+ public static final int EAGER = 0x200;
/**
* When set, an unescaped '/' inside a character class causes the entire class
* to be interpreted as a literal character sequence.
* This is set implicitly by the pathname matching methods.
*/
- public static final int SLASH_DISABLES_CHARACTER_CLASSES = 0x200;
+ public static final int SLASH_DISABLES_CHARACTER_CLASSES = 0x400;
public static final int DEFAULT_FLAGS = SORT_MATCHES | HIDE_DOT_FILENAMES
| INCLUDE_DOT_AND_DOTDOT | BACKSLASH_ESCAPES | SINGLE_QUOTE_ESCAPES
- | CHARACTER_CLASSES;
+ | DOUBLE_QUOTE_ESCAPES | CHARACTER_CLASSES;
private static final boolean DEBUG = false;
@@ -322,6 +330,15 @@
}
return pat;
}
+
+ /**
+ * Clear the pattern cache
+ */
+ public static void clearCache() {
+ synchronized (PathnamePattern.class) {
+ cache = null;
+ }
+ }
/**
* Provide a fast determination if a string requires pattern expansion,
@@ -365,6 +382,11 @@
return true;
}
break;
+ case '\"':
+ if ((flags & DOUBLE_QUOTE_ESCAPES) != 0) {
+ return true;
+ }
+ break;
default:
}
}
@@ -384,7 +406,7 @@
// meta-characters.
int len = pattern.length();
StringBuffer sb = new StringBuffer(len);
- boolean quoted = false;
+ char quote = 0;
boolean eager = (flags & EAGER) != 0;
if ((flags & ANCHOR_LEFT) != 0) {
sb.append('^');
@@ -393,8 +415,8 @@
char ch = pattern.charAt(i);
switch (ch) {
case '?':
- if (quoted) {
- sb.append(ch);
+ if (quote != 0) {
+ sb.append(protect(ch));
} else if (i == 0 && (flags & HIDE_DOT_FILENAMES) != 0) {
sb.append("[^\\.]");
} else {
@@ -402,8 +424,8 @@
}
break;
case '*':
- if (quoted) {
- sb.append(ch);
+ if (quote != 0) {
+ sb.append(protect(ch));
} else if (i == 0 && (flags & HIDE_DOT_FILENAMES) != 0) {
sb.append("(|[^\\.]").append(eager ? ".*" : ".*?").append(")");
} else {
@@ -461,11 +483,30 @@
break;
case '\'':
if ((flags & SINGLE_QUOTE_ESCAPES) != 0) {
- quoted = !quoted;
+ if (quote == '\'') {
+ quote = 0;
+ } else if (quote == 0) {
+ quote = '\'';
+ } else {
+ sb.append(protect(ch));
+ }
} else {
sb.append(protect(ch));
}
break;
+ case '\"':
+ if ((flags & DOUBLE_QUOTE_ESCAPES) != 0) {
+ if (quote == '\"') {
+ quote = 0;
+ } else if (quote == 0) {
+ quote = '\"';
+ } else {
+ sb.append(protect(ch));
+ }
+ } else {
+ sb.append(protect(ch));
+ }
+ break;
default:
sb.append(protect(ch));
}
@@ -499,4 +540,19 @@
public String toString() {
return source;
}
+
+ public String toRegexString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("PathnamePattern{source='").append(this.source);
+ sb.append("',absolute=").append(this.isAbsolute);
+ sb.append(",pattern=[");
+ for (int i = 0; i < this.pattern.length; i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append('\'').append(pattern[i]).append('\'');
+ }
+ sb.append("]}");
+ return sb.toString();
+ }
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -339,69 +339,109 @@
void undefineAlias(String aliasName) {
aliases.remove(aliasName);
}
-
+
/**
- * Perform expand-and-split processing on a list of word tokens. The resulting
+ * Perform expand-and-split processing on an array of word tokens. The resulting
* wordTokens are assembled into a CommandLine.
*
* @param tokens the tokens to be expanded and split into words
* @return the command line
* @throws ShellException
*/
- public CommandLine expandAndSplit(Iterable<BjorneToken> tokens) throws ShellException {
- List<BjorneToken> wordTokens = new LinkedList<BjorneToken>();
- expandAndSplit(tokens, wordTokens);
- return makeCommandLine(wordTokens);
+ public CommandLine buildCommandLine(BjorneToken ... tokens) throws ShellException {
+ List<BjorneToken> wordTokens = expandAndSplit(tokens);
+ int nosWords = wordTokens.size();
+ if (nosWords == 0) {
+ return new CommandLine(null, null);
+ } else {
+ BjorneToken alias = wordTokens.remove(0);
+ BjorneToken[] args = wordTokens.toArray(new BjorneToken[nosWords - 1]);
+ return new CommandLine(alias, args, null);
+ }
}
/**
- * Perform expand-and-split processing on an array of word tokens. The resulting
- * wordTokens are assembled into a CommandLine.
+ * Perform expand-and-split processing on a list of word tokens.
*
* @param tokens the tokens to be expanded and split into words
- * @return the command line
* @throws ShellException
*/
- public CommandLine expandAndSplit(BjorneToken[] tokens) throws ShellException {
+ public List<BjorneToken> expandAndSplit(Iterable<BjorneToken> tokens)
+ throws ShellException {
List<BjorneToken> wordTokens = new LinkedList<BjorneToken>();
- expandAndSplit(tokens, wordTokens);
- return makeCommandLine(wordTokens);
+ for (BjorneToken token : tokens) {
+ dollarBacktickSplit(token, wordTokens);
+ }
+ wordTokens = doFileExpansions(wordTokens);
+ wordTokens = dequote(wordTokens);
+ return wordTokens;
}
/**
- * Perform expand-and-split processing on a list of word tokens. The resulting
- * tokens are appended to wordTokens.
+ * Perform full expand-and-split processing on an array of word tokens.
*
* @param tokens the tokens to be expanded and split into words
- * @param wordTokens append expanded/split tokens to this list
* @throws ShellException
*/
- public void expandAndSplit(Iterable<BjorneToken> tokens, List<BjorneToken> wordTokens)
+ public List<BjorneToken> expandAndSplit(BjorneToken ... tokens)
throws ShellException {
+ List<BjorneToken> wordTokens = new LinkedList<BjorneToken>();
for (BjorneToken token : tokens) {
- expandSplitAndAppend(token, wordTokens);
+ dollarBacktickSplit(token, wordTokens);
}
+ wordTokens = doFileExpansions(wordTokens);
+ wordTokens = dequote(wordTokens);
+ return wordTokens;
}
+ private List<BjorneToken> dequote(List<BjorneToken> wordTokens) {
+ List<BjorneToken> resTokens = new LinkedList<BjorneToken>();
+ for (BjorneToken token : wordTokens) {
+ String text = token.getText();
+ int len = text.length();
+ StringBuffer sb = new StringBuffer(len);
+ int quote = 0;
+ for (int i = 0; i < len; i++) {
+ char ch = text.charAt(i);
+ switch (ch) {
+ case '"':
+ case '\'':
+ if (quote == 0) {
+ quote = ch;
+ } else if (quote == ch) {
+ quote = 0;
+ } else {
+ sb.append(ch);
+ }
+ break;
+ case '\\':
+ if (i + 1 < len) {
+ ch = text.charAt(++i);
+ }
+ sb.append(ch);
+ break;
+ default:
+ sb.append(ch);
+ break;
+ }
+ }
+ resTokens.add(token.remake(sb));
+ }
+ return resTokens;
+ }
+
/**
- * Perform expand-and-split processing on an array of word tokens. The resulting
- * tokens are appended to wordTokens.
+ * Do dollar and backtick expansion on a token, split into words, retokenize and
+ * append the resulting tokens to 'wordTokens.
*
- * @param tokens the tokens to be expanded and split into words
- * @param wordTokens append expanded/split tokens to this list
+ * @param token
+ * @param wordTokens
* @throws ShellException
*/
- public void expandAndSplit(BjorneToken[] tokens, List<BjorneToken> wordTokens)
+ private void dollarBacktickSplit(BjorneToken token, List<BjorneToken> wordTokens)
throws ShellException {
- for (BjorneToken token : tokens) {
- expandSplitAndAppend(token, wordTokens);
- }
- }
-
- private void expandSplitAndAppend(BjorneToken token, List<BjorneToken> wordTokens)
- throws ShellException {
String word = token.getText();
- CharSequence expanded = expand(word);
+ CharSequence expanded = dollarBacktickExpand(word);
if (expanded == word) {
splitAndAppend(token, wordTokens);
} else {
@@ -411,21 +451,8 @@
}
}
}
-
- /**
- * Perform expand-and-split processing on a sequence of characters. This method is only
- * used in tests at the moment, and probably should be removed. (It does not set token
- * attributes properly ...)
- *
- * @param text the characters to be split
- * @return the command line
- * @throws ShellException
- */
- public List<BjorneToken> expandAndSplit(CharSequence text) throws ShellException {
- return split(expand(text));
- }
-
- private CommandLine makeCommandLine(List<BjorneToken> wordTokens) {
+
+ private List<BjorneToken> doFileExpansions(List<BjorneToken> wordTokens) {
if (globbing || tildeExpansion) {
List<BjorneToken> globbedWordTokens = new LinkedList<BjorneToken>();
for (BjorneToken wordToken : wordTokens) {
@@ -438,15 +465,9 @@
globbedWordTokens.add(wordToken);
}
}
- wordTokens = globbedWordTokens;
- }
- int nosWords = wordTokens.size();
- if (nosWords == 0) {
- return new CommandLine(null, null);
+ return globbedWordTokens;
} else {
- BjorneToken alias = wordTokens.remove(0);
- BjorneToken[] args = wordTokens.toArray(new BjorneToken[nosWords - 1]);
- return new CommandLine(alias, args, null);
+ return wordTokens;
}
}
@@ -476,6 +497,7 @@
return;
}
PathnamePattern pattern = PathnamePattern.compilePathPattern(word);
+ // Expand using the current directory as the base for relative path patterns.
LinkedList<String> paths = pattern.expand(new File("."));
// If it doesn't match anything, a pattern 'expands' to itself.
if (paths.isEmpty()) {
@@ -486,24 +508,10 @@
}
}
}
-
- /**
- * Split a character sequence into word tokens, dealing with and removing any
- * non-literal quotes.
- *
- * @param text the characters to be split
- * @return the resulting list of tokens.
- * @throws ShellException
- */
- public List<BjorneToken> split(CharSequence text) throws ShellException {
- List<BjorneToken> wordTokens = new LinkedList<BjorneToken>();
- splitAndAppend(new BjorneToken(BjorneToken.TOK_WORD, text.toString(), -1, -1), wordTokens);
- return wordTokens;
- }
/**
- * Split a token into a series of word tokens, dealing with and removing any
- * non-literal quotes. The resulting tokens are appended to a supplied list.
+ * Split a token into a series of word tokens, leaving quoting intact.
+ * The resulting tokens are appended to a supplied list.
*
* @param token the token to be split
* @param wordTokens the destination for the tokens.
@@ -522,14 +530,10 @@
case '\'':
if (quote == 0) {
quote = ch;
- if (sb == null) {
- sb = new StringBuffer();
- }
} else if (quote == ch) {
quote = 0;
- } else {
- sb = accumulate(sb, ch);
- }
+ }
+ sb = accumulate(sb, ch);
break;
case ' ':
case '\t':
@@ -544,6 +548,7 @@
break;
case '\\':
if (i + 1 < len) {
+ sb = accumulate(sb, ch);
ch = text.charAt(++i);
}
sb = accumulate(sb, ch);
@@ -577,13 +582,14 @@
}
/**
- * Perform '$' expansion and backtick substitution. Any quotes and escapes should be preserved (?!?!?)
+ * Perform '$' expansion and backtick substitution. Any quotes and escapes must
+ * be preserved so that they escape globbing and tilde expansion.
*
* @param text the characters to be expanded
* @return the result of the expansion.
* @throws ShellException
*/
- public CharSequence expand(CharSequence text) throws ShellException {
+ public CharSequence dollarBacktickExpand(CharSequence text) throws ShellException {
CharIterator ci = new CharIterator(text);
StringBuffer sb = new StringBuffer(text.length());
char quote = 0;
@@ -1066,7 +1072,7 @@
throw new ShellFailureException("misplaced '=' in assignment");
}
String name = assignment.substring(0, pos);
- String value = expand(assignment.substring(pos + 1)).toString();
+ String value = dollarBacktickExpand(assignment.substring(pos + 1)).toString();
this.setVariable(name, value);
}
}
@@ -1141,7 +1147,7 @@
case REDIR_DLESSDASH:
String here = redir.getHereDocument();
if (redir.isHereDocumentExpandable()) {
- here = expand(here).toString();
+ here = dollarBacktickExpand(here).toString();
}
in = new CommandInput(new StringReader(here));
stream = new CommandIOHolder(in, true);
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneToken.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneToken.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneToken.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -129,6 +129,11 @@
validate();
}
+ public BjorneToken(final String text) {
+ super(text == null ? "" : text, TOK_WORD, 0, 0);
+ validate();
+ }
+
public BjorneToken remake(CharSequence newText) {
if (newText.length() == 0) {
return null;
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/CaseCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/CaseCommandNode.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/CaseCommandNode.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -62,11 +62,11 @@
public int execute(BjorneContext context) throws ShellException {
int rc = 0;
- CharSequence expandedWord = context.expand(word.text);
+ CharSequence expandedWord = context.dollarBacktickExpand(word.text);
LOOP:
for (CaseItemNode caseItem : caseItems) {
for (BjorneToken pattern : caseItem.getPattern()) {
- CharSequence pat = context.expand(pattern.text);
+ CharSequence pat = context.dollarBacktickExpand(pattern.text);
if (context.patternMatch(expandedWord, pat)) {
rc = caseItem.getBody().execute(context);
break LOOP;
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/ForCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/ForCommandNode.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/ForCommandNode.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -20,7 +20,6 @@
package org.jnode.shell.bjorne;
-import java.util.LinkedList;
import java.util.List;
import org.jnode.shell.CommandRunnable;
@@ -94,8 +93,7 @@
@Override
public int execute(BjorneContext context) throws ShellException {
int rc = 0;
- List<BjorneToken> expanded = new LinkedList<BjorneToken>();
- context.expandAndSplit(words, expanded);
+ List<BjorneToken> expanded = context.expandAndSplit(words);
for (BjorneToken word : expanded) {
context.setVariable(var.getText(), word.getText());
rc = body.execute(context);
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -86,7 +86,7 @@
// FIXME ... strictly speaking, alias substitution should be performed
// before "applying the grammatical rules" (i.e. parsing).
words = context.substituteAliases(words);
- CommandLine command = context.expandAndSplit(words);
+ CommandLine command = context.buildCommandLine(words);
// Assignments and redirections are done in the command's context
BjorneContext childContext = new BjorneContext(context);
childContext.performAssignments(assignments);
@@ -118,7 +118,7 @@
public CommandThread fork(CommandShell shell, BjorneContext context)
throws ShellException {
- CommandLine command = context.expandAndSplit(getWords());
+ CommandLine command = context.buildCommandLine(getWords());
command.setStreams(context.getIOs());
CommandInfo cmdInfo = command.parseCommandLine(shell);
return shell.invokeAsynchronous(command, cmdInfo);
@@ -128,7 +128,7 @@
public void complete(CompletionInfo completion, BjorneContext context, CommandShell shell)
throws CompletionException {
try {
- CommandLine command = context.expandAndSplit(words);
+ CommandLine command = context.buildCommandLine(words);
command.complete(completion, shell);
} catch (ShellException ex) {
throw new CompletionException("Shell exception", ex);
Modified: trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -48,17 +48,36 @@
public void testCompilePosixShellPattern() {
assertEquals("abc", PathnamePattern.compilePosixShellPattern("abc", 0).toString());
assertEquals("abc", PathnamePattern.compilePosixShellPattern("abc", DF).toString());
+
assertEquals(".", PathnamePattern.compilePosixShellPattern("?", 0).toString());
assertEquals("[^\\.]", PathnamePattern.compilePosixShellPattern("?", DF).toString());
+
assertEquals(".*?", PathnamePattern.compilePosixShellPattern("*", 0).toString());
assertEquals("(|[^\\.].*?)", PathnamePattern.compilePosixShellPattern("*", DF).toString());
+
assertEquals(".*?a.*?", PathnamePattern.compilePosixShellPattern("*a*", 0).toString());
assertEquals("(|[^\\.].*?)a.*?", PathnamePattern.compilePosixShellPattern("*a*", DF).toString());
+
assertEquals("\".*?a.*?\"", PathnamePattern.compilePosixShellPattern("\"*a*\"", 0).toString());
assertEquals("\\*a\\*", PathnamePattern.compilePosixShellPattern("\"*a*\"", DF).toString());
+
assertEquals("\'.*?a.*?\'", PathnamePattern.compilePosixShellPattern("\'*a*\'", 0).toString());
assertEquals("\\*a\\*", PathnamePattern.compilePosixShellPattern("\'*a*\'", DF).toString());
+
assertEquals("\\\\.*?a.*?", PathnamePattern.compilePosixShellPattern("\\*a*", 0).toString());
assertEquals("\\*a.*?", PathnamePattern.compilePosixShellPattern("\\*a*", DF).toString());
}
+
+ public void testCompilePathPattern() {
+ assertEquals("PathnamePattern{source='abc',absolute=false,pattern=['abc']}",
+ PathnamePattern.compilePathPattern("abc", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='?',absolute=false,pattern=['^[^\\.]$']}",
+ PathnamePattern.compilePathPattern("?", DF).toRegexString());
+
+ // The following (which matches an empty pathname component) is suboptimal but
+ // not incorrect. In practice, we should never encounter an empty pathname component.
+ assertEquals("PathnamePattern{source='*',absolute=false,pattern=['^(|[^\\.].*)$']}",
+ PathnamePattern.compilePathPattern("*", DF).toRegexString());
+ }
}
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneContextTests.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneContextTests.java 2009-04-13 09:39:48 UTC (rev 5259)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneContextTests.java 2009-04-13 10:06:04 UTC (rev 5260)
@@ -28,6 +28,7 @@
import junit.framework.TestCase;
import org.jnode.shell.CommandLine;
+import org.jnode.shell.PathnamePattern;
import org.jnode.shell.ShellException;
import org.jnode.shell.bjorne.BjorneContext;
import org.jnode.shell.bjorne.BjorneToken;
@@ -41,83 +42,88 @@
public void testExpand1() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("");
+ List<BjorneToken> expansion = context.expandAndSplit();
checkExpansion(expansion, new String[] {});
}
- public void testExpand2() throws ShellException {
- BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit(" ");
- checkExpansion(expansion, new String[] {});
- }
-
public void testExpand3() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("hi");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("hi"));
checkExpansion(expansion, new String[] {"hi"});
}
public void testExpand4() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("hi there ");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("hi there"));
checkExpansion(expansion, new String[] {"hi", "there"});
}
public void testExpand5() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("'hi there '");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("'hi there '"));
checkExpansion(expansion, new String[] {"hi there "});
}
public void testExpand6() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("\"hi there \" ");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("\"hi there \" "));
checkExpansion(expansion, new String[] {"hi there "});
}
public void testExpand7() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("hi\\ there");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("hi\\ there"));
checkExpansion(expansion, new String[] {"hi there"});
}
public void testExpand8() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("\\\"hi\\ there\\\"");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("\\\"hi\\ there\\\""));
checkExpansion(expansion, new String[] {"\"hi there\""});
}
public void testExpand9() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
- List<BjorneToken> expansion = context.expandAndSplit("$?");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("$?"));
checkExpansion(expansion, new String[] {"0"});
}
public void testExpand10() throws ShellException {
BjorneContext context = new BjorneContext(null, null);
context.setVariable("A", "A");
- List<BjorneToken> expansion = context.expandAndSplit("$A");
+ List<BjorneToken> expansion = context.expandAndSplit(
+ new BjorneToken("$A"));
checkExpansion(expansion, new String[] {"A"});
}
public void testExpand11() throws ShellException {
BjorneContext contex...
[truncated message content] |
|
From: <cr...@us...> - 2009-04-13 14:01:17
|
Revision: 5262
http://jnode.svn.sourceforge.net/jnode/?rev=5262&view=rev
Author: crawley
Date: 2009-04-13 13:24:06 +0000 (Mon, 13 Apr 2009)
Log Message:
-----------
Fix for bug where expanding the pattern "/tmp/*" gave strings with the
leading "/" missing.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 11:02:36 UTC (rev 5261)
+++ trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 13:24:06 UTC (rev 5262)
@@ -252,6 +252,9 @@
for (File match : matches) {
String name = match.getName();
+ if (pos == 0 && isAbsolute) {
+ name = File.separator + name;
+ }
if (pos == pattern.length - 1) {
res.add(name);
} else if (match.isDirectory()) {
Modified: trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 11:02:36 UTC (rev 5261)
+++ trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 13:24:06 UTC (rev 5262)
@@ -20,6 +20,9 @@
package org.jnode.test.shell;
+import java.io.File;
+import java.util.LinkedList;
+
import junit.framework.TestCase;
import org.jnode.shell.PathnamePattern;
@@ -80,4 +83,17 @@
assertEquals("PathnamePattern{source='*',absolute=false,pattern=['^(|[^\\.].*)$']}",
PathnamePattern.compilePathPattern("*", DF).toRegexString());
}
+
+ public void testExpand() {
+ PathnamePattern pat = PathnamePattern.compilePathPattern("/tmp/*");
+ LinkedList<String> list = pat.expand(new File("."));
+ for (String path : list) {
+ assertTrue(new File(path).exists());
+ }
+ pat = PathnamePattern.compilePathPattern("*");
+ list = pat.expand(new File("."));
+ for (String path : list) {
+ assertTrue(new File(path).exists());
+ }
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-13 14:57:04
|
Revision: 5263
http://jnode.svn.sourceforge.net/jnode/?rev=5263&view=rev
Author: crawley
Date: 2009-04-13 14:56:44 +0000 (Mon, 13 Apr 2009)
Log Message:
-----------
Tests and a minor bugfix.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 13:24:06 UTC (rev 5262)
+++ trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 14:56:44 UTC (rev 5263)
@@ -299,16 +299,17 @@
}
}
+ String src = source;
boolean isAbsolute;
- if (source.startsWith(File.separator)) {
- while (source.startsWith(File.separator)) {
- source = source.substring(1);
+ if (src.startsWith(File.separator)) {
+ while (src.startsWith(File.separator)) {
+ src = src.substring(1);
}
isAbsolute = true;
} else {
isAbsolute = false;
}
- String[] parts = source.split(File.separator + "+", -1);
+ String[] parts = src.split(File.separator + "+", -1);
Object[] res = new Object[parts.length];
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
Modified: trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 13:24:06 UTC (rev 5262)
+++ trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 14:56:44 UTC (rev 5263)
@@ -82,6 +82,18 @@
// not incorrect. In practice, we should never encounter an empty pathname component.
assertEquals("PathnamePattern{source='*',absolute=false,pattern=['^(|[^\\.].*)$']}",
PathnamePattern.compilePathPattern("*", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='\"*\"',absolute=false,pattern=['^\\*$']}",
+ PathnamePattern.compilePathPattern("\"*\"", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='a/b',absolute=false,pattern=['a','b']}",
+ PathnamePattern.compilePathPattern("a/b", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='a/*',absolute=false,pattern=['a','^(|[^\\.].*)$']}",
+ PathnamePattern.compilePathPattern("a/*", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='/a/*',absolute=true,pattern=['a','^(|[^\\.].*)$']}",
+ PathnamePattern.compilePathPattern("/a/*", DF).toRegexString());
}
public void testExpand() {
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-04-13 13:24:06 UTC (rev 5262)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-04-13 14:56:44 UTC (rev 5263)
@@ -640,16 +640,6 @@
echo @TEMP_DIR@/'*'
echo "@TEMP_DIR@/*"
echo '@TEMP_DIR@/*'
- PWD=`pwd`
- # echo $PWD
- cd @TEMP_DIR@
- # pwd
- echo *
- echo \*
- echo "*"
- echo '*'
- cd $PWD
- # pwd
</script>
<file name="xyzzy" input="false">Hi mum
</file>
@@ -659,10 +649,6 @@
/tmp/jnodeTestDir/*
/tmp/jnodeTestDir/*
/tmp/jnodeTestDir/*
-xyzzy
-*
-*
-*
</output>
</testSpec>
<testSpec title="redirection" command="test" runMode="AS_SCRIPT" rc="0">
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-14 13:03:02
|
Revision: 5266
http://jnode.svn.sourceforge.net/jnode/?rev=5266&view=rev
Author: crawley
Date: 2009-04-14 13:02:59 +0000 (Tue, 14 Apr 2009)
Log Message:
-----------
Fixed the remaining bug with handling of quotes, and another with the
handling of doubled '/' characters.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-13 19:28:59 UTC (rev 5265)
+++ trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-04-14 13:02:59 UTC (rev 5266)
@@ -23,6 +23,7 @@
import java.io.File;
import java.io.FilenameFilter;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -166,16 +167,16 @@
private static final boolean DEBUG = false;
private final String source;
- private final Object[] pattern;
- private final boolean isAbsolute;
+ private ArrayList<Object> patterns;
+ private boolean isAbsolute;
+ private char lastQuote;
// Use a weak reference for the pattern cache to avoid storage leakage.
private static WeakReference<HashMap<String, PathnamePattern>> cache;
- private PathnamePattern(String source, Object[] pattern, boolean isAbsolute) {
+ private PathnamePattern(String source) {
this.source = source;
- this.pattern = pattern;
- this.isAbsolute = isAbsolute;
+ this.patterns = new ArrayList<Object>();
}
/**
@@ -218,13 +219,13 @@
private LinkedList<String> doGlob(File current, int pos, int flags) {
LinkedList<File> matches = new LinkedList<File>();
LinkedList<String> res = new LinkedList<String>();
- if (pattern[pos] instanceof String) {
- File file = new File(current, (String) pattern[pos]);
+ if (patterns.get(pos) instanceof String) {
+ File file = new File(current, (String) patterns.get(pos));
if (file.exists()) {
matches.add(file);
}
} else {
- final Pattern pat = (Pattern) pattern[pos];
+ final Pattern pat = (Pattern) patterns.get(pos);
final Matcher mat = pat.matcher("");
final FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
@@ -255,7 +256,7 @@
if (pos == 0 && isAbsolute) {
name = File.separator + name;
}
- if (pos == pattern.length - 1) {
+ if (pos == patterns.size() - 1) {
res.add(name);
} else if (match.isDirectory()) {
LinkedList<String> subList = doGlob(match, pos + 1, flags);
@@ -299,40 +300,37 @@
}
}
- String src = source;
- boolean isAbsolute;
- if (src.startsWith(File.separator)) {
- while (src.startsWith(File.separator)) {
- src = src.substring(1);
- }
- isAbsolute = true;
- } else {
- isAbsolute = false;
- }
- String[] parts = src.split(File.separator + "+", -1);
- Object[] res = new Object[parts.length];
+ PathnamePattern pp = new PathnamePattern(source);
+ String[] parts = source.split(File.separator + "+", -1);
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
- if (isPattern(part, flags)) {
- res[i] = compilePosixShellPattern(part,
- flags | ANCHOR_LEFT | ANCHOR_RIGHT | EAGER | SLASH_DISABLES_CHARACTER_CLASSES);
+ Object pat = (isPattern(part, flags)) ?
+ compilePosixShellPattern(part,
+ flags | ANCHOR_LEFT | ANCHOR_RIGHT | EAGER | SLASH_DISABLES_CHARACTER_CLASSES,
+ pp) : part;
+ if (pat == null || pat.toString().length() == 0) {
+ if (i == 0) {
+ pp.isAbsolute = true;
+ }
} else {
- res[i] = part;
+ pp.patterns.add(pat);
}
if (DEBUG) {
- System.err.println(i + ": " + res[i]);
+ System.err.println(i + ": " + pat);
}
}
- PathnamePattern pat = new PathnamePattern(source, res, isAbsolute);
+ if (pp.lastQuote != 0) {
+ throw new IllegalArgumentException("Unbalanced quotes in pattern");
+ }
synchronized (PathnamePattern.class) {
HashMap<String, PathnamePattern> cp = null;
if (cache == null || (cp = cache.get()) == null) {
cp = new HashMap<String, PathnamePattern>();
cache = new WeakReference<HashMap<String, PathnamePattern>>(cp);
}
- cp.put(key, pat);
+ cp.put(key, pp);
}
- return pat;
+ return pp;
}
/**
@@ -402,19 +400,28 @@
* generates a {@link Pattern} that can be matched against a character sequence.
*
* @param pattern the pattern in shell syntax.
+ * @param flags compilation flags
* @return the corresponding regex as a {@link Pattern}.
*/
public static Pattern compilePosixShellPattern(CharSequence pattern, int flags) {
+ return compilePosixShellPattern(pattern, flags, null);
+ }
+
+ /**
+ * @param pattern the pattern in shell syntax.
+ * @param flags compilation flags
+ * @param pp if not {@code null},
+ * @return the corresponding regex as a {@link Pattern}.
+ */
+ private static Pattern compilePosixShellPattern(
+ CharSequence pattern, int flags, PathnamePattern pp) {
// This method needs to be really careful to avoid 'ordinary' characters
// in the source pattern being accidentally mapped to Java regex
// meta-characters.
int len = pattern.length();
StringBuffer sb = new StringBuffer(len);
- char quote = 0;
+ char quote = (pp == null) ? ((char) 0) : pp.lastQuote;
boolean eager = (flags & EAGER) != 0;
- if ((flags & ANCHOR_LEFT) != 0) {
- sb.append('^');
- }
for (int i = 0; i < len; i++) {
char ch = pattern.charAt(i);
switch (ch) {
@@ -515,6 +522,15 @@
sb.append(protect(ch));
}
}
+ if (pp != null) {
+ pp.lastQuote = quote;
+ }
+ if (sb.length() == 0) {
+ return null;
+ }
+ if ((flags & ANCHOR_LEFT) != 0) {
+ sb.insert(0, '^');
+ }
if ((flags & ANCHOR_RIGHT) != 0) {
sb.append('$');
}
@@ -549,12 +565,13 @@
StringBuffer sb = new StringBuffer();
sb.append("PathnamePattern{source='").append(this.source);
sb.append("',absolute=").append(this.isAbsolute);
- sb.append(",pattern=[");
- for (int i = 0; i < this.pattern.length; i++) {
+ sb.append(",patterns=[");
+ int len = this.patterns.size();
+ for (int i = 0; i < len; i++) {
if (i > 0) {
sb.append(",");
}
- sb.append('\'').append(pattern[i]).append('\'');
+ sb.append('\'').append(patterns.get(i)).append('\'');
}
sb.append("]}");
return sb.toString();
Modified: trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-13 19:28:59 UTC (rev 5265)
+++ trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-04-14 13:02:59 UTC (rev 5266)
@@ -61,6 +61,9 @@
assertEquals(".*?a.*?", PathnamePattern.compilePosixShellPattern("*a*", 0).toString());
assertEquals("(|[^\\.].*?)a.*?", PathnamePattern.compilePosixShellPattern("*a*", DF).toString());
+ assertEquals("a.*?a.*?a", PathnamePattern.compilePosixShellPattern("a*a*a", 0).toString());
+ assertEquals("a.*?a.*?a", PathnamePattern.compilePosixShellPattern("a*a*a", DF).toString());
+
assertEquals("\".*?a.*?\"", PathnamePattern.compilePosixShellPattern("\"*a*\"", 0).toString());
assertEquals("\\*a\\*", PathnamePattern.compilePosixShellPattern("\"*a*\"", DF).toString());
@@ -72,28 +75,43 @@
}
public void testCompilePathPattern() {
- assertEquals("PathnamePattern{source='abc',absolute=false,pattern=['abc']}",
+ assertEquals("PathnamePattern{source='abc',absolute=false,patterns=['abc']}",
PathnamePattern.compilePathPattern("abc", DF).toRegexString());
- assertEquals("PathnamePattern{source='?',absolute=false,pattern=['^[^\\.]$']}",
+ assertEquals("PathnamePattern{source='?',absolute=false,patterns=['^[^\\.]$']}",
PathnamePattern.compilePathPattern("?", DF).toRegexString());
// The following (which matches an empty pathname component) is suboptimal but
// not incorrect. In practice, we should never encounter an empty pathname component.
- assertEquals("PathnamePattern{source='*',absolute=false,pattern=['^(|[^\\.].*)$']}",
+ assertEquals("PathnamePattern{source='*',absolute=false,patterns=['^(|[^\\.].*)$']}",
PathnamePattern.compilePathPattern("*", DF).toRegexString());
- assertEquals("PathnamePattern{source='\"*\"',absolute=false,pattern=['^\\*$']}",
+ assertEquals("PathnamePattern{source='\"*\"',absolute=false,patterns=['^\\*$']}",
PathnamePattern.compilePathPattern("\"*\"", DF).toRegexString());
- assertEquals("PathnamePattern{source='a/b',absolute=false,pattern=['a','b']}",
+ assertEquals("PathnamePattern{source='a/b',absolute=false,patterns=['a','b']}",
PathnamePattern.compilePathPattern("a/b", DF).toRegexString());
- assertEquals("PathnamePattern{source='a/*',absolute=false,pattern=['a','^(|[^\\.].*)$']}",
+ assertEquals("PathnamePattern{source='a/*',absolute=false,patterns=['a','^(|[^\\.].*)$']}",
PathnamePattern.compilePathPattern("a/*", DF).toRegexString());
- assertEquals("PathnamePattern{source='/a/*',absolute=true,pattern=['a','^(|[^\\.].*)$']}",
+ assertEquals("PathnamePattern{source='/a/*',absolute=true,patterns=['a','^(|[^\\.].*)$']}",
PathnamePattern.compilePathPattern("/a/*", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='/a/\\*',absolute=true,patterns=['a','^\\*$']}",
+ PathnamePattern.compilePathPattern("/a/\\*", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='a//\"*\"',absolute=false,patterns=['a','^\\*$']}",
+ PathnamePattern.compilePathPattern("a//\"*\"", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='/a/\"*\"',absolute=true,patterns=['a','^\\*$']}",
+ PathnamePattern.compilePathPattern("/a/\"*\"", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='\"/a/*\"',absolute=true,patterns=['a','^\\*$']}",
+ PathnamePattern.compilePathPattern("\"/a/*\"", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='\"/a/*\"',absolute=true,patterns=['a','^\\*$']}",
+ PathnamePattern.compilePathPattern("\"/a/*\"", DF).toRegexString());
}
public void testExpand() {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-20 14:53:59
|
Revision: 5324
http://jnode.svn.sourceforge.net/jnode/?rev=5324&view=rev
Author: crawley
Date: 2009-04-20 14:53:47 +0000 (Mon, 20 Apr 2009)
Log Message:
-----------
Yesterdays changes to CommandShell messed up initialization in the
EmuShell ... and hence for TestHarness.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/CommandShell.java
trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java
Modified: trunk/shell/src/shell/org/jnode/shell/CommandShell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-04-20 11:39:59 UTC (rev 5323)
+++ trunk/shell/src/shell/org/jnode/shell/CommandShell.java 2009-04-20 14:53:47 UTC (rev 5324)
@@ -272,9 +272,10 @@
* @param syntaxMgr test framework supplies a syntax manager
*/
protected CommandShell(AliasManager aliasMgr, SyntaxManager syntaxMgr) {
+ this.debugEnabled = true;
this.aliasMgr = aliasMgr;
this.syntaxMgr = syntaxMgr;
- this.debugEnabled = true;
+ propertyMap = initShellProperties();
setupStreams(
new InputStreamReader(System.in),
new OutputStreamWriter(System.out),
@@ -479,7 +480,7 @@
try {
setupFromProperties();
- } catch (ShellException ex) {
+ } catch (Throwable ex) {
errPW.println("Problem shell configuration");
errPW.println(ex.getMessage());
stackTrace(ex);
@@ -488,7 +489,7 @@
propertyMap.put(INTERPRETER_PROPERTY_NAME, FALLBACK_INTERPRETER);
try {
setupFromProperties();
- } catch (ShellException ex2) {
+ } catch (Throwable ex2) {
throw new ShellFailureException(
"Bailing out: fatal error during CommandShell configuration", ex2);
}
@@ -498,6 +499,11 @@
ownThread = Thread.currentThread();
}
+ public void configureEmuShell() throws ShellException {
+ propertyMap.put(INVOKER_PROPERTY_NAME, "thread");
+ configureShell();
+ }
+
@Override
public String getProperty(String propName) {
return propertyMap.get(propName);
Modified: trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java 2009-04-20 11:39:59 UTC (rev 5323)
+++ trunk/shell/src/test/org/jnode/test/shell/harness/TestRunnerBase.java 2009-04-20 14:53:47 UTC (rev 5324)
@@ -92,7 +92,7 @@
public CommandShell getShell() throws ShellException {
CommandShell shell = new TestCommandShell(System.in, System.out, System.err);
- shell.configureShell();
+ shell.configureEmuShell();
return shell;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-26 14:28:12
|
Revision: 5350
http://jnode.svn.sourceforge.net/jnode/?rev=5350&view=rev
Author: crawley
Date: 2009-04-26 14:28:11 +0000 (Sun, 26 Apr 2009)
Log Message:
-----------
Fix bjorne so that builtins are only recognized if they first word
of a "simple command" matches a builtin command name BEFORE any expansion.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-04-26 14:25:50 UTC (rev 5349)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-04-26 14:28:11 UTC (rev 5350)
@@ -983,7 +983,7 @@
throw new ShellFailureException("not implemented");
}
- int execute(CommandLine command, CommandIO[] streams) throws ShellException {
+ int execute(CommandLine command, CommandIO[] streams, boolean isBuiltin) throws ShellException {
if (isEchoExpansions()) {
StringBuilder sb = new StringBuilder();
sb.append(" + ").append(command.getCommandName());
@@ -993,7 +993,7 @@
resolvePrintStream(streams[Command.STD_ERR]).println(sb);
}
Map<String, String> env = buildEnvFromExports();
- lastReturnCode = interpreter.executeCommand(command, this, streams, null, env);
+ lastReturnCode = interpreter.executeCommand(command, this, streams, null, env, isBuiltin);
return lastReturnCode;
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-04-26 14:25:50 UTC (rev 5349)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-04-26 14:28:11 UTC (rev 5350)
@@ -130,7 +130,7 @@
public static final int FLAG_PIPE = 0x0010;
public static final CommandNode EMPTY =
- new SimpleCommandNode(CMD_EMPTY, new BjorneToken[0]);
+ new SimpleCommandNode(CMD_EMPTY, new BjorneToken[0], false);
private static HashMap<String, BjorneBuiltin> BUILTINS =
new HashMap<String, BjorneBuiltin>();
@@ -327,14 +327,18 @@
this.shell = shell;
}
}
+
+ static boolean isBuiltin(String commandWord) {
+ return BUILTINS.containsKey(commandWord);
+ }
int executeCommand(CommandLine cmdLine, BjorneContext context, CommandIO[] streams,
- Properties sysProps, Map<String, String> env)
+ Properties sysProps, Map<String, String> env, boolean isBuiltin)
throws ShellException {
- BjorneBuiltin builtin = BUILTINS.get(cmdLine.getCommandName());
- if (builtin != null) {
+ if (isBuiltin) {
// FIXME ... built-in commands should use the Syntax mechanisms so
- // that completion, help, etc work as expected.
+ // that completion, help, etc will work as expected.
+ BjorneBuiltin builtin = BUILTINS.get(cmdLine.getCommandName());
return builtin.invoke(cmdLine, this, context);
} else {
cmdLine.setStreams(streams);
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-04-26 14:25:50 UTC (rev 5349)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-04-26 14:28:11 UTC (rev 5350)
@@ -276,6 +276,7 @@
List<BjorneToken> assignments = new LinkedList<BjorneToken>();
List<RedirectionNode> redirects = new LinkedList<RedirectionNode>();
List<BjorneToken> words = new LinkedList<BjorneToken>();
+ boolean builtin = false;
// Deal with cmd_prefix'es before the command name; i.e. assignments and
// redirections
@@ -334,12 +335,19 @@
break LOOP;
}
}
+ if (words.size() > 0) {
+ String commandWord = words.get(0).getText();
+ builtin = BjorneInterpreter.isBuiltin(commandWord);
+ // FIXME ... built-in commands should use the Syntax mechanisms so
+ // that completion, help, etc will work as expected.
+ }
} else {
// An empty command is legal, as are assignments and redirections
// w/o a command.
}
SimpleCommandNode res =
- new SimpleCommandNode(CMD_COMMAND, words.toArray(new BjorneToken[words.size()]));
+ new SimpleCommandNode(CMD_COMMAND,
+ words.toArray(new BjorneToken[words.size()]), builtin);
if (!redirects.isEmpty()) {
res.setRedirects(redirects.toArray(new RedirectionNode[redirects.size()]));
}
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-04-26 14:25:50 UTC (rev 5349)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/SimpleCommandNode.java 2009-04-26 14:28:11 UTC (rev 5350)
@@ -36,10 +36,13 @@
private BjorneToken[] assignments;
private final BjorneToken[] words;
+
+ private final boolean builtin;
- public SimpleCommandNode(int nodeType, BjorneToken[] words) {
+ public SimpleCommandNode(int nodeType, BjorneToken[] words, boolean builtin) {
super(nodeType);
this.words = words;
+ this.builtin = builtin;
}
public void setAssignments(BjorneToken[] assignments) {
@@ -54,6 +57,10 @@
return assignments;
}
+ public boolean isBuiltin() {
+ return builtin;
+ }
+
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("SimpleCommand{").append(super.toString());
@@ -61,6 +68,9 @@
sb.append(",assignments=");
appendArray(sb, assignments);
}
+ if (builtin) {
+ sb.append(",builtin=true");
+ }
if (words != null) {
sb.append(",words=");
appendArray(sb, words);
@@ -99,7 +109,7 @@
throw new ShellFailureException(
"asynchronous execution (&) not implemented yet");
} else {
- rc = childContext.execute(command, ios);
+ rc = childContext.execute(command, ios, builtin);
}
}
} finally {
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-04-26 14:25:50 UTC (rev 5349)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-04-26 14:28:11 UTC (rev 5350)
@@ -74,4 +74,22 @@
<output>fred='ls'
</output>
</testSpec>
+ <testSpec title="builtins recognized early" command="test"
+ runMode="AS_SCRIPT" rc="0" trapException="org.jnode.shell.ShellException">
+ <script>#!bjorne
+ alias fred=ls
+ alias
+ unalias -a
+ echo done
+ UNALIAS=unalias
+ alias fred=dir
+ alias
+ $UNALIAS -a
+ echo done
+ </script>
+ <output>fred='ls'
+done
+fred='dir'
+</output>
+ </testSpec>
</testSet>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-04-30 14:11:12
|
Revision: 5373
http://jnode.svn.sourceforge.net/jnode/?rev=5373&view=rev
Author: crawley
Date: 2009-04-30 14:11:06 +0000 (Thu, 30 Apr 2009)
Log Message:
-----------
Starting to get black-box tests running again after reorg.
Modified Paths:
--------------
trunk/shell/src/emu/org/jnode/emu/Emu.java
trunk/shell/src/test/org/jnode/test/shell/all-tests.xml
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
Modified: trunk/shell/src/emu/org/jnode/emu/Emu.java
===================================================================
--- trunk/shell/src/emu/org/jnode/emu/Emu.java 2009-04-30 12:27:53 UTC (rev 5372)
+++ trunk/shell/src/emu/org/jnode/emu/Emu.java 2009-04-30 14:11:06 UTC (rev 5373)
@@ -55,13 +55,21 @@
* @author cr...@jn...
*/
public class Emu {
- private static final String[] ALL_PROJECTS = new String[]{
- "core", "distr", "fs", "gui", "net", "shell", "sound", "textui"
+ // FIXME configuring a hard-coded list of projects is a bad idea.
+ private static final String[] ALL_PROJECTS = new String[]{
+ "cli", "core", "distr", "fs", "gui", "net", "shell", "sound", "textui"
};
// FIXME configuring a hard-coded list of command plugins is a bad idea.
private static final String[] DEFAULT_PLUGIN_IDS = new String[] {
- "org.jnode.shell.command",
+ "org.jnode.command.archive",
+ "org.jnode.command.common",
+ "org.jnode.command.dev.ant",
+ "org.jnode.command.dev",
+ "org.jnode.command.file",
+ "org.jnode.command.net",
+ "org.jnode.command.system",
+ "org.jnode.command.util",
"org.jnode.shell.command.driver.console",
"org.jnode.apps.editor",
"org.jnode.apps.edit",
Modified: trunk/shell/src/test/org/jnode/test/shell/all-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/all-tests.xml 2009-04-30 12:27:53 UTC (rev 5372)
+++ trunk/shell/src/test/org/jnode/test/shell/all-tests.xml 2009-04-30 14:11:06 UTC (rev 5373)
@@ -1,8 +1,8 @@
<testSet title="All shell tests">
<include setName="bjorne/bjorne-shell-tests.xml"/>
<include setName="bjorne/bjorne-builtin-tests.xml"/>
- <include setName="command/posix/posix-command-tests.xml"/>
- <include setName="command/posix/basename-command-tests.xml"/>
- <include setName="command/posix/dirname-command-tests.xml"/>
- <include setName="command/posix/wc-command-tests.xml"/>
+<!-- <include setName="command/posix/posix-command-tests.xml"/>-->
+<!-- <include setName="command/posix/basename-command-tests.xml"/>-->
+<!-- <include setName="command/posix/dirname-command-tests.xml"/>-->
+<!-- <include setName="command/posix/wc-command-tests.xml"/>-->
</testSet>
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-04-30 12:27:53 UTC (rev 5372)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-04-30 14:11:06 UTC (rev 5373)
@@ -1,6 +1,6 @@
<testSet title="Bjorne interpreter tests">
<plugin id="org.jnode.shell.bjorne" class="org.jnode.test.shell.bjorne.BjornePseudoPlugin"/>
- <plugin id="org.jnode.shell.command.posix"/>
+ <plugin id="org.jnode.command.common"/>
<testSpec title="exit 0" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
exit 0
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-04-30 12:27:53 UTC (rev 5372)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-shell-tests.xml 2009-04-30 14:11:06 UTC (rev 5373)
@@ -1,7 +1,7 @@
<testSet title="Bjorne interpreter tests">
<plugin id="org.jnode.shell.bjorne" class="org.jnode.test.shell.bjorne.BjornePseudoPlugin"/>
- <plugin id="org.jnode.shell.command.posix"/>
- <plugin id="org.jnode.fs.command"/>
+ <plugin id="org.jnode.command.common"/>
+ <plugin id="org.jnode.command.file"/>
<testSpec title="simple" command="test" runMode="AS_SCRIPT" rc="0">
<script>#!bjorne
echo HI
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-05-11 12:36:14
|
Revision: 5471
http://jnode.svn.sourceforge.net/jnode/?rev=5471&view=rev
Author: crawley
Date: 2009-05-11 12:36:06 +0000 (Mon, 11 May 2009)
Log Message:
-----------
Curly brackets in path patterns need to be escaped ... until they are
implemented.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-05-09 12:11:05 UTC (rev 5470)
+++ trunk/shell/src/shell/org/jnode/shell/PathnamePattern.java 2009-05-11 12:36:06 UTC (rev 5471)
@@ -549,6 +549,8 @@
case '*':
case '?':
case '$':
+ case '{':
+ case '}':
case '^':
case '\\':
return "\\" + ch;
Modified: trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-05-09 12:11:05 UTC (rev 5470)
+++ trunk/shell/src/test/org/jnode/test/shell/PathnamePatternTest.java 2009-05-11 12:36:06 UTC (rev 5471)
@@ -112,6 +112,9 @@
assertEquals("PathnamePattern{source='\"/a/*\"',absolute=true,patterns=['a','^\\*$']}",
PathnamePattern.compilePathPattern("\"/a/*\"", DF).toRegexString());
+
+ assertEquals("PathnamePattern{source='{print \\$1}',absolute=false,patterns=['^\\{print \\$1\\}$']}",
+ PathnamePattern.compilePathPattern("{print \\$1}", DF).toRegexString());
}
public void testExpand() {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <chr...@us...> - 2009-05-12 03:07:41
|
Revision: 5484
http://jnode.svn.sourceforge.net/jnode/?rev=5484&view=rev
Author: chrisboertien
Date: 2009-05-12 03:07:33 +0000 (Tue, 12 May 2009)
Log Message:
-----------
compile fix
Signed-off-by: chrisboertien <chr...@gm...>
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/syntax/ArgumentSpecLoader.java
trunk/shell/src/test/org/jnode/test/shell/syntax/TestSyntaxManager.java
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/ArgumentSpecLoader.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/ArgumentSpecLoader.java 2009-05-12 01:01:18 UTC (rev 5483)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/ArgumentSpecLoader.java 2009-05-12 03:07:33 UTC (rev 5484)
@@ -207,7 +207,7 @@
}
}
- static class ArgumentSpec<T extends Argument<?>> {
+ public static class ArgumentSpec<T extends Argument<?>> {
private Constructor<T> ctor;
private Object[] params;
Modified: trunk/shell/src/test/org/jnode/test/shell/syntax/TestSyntaxManager.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/syntax/TestSyntaxManager.java 2009-05-12 01:01:18 UTC (rev 5483)
+++ trunk/shell/src/test/org/jnode/test/shell/syntax/TestSyntaxManager.java 2009-05-12 03:07:33 UTC (rev 5484)
@@ -23,6 +23,8 @@
import java.util.Collection;
import java.util.HashMap;
+import org.jnode.shell.syntax.ArgumentBundle;
+import org.jnode.shell.syntax.ArgumentSpecLoader.ArgumentSpec;
import org.jnode.shell.syntax.SyntaxBundle;
import org.jnode.shell.syntax.SyntaxManager;
@@ -36,7 +38,11 @@
public void add(SyntaxBundle bundle) {
syntaxes.put(bundle.getAlias(), bundle);
}
-
+
+ public void add(String alias, ArgumentSpec[] args) {
+ return;
+ }
+
public SyntaxBundle remove(String alias) {
return syntaxes.remove(alias);
}
@@ -44,6 +50,10 @@
public SyntaxBundle getSyntaxBundle(String alias) {
return syntaxes.get(alias);
}
+
+ public ArgumentBundle getArgumentBundle(String alias) {
+ return null;
+ }
public SyntaxManager createSyntaxManager() {
return new TestSyntaxManager();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-05-27 14:29:43
|
Revision: 5528
http://jnode.svn.sourceforge.net/jnode/?rev=5528&view=rev
Author: crawley
Date: 2009-05-27 14:29:36 +0000 (Wed, 27 May 2009)
Log Message:
-----------
Another bjorne completion bug.
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java 2009-05-27 13:09:32 UTC (rev 5527)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java 2009-05-27 14:29:36 UTC (rev 5528)
@@ -35,8 +35,12 @@
public void complete(CompletionInfo completion, CommandShell shell) throws CompletionException {
Logger.getLogger(BjorneCompleter.class).debug(toString());
if (endToken == null) {
- new CommandLine(null, null).complete(completion, shell);
- return;
+ if (penultimateToken == null) {
+ new CommandLine(null, null).complete(completion, shell);
+ return;
+ }
+ endToken = penultimateToken;
+ endExpectedSet = penultimateExpectedSet;
}
if (command != null) {
BjorneToken[] words = command.getWords();
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-27 13:09:32 UTC (rev 5527)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-27 14:29:36 UTC (rev 5528)
@@ -114,6 +114,18 @@
doCompletionTest("if cpuid\nthen echo hi ; fi", "TTTTETT");
}
+ public void testIf3Command() throws ShellSyntaxException, CompletionException {
+ doCompletionTest("if cpuid ; then\necho hi ; fi", "TTTTTETT");
+ }
+
+ public void testIf4Command() throws ShellSyntaxException, CompletionException {
+ doCompletionTest("if cpuid ; then\necho hi\nfi", "TTTTTET");
+ }
+
+ public void testWhileCommand() throws ShellSyntaxException, CompletionException {
+ doCompletionTest("while cpuid ; do echo hi ; done", "TTTTTETT");
+ }
+
private void doCompletionTest(String input, String flags)
throws ShellSyntaxException, CompletionException {
BjorneInterpreter interpreter = new BjorneInterpreter();
@@ -152,7 +164,9 @@
// Maybe completions, maybe not
}
for (String completionWord : completionWords) {
- assertTrue(completionWord.startsWith(lastWord));
+ if (!completionWord.startsWith(lastWord)) {
+ fail("completion(s) don't start with '" + lastWord + "': " + diag(partial, completions));
+ }
}
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-05-31 02:13:58
|
Revision: 5531
http://jnode.svn.sourceforge.net/jnode/?rev=5531&view=rev
Author: crawley
Date: 2009-05-31 02:13:50 +0000 (Sun, 31 May 2009)
Log Message:
-----------
javadoc and checkstyle fixes
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java
trunk/shell/src/shell/org/jnode/shell/CommandInfo.java
trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
trunk/shell/src/shell/org/jnode/shell/Shell.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxManager.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
Modified: trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -22,7 +22,6 @@
import org.apache.log4j.Logger;
import org.jnode.driver.console.CompletionInfo;
-import org.jnode.shell.bjorne.BjorneCompleter;
import org.jnode.shell.syntax.Argument;
import org.jnode.shell.syntax.ArgumentBundle;
Modified: trunk/shell/src/shell/org/jnode/shell/CommandInfo.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/CommandInfo.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/CommandInfo.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -55,7 +55,6 @@
* @param clazz the designated {@code Class} for executing the command
* @param commandName the name, or alias, for the command
* @param syntaxBundle the syntax definition to parse the command line against
- * @param argBundle the optional {@code ArgumentBundle} to parse the command line against
*/
public CommandInfo(Class<?> clazz, String commandName, SyntaxBundle syntaxBundle, boolean internal) {
this.clazz = clazz;
@@ -94,7 +93,7 @@
}
/**
- * Checks wether this command is considered internal or not.
+ * Checks whether this command is considered internal or not.
*
* @return true if this is an internal command
* @see org.jnode.shell.alias.AliasManager#isInternal
Modified: trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/DefaultCommandInvoker.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -43,7 +43,7 @@
/**
* This CommandInvoker runs a command in the current thread, using the command
* classes <code>public static void main(String[] args)</code> entry point.
- * The {@link #invokeAsynchronous(CommandLine, CommandInfo)} method is not
+ * The {@link #invokeAsynchronous(CommandLine)} method is not
* supported for this implementation of the CommandInvoker API.
*
* @author Sam Reid
@@ -76,7 +76,10 @@
}
/**
- * Invoke the command.
+ * Invoke the command, running is by calling the entry point method from the
+ * current thread. No redirection is allowed.
+ *
+ * @param cmdLine the command line.
*/
public int invoke(CommandLine cmdLine) throws ShellException {
CommandInfo cmdInfo = cmdLine.parseCommandLine(shell);
Modified: trunk/shell/src/shell/org/jnode/shell/Shell.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/Shell.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/Shell.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -105,25 +105,25 @@
* Set a shell property. Some properties have special meaning to a Shell
* and may cause its behavior to change.
*
- * @param propName the name of the property
+ * @param key the name of the property
* @param value the property value
* @throws ShellException This may be thrown if the name / value pair is
* not acceptable.
*/
- public void setProperty(String propName, String value) throws ShellException;
+ public void setProperty(String key, String value) throws ShellException;
/**
* Get the current value of a shell property.
*
- * @param propName the property name.
+ * @param key the property name.
* @return the property value or {@code null}
*/
- public String getProperty(String propName);
+ public String getProperty(String key);
/**
* Remove a shell property. Special properties typically may not be removed,
*
- * @param propName the name of the property
+ * @param key the name of the property
* @throws ShellException This may be thrown if the property cannot be removed.
*/
public void removeProperty(String key) throws ShellException;
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneParser.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -612,7 +612,8 @@
CommandNode cond = parseCompoundList(TOK_THEN_BIT);
allowLineBreaks();
expectNext(TOK_THEN_BIT, RULE_1_CONTEXT);
- return new IfCommandNode(CMD_ELIF, cond, parseCompoundList(TOK_ELIF_BIT | TOK_ELSE_BIT | TOK_FI_BIT), parseOptElsePart());
+ return new IfCommandNode(CMD_ELIF, cond,
+ parseCompoundList(TOK_ELIF_BIT | TOK_ELSE_BIT | TOK_FI_BIT), parseOptElsePart());
} else {
return parseCompoundList(TOK_FI_BIT);
}
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxManager.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxManager.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxManager.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -25,7 +25,8 @@
/**
* A SyntaxManager manages the association between a command "alias" and
- * the Syntax that specifies its argument syntax.
+ * the Syntax that specifies its argument syntax. The manager can also
+ * record a set of argument specs for non-native commands.
*
* @author cr...@jn...
*/
@@ -39,14 +40,23 @@
public static final String SYNTAXES_EP_NAME = "org.jnode.shell.syntaxes";
/**
- * Add a syntax bundle
+ * Add a syntax bundle, using the alias name embedded in the bundle.
*
* @param bundle The syntax to be added
*/
public abstract void add(SyntaxBundle bundle);
/**
- * Remove the syntaxBundle and argumentBundle(if one exists) for an alias
+ * Add the argument specs for a non-native command; i.e. one which does
+ * not define and register its own arguments.
+ *
+ * @param argSpecs the specs for the arguments
+ * @param alias the alias
+ */
+ public abstract void add(String alias, ArgumentSpec<?>[] argSpecs);
+
+ /**
+ * Remove the syntaxBundle and argumentBundle (if one exists) for an alias
*
* @param alias The alias
*/
@@ -55,20 +65,12 @@
/**
* Gets the syntax bundle for a given alias
*
- * @param alias The alias
+ * @param alias the alias
* @return The syntax for the given alias, or <code>null</code>
*/
public abstract SyntaxBundle getSyntaxBundle(String alias);
/**
- * Add an argument bundle for a bare command.
- *
- * @param bundle an argument bundle holding the arguments of a bare command
- * @param alias the alias to bind the arguments to
- */
- public abstract void add(String alias, ArgumentSpec<?>[] args);
-
- /**
* Gets the argument bundle for a given alias if one exists.
*
* @param alias an alias that corresponds to a particular bundle
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-31 01:45:21 UTC (rev 5530)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-31 02:13:50 UTC (rev 5531)
@@ -259,25 +259,30 @@
switch (flags.charAt(inWord)) {
case 'T':
// Expect completions
- assertTrue("got no completions: " + diag(partial, completions), completionWords.size() > 0);
+ assertTrue("got no completions: " + diag(partial, completions),
+ completionWords.size() > 0);
break;
case 'F':
// Expect no completions
- assertTrue("got unexpected completions: " + diag(partial, completions), completionWords.size() == 0);
+ assertTrue("got unexpected completions: " + diag(partial, completions),
+ completionWords.size() == 0);
break;
case 'E':
// Expect completions if the last char is ' ', otherwise not
if (wordStart >= partial.length()) {
- assertTrue("got no completions: " + diag(partial, completions), completionWords.size() > 0);
+ assertTrue("got no completions: " + diag(partial, completions),
+ completionWords.size() > 0);
} else {
- assertTrue("got unexpected completions: " + diag(partial, completions), completionWords.size() == 0);
+ assertTrue("got unexpected completions: " + diag(partial, completions),
+ completionWords.size() == 0);
}
break;
case 'Z':
// Expect completions if the last char is NOT ' '
if (wordStart >= partial.length()) {
} else {
- assertTrue("got no completions: " + diag(partial, completions), completionWords.size() > 0);
+ assertTrue("got no completions: " + diag(partial, completions),
+ completionWords.size() > 0);
}
break;
case '?':
@@ -285,7 +290,8 @@
}
for (String completionWord : completionWords) {
if (!completionWord.startsWith(lastWord)) {
- fail("completion(s) don't start with '" + lastWord + "': " + diag(partial, completions));
+ fail("completion(s) don't start with '" + lastWord + "': " +
+ diag(partial, completions));
}
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-05-31 04:15:59
|
Revision: 5532
http://jnode.svn.sourceforge.net/jnode/?rev=5532&view=rev
Author: crawley
Date: 2009-05-31 04:15:41 +0000 (Sun, 31 May 2009)
Log Message:
-----------
Completion tidyups
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java
trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java
trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
Modified: trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java 2009-05-31 02:13:50 UTC (rev 5531)
+++ trunk/shell/src/shell/org/jnode/shell/ArgumentCompleter.java 2009-05-31 04:15:41 UTC (rev 5532)
@@ -51,7 +51,6 @@
}
public void complete(CompletionInfo completion, CommandShell shell) {
- Logger.getLogger(ArgumentCompleter.class).debug("text = " + (token == null ? "" : token.text));
argument.complete(completion, token == null ? "" : token.text, 0);
if (token != null) {
completion.setCompletionStart(token.start);
Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java 2009-05-31 02:13:50 UTC (rev 5531)
+++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneCompleter.java 2009-05-31 04:15:41 UTC (rev 5532)
@@ -61,11 +61,9 @@
}
if (command != null) {
BjorneToken[] words = command.getWords();
- if (words.length > 0 && words[words.length - 1] == penultimateToken) {
+ if (words.length > 1 && words[words.length - 1] == penultimateToken) {
boolean argumentAnticipated = penultimateToken.end < endToken.end;
command.complete(completion, context, shell, argumentAnticipated);
- } else if (words.length == 0) {
- new CommandLine(null, null).complete(completion, shell);
}
}
String partial;
Modified: trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-31 02:13:50 UTC (rev 5531)
+++ trunk/shell/src/test/org/jnode/test/shell/bjorne/BjorneCompletionTests.java 2009-05-31 04:15:41 UTC (rev 5532)
@@ -228,7 +228,7 @@
public void testBad2Command() throws ShellSyntaxException, CompletionException {
try {
- doCompletionTest("if fi ;", "T?");
+ doCompletionTest("if fi ;", "T??");
} catch (CompletionException ex) {
assertEquals("Cannot find an alias or load a command class for 'fi'", ex.getMessage());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-06-07 04:58:48
|
Revision: 5543
http://jnode.svn.sourceforge.net/jnode/?rev=5543&view=rev
Author: crawley
Date: 2009-06-07 04:58:47 +0000 (Sun, 07 Jun 2009)
Log Message:
-----------
Adding 'eager' forms of the Powerset and Repeat syntaxes. (The latter is
not implemented yet.)
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/syntax/OptionalSyntax.java
trunk/shell/src/shell/org/jnode/shell/syntax/PowersetSyntax.java
trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java
trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxSpecLoader.java
trunk/shell/src/test/org/jnode/test/shell/syntax/PowersetSyntaxTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/OptionalSyntax.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/OptionalSyntax.java 2009-06-03 14:47:18 UTC (rev 5542)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/OptionalSyntax.java 2009-06-07 04:58:47 UTC (rev 5543)
@@ -43,11 +43,11 @@
}
public OptionalSyntax(String label, Syntax...syntaxes) {
- this(label, null, syntaxes);
+ this(label, null, false, syntaxes);
}
public OptionalSyntax(Syntax...syntaxes) {
- this(null, null, syntaxes);
+ this(null, null, false, syntaxes);
}
@Override
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/PowersetSyntax.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/PowersetSyntax.java 2009-06-03 14:47:18 UTC (rev 5542)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/PowersetSyntax.java 2009-06-07 04:58:47 UTC (rev 5543)
@@ -28,21 +28,26 @@
* The syntax allows a child syntax to appear more than once, subject to Argument
* multiplicity constraints. As with an Alternatives, the child syntaxes are tried
* one at a time in the same order as the they were provided to the constructor.
+ * The 'eager' parameter specifies whether the syntax is 'eager' (i.e. matching as
+ * many instances as possible) or 'lazy' (i.e. matching as few instances as possible).
*
* @author cr...@jn...
*/
public class PowersetSyntax extends GroupSyntax {
- public PowersetSyntax(String label, String description, Syntax...syntaxes) {
+ private final boolean eager;
+
+ public PowersetSyntax(String label, boolean eager, String description, Syntax...syntaxes) {
super(label, description, syntaxes);
+ this.eager = eager;
}
public PowersetSyntax(String label, Syntax...syntaxes) {
- this(label, null, syntaxes);
+ this(label, false, null, syntaxes);
}
public PowersetSyntax(Syntax...syntaxes) {
- this(null, null, syntaxes);
+ this(null, false, null, syntaxes);
}
@Override
@@ -58,9 +63,17 @@
childMuSyntaxes[i] = children[i].prepare(bundle);
}
String label = this.label == null ? MuSyntax.genLabel() : this.label;
- MuSyntax res = new MuAlternation(label, null,
- new MuSequence(new MuAlternation((String) null, childMuSyntaxes),
- new MuBackReference(label)));
+ MuSyntax res;
+ if (eager) {
+ res = new MuAlternation(label,
+ new MuSequence(new MuAlternation((String) null, childMuSyntaxes),
+ new MuBackReference(label)),
+ null);
+ } else {
+ res = new MuAlternation(label, null,
+ new MuSequence(new MuAlternation((String) null, childMuSyntaxes),
+ new MuBackReference(label)));
+ }
res.resolveBackReferences();
return res;
}
@@ -89,6 +102,10 @@
@Override
public XMLElement toXML() {
- return basicElement("powerSet");
+ XMLElement element = basicElement("powerSet");
+ if (eager) {
+ element.setAttribute("eager", "true");
+ }
+ return element;
}
}
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java 2009-06-03 14:47:18 UTC (rev 5542)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java 2009-06-07 04:58:47 UTC (rev 5543)
@@ -24,8 +24,11 @@
/**
- * A RepeatedSyntax instance specifies that a given 'child' syntax may appear
- * some number of times.
+ * A RepeatedSyntax instance specifies that a given 'child' syntax may be repeated
+ * a number of times as determined by the constructor arguments. These allow you
+ * to specify a minimum and/or maximum bound on the number of repetitions, and to
+ * specify whether the syntax is 'eager' (i.e. matching as many instances as possible) or
+ * 'lazy' (i.e. matching as few instances as possible).
*
* @author cr...@jn...
*/
@@ -34,6 +37,7 @@
private final Syntax child;
private final int minCount;
private final int maxCount;
+ private final boolean eager;
/**
* Construct syntax with caller-specified repetition count range and a label.
@@ -42,9 +46,12 @@
* @param child the child Syntax that may be repeated.
* @param minCount the minimum number of occurrences required.
* @param maxCount the maximum number of occurrences allowed.
+ * @param eager if {@code true}, the syntax matches as many child instances
+ * as possible, subject to the 'maxCount' constraint.
* @param description the description for this syntax
*/
- public RepeatSyntax(String label, Syntax child, int minCount, int maxCount, String description) {
+ public RepeatSyntax(String label, Syntax child, int minCount, int maxCount,
+ boolean eager, String description) {
super(label, description, child);
if (minCount < 0 || maxCount < minCount) {
throw new IllegalArgumentException("bad min/max counts");
@@ -52,6 +59,7 @@
this.child = child;
this.minCount = minCount;
this.maxCount = maxCount;
+ this.eager = eager;
}
/**
@@ -63,7 +71,7 @@
* @param maxCount the maximum number of occurrences allowed.
*/
public RepeatSyntax(String label, Syntax child, int minCount, int maxCount) {
- this(label, child, minCount, maxCount, null);
+ this(label, child, minCount, maxCount, false, null);
}
/**
@@ -74,7 +82,7 @@
* @param maxCount the maximum number of occurrences allowed.
*/
public RepeatSyntax(Syntax child, int minCount, int maxCount) {
- this(null, child, minCount, maxCount, null);
+ this(null, child, minCount, maxCount, false, null);
}
/**
@@ -83,7 +91,7 @@
* @param child the child Syntax that may be repeated.
*/
public RepeatSyntax(Syntax child) {
- this(null, child, 0, Integer.MAX_VALUE, null);
+ this(null, child, 0, Integer.MAX_VALUE, false, null);
}
@Override
@@ -170,6 +178,9 @@
if (maxCount != Integer.MAX_VALUE) {
element.setAttribute("maxCount", maxCount);
}
+ if (eager) {
+ element.setAttribute("eager", "true");
+ }
return element;
}
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxSpecLoader.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxSpecLoader.java 2009-06-03 14:47:18 UTC (rev 5542)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/SyntaxSpecLoader.java 2009-06-07 04:58:47 UTC (rev 5543)
@@ -100,13 +100,15 @@
}
} else if (kind.equals("powerset")) {
int nos = syntaxElement.getNosChildren();
+ boolean eager = getFlag(syntaxElement, "eager", false);
Syntax[] members = new Syntax[nos];
for (int i = 0; i < nos; i++) {
members[i] = doLoad(syntaxElement.getChild(i));
}
- return new PowersetSyntax(label, description, members);
+ return new PowersetSyntax(label, eager, description, members);
} else if (kind.equals("repeat")) {
int nos = syntaxElement.getNosChildren();
+ boolean eager = getFlag(syntaxElement, "eager", false);
int minCount = getCount(syntaxElement, "minCount", 0);
int maxCount = getCount(syntaxElement, "maxCount", Integer.MAX_VALUE);
Syntax[] members = new Syntax[nos];
@@ -114,7 +116,7 @@
members[i] = doLoad(syntaxElement.getChild(i));
}
Syntax childSyntax = (members.length == 1) ? members[0] : new SequenceSyntax(members);
- return new RepeatSyntax(label, childSyntax, minCount, maxCount, description);
+ return new RepeatSyntax(label, childSyntax, minCount, maxCount, eager, description);
} else if (kind.equals("sequence")) {
int nos = syntaxElement.getNosChildren();
Syntax[] seq = new Syntax[nos];
Modified: trunk/shell/src/test/org/jnode/test/shell/syntax/PowersetSyntaxTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/syntax/PowersetSyntaxTest.java 2009-06-03 14:47:18 UTC (rev 5542)
+++ trunk/shell/src/test/org/jnode/test/shell/syntax/PowersetSyntaxTest.java 2009-06-07 04:58:47 UTC (rev 5543)
@@ -34,6 +34,9 @@
import org.jnode.shell.syntax.IntegerArgument;
import org.jnode.shell.syntax.OptionSyntax;
import org.jnode.shell.syntax.PowersetSyntax;
+import org.jnode.shell.syntax.RepeatSyntax;
+import org.jnode.shell.syntax.SequenceSyntax;
+import org.jnode.shell.syntax.StringArgument;
import org.jnode.shell.syntax.Syntax;
public class PowersetSyntaxTest extends TestCase {
@@ -43,9 +46,11 @@
new FileArgument("fileArg", Argument.OPTIONAL + Argument.MULTIPLE);
private final IntegerArgument intArg =
new IntegerArgument("intArg", Argument.OPTIONAL + Argument.MULTIPLE);
+ private final StringArgument otherArg =
+ new StringArgument("otherArg", Argument.OPTIONAL + Argument.MULTIPLE);
public Test() {
- registerArguments(fileArg, intArg);
+ registerArguments(fileArg, intArg, otherArg);
}
public void execute() throws Exception {
@@ -116,4 +121,129 @@
// expected
}
}
+
+ public void testLazy() throws Exception {
+ TestShell shell = new TestShell();
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.PowersetSyntaxTest$Test");
+ shell.addSyntax("cmd", new SequenceSyntax(
+ new PowersetSyntax(
+ new OptionSyntax("intArg", 'i'),
+ new OptionSyntax("fileArg", 'f')),
+ new RepeatSyntax(new OptionSyntax("otherArg", 'i'))));
+
+ CommandLine cl;
+ CommandInfo cmdInfo;
+ Command cmd;
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("-f"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{new Token("-f"), new Token("F1"), new Token("-i"), new Token("1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+ assertEquals("1", cmd.getArgumentBundle().getArgument("otherArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{new Token("-i"), new Token("1"), new Token("-f"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+ assertEquals("1", cmd.getArgumentBundle().getArgument("intArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{
+ new Token("-i"), new Token("1"), new Token("-f"), new Token("F1"),
+ new Token("-i"), new Token("2")},
+ null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+ assertEquals("1", cmd.getArgumentBundle().getArgument("intArg").getValue().toString());
+ assertEquals("2", cmd.getArgumentBundle().getArgument("otherArg").getValue().toString());
+ }
+
+
+
+ public void testEager() throws Exception {
+ TestShell shell = new TestShell();
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.PowersetSyntaxTest$Test");
+ shell.addSyntax("cmd", new SequenceSyntax(
+ new PowersetSyntax(null, true, null,
+ new OptionSyntax("intArg", 'i'),
+ new OptionSyntax("fileArg", 'f')),
+ new RepeatSyntax(new OptionSyntax("otherArg", 'i'))));
+
+ CommandLine cl;
+ CommandInfo cmdInfo;
+ Command cmd;
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("-f"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{new Token("-f"), new Token("F1"), new Token("-i"), new Token("1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+ assertEquals("1", cmd.getArgumentBundle().getArgument("intArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{new Token("-i"), new Token("1"), new Token("-f"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ assertEquals("F1", cmd.getArgumentBundle().getArgument("fileArg").getValue().toString());
+ assertEquals("1", cmd.getArgumentBundle().getArgument("intArg").getValue().toString());
+
+ cl = new CommandLine(new Token("cmd"),
+ new Token[]{
+ new Token("-i"), new Token("1"), new Token("-f"), new Token("F1"),
+ new Token("-i"), new Token("2")},
+ null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("fileArg").getValues().length);
+ assertEquals(2, cmd.getArgumentBundle().getArgument("intArg").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("otherArg").getValues().length);
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cr...@us...> - 2009-06-07 05:49:44
|
Revision: 5545
http://jnode.svn.sourceforge.net/jnode/?rev=5545&view=rev
Author: crawley
Date: 2009-06-07 05:49:03 +0000 (Sun, 07 Jun 2009)
Log Message:
-----------
Implemented eager form of RepeatSyntax ( + fixed unit test regression)
Modified Paths:
--------------
trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java
trunk/shell/src/test/org/jnode/test/shell/syntax/RepeatSyntaxTest.java
Modified: trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java
===================================================================
--- trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java 2009-06-07 05:30:04 UTC (rev 5544)
+++ trunk/shell/src/shell/org/jnode/shell/syntax/RepeatSyntax.java 2009-06-07 05:49:03 UTC (rev 5545)
@@ -110,16 +110,28 @@
MuSyntax childSyntax = child.prepare(bundle);
MuSyntax res, tail;
if (maxCount == Integer.MAX_VALUE) {
- tail = new MuAlternation(label,
- null,
- new MuSequence(childSyntax, new MuBackReference(label)));
+ if (eager) {
+ tail = new MuAlternation(label,
+ new MuSequence(childSyntax, new MuBackReference(label)),
+ null);
+ } else {
+ tail = new MuAlternation(label,
+ null,
+ new MuSequence(childSyntax, new MuBackReference(label)));
+ }
} else {
int tailCount = maxCount - minCount;
tail = null;
while (tailCount-- > 0) {
- tail = new MuAlternation(
- (MuSyntax) null,
- (tail == null) ? childSyntax : new MuSequence(childSyntax, tail));
+ if (eager) {
+ tail = new MuAlternation(
+ (tail == null) ? childSyntax : new MuSequence(childSyntax, tail),
+ null);
+ } else {
+ tail = new MuAlternation(
+ (MuSyntax) null,
+ (tail == null) ? childSyntax : new MuSequence(childSyntax, tail));
+ }
}
}
if (minCount == 0) {
Modified: trunk/shell/src/test/org/jnode/test/shell/syntax/RepeatSyntaxTest.java
===================================================================
--- trunk/shell/src/test/org/jnode/test/shell/syntax/RepeatSyntaxTest.java 2009-06-07 05:30:04 UTC (rev 5544)
+++ trunk/shell/src/test/org/jnode/test/shell/syntax/RepeatSyntaxTest.java 2009-06-07 05:49:03 UTC (rev 5545)
@@ -32,20 +32,23 @@
import org.jnode.shell.syntax.CommandSyntaxException;
import org.jnode.shell.syntax.FileArgument;
import org.jnode.shell.syntax.RepeatSyntax;
+import org.jnode.shell.syntax.SequenceSyntax;
import org.jnode.shell.syntax.Syntax;
public class RepeatSyntaxTest extends TestCase {
public static class Test extends AbstractCommand {
- private final FileArgument arg =
+ private final FileArgument arg1 =
new FileArgument("arg1", Argument.OPTIONAL + Argument.MULTIPLE);
+ private final FileArgument arg2 =
+ new FileArgument("arg2", Argument.OPTIONAL + Argument.MULTIPLE);
public Test() {
- registerArguments(arg);
+ registerArguments(arg1, arg2);
}
public void execute() throws Exception {
- getOutput().getPrintWriter().print(arg.getValue());
+ getOutput().getPrintWriter().print(arg1.getValue());
}
}
@@ -63,7 +66,7 @@
public void testZeroToMany() throws Exception {
TestShell shell = new TestShell();
- shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatedSyntaxTest$Test");
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
shell.addSyntax("cmd", new RepeatSyntax(new ArgumentSyntax("arg1")));
CommandLine cl = new CommandLine(new Token("cmd"), new Token[]{}, null);
@@ -85,7 +88,7 @@
public void testOneToMany() throws Exception {
TestShell shell = new TestShell();
- shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatedSyntaxTest$Test");
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
shell.addSyntax("cmd", new RepeatSyntax(new ArgumentSyntax("arg1"), 1, Integer.MAX_VALUE));
CommandLine cl;
@@ -113,7 +116,7 @@
public void testOneToTwo() throws Exception {
TestShell shell = new TestShell();
- shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatedSyntaxTest$Test");
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
shell.addSyntax("cmd", new RepeatSyntax(new ArgumentSyntax("arg1"), 1, 2));
CommandLine cl;
@@ -150,7 +153,7 @@
public void testThreeToSix() throws Exception {
TestShell shell = new TestShell();
- shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatedSyntaxTest$Test");
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
shell.addSyntax("cmd", new RepeatSyntax(new ArgumentSyntax("arg1"), 3, 6));
CommandLine cl;
@@ -215,4 +218,56 @@
// expected
}
}
+
+ public void testLazy() throws Exception {
+ TestShell shell = new TestShell();
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
+ shell.addSyntax("cmd", new SequenceSyntax(
+ new RepeatSyntax(new ArgumentSyntax("arg1")),
+ new RepeatSyntax(new ArgumentSyntax("arg2"))));
+
+ CommandLine cl = new CommandLine(new Token("cmd"), new Token[]{}, null);
+ CommandInfo cmdInfo = cl.parseCommandLine(shell);
+ Command cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(1, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("F1"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(2, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+ }
+
+ public void testEager() throws Exception {
+ TestShell shell = new TestShell();
+ shell.addAlias("cmd", "org.jnode.test.shell.syntax.RepeatSyntaxTest$Test");
+ shell.addSyntax("cmd", new SequenceSyntax(
+ new RepeatSyntax(null, new ArgumentSyntax("arg1"), 0, Integer.MAX_VALUE, true, null),
+ new RepeatSyntax(new ArgumentSyntax("arg2"))));
+
+ CommandLine cl = new CommandLine(new Token("cmd"), new Token[]{}, null);
+ CommandInfo cmdInfo = cl.parseCommandLine(shell);
+ Command cmd = cmdInfo.createCommandInstance();
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(1, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+
+ cl = new CommandLine(new Token("cmd"), new Token[]{new Token("F1"), new Token("F1")}, null);
+ cmdInfo = cl.parseCommandLine(shell);
+ cmd = cmdInfo.createCommandInstance();
+ assertEquals(2, cmd.getArgumentBundle().getArgument("arg1").getValues().length);
+ assertEquals(0, cmd.getArgumentBundle().getArgument("arg2").getValues().length);
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|