Revision: 5626 http://jnode.svn.sourceforge.net/jnode/?rev=5626&view=rev Author: crawley Date: 2009-08-01 16:04:05 +0000 (Sat, 01 Aug 2009)
Log Message: ----------- Implemented the bjorne 'read' 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 Added Paths: ----------- trunk/shell/src/shell/org/jnode/shell/bjorne/ReadBuiltin.java Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-07-30 14:06:07 UTC (rev 5625) +++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneContext.java 2009-08-01 16:04:05 UTC (rev 5626) @@ -156,6 +156,7 @@ setVariable("PS1", "$ "); setVariable("PS2", "> "); setVariable("PS4", "+ "); + setVariable("IFS", " \t\n"); } /** @@ -568,7 +569,7 @@ * @param wordTokens the destination for the tokens. * @throws ShellException */ - private void splitAndAppend(BjorneToken token, List<BjorneToken> wordTokens) + void splitAndAppend(BjorneToken token, List<BjorneToken> wordTokens) throws ShellException { String text = token.getText(); StringBuffer sb = null; Modified: trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-07-30 14:06:07 UTC (rev 5625) +++ trunk/shell/src/shell/org/jnode/shell/bjorne/BjorneInterpreter.java 2009-08-01 16:04:05 UTC (rev 5626) @@ -137,6 +137,7 @@ BUILTINS.put("continue", ContinueBuiltin.FACTORY); BUILTINS.put("exit", ExitBuiltin.FACTORY); BUILTINS.put("export", ExportBuiltin.FACTORY); + BUILTINS.put("read", ReadBuiltin.FACTORY); BUILTINS.put("readonly", ReadonlyBuiltin.FACTORY); BUILTINS.put("return", ReturnBuiltin.FACTORY); BUILTINS.put("set", SetBuiltin.FACTORY); @@ -153,6 +154,8 @@ private BjorneContext context; private BjorneParser parser; + + private Reader reader; public BjorneInterpreter() { this.context = new BjorneContext(this); @@ -210,13 +213,15 @@ myContext.setIO(1, new CommandOutput(capture), true); } BjorneTokenizer tokens = new BjorneTokenizer(reader); - // (Save the current parser value in the case where we are called + // (Save the current parser and reader objects in the case where we are called // recursively ... to interpret a back-tick command.) - BjorneParser saved = parser; + BjorneParser savedParser = this.parser; + Reader savedReader = this.reader; + this.reader = reader; parser = new BjorneParser(tokens); try { do { - CommandNode tree = parser.parse(); + CommandNode tree = this.parser.parse(); if (tree == null) { break; } @@ -227,7 +232,8 @@ } while (script); return myContext.getLastReturnCode(); } finally { - parser = saved; + this.parser = savedParser; + this.reader = savedReader; } } @@ -288,6 +294,10 @@ public boolean supportsMultiline() { return true; } + + Reader getReader() { + return this.reader; + } private void bindShell(CommandShell shell) { if (this.shell != shell) { Added: trunk/shell/src/shell/org/jnode/shell/bjorne/ReadBuiltin.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/bjorne/ReadBuiltin.java (rev 0) +++ trunk/shell/src/shell/org/jnode/shell/bjorne/ReadBuiltin.java 2009-08-01 16:04:05 UTC (rev 5626) @@ -0,0 +1,212 @@ +/* + * $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.io.Reader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jnode.shell.ShellSyntaxException; +import org.jnode.shell.syntax.Argument; +import org.jnode.shell.syntax.ArgumentSyntax; +import org.jnode.shell.syntax.FlagArgument; +import org.jnode.shell.syntax.OptionSyntax; +import org.jnode.shell.syntax.OptionalSyntax; +import org.jnode.shell.syntax.RepeatSyntax; +import org.jnode.shell.syntax.SequenceSyntax; +import org.jnode.shell.syntax.SyntaxBundle; + +/** + * This class implements the 'read' built-in. + * + * @author craw...@jnode.org + */ +final class ReadBuiltin extends BjorneBuiltin { + private static final SyntaxBundle SYNTAX = + new SyntaxBundle("read", new SequenceSyntax( + new OptionalSyntax(new OptionSyntax("noEscape", 'r')), + new RepeatSyntax(new ArgumentSyntax("varName"), 0, Integer.MAX_VALUE))); + + static final Factory FACTORY = new Factory() { + public BjorneBuiltinCommandInfo buildCommandInfo(BjorneContext context) { + return new BjorneBuiltinCommandInfo("read", SYNTAX, new ReadBuiltin(context), context); + } + }; + + + private final VariableNameArgument varNameArg; + private final FlagArgument noEscapeArg = new FlagArgument( + "noEscape", Argument.OPTIONAL, "if set, '\' does not escape a newline"); + + private final BjorneContext context; + Pattern ifsSplittingPattern; + Pattern ifsTrimmingPattern; + + ReadBuiltin(BjorneContext context) { + super("Read a line of input and repopulate the shell 'args'"); + this.context = context; + varNameArg = new VariableNameArgument( + "varName", context, Argument.OPTIONAL | Argument.MULTIPLE, "shell variables to be set"); + registerArguments(noEscapeArg, varNameArg); + } + + public void execute() throws Exception { + boolean escapeCheck = !noEscapeArg.isSet(); + String line = readLine(getInput().getReader(), escapeCheck); + String[] varNames = varNameArg.getValues(); + if (varNames.length > 0) { + String[] fields = extractFields(line, varNames.length); + for (int i = 0; i < varNames.length; i++) { + String value = (i >= fields.length || fields[i] == null) ? "" : fields[i]; + context.getParent().setVariable(varNames[i], value); + } + } + } + + private String[] extractFields(String line, int nosVars) throws ShellSyntaxException { + String ifs = context.variable("IFS"); + if (ifs == null) { + ifs = " \t\n"; + } else if (ifs.length() == 0) { + return new String[]{line}; + } + + String[] fields = new String[nosVars]; + createIfsPatterns(ifs); + String content; + if (ifsTrimmingPattern != null) { + Matcher trimMatcher = ifsTrimmingPattern.matcher(line); + trimMatcher.matches(); + content = trimMatcher.group(1); + } else { + content = line; + } + if (line.length() == 0) { + return new String[0]; + } + Matcher fieldMatcher = null; + for (int i = 0; i < fields.length - 1; i++) { + if (fieldMatcher == null) { + fieldMatcher = ifsSplittingPattern.matcher(content); + } else { + fieldMatcher.reset(content); + } + if (fieldMatcher.matches()) { + fields[i] = fieldMatcher.group(1); + content = fieldMatcher.group(2); + } else { + fields[i] = content; + content = null; + break; + } + } + if (content != null) { + fields[fields.length - 1] = content; + } + return fields; + } + + private void createIfsPatterns(String ifs) { + if (ifs.equals(" ") || ifs.equals("\t") || ifs.equals("\n")) { + ifsTrimmingPattern = Pattern.compile("[ \\t\\n]*(.*[^ \\t\\n])[ \\t\\n]*"); + ifsSplittingPattern = Pattern.compile("([^ \\t\\n]+)[ \\t\\n]+([^ \\t\\n].*)"); + } else { + // First separate the IFS into whitespace and non-whitespace characters, + // adding '\' escapes for any that characters that need to be escaped. + StringBuilder sb1 = new StringBuilder(4); + StringBuilder sb2 = new StringBuilder(4); + for (char ch : ifs.toCharArray()) { + switch (ch) { + case ' ': + sb1.append(' '); + break; + case '\t': + sb1.append("\\t"); + break; + case '\n': + sb1.append("\\n"); + break; + case '.': + case '?': + case '*': + case '+': + case '[': + case ']': + case '(': + case ')': + case '|': + case '{': + case '}': + case '\\': + case '^': + case '$': + case '-': + sb2.append('\\').append(ch); + break; + default: + sb2.append("\\\n"); + break; + } + } + String ifsWhitespace = sb1.toString(); + String ifsNonWhitespace = sb2.toString(); + // If we have any IFS whitespace, create the pattern to trim it. + if (ifsWhitespace.length() == 0) { + ifsTrimmingPattern = null; + } else { + ifsTrimmingPattern = Pattern.compile( + "[" + ifsWhitespace + "]*(.*[^" + ifsWhitespace + "])[" + ifsWhitespace + "]*"); + } + // Create the pattern to split a (possibly empty) field + if (ifsWhitespace.length() > 0 && ifsNonWhitespace.length() > 0) { + ifsSplittingPattern = Pattern.compile( + "([^" + ifsWhitespace + ifsNonWhitespace + "]*)[" + ifsWhitespace + "]*[" + + ifsNonWhitespace + "][" + ifsWhitespace + "]*(|[^" + ifsWhitespace + "].*)"); + } else if (ifsWhitespace.length() > 0) { + ifsSplittingPattern = Pattern.compile( + "([^" + ifsWhitespace +"]*)[" + ifsWhitespace + "]+(|[^" + ifsWhitespace + "].*)"); + } else { + ifsSplittingPattern = Pattern.compile( + "([^" + ifsNonWhitespace + "]*)[" + ifsNonWhitespace + "](.*)"); + } + } + } + + private String readLine(Reader reader, boolean escapeCheck) throws IOException { + StringBuilder sb = new StringBuilder(40); + int ch; + while ((ch = reader.read()) != -1 && ch != '\n') { + if (ch == '\\' && escapeCheck) { + ch = reader.read(); + if (ch == -1) { + sb.append('\\'); + break; + } else if (ch != '\n') { + sb.append('\\').append((char) ch); + } + } else { + sb.append((char) ch); + } + } + return sb.toString(); + } +} 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-07-30 14:06:07 UTC (rev 5625) +++ trunk/shell/src/test/org/jnode/test/shell/bjorne/bjorne-builtin-tests.xml 2009-08-01 16:04:05 UTC (rev 5626) @@ -128,4 +128,27 @@ A -- </output> </testSpec> + <testSpec title="read" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + read <<EOF +1 2 3 +EOF + read A B C <<EOF +1 2 3 +EOF + echo +$A+ +$B+ +$C+ + read A B C D <<EOF + 1 2 3 +EOF + echo +$A+ +$B+ +$C+ +$D+ + read A B <<EOF + 1 2 3 +EOF + echo +$A+ +$B+ + </script> + <output>+1+ +2+ +3+ ++1+ +2+ +3+ ++ ++1+ +2 3+ +</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. ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Jnode-svn-commits mailing list Jnode-svn-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits