diff --git a/hdbcommand.c b/hdbcommand.c new file mode 100644 index 00000000..b5422412 --- /dev/null +++ b/hdbcommand.c @@ -0,0 +1,291 @@ +/** + * This module implements a generalized scheme for executing functions. + * Functions are described by a special data structure containing the + * parameters as a Hipadaba list and and an execute function which implements + * the actual operation. This is augmented by list mechanisms in order to + * allow for a list of functions. This shall facilitate a couple of things: + * - when functions are defined in such a structured form, general invocation + * functions can be devised for handling the interpreter interface. + * - The set of functions of an object can be configured and extended at + * runtime. + * - A common usage case: execute a function with the same arguments, can be + * easily catered for. + * All this is not new and was pioneered in the language self or other + * dynamic object systems. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, September 2006 + */ +#include +#include +#include +#include +#include +/*-------------------------------------------------------------------------*/ +static int debug = 1; +/* ============================= live and death ============================*/ +pHdbCommand CreateHdbCommand(char *name, int (*execute)(pHdb parameters)){ + pHdbCommand result = NULL; + + assert(name != NULL); + assert(execute != NULL); + + result = malloc(sizeof(hdbCommand)); + if(result == NULL){ + return NULL; + } + memset(result,0,sizeof(hdbCommand)); + result->name = strdup(name); + if(result->name == NULL){ + free(result); + return NULL; + } + result->execute = execute; + return result; +} +/*--------------------------------------------------------------------------*/ +void AppendHdbCommandToList(pHdbCommand commandList, pHdbCommand command){ + pHdbCommand current = NULL; + + assert(commandList != NULL); + assert(command != NULL); + + current = commandList; + while(current->next != NULL){ + current = (pHdbCommand)current->next; + } + command->previous = (struct __hdbCommand *)current; + current->next = (struct __hdbCommand *)command; + command->next = NULL; +} +/*--------------------------------------------------------------------------*/ +void AppendCommandParameter(pHdbCommand command, pHdb par){ + assert(command != NULL); + assert(par != NULL); + + AddHipadabaChild(command->parameters,par); +} +/*--------------------------------------------------------------------------*/ +void KillHdbCommandList(pHdbCommand commandList){ + pHdbCommand next = NULL, current = NULL; + + assert(commandList != NULL); + + current = commandList; + next = (pHdbCommand)current->next; + while(current != NULL){ + if(current->name != NULL){ + free(current->name); + } + if(current->parameters != NULL){ + DeleteHipadabaNode(current->parameters); + } + free(current); + current = next; + if(current != NULL){ + next = (pHdbCommand)current->next; + } else { + next = NULL; + } + } +} +/*======================= Invocation =======================================*/ +static pHdbCommand locateCommand(pHdbCommand commandList, char *name){ + pHdbCommand current = NULL; + + current = commandList; + while(current != NULL){ + if(strcmp(current->name,name) == 0) { + return current; + } + current = (pHdbCommand)current->next; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +int HdbCommandInvoke(pHdbCommand commandList, char *name, ...){ + va_list ap; + pHdbCommand toInvoke = NULL; + pHdb currentPar = NULL; + char *txt = NULL; + hdbValue *v = NULL; + + va_start(ap,name); + toInvoke = locateCommand(commandList,name); + if(toInvoke == NULL){ + return HDBCOMNOCOM; + } + + currentPar = toInvoke->parameters; + while(currentPar != NULL){ + /* + * I cannot call a function for this as ap would be undefined after + * a call to a function here + */ + switch(currentPar->value.dataType){ + case HIPNONE: + break; + case HIPINT: + currentPar->value.v.intValue = va_arg(ap,int); + if(debug == 1){ + printf("Read %d for parameter %s\n", + currentPar->value.v.intValue, currentPar->name); + } + break; + case HIPFLOAT: + currentPar->value.v.doubleValue = va_arg(ap,double); + if(debug == 1){ + printf("Read %lf for parameter %s\n", + currentPar->value.v.doubleValue, currentPar->name); + } + break; + case HIPTEXT: + txt = va_arg(ap,char *); + if(currentPar->value.v.text != NULL){ + free(currentPar->value.v.text); + } + currentPar->value.v.text = strdup(txt); + if(debug == 1){ + printf("Read %s for parameter %s\n", + currentPar->value.v.text, currentPar->name); + } + break; + case HIPOBJ: + currentPar->value.v.obj = va_arg(ap,void *); + break; + case HIPINTAR: + case HIPINTVARAR: + case HIPFLOATAR: + case HIPFLOATVARAR: + v = (hdbValue *)va_arg(ap,void *); + copyHdbValue(v,¤tPar->value); + break; + default: + assert(0); + break; + + } + currentPar = currentPar->next; + } + va_end(ap); + return toInvoke->execute(toInvoke->parameters); +} +/*-------------------------------------------------------------------------*/ +static void *(*objMap)(char *name) = NULL; +/*-------------------------------------------------------------------------*/ +void SetHdbComObjMapper(void *(*mapObj)(char *name)){ + objMap = mapObj; +} +/*-------------------------------------------------------------------------*/ +static int readParArguments(pHdb parNode, int argc, char *argv[]){ + int i, intVal; + double doVal; + + switch(parNode->value.dataType){ + case HIPNONE: + return 0; + break; + case HIPINT: + if(argc < 1){ + return HDBCOMNOARGS; + } + if(sscanf(argv[0],"%d",&parNode->value.v.intValue) != 1){ + return HDBCOMBADARG; + } + return 1; + break; + case HIPFLOAT: + if(argc < 1){ + return HDBCOMNOARGS; + } + if(sscanf(argv[0],"%lf",&parNode->value.v.doubleValue) != 1){ + return HDBCOMBADARG; + } + return 1; + break; + case HIPOBJ: + if(objMap != NULL){ + parNode->value.v.obj = objMap(argv[0]); + if(parNode->value.v.obj == NULL){ + return HDBCOMBADOBJ; + } else { + return 1; + } + } + return 0; + break; + case HIPTEXT: + if(argc < 1){ + return HDBCOMNOARGS; + } + if(parNode->value.v.text != NULL){ + free(parNode->value.v.text); + } + parNode->value.v.text = strdup(argv[0]); + return 1; + break; + case HIPINTAR: + if(parNode->value.arrayLength > argc){ + return HDBCOMNOARGS; + } + for(i = 0; i < parNode->value.arrayLength; i++){ + if(sscanf(argv[i],"%d",&intVal) != 1){ + return HDBCOMBADARG; + } + parNode->value.v.intArray[i] = intVal; + } + return parNode->value.arrayLength; + break; + case HIPFLOATAR: + if(parNode->value.arrayLength > argc){ + return HDBCOMNOARGS; + } + for(i = 0; i < parNode->value.arrayLength; i++){ + if(sscanf(argv[i],"%lf",&doVal) != 1){ + return HDBCOMBADARG; + } + parNode->value.v.floatArray[i] = doVal; + } + return parNode->value.arrayLength; + break; + default: + /* + * I cannot process such variables + */ + return HDBCOMINVARG; + break; + } + return 0; +} +/*--------------------------------------------------------------------------*/ +int HdbCommandTextInvoke(pHdbCommand commandList, int argc, char *argv[]){ + pHdbCommand toInvoke = NULL; + pHdb currentPar = NULL; + int argPointer, status; + + assert(commandList != NULL); + + if(argc < 1){ + return HDBCOMNOARGS; + } + + toInvoke = locateCommand(commandList,argv[0]); + if(toInvoke == NULL){ + return HDBCOMNOCOM; + } + + currentPar = toInvoke->parameters; + argPointer = 1; + while(currentPar != NULL){ + status = readParArguments(currentPar,argc-argPointer, + &argv[argPointer]); + if(status < 0){ + return status; + } else { + argPointer += status; + } + currentPar = currentPar->next; + } + return toInvoke->execute(toInvoke->parameters); +} diff --git a/hdbcommand.h b/hdbcommand.h new file mode 100644 index 00000000..b1b8285f --- /dev/null +++ b/hdbcommand.h @@ -0,0 +1,96 @@ +/** + * This module implements a generalized scheme for executing functions. + * Functions are described by a special data structure containing the + * parameters as a Hipadaba list and and an execute function which implements + * the actual operation. This is augmented by list mechanisms in order to + * allow for a list of functions. This shall facilitate a couple of things: + * - when functions are defined in such a structured form, general invocation + * functions can be devised for handling the interpreter interface. + * - The set of functions of an object can be configured and extended at + * runtime. + * - A common usage case: execute a function with the same arguments, can be + * easily catered for. + * All this is not new and was pioneered in the language self or other + * dynamic object systems. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, September 2006 + */ +#ifndef HDBCOMMAND_H_ +#define HDBCOMMAND_H_ +#include +#include +/*--------------- error codes ----------------------------------------------*/ +#define HDCOMNOMEM -7801 +#define HDBCOMNOCOM -7802 +#define HDBCOMNOARGS -7803 +#define HDBCOMBADARG -7804 +#define HDBCOMINVARG -7805 +#define HDBCOMBADOBJ -7806 +/*---------------------------------------------------------------------------*/ +typedef struct __hdbCommmand { + char *name; + pHdb parameters; + int (*execute)(pHdb parameters); + struct __hdbCommand *next; + struct __hdbCommand *previous; +}hdbCommand, *pHdbCommand; +/*======================= live and death ===================================*/ +/** + * create a hdbCommand with an empty parameter list + * @param name The name of teh command + * @param execute The execute function for this command + * @return a fresh hdbCommand or NULL when out of memory + * */ +pHdbCommand CreateHdbCommand(char *name, int (*execute)(pHdb parameters)); +/** + * append a hdbCommand to a command list + * @param commandList The list to append the command to + * @param command The command to append + * @return 1 on success, a negative error code else. + */ +void AppendHdbCommandToList(pHdbCommand commandList, pHdbCommand command); +/** + * append a parameter to the parameter list + * @param command The command to append the parameter too + * @param par The parameter to append + */ +void AppendCommandParameter(pHdbCommand command, pHdb par); +/** + * delete a command list recursively + * @param commandList The command list to delete + */ +void KillHdbCommandList(pHdbCommand commandList); +/*===================== invocation ========================================*/ +/** + * invoke a hdbCommand name. This does a lot: it locates the command, + * it assigne the parameter values and finally calls the execute function. + * @param commandList The command list in which to search for the command + * @param name The name of the command + * @param ... arguments to the command. ints, double, text and objects (pointers) + * are accepted as is.Arrays have to be passed in a pointers to a + * hdbValue structure. Otherwise there is not eonough information to safely + * copy array data. + * @return Negative error codes on invocation error, else the return + * value of the execute function. + */ +int HdbCommandInvoke(pHdbCommand commandList, char *name, ...); +/** + * invoke a hdbCommand name. This does a lot: it locates the command, + * it assigne the parameter values and finally calls the execute function. + * The name of the command must be in argv[0] + * @param commandList The command list in which to search for the command + * @param argc The number of arguments + * @param argv[] An array of strings holding the argument data + * @return Negative error codes on invocation error, else the return + * value of the execute function. + */ +int HdbCommandTextInvoke(pHdbCommand commandList, int argc, char *argv[]); +/** + * set a mapper which returns a void pointer for a name in order to resolve + * object references + * @param mapfunc + */ +void SetHdbComObjMapper(void *(*mapObj)(char *name)); +#endif /*HDBCOMMAND_H_*/