karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject [1/2] karaf git commit: [KARAF-3455] Support for custom command parsers
Date Wed, 28 Jan 2015 13:08:09 GMT
Repository: karaf
Updated Branches:
  refs/heads/master cb7518351 -> cbbed8ac4


http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
index 16e73ca..f0652f8 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
@@ -32,6 +32,7 @@ import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
 import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
 import org.apache.karaf.shell.support.ShellUtil;
 
 public class HeadlessSessionImpl implements Session {
@@ -68,7 +69,8 @@ public class HeadlessSessionImpl implements Session {
 
     @Override
     public Object execute(CharSequence commandline) throws Exception {
-        return session.execute(commandline);
+        String command = CommandLineParser.parse(this, commandline.toString());
+        return session.execute(command);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
index ad2c729..1f52fbe 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.support.CommandException;
 
@@ -45,6 +46,11 @@ public abstract class TopLevelCommand implements Command {
     }
 
     @Override
+    public Parser getParser() {
+        return null;
+    }
+
+    @Override
     public Object execute(Session session, List<Object> arguments) throws Exception {
         if (arguments.contains("--help")) {
             printHelp(System.out);

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
index 3b9ae33..945a429 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
@@ -29,6 +29,7 @@ import org.apache.felix.utils.properties.InterpolationHelper;
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.CommandLine;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
@@ -129,6 +130,11 @@ public class HelpCommand implements Command {
         };
     }
 
+    @Override
+    public Parser getParser() {
+        return null;
+    }
+
     protected void printHelp(PrintStream out) {
         out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
         out.print("        ");

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
index 0fc6cde..822c712 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
@@ -25,6 +25,7 @@ import org.apache.felix.service.command.CommandSession;
 import org.apache.felix.service.command.Function;
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Session;
 
 public class SecuredCommand implements Command, Function {
@@ -56,6 +57,11 @@ public class SecuredCommand implements Command, Function {
     }
 
     @Override
+    public Parser getParser() {
+        return null;
+    }
+
+    @Override
     public Object execute(Session session, List<Object> arguments) throws Exception {
         factory.checkSecurity(this, session, arguments);
         return command.execute(session, arguments);

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
deleted file mode 100644
index 9124795..0000000
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.shell.impl.console.parsing;
-
-import java.util.List;
-
-import org.apache.karaf.shell.api.console.CommandLine;
-
-/**
- *  The result of a delimited buffer.
- */
-public class CommandLineImpl implements CommandLine {
-
-    private final String[] arguments;
-    private final int cursorArgumentIndex;
-    private final int argumentPosition;
-    private final int bufferPosition;
-    private final String buffer;
-
-    public static CommandLine build(String buffer, int cursor) {
-        return build(buffer, cursor, true);
-    }
-    
-	public static CommandLine build(String buffer, int cursor, boolean expansionEnabled) { //CQL-Handling
-		Parser parser = new Parser(buffer, cursor, expansionEnabled);
-        try {
-            List<List<List<String>>> program = parser.program();
-            List<String> pipe = program.get(parser.c0).get(parser.c1);
-            return new CommandLineImpl(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor, buffer);
-        } catch (Throwable t) {
-            return new CommandLineImpl(new String[] { buffer }, 0, cursor, cursor, buffer);
-        }
-	}
-
-    /**
-     *  @param  arguments           the array of tokens
-     *  @param  cursorArgumentIndex the token index of the cursor
-     *  @param  argumentPosition    the position of the cursor in the
-     *                              current token
-     *  @param  bufferPosition      the position of the cursor in the whole buffer
-     *  @param buffer               the whole buffer
-     */
-    public CommandLineImpl(String[] arguments, int cursorArgumentIndex, int argumentPosition, int bufferPosition, String buffer) {
-        this.arguments = arguments;
-        this.cursorArgumentIndex = cursorArgumentIndex;
-        this.argumentPosition = argumentPosition;
-        this.bufferPosition = bufferPosition;
-        this.buffer = buffer;
-    }
-
-    public int getCursorArgumentIndex() {
-        return this.cursorArgumentIndex;
-    }
-
-    public String getCursorArgument() {
-        if ((cursorArgumentIndex < 0)
-            || (cursorArgumentIndex >= arguments.length)) {
-            return null;
-        }
-
-        return arguments[cursorArgumentIndex];
-    }
-
-    public int getArgumentPosition() {
-        return this.argumentPosition;
-    }
-
-    public String[] getArguments() {
-        return this.arguments;
-    }
-
-    public int getBufferPosition() {
-        return this.bufferPosition;
-    }
-
-    public String getBuffer() {
-        return this.buffer;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
new file mode 100644
index 0000000..b5f28fb
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.parsing;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
+import org.apache.karaf.shell.support.parsing.GogoParser;
+
+public class CommandLineParser {
+
+    public static CommandLine buildCommandLine(Session session, String command, int cursor) {
+        int pos = 0;
+        while (true) {
+            String rem = command.substring(pos);
+            GogoParser cmdNameParser = new GogoParser(rem, rem.length());
+            String name = cmdNameParser.value();
+            name = session.resolveCommand(name);
+
+            Parser cmdParser = null;
+            for (Command cmd : session.getRegistry().getCommands()) {
+                if (name.equals(cmd.getScope() + ":" + cmd.getName())) {
+                    cmdParser = cmd.getParser();
+                    break;
+                }
+            }
+            if (cmdParser == null) {
+                cmdParser = new DefaultParser();
+            }
+
+            CommandLine cmdLine = cmdParser.parse(session, rem, cursor - pos);
+            int length = cmdLine.getBuffer().length();
+            if (length < rem.length()) {
+                char ch = rem.charAt(length);
+                if (ch == ';' || ch == '|') {
+                    length++;
+                } else {
+                    throw new IllegalArgumentException("Unrecognized character: '" + ch + "'");
+                }
+            }
+            pos += length;
+            if (cursor <= pos) {
+                return cmdLine;
+            }
+        }
+    }
+
+    public static String parse(Session session, String command) {
+        StringBuilder parsed = new StringBuilder();
+        int pos = 0;
+        while (pos < command.length()) {
+            String rem = command.substring(pos);
+            GogoParser cmdNameParser = new GogoParser(rem, rem.length());
+            String name = cmdNameParser.value();
+            name = session.resolveCommand(name);
+
+            Parser cmdParser = null;
+            for (Command cmd : session.getRegistry().getCommands()) {
+                if (name.equals(cmd.getScope() + ":" + cmd.getName())) {
+                    cmdParser = cmd.getParser();
+                    break;
+                }
+            }
+            if (cmdParser == null) {
+                cmdParser = new DefaultParser();
+            }
+
+            CommandLine cmdLine = cmdParser.parse(session, rem, rem.length());
+            for (int i = 0 ; i < cmdLine.getArguments().length; i++) {
+                String arg = cmdLine.getArguments()[i];
+                if (i > 0) {
+                    parsed.append(" ");
+                }
+                parsed.append(arg);
+            }
+
+            int length = cmdLine.getBuffer().length();
+            if (length < rem.length()) {
+                char ch = rem.charAt(length);
+                if (ch == ';' || ch == '|') {
+                    parsed.append(" ");
+                    parsed.append(ch);
+                    parsed.append(" ");
+                    length++;
+                } else {
+                    throw new IllegalArgumentException("Unrecognized character: '" + ch + "'");
+                }
+            }
+            pos += length;
+        }
+
+        return parsed.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
deleted file mode 100644
index 73f4b98..0000000
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-// DWB14: parser loops if // comment at start of program
-// DWB15: allow program to have trailing ';'
-package org.apache.karaf.shell.impl.console.parsing;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Parser {
-
-    int current = 0;
-    String text;
-    boolean escaped;
-    static final String SPECIAL = "<;|{[\"'$`(=";
-
-    List<List<List<String>>> program;
-    List<List<String>> statements;
-    List<String> statement;
-    int cursor;
-    int start = -1;
-    int c0;
-    int c1;
-    int c2;
-    int c3;
-    
-    private boolean isExpansionEnabled; //CQL-Handling
-
-    public Parser(String text, int cursor) {
-        this(text, cursor, true);
-    }
-
-    //CQL-Handling
-    public Parser(String text, int cursor, boolean expansionEnabled) {
-    	this.text = text;
-        this.cursor = cursor;
-        this.isExpansionEnabled = expansionEnabled; //CQL-Handling
-	}
-
-	void ws() {
-        // derek: BUGFIX: loop if comment  at beginning of input
-        //while (!eof() && Character.isWhitespace(peek())) {
-        while (!eof() && (!escaped && Character.isWhitespace(peek()) || current == 0)) {
-            if (current != 0 || !escaped && Character.isWhitespace(peek())) {
-                current++;
-            }
-            if (peek() == '/' && current < text.length() - 2
-                && text.charAt(current + 1) == '/') {
-                comment();
-            }
-            if (current == 0) {
-                break;
-            }
-        }
-    }
-
-    private void comment() {
-        while (!eof() && peek() != '\n' && peek() != '\r') {
-            next();
-        }
-    }
-
-    boolean eof() {
-        return current >= text.length();
-    }
-
-    char peek() {
-        return peek(false);
-    }
-
-    char peek(boolean increment) {
-        escaped = false;
-        if (eof()) {
-            return 0;
-        }
-
-        int last = current;
-        char c = text.charAt(current++);
-
-        if (c == '\\') {
-            escaped = true;
-            if (eof()) {
-                throw new RuntimeException("Eof found after \\");
-            }
-
-            c = text.charAt(current++);
-
-            switch (c) {
-                case 't':
-                    c = '\t';
-                    break;
-                case '\r':
-                case '\n':
-                    c = ' ';
-                    break;
-                case 'b':
-                    c = '\b';
-                    break;
-                case 'f':
-                    c = '\f';
-                    break;
-                case 'n':
-                    c = '\n';
-                    break;
-                case 'r':
-                    c = '\r';
-                    break;
-                case 'u':
-                    c = unicode();
-                    current += 4;
-                    break;
-                default:
-                    // We just take the next character literally
-                    // but have the escaped flag set, important for {},[] etc
-            }
-        }
-        if (cursor > last && cursor <= current) {
-            c0 = program != null ? program.size() : 0;
-            c1 = statements != null ? statements.size() : 0;
-            c2 = statement != null ? statement.size() : 0;
-            c3 = (start >= 0) ? current - start : 0;
-        }
-        if (!increment) {
-            current = last;
-        }
-        return c;
-    }
-
-    public List<List<List<String>>> program() {
-        program = new ArrayList<List<List<String>>>();
-        ws();
-        if (!eof()) {
-            program.add(pipeline());
-            while (peek() == ';') {
-                current++;
-                List<List<String>> pipeline = pipeline();
-                program.add(pipeline);
-            }
-        }
-        if (!eof()) {
-            throw new RuntimeException("Program has trailing text: " + context(current));
-        }
-
-        List<List<List<String>>> p = program;
-        program = null;
-        return p;
-    }
-
-    CharSequence context(int around) {
-        return text.subSequence(Math.max(0, current - 20), Math.min(text.length(),
-            current + 4));
-    }
-
-    public List<List<String>> pipeline() {
-        statements = new ArrayList<List<String>>();
-        statements.add(statement());
-        while (peek() == '|') {
-            current++;
-            ws();
-            if (!eof()) {
-                statements.add(statement());
-            }
-            else {
-                statements.add(new ArrayList<String>());
-                break;
-            }
-        }
-        List<List<String>> s = statements;
-        statements = null;
-        return s;
-    }
-
-    public List<String> statement() {
-        statement = new ArrayList<String>();
-        statement.add(value());
-        while (!eof()) {
-            ws();
-            if (peek() == '|' || peek() == ';') {
-                break;
-            }
-
-            if (!eof()) {
-                statement.add(messy());
-            }
-        }
-        List<String> s = statement;
-        statement = null;
-        return s;
-    }
-
-    public String messy()
-    {
-        start = current;
-        char c = peek();
-        if (c > 0 && SPECIAL.indexOf(c) < 0) {
-            current++;
-            try {
-                while (!eof()) {
-                    c = peek();
-                    if (!escaped && (c == ';' || c == '|' || Character.isWhitespace(c))) {
-                        break;
-                    }
-                    next();
-                }
-                return text.substring(start, current);
-            } finally {
-                start = -1;
-            }
-        }
-        else {
-            return value();
-        }
-    }
-
-    String value() {
-        ws();
-
-        start = current;
-        try {
-            char c = next();
-            if (!escaped && isExpansionEnabled) { //CQL-Handling
-                switch (c) {
-                    case '{':
-                        return text.substring(start, find('}', '{'));
-                    case '(':
-                        return text.substring(start, find(')', '('));
-                    case '[':
-                        return text.substring(start, find(']', '['));
-                    case '<':
-                        return text.substring(start, find('>', '<'));
-                    case '=':
-                        return text.substring(start, current);
-                    case '"':
-                    case '\'':
-                        quote(c);
-                        break;
-                }
-            }
-
-            // Some identifier or number
-            while (!eof()) {
-                c = peek();
-                if (!escaped) {
-                    if (Character.isWhitespace(c) || c == ';' || c == '|' || c == '=') {
-                        break;
-                    }
-                    else if (c == '{' && isExpansionEnabled) { //CQL-Handling
-                        next();
-                        find('}', '{');
-                    }
-                    else if (c == '(' && isExpansionEnabled) { //CQL-Handling
-                        next();
-                        find(')', '(');
-                    }
-                    else if (c == '<') {
-                        next();
-                        find('>', '<');
-                    }
-                    else if (c == '[') {
-                        next();
-                        find(']', '[');
-                    }
-                    else if (c == '\'' || c == '"') {
-                        next();
-                        quote(c);
-                        next();
-                    }
-                    else {
-                        next();
-                    }
-                }
-                else {
-                    next();
-                }
-            }
-            return text.substring(start, current);
-        } finally {
-            start = -1;
-        }
-    }
-
-    boolean escaped() {
-        return escaped;
-    }
-
-    char next() {
-        return peek(true);
-    }
-
-    char unicode() {
-        if (current + 4 > text.length()) {
-            throw new IllegalArgumentException("Unicode \\u escape at eof at pos ..."
-                + context(current) + "...");
-        }
-
-        String s = text.subSequence(current, current + 4).toString();
-        int n = Integer.parseInt(s, 16);
-        return (char) n;
-    }
-
-    int find(char target, char deeper) {
-        int start = current;
-        int level = 1;
-
-        while (level != 0) {
-            if (eof()) {
-                throw new RuntimeException("Eof found in the middle of a compound for '"
-                    + target + deeper + "', begins at " + context(start));
-            }
-
-            char c = next();
-            if (!escaped) {
-                if (c == target) {
-                    level--;
-                } else {
-                    if (c == deeper) {
-                        level++;
-                    } else {
-                        if (c == '"') {
-                            quote('"');
-                        } else {
-                            if (c == '\'') {
-                                quote('\'');
-                            }
-                            else {
-                                if (c == '`') {
-                                    quote('`');
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return current;
-    }
-
-    int quote(char which) {
-        while (!eof() && (peek() != which || escaped)) {
-            next();
-        }
-
-        return current++;
-    }
-
-    CharSequence findVar() {
-        int start = current;
-        char c = peek();
-
-        if (c == '{') {
-            next();
-            int end = find('}', '{');
-            return text.subSequence(start, end);
-        }
-        if (c == '(') {
-            next();
-            int end = find(')', '(');
-            return text.subSequence(start, end);
-        }
-
-        if (Character.isJavaIdentifierPart(c)) {
-            while (c == '$') {
-                c = next();
-            }
-            while (!eof() && (Character.isJavaIdentifierPart(c) || c == '.') && c != '$') {
-                next();
-                c = peek();
-            }
-            return text.subSequence(start, current);
-        }
-        throw new IllegalArgumentException(
-            "Reference to variable does not match syntax of a variable: "
-                + context(start));
-    }
-
-    public String toString() {
-        return "..." + context(current) + "...";
-    }
-
-    public String unescape() {
-        StringBuilder sb = new StringBuilder();
-        while (!eof()) {
-            sb.append(next());
-        }
-        return sb.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
new file mode 100644
index 0000000..0589a29
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.support.parsing;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+
+/**
+ *  The result of a delimited buffer.
+ */
+public class CommandLineImpl implements CommandLine {
+
+    private final String[] arguments;
+    private final int cursorArgumentIndex;
+    private final int argumentPosition;
+    private final int bufferPosition;
+    private final String buffer;
+
+    /**
+     *  @param  arguments           the array of tokens
+     *  @param  cursorArgumentIndex the token index of the cursor
+     *  @param  argumentPosition    the position of the cursor in the
+     *                              current token
+     *  @param  bufferPosition      the position of the cursor in the whole buffer
+     *  @param buffer               the whole buffer
+     */
+    public CommandLineImpl(String[] arguments, int cursorArgumentIndex, int argumentPosition, int bufferPosition, String buffer) {
+        this.arguments = arguments;
+        this.cursorArgumentIndex = cursorArgumentIndex;
+        this.argumentPosition = argumentPosition;
+        this.bufferPosition = bufferPosition;
+        this.buffer = buffer;
+    }
+
+    public int getCursorArgumentIndex() {
+        return this.cursorArgumentIndex;
+    }
+
+    public String getCursorArgument() {
+        if ((cursorArgumentIndex < 0)
+            || (cursorArgumentIndex >= arguments.length)) {
+            return null;
+        }
+
+        return arguments[cursorArgumentIndex];
+    }
+
+    public int getArgumentPosition() {
+        return this.argumentPosition;
+    }
+
+    public String[] getArguments() {
+        return this.arguments;
+    }
+
+    public int getBufferPosition() {
+        return this.bufferPosition;
+    }
+
+    public String getBuffer() {
+        return this.buffer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
new file mode 100644
index 0000000..7b01042
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+// DWB14: parser loops if // comment at start of program
+// DWB15: allow program to have trailing ';'
+package org.apache.karaf.shell.support.parsing;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+
+public class DefaultParser implements Parser {
+
+    @Override
+    public CommandLine parse(Session session, String command, int cursor) {
+        GogoParser parser = new GogoParser(command, cursor);
+        List<String> args = parser.statement();
+        return new CommandLineImpl(
+                        args.toArray(new String[args.size()]),
+                        parser.cursorArgumentIndex(),
+                        parser.argumentPosition(),
+                        cursor,
+                        command.substring(0, parser.position()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
new file mode 100644
index 0000000..73a1584
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+// DWB14: parser loops if // comment at start of program
+// DWB15: allow program to have trailing ';'
+package org.apache.karaf.shell.support.parsing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GogoParser {
+
+    int current = 0;
+    String text;
+    boolean escaped;
+    static final String SPECIAL = "<;|{[\"'$`(=";
+
+    List<List<List<String>>> program;
+    List<List<String>> statements;
+    List<String> statement;
+    int cursor;
+    int start = -1;
+    int c0;
+    int c1;
+    int c2;
+    int c3;
+    
+    public GogoParser(String text, int cursor) {
+    	this.text = text;
+        this.cursor = cursor;
+	}
+
+	public void ws() {
+        // derek: BUGFIX: loop if comment  at beginning of input
+        //while (!eof() && Character.isWhitespace(peek())) {
+        while (!eof() && (!escaped && Character.isWhitespace(peek()) || current == 0)) {
+            if (current != 0 || !escaped && Character.isWhitespace(peek())) {
+                current++;
+            }
+            if (peek() == '/' && current < text.length() - 2
+                && text.charAt(current + 1) == '/') {
+                comment();
+            }
+            if (current == 0) {
+                break;
+            }
+        }
+    }
+
+    private void comment() {
+        while (!eof() && peek() != '\n' && peek() != '\r') {
+            next();
+        }
+    }
+
+    public boolean eof() {
+        return current >= text.length();
+    }
+
+    public char peek() {
+        return peek(false);
+    }
+
+    char peek(boolean increment) {
+        escaped = false;
+        if (eof()) {
+            return 0;
+        }
+
+        int last = current;
+        char c = text.charAt(current++);
+
+        if (c == '\\') {
+            escaped = true;
+            if (eof()) {
+                throw new RuntimeException("Eof found after \\");
+            }
+
+            c = text.charAt(current++);
+
+            switch (c) {
+                case 't':
+                    c = '\t';
+                    break;
+                case '\r':
+                case '\n':
+                    c = ' ';
+                    break;
+                case 'b':
+                    c = '\b';
+                    break;
+                case 'f':
+                    c = '\f';
+                    break;
+                case 'n':
+                    c = '\n';
+                    break;
+                case 'r':
+                    c = '\r';
+                    break;
+                case 'u':
+                    c = unicode();
+                    current += 4;
+                    break;
+                default:
+                    // We just take the next character literally
+                    // but have the escaped flag set, important for {},[] etc
+            }
+        }
+        if (cursor > last && cursor <= current) {
+            c0 = program != null ? program.size() : 0;
+            c1 = statements != null ? statements.size() : 0;
+            c2 = statement != null ? statement.size() : 0;
+            c3 = (start >= 0) ? current - start : 0;
+        }
+        if (!increment) {
+            current = last;
+        }
+        return c;
+    }
+
+    public List<List<List<String>>> program() {
+        program = new ArrayList<List<List<String>>>();
+        ws();
+        if (!eof()) {
+            program.add(pipeline());
+            while (peek() == ';') {
+                current++;
+                List<List<String>> pipeline = pipeline();
+                program.add(pipeline);
+            }
+        }
+        if (!eof()) {
+            throw new RuntimeException("Program has trailing text: " + context(current));
+        }
+
+        List<List<List<String>>> p = program;
+        program = null;
+        return p;
+    }
+
+    CharSequence context(int around) {
+        return text.subSequence(Math.max(0, current - 20), Math.min(text.length(),
+            current + 4));
+    }
+
+    public List<List<String>> pipeline() {
+        statements = new ArrayList<List<String>>();
+        statements.add(statement());
+        while (peek() == '|') {
+            current++;
+            ws();
+            if (!eof()) {
+                statements.add(statement());
+            }
+            else {
+                statements.add(new ArrayList<String>());
+                break;
+            }
+        }
+        List<List<String>> s = statements;
+        statements = null;
+        return s;
+    }
+
+    public List<String> statement() {
+        statement = new ArrayList<String>();
+        statement.add(value());
+        while (!eof()) {
+            ws();
+            if (peek() == '|' || peek() == ';') {
+                break;
+            }
+
+            if (!eof()) {
+                statement.add(messy());
+            }
+        }
+        List<String> s = statement;
+        statement = null;
+        return s;
+    }
+
+    public String messy()
+    {
+        start = current;
+        char c = peek();
+        if (c > 0 && SPECIAL.indexOf(c) < 0) {
+            current++;
+            try {
+                while (!eof()) {
+                    c = peek();
+                    if (!escaped && (c == ';' || c == '|' || Character.isWhitespace(c))) {
+                        break;
+                    }
+                    next();
+                }
+                return text.substring(start, current);
+            } finally {
+                start = -1;
+            }
+        }
+        else {
+            return value();
+        }
+    }
+
+    public int position() {
+        return current;
+    }
+
+    public int cursorArgumentIndex() {
+        return c2;
+    }
+
+    public int argumentPosition() {
+        return c3;
+    }
+
+    public String value() {
+        ws();
+
+        start = current;
+        try {
+            char c = next();
+            if (!escaped) {
+                switch (c) {
+                    case '{':
+                        return text.substring(start, find('}', '{'));
+                    case '(':
+                        return text.substring(start, find(')', '('));
+                    case '[':
+                        return text.substring(start, find(']', '['));
+                    case '<':
+                        return text.substring(start, find('>', '<'));
+                    case '=':
+                        return text.substring(start, current);
+                    case '"':
+                    case '\'':
+                        quote(c);
+                        break;
+                }
+            }
+
+            // Some identifier or number
+            while (!eof()) {
+                c = peek();
+                if (!escaped) {
+                    if (Character.isWhitespace(c) || c == ';' || c == '|' || c == '=') {
+                        break;
+                    }
+                    else if (c == '{') {
+                        next();
+                        find('}', '{');
+                    }
+                    else if (c == '(') {
+                        next();
+                        find(')', '(');
+                    }
+                    else if (c == '<') {
+                        next();
+                        find('>', '<');
+                    }
+                    else if (c == '[') {
+                        next();
+                        find(']', '[');
+                    }
+                    else if (c == '\'' || c == '"') {
+                        next();
+                        quote(c);
+                        next();
+                    }
+                    else {
+                        next();
+                    }
+                }
+                else {
+                    next();
+                }
+            }
+            return text.substring(start, current);
+        } finally {
+            start = -1;
+        }
+    }
+
+    public boolean escaped() {
+        return escaped;
+    }
+
+    public char next() {
+        return peek(true);
+    }
+
+    char unicode() {
+        if (current + 4 > text.length()) {
+            throw new IllegalArgumentException("Unicode \\u escape at eof at pos ..."
+                + context(current) + "...");
+        }
+
+        String s = text.subSequence(current, current + 4).toString();
+        int n = Integer.parseInt(s, 16);
+        return (char) n;
+    }
+
+    int find(char target, char deeper) {
+        int start = current;
+        int level = 1;
+
+        while (level != 0) {
+            if (eof()) {
+                throw new RuntimeException("Eof found in the middle of a compound for '"
+                    + target + deeper + "', begins at " + context(start));
+            }
+
+            char c = next();
+            if (!escaped) {
+                if (c == target) {
+                    level--;
+                } else {
+                    if (c == deeper) {
+                        level++;
+                    } else {
+                        if (c == '"') {
+                            quote('"');
+                        } else {
+                            if (c == '\'') {
+                                quote('\'');
+                            }
+                            else {
+                                if (c == '`') {
+                                    quote('`');
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return current;
+    }
+
+    int quote(char which) {
+        while (!eof() && (peek() != which || escaped)) {
+            next();
+        }
+
+        return current++;
+    }
+
+    CharSequence findVar() {
+        int start = current;
+        char c = peek();
+
+        if (c == '{') {
+            next();
+            int end = find('}', '{');
+            return text.subSequence(start, end);
+        }
+        if (c == '(') {
+            next();
+            int end = find(')', '(');
+            return text.subSequence(start, end);
+        }
+
+        if (Character.isJavaIdentifierPart(c)) {
+            while (c == '$') {
+                c = next();
+            }
+            while (!eof() && (Character.isJavaIdentifierPart(c) || c == '.') && c != '$') {
+                next();
+                c = peek();
+            }
+            return text.subSequence(start, current);
+        }
+        throw new IllegalArgumentException(
+            "Reference to variable does not match syntax of a variable: "
+                + context(start));
+    }
+
+    public String toString() {
+        return "..." + context(current) + "...";
+    }
+
+    public String unescape() {
+        StringBuilder sb = new StringBuilder();
+        while (!eof()) {
+            sb.append(next());
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
----------------------------------------------------------------------
diff --git a/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java b/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
new file mode 100644
index 0000000..7e8a727
--- /dev/null
+++ b/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.parsing;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Parsing;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.impl.action.command.ActionCommand;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.apache.karaf.shell.impl.console.HeadlessSessionImpl;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.support.parsing.CommandLineImpl;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
+import org.apache.karaf.shell.support.parsing.GogoParser;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ParsingTest {
+
+    @Test
+    public void testDefaultParser() {
+        String command = " foo  bar (a +  b) ; another command ";
+        String subCmd = " foo  bar (a +  b) ";
+        DefaultParser parser = new DefaultParser();
+        CommandLine line = parser.parse(null, command, command.length());
+        assertEquals(3, line.getArguments().length);
+        assertEquals("foo", line.getArguments()[0]);
+        assertEquals("bar", line.getArguments()[1]);
+        assertEquals("(a +  b)", line.getArguments()[2]);
+        assertEquals(subCmd, line.getBuffer());
+
+    }
+
+    @Test
+    public void testCommandLineParser() {
+
+        SessionFactoryImpl sessionFactory = new SessionFactoryImpl(new ThreadIOImpl());
+        ManagerImpl manager = new ManagerImpl(sessionFactory, sessionFactory);
+        sessionFactory.getRegistry().register(new ActionCommand(manager, FooCommand.class));
+        sessionFactory.getRegistry().register(new ActionCommand(manager, AnotherCommand.class));
+        sessionFactory.getRegistry().register(new CustomParser());
+        Session session = new HeadlessSessionImpl(sessionFactory, sessionFactory.getCommandProcessor(),
+                new ByteArrayInputStream(new byte[0]), new PrintStream(new ByteArrayOutputStream()), new PrintStream(new ByteArrayOutputStream())
+        );
+
+        String parsed = CommandLineParser.parse(session, " foo bar (a + b); another   command with spaces ");
+        assertEquals("foo bar (a + b) ; another \"command with spaces\"", parsed);
+
+    }
+
+    @Command(scope = "scope", name = "foo")
+    static class FooCommand implements Action {
+        @Override
+        public Object execute() throws Exception {
+            return null;
+        }
+    }
+
+    @Command(scope = "scope", name = "another")
+    @Parsing(CustomParser.class)
+    static class AnotherCommand implements Action {
+        @Override
+        public Object execute() throws Exception {
+            return null;
+        }
+    }
+
+    static class CustomParser implements Parser {
+
+        @Override
+        public CommandLine parse(Session session, String command, int cursor) {
+            GogoParser parser = new GogoParser(command, cursor);
+            List<String> args = new ArrayList<>();
+            args.add(parser.value());
+            parser.ws();
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                char ch = parser.next();
+                if (ch == 0 || ch == ';' || ch == '|') {
+                    break;
+                } else {
+                    sb.append(ch);
+                }
+            }
+            String arg = sb.toString().trim();
+            if (!arg.isEmpty()) {
+                args.add("\"" + arg + "\"");
+            }
+            return new CommandLineImpl(args.toArray(new String[args.size()]), args.size() - 1, sb.length(),
+                            parser.position(),
+                            command.substring(0, parser.position()));
+        }
+    }
+
+}


Mime
View raw message