| /* |
| * 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[]) |
| { |
| if (entry != NULL && entry->argType == CMD_ARGS_WORDS && |
| (argc == 0 || (argc > 0 && argv != 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); |
| } |
| bail: |
| return -1; |
| } |
| |
| static int |
| callBooleanCommandInternal(CommandEntry *entry, bool arg) |
| { |
| 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); |
| } |
| return -1; |
| } |
| |
| int |
| callCommand(Command *cmd, int argc, const char *argv[]) |
| { |
| return callCommandInternal((CommandEntry *)cmd, argc, argv); |
| } |
| |
| int |
| callBooleanCommand(Command *cmd, bool arg) |
| { |
| return callBooleanCommandInternal((CommandEntry *)cmd, arg); |
| } |
| |
| int |
| callFunctionInternal(CommandEntry *entry, int argc, const char *argv[], |
| char **result, size_t *resultLen) |
| { |
| if (entry != NULL && entry->argType == CMD_ARGS_WORDS && |
| (argc == 0 || (argc > 0 && argv != NULL))) |
| { |
| if (result != 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); |
| } |
| } |
| 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); |
| } |