274 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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;
 | |
| }
 |