292 lines
9.3 KiB
C
292 lines
9.3 KiB
C
/**
|
|
* 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 <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <hdbcommand.h>
|
|
/*-------------------------------------------------------------------------*/
|
|
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);
|
|
}
|