auto import from //depot/cupcake/@135843
diff --git a/amend/commands.c b/amend/commands.c
new file mode 100644
index 0000000..75ff828
--- /dev/null
+++ b/amend/commands.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "symtab.h"
+#include "commands.h"
+
+#if 1
+#define TRACE(...)  printf(__VA_ARGS__)
+#else
+#define TRACE(...)  /**/
+#endif
+
+typedef enum {
+    CMD_TYPE_UNKNOWN = -1,
+    CMD_TYPE_COMMAND = 0,
+    CMD_TYPE_FUNCTION
+} CommandType;
+
+typedef struct {
+    const char *name;
+    void *cookie;
+    CommandType type;
+    CommandArgumentType argType;
+    CommandHook hook;
+} CommandEntry;
+
+static struct {
+    SymbolTable *symbolTable;
+    bool commandStateInitialized;
+} gCommandState;
+
+int
+commandInit()
+{
+    if (gCommandState.commandStateInitialized) {
+        return -1;
+    }
+    gCommandState.symbolTable = createSymbolTable();
+    if (gCommandState.symbolTable == NULL) {
+        return -1;
+    }
+    gCommandState.commandStateInitialized = true;
+    return 0;
+}
+
+void
+commandCleanup()
+{
+    if (gCommandState.commandStateInitialized) {
+        gCommandState.commandStateInitialized = false;
+        deleteSymbolTable(gCommandState.symbolTable);
+        gCommandState.symbolTable = NULL;
+//xxx need to free the entries and names in the symbol table
+    }
+}
+
+static int
+registerCommandInternal(const char *name, CommandType type,
+        CommandArgumentType argType, CommandHook hook, void *cookie)
+{
+    CommandEntry *entry;
+
+    if (!gCommandState.commandStateInitialized) {
+        return -1;
+    }
+    if (name == NULL || hook == NULL) {
+        return -1;
+    }
+    if (type != CMD_TYPE_COMMAND && type != CMD_TYPE_FUNCTION) {
+        return -1;
+    }
+    if (argType != CMD_ARGS_BOOLEAN && argType != CMD_ARGS_WORDS) {
+        return -1;
+    }
+
+    entry = (CommandEntry *)malloc(sizeof(CommandEntry));
+    if (entry != NULL) {
+        entry->name = strdup(name);
+        if (entry->name != NULL) {
+            int ret;
+
+            entry->cookie = cookie;
+            entry->type = type;
+            entry->argType = argType;
+            entry->hook = hook;
+            ret = addToSymbolTable(gCommandState.symbolTable,
+                        entry->name, entry->type, entry);
+            if (ret == 0) {
+                return 0;
+            }
+        }
+        free(entry);
+    }
+
+    return -1;
+}
+
+int
+registerCommand(const char *name,
+        CommandArgumentType argType, CommandHook hook, void *cookie)
+{
+    return registerCommandInternal(name,
+            CMD_TYPE_COMMAND, argType, hook, cookie);
+}
+
+int
+registerFunction(const char *name, FunctionHook hook, void *cookie)
+{
+    return registerCommandInternal(name,
+            CMD_TYPE_FUNCTION, CMD_ARGS_WORDS, (CommandHook)hook, cookie);
+}
+
+Command *
+findCommand(const char *name)
+{
+    return (Command *)findInSymbolTable(gCommandState.symbolTable,
+            name, CMD_TYPE_COMMAND);
+}
+
+Function *
+findFunction(const char *name)
+{
+    return (Function *)findInSymbolTable(gCommandState.symbolTable,
+            name, CMD_TYPE_FUNCTION);
+}
+
+CommandArgumentType
+getCommandArgumentType(Command *cmd)
+{
+    CommandEntry *entry = (CommandEntry *)cmd;
+
+    if (entry != NULL) {
+        return entry->argType;
+    }
+    return CMD_ARGS_UNKNOWN;
+}
+
+static int
+callCommandInternal(CommandEntry *entry, int argc, const char *argv[],
+        PermissionRequestList *permissions)
+{
+    if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
+            (argc == 0 || (argc > 0 && argv != NULL)))
+    {
+        if (permissions == NULL) {
+            int i;
+            for (i = 0; i < argc; i++) {
+                if (argv[i] == NULL) {
+                    goto bail;
+                }
+            }
+        }
+        TRACE("calling command %s\n", entry->name);
+        return entry->hook(entry->name, entry->cookie, argc, argv, permissions);
+//xxx if permissions, make sure the entry has added at least one element.
+    }
+bail:
+    return -1;
+}
+
+static int
+callBooleanCommandInternal(CommandEntry *entry, bool arg,
+        PermissionRequestList *permissions)
+{
+    if (entry != NULL && entry->argType == CMD_ARGS_BOOLEAN) {
+        TRACE("calling boolean command %s\n", entry->name);
+        return entry->hook(entry->name, entry->cookie, arg ? 1 : 0, NULL,
+                permissions);
+//xxx if permissions, make sure the entry has added at least one element.
+    }
+    return -1;
+}
+
+int
+callCommand(Command *cmd, int argc, const char *argv[])
+{
+    return callCommandInternal((CommandEntry *)cmd, argc, argv, NULL);
+}
+
+int
+callBooleanCommand(Command *cmd, bool arg)
+{
+    return callBooleanCommandInternal((CommandEntry *)cmd, arg, NULL);
+}
+
+int
+getCommandPermissions(Command *cmd, int argc, const char *argv[],
+        PermissionRequestList *permissions)
+{
+    if (permissions != NULL) {
+        return callCommandInternal((CommandEntry *)cmd, argc, argv,
+                permissions);
+    }
+    return -1;
+}
+
+int
+getBooleanCommandPermissions(Command *cmd, bool arg,
+        PermissionRequestList *permissions)
+{
+    if (permissions != NULL) {
+        return callBooleanCommandInternal((CommandEntry *)cmd, arg,
+                permissions);
+    }
+    return -1;
+}
+
+int
+callFunctionInternal(CommandEntry *entry, int argc, const char *argv[],
+        char **result, size_t *resultLen, PermissionRequestList *permissions)
+{
+    if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
+            (argc == 0 || (argc > 0 && argv != NULL)))
+    {
+        if ((permissions == NULL && result != NULL) ||
+                (permissions != NULL && result == NULL))
+        {
+            if (permissions == NULL) {
+                /* This is the actual invocation of the function,
+                 * which means that none of the arguments are allowed
+                 * to be NULL.
+                 */
+                int i;
+                for (i = 0; i < argc; i++) {
+                    if (argv[i] == NULL) {
+                        goto bail;
+                    }
+                }
+            }
+            TRACE("calling function %s\n", entry->name);
+            return ((FunctionHook)entry->hook)(entry->name, entry->cookie,
+                    argc, argv, result, resultLen, permissions);
+//xxx if permissions, make sure the entry has added at least one element.
+        }
+    }
+bail:
+    return -1;
+}
+
+int
+callFunction(Function *fn, int argc, const char *argv[],
+        char **result, size_t *resultLen)
+{
+    return callFunctionInternal((CommandEntry *)fn, argc, argv,
+            result, resultLen, NULL);
+}
+
+int
+getFunctionPermissions(Function *fn, int argc, const char *argv[],
+        PermissionRequestList *permissions)
+{
+    if (permissions != NULL) {
+        return callFunctionInternal((CommandEntry *)fn, argc, argv,
+                NULL, NULL, permissions);
+    }
+    return -1;
+}