/** * 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,NULL); } /*--------------------------------------------------------------------------*/ 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,NULL); } 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); }