1810 lines
44 KiB
C
1810 lines
44 KiB
C
/*---------------------------------------------------------------------------
|
|
pardef.c
|
|
|
|
my way to define and handle object parameters
|
|
|
|
Markus Zolliker, March 2005
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <fortify.h>
|
|
#include <limits.h>
|
|
#include <ctype.h>
|
|
#include "logger.h"
|
|
#include "logsetup.h"
|
|
#include "pardef.h"
|
|
#include "sugar.h"
|
|
#include "dynstring.h"
|
|
#include "sicshipadaba.h"
|
|
#include "ease.h"
|
|
|
|
#define ILLNUM -2
|
|
#define ILLARGC -3
|
|
#define AMBIGUOS -4
|
|
#define ILLPRIV -5
|
|
#define BADLOG -6
|
|
#define UNKPAR -7
|
|
#define PARUNDEF -8
|
|
#define ERRCMD -9
|
|
|
|
Logger dummy_logger;
|
|
Logger *secop_logger = &dummy_logger; /* disable parlog, and do it with hdb logger */
|
|
|
|
typedef enum { NO_OP, FMT_OP, SET_OP, GET_OP, INIT_OP, UPD_OP } ParOp;
|
|
|
|
/* Context holds all the information needed during the pardef function */
|
|
typedef struct Context {
|
|
struct Context *next;
|
|
ParData *obj;
|
|
ParAct act; /* action called */
|
|
ParAct action; /* copy of act, but set to PAR_NOOP when name does not match */
|
|
char *parName;
|
|
int argc;
|
|
char **argv;
|
|
char *valueArg;
|
|
char *thisPar;
|
|
int returnValue;
|
|
SConnection *con;
|
|
char *fmt;
|
|
int access;
|
|
FILE *saveFile;
|
|
int doit;
|
|
char *listTail;
|
|
char **enumList;
|
|
char *logName;
|
|
time_t now;
|
|
ParInfo *par;
|
|
float value;
|
|
char combiName[80];
|
|
char *grpFmt;
|
|
int exact;
|
|
char *callName; /* the called name of the object (different from obj->name in case of an alias) */
|
|
int enumText; /* show enum text */
|
|
hdbValue *hvalue;
|
|
} Context;
|
|
|
|
static char *loggerDir = NULL;
|
|
static int showTime = 0;
|
|
static void *initObj; /* this object is in initialization mode */
|
|
|
|
static Context *ctx = NULL, *freeContexts = NULL;
|
|
|
|
void ParKill(void *object);
|
|
|
|
static ParClass parClass = { "Par", sizeof(ParData), 0, {&parClass}
|
|
};
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void *ParCast(ParClass * class, void *object)
|
|
{
|
|
ParClass *t;
|
|
|
|
if (!object)
|
|
return NULL;
|
|
t = ((ParData *) object)->class;
|
|
assert(t->base[0] == &parClass);
|
|
if (t && t->base[class->level] == class) {
|
|
return object;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void *ParCheck(ParClass * class, void *object)
|
|
{
|
|
ParClass *t;
|
|
|
|
assert(object);
|
|
t = ((ParData *) object)->class;
|
|
assert(t->base[0] == &parClass);
|
|
assert(t && t->base[class->level] == class);
|
|
return object;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void *ParMakeClass(ParClass * class, ParClass * base)
|
|
{
|
|
int i;
|
|
|
|
if (class->base[0] == NULL) { /* initialize */
|
|
if (base == NULL) {
|
|
base = &parClass;
|
|
}
|
|
assert(class->size >= base->size);
|
|
for (i = 0; i <= base->level; i++) {
|
|
class->base[i] = base->base[i];
|
|
}
|
|
assert(i < PAR_LEVELS);
|
|
class->base[i] = class;
|
|
class->level = i;
|
|
} else if (base) { /* check */
|
|
for (i = 0; i <= base->level; i++) {
|
|
assert(class->base[i] == base->base[i]);
|
|
}
|
|
assert(class->base[i] == class);
|
|
assert(class->level == i);
|
|
}
|
|
return class;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ParPrintf(void *object, int iOut, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char buf0[128];
|
|
int l;
|
|
char *buf, *dyn = NULL;
|
|
SConnection *con;
|
|
ParData *pobj = object;
|
|
|
|
con = NULL;
|
|
if (pobj) {
|
|
if (ctx && pobj == ctx->obj && ctx->con) {
|
|
con = ctx->con;
|
|
} else {
|
|
con = pobj->conn;
|
|
}
|
|
} else if (ctx) {
|
|
con = ctx->con;
|
|
}
|
|
|
|
if (iOut < 0) {
|
|
if (!con)
|
|
return 0; /* no connection, no verbose output */
|
|
if (-iOut > pobj->verbose)
|
|
return 0; /* check verbosity level */
|
|
iOut = eLog;
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
l = vsnprintf(buf0, sizeof(buf0), fmt, ap);
|
|
va_end(ap);
|
|
if (l >= sizeof buf0) {
|
|
/* we have probably a C99 conforming snprintf and need a larger buffer */
|
|
dyn = malloc(l + 1);
|
|
if (dyn != NULL) {
|
|
va_start(ap, fmt);
|
|
vsnprintf(dyn, l + 1, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
buf = dyn;
|
|
} else {
|
|
buf = buf0;
|
|
}
|
|
|
|
if (con) {
|
|
SCWrite(con, buf, iOut); /* writes to command log when user or manager */
|
|
} else if (iOut >= 0) {
|
|
Log(INFO,"par", "%s", buf); /* no connection, write to commandlog only */
|
|
}
|
|
|
|
if (dyn)
|
|
free(dyn);
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void ParBegin(void)
|
|
{
|
|
Context *p;
|
|
|
|
if (freeContexts) {
|
|
p = freeContexts;
|
|
freeContexts = p->next;
|
|
} else {
|
|
p = calloc(1, sizeof(*ctx));
|
|
assert(p);
|
|
}
|
|
p->next = ctx;
|
|
ctx = p;
|
|
ctx->callName = NULL;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void ParEnd(void)
|
|
{
|
|
Context *p;
|
|
|
|
assert(ctx);
|
|
p = ctx->next;
|
|
ctx->next = freeContexts;
|
|
freeContexts = ctx;
|
|
ctx = p;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void ParDo(SConnection * con, ParData * o, ParAct a, char *parName)
|
|
{
|
|
ctx->act = a;
|
|
ctx->action = a;
|
|
ctx->con = con;
|
|
if (parName && strcmp(parName, "*") == 0) {
|
|
ctx->thisPar = "";
|
|
} else {
|
|
ctx->thisPar = parName;
|
|
}
|
|
ctx->returnValue = 0;
|
|
ctx->par = NULL;
|
|
ctx->grpFmt = NULL;
|
|
ctx->obj = o;
|
|
if (!ctx->callName) {
|
|
ctx->callName = o->name;
|
|
}
|
|
o->pardef(o);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
char *ParArg2Str(int argc, char *argv[], char *result, int maxsize)
|
|
{
|
|
int i, argsize;
|
|
char *p, *res;
|
|
|
|
argsize = 0;
|
|
if (result == NULL) {
|
|
maxsize = INT_MAX;
|
|
for (i = 0; i < argc; i++) {
|
|
argsize += strlen(argv[i]) + 1;
|
|
}
|
|
if (argsize == 0) argsize = 1;
|
|
result = malloc(argsize);
|
|
if (!result)
|
|
return NULL;
|
|
res = result;
|
|
} else {
|
|
res = result;
|
|
for (i = 0; i < argc; i++) {
|
|
argsize += strlen(argv[i]) + 1;
|
|
if (argsize > maxsize) {
|
|
argc = i;
|
|
res = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
p = result;
|
|
*p = '\0';
|
|
for (i = 0; i < argc; i++) {
|
|
if (i > 0) {
|
|
*p = ' ';
|
|
p++;
|
|
}
|
|
strcpy(p, argv[i]);
|
|
p += strlen(argv[i]);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ParSaveAll(void *object, char *name, FILE * fil)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
int ret;
|
|
|
|
ParBegin();
|
|
ctx->saveFile = fil;
|
|
/*
|
|
* Markus: why is this? This killed SICS unexpectedly once for me.
|
|
* And it is not required: the code can work even if name and o->name
|
|
* do not match.
|
|
*
|
|
* assert(0 == strcasecmp(o->name, name));
|
|
*/
|
|
if (o->creationCmd) {
|
|
fprintf(fil, "%s\n", o->creationCmd);
|
|
}
|
|
ParDo(0, o, PAR_SAVE, NULL);
|
|
if (o->creationCmd) {
|
|
fprintf(fil, "%s endinit\n\n", name);
|
|
/* fprintf(fil, "put_secop_info %s\n\n", name); */
|
|
}
|
|
ctx->saveFile = NULL;
|
|
ret = ctx->returnValue;
|
|
ParEnd();
|
|
return ret;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
FILE *ParSaveFile(void)
|
|
{
|
|
if (ctx) {
|
|
return ctx->saveFile;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
void ParUpdateAll(void *object)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
|
|
ParBegin();
|
|
ParDo(0, o, PAR_UPDATE, NULL);
|
|
ParEnd();
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int ParLog(void *object)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
int next;
|
|
|
|
if (o->desc == NULL) {
|
|
free(o);
|
|
return 0;
|
|
}
|
|
if (o->logPending == 2) {
|
|
o->logPending = 0;
|
|
return 0;
|
|
}
|
|
ParBegin();
|
|
ctx->now = time(NULL);
|
|
next = ctx->now - (o->logTime / o->period + 1) * o->period;
|
|
if (next < 0) {
|
|
return 1;
|
|
}
|
|
showTime = 1;
|
|
if (!secop_logger) {
|
|
ParDo(0, o, PAR_LOG, NULL);
|
|
o->logTime = ctx->now;
|
|
o->logPending = 0;
|
|
ParEnd();
|
|
}
|
|
ParUpdateAll(o);
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void ParLogForced(void *object)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
int next;
|
|
|
|
ParBegin();
|
|
ctx->now = time(NULL);
|
|
showTime = 1;
|
|
if (!secop_logger) {
|
|
ParDo(0, o, PAR_LOG, NULL);
|
|
o->logTime = ctx->now;
|
|
if (o->logPending) {
|
|
o->logPending = 2; /* tell ParLog that we are done already, but task is still pending */
|
|
}
|
|
ParEnd();
|
|
}
|
|
ParUpdateAll(o);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ParCallBack(int event, void *eventData, void *userData)
|
|
{
|
|
char *pBuf = (char *) eventData;
|
|
SConnection *con = (SConnection *) userData;
|
|
|
|
/* check kill condition */
|
|
if (con == NULL || !SCisConnected(con)) {
|
|
return -1;
|
|
}
|
|
|
|
if (event == VALUECHANGE) {
|
|
SCWrite(con, pBuf, eValue);
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int ParOutError(SConnection * con, ParData * o)
|
|
{
|
|
switch (ctx->returnValue) {
|
|
case AMBIGUOS:
|
|
SCPrintf(con, eError, "ERROR: doubly defined parameter %s.%s", o->name,
|
|
ctx->thisPar);
|
|
break;
|
|
case ILLPRIV:
|
|
SCPrintf(con, eError, "ERROR: insufficient privilege for %s.%s",
|
|
o->name, ctx->thisPar);
|
|
break;
|
|
case ILLNUM:
|
|
SCPrintf(con, eError, "ERROR: illegal value %s %s", o->name, ctx->valueArg);
|
|
break;
|
|
case ILLARGC:
|
|
SCPrintf(con, eError, "ERROR: illegal number of arguments for %s %s",
|
|
o->name, ctx->thisPar);
|
|
break;
|
|
case BADLOG:
|
|
SCPrintf(con, eError, "ERROR: can not create log directory for %s %s",
|
|
o->name, ctx->thisPar);
|
|
break;
|
|
case UNKPAR:
|
|
SCPrintf(con, eError, "ERROR: %s %s is unknown", o->name,
|
|
ctx->thisPar);
|
|
break;
|
|
case PARUNDEF:
|
|
SCPrintf(con, eError, "ERROR: %s %s is undefined",
|
|
o->name, ctx->thisPar);
|
|
break;
|
|
default:
|
|
if (ctx->returnValue < 0) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void ParListSugar(SConnection * con, ParData * o)
|
|
{
|
|
ParInfo *p;
|
|
char buf[512];
|
|
int l, i;
|
|
char *sugar;
|
|
|
|
p = o->infoList;
|
|
l = snprintf(buf, sizeof buf, "%s sugar =", o->name);
|
|
while (p != NULL) {
|
|
if (p->log) {
|
|
sugar = LoggerName(p->log);
|
|
if (strchr(sugar, '.') == NULL && strcmp(sugar, o->name) != 0) {
|
|
i = snprintf(buf + l, sizeof buf - l, " %s", sugar);
|
|
if (i <= 0)
|
|
break;
|
|
l += i;
|
|
if (l >= sizeof buf - 1)
|
|
break;
|
|
}
|
|
}
|
|
p = p->next;
|
|
}
|
|
SCWrite(con, buf, eValue);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParSaveConn(void *object, SConnection * con)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
int rights;
|
|
|
|
rights = SCGetRights(con);
|
|
if (rights >= usMugger && rights <= usUser && con->sockHandle >= 0) {
|
|
if (o->conn != NULL) {
|
|
if (o->conn->ident != con->ident) {
|
|
SCDeleteConnection(o->conn);
|
|
o->conn = SCCopyConnection(con);
|
|
}
|
|
} else {
|
|
o->conn = SCCopyConnection(con);
|
|
}
|
|
SCsetMacro(o->conn, 0);
|
|
if (o->conn->write != SCNormalWrite) {
|
|
o->conn->write = SCNormalWrite;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int ParExecute(SConnection * con, SicsInterp * sics, void *object,
|
|
int argc, char *argv[])
|
|
{
|
|
static char *empty[1] = { "" };
|
|
long id;
|
|
int iret, logIt = 0;
|
|
ParData *o = ParCheck(&parClass, object);
|
|
char *setArgv[2];
|
|
ParInfo *info;
|
|
|
|
/* debugging
|
|
int i;
|
|
printf("ParExecute");
|
|
for (i=0;i<argc;i++) {
|
|
printf(" %s", argv[i]);
|
|
}
|
|
printf("\n");
|
|
*/
|
|
if (argc >= 2 && 0 == strcasecmp(argv[1], "loggeditems")) {
|
|
pDynString dyn = CreateDynString(124,128);
|
|
for (info = o->infoList; info != NULL; info = info->next) {
|
|
if (info->log && (argc==2 || strcasecmp(argv[2], info->name) == 0)) {
|
|
DynStringConcat(dyn, " ");
|
|
DynStringConcat(dyn, argv[0]);
|
|
if (info->name[0] != '\0') {
|
|
DynStringConcat(dyn, ".");
|
|
DynStringConcat(dyn, info->name);
|
|
}
|
|
}
|
|
}
|
|
SCWrite(con, GetCharArray(dyn) + 1, eValue);
|
|
DeleteDynString(dyn);
|
|
return 1;
|
|
}
|
|
ParBegin();
|
|
ctx->callName = argv[0];
|
|
ParSaveConn(o, con);
|
|
|
|
if (argc > 1)
|
|
ctx->thisPar = argv[1];
|
|
if (argc >= 2 && 0 == strcasecmp(argv[1], "list")) {
|
|
ctx->argc = argc - 2;
|
|
ctx->argv = argv + 2;
|
|
ParDo(con, o, PAR_LIST, NULL);
|
|
ParEnd();
|
|
return 1;
|
|
}
|
|
if (argc == 1) { /* no args */
|
|
ctx->enumText = 0;
|
|
ParDo(con, o, PAR_SHOW, "");
|
|
if (ctx->returnValue == 0) {
|
|
SCSendOK(con);
|
|
ctx->returnValue = 1;
|
|
}
|
|
} else if ((0 == strcasecmp(argv[1], "log")
|
|
|| 0 == strcasecmp(argv[1], "unlog"))) {
|
|
if (argc < 3) {
|
|
ctx->returnValue = ILLARGC;
|
|
ctx->thisPar = argv[1];
|
|
} else if (!secop_logger) {
|
|
ctx->argc = argc - 3;
|
|
ctx->argv = argv + 3;
|
|
ctx->doit = toupper(argv[1][0]) != 'U';
|
|
ctx->exact = 0;
|
|
ParDo(con, o, PAR_LOGSWITCH, argv[2]);
|
|
}
|
|
} else if ((0 == strcasecmp(argv[1], "save")
|
|
|| 0 == strcasecmp(argv[1], "unsave"))) {
|
|
if (argc != 3) {
|
|
ctx->returnValue = ILLARGC;
|
|
} else if (!secop_logger) {
|
|
ctx->doit = toupper(argv[1][0]) != 'U';
|
|
ParDo(con, o, PAR_SAVESWITCH, argv[2]);
|
|
SCparChange(con);
|
|
}
|
|
} else if (strcmp(argv[1], "interest") == 0) {
|
|
if (!o->pCall) {
|
|
o->pCall = CreateCallBackInterface();
|
|
}
|
|
assert(o->pCall);
|
|
id = RegisterCallback(o->pCall, VALUECHANGE, ParCallBack,
|
|
SCCopyConnection(con), SCDeleteConnection);
|
|
SCSendOK(con);
|
|
ParEnd();
|
|
return 1;
|
|
} else if (strcmp(argv[1], "uninterest") == 0) {
|
|
if (o->pCall) {
|
|
RemoveCallbackCon(o->pCall, con);
|
|
}
|
|
SCSendOK(con);
|
|
ParEnd();
|
|
return 1;
|
|
} else if (strcmp(argv[1], "sugar") == 0) {
|
|
ParListSugar(con, o);
|
|
ParEnd();
|
|
return 1;
|
|
} else if (strcmp(argv[1], "enumText") == 0) {
|
|
if (argc == 3) {
|
|
ctx->enumText = 1;
|
|
ParDo(con, o, PAR_SHOW, argv[2]);
|
|
}
|
|
} else if (strcmp(argv[1], "endinit") == 0) {
|
|
initObj = NULL;
|
|
ParEnd();
|
|
return 1;
|
|
} else {
|
|
if (strcmp(argv[1], "=") == 0) {
|
|
ctx->argc = argc - 2;
|
|
ctx->argv = argv + 2;
|
|
ctx->valueArg = argv[2];
|
|
ParDo(con, o, PAR_SET, "");
|
|
logIt = 1;
|
|
} else {
|
|
if (argc == 2) {
|
|
ctx->enumText = 0;
|
|
ctx->argc = 0;
|
|
ParDo(con, o, PAR_SHOW, argv[1]);
|
|
} else {
|
|
ctx->argc = argc - 2;
|
|
ctx->argv = argv + 2;
|
|
ctx->valueArg = argv[2];
|
|
ParDo(con, o, PAR_SET, argv[1]);
|
|
logIt = 1;
|
|
}
|
|
/* parameter not found, try to use args as set value for pure object
|
|
not a very good idea: a typo in a parameter name will change pure value
|
|
--> use always '='
|
|
if (ctx->returnValue == 0) {
|
|
ctx->argc = argc - 1;
|
|
ctx->argv = argv + 1;
|
|
errPar = ctx->thisPar;
|
|
ParDo(con, o, PAR_SET, "");
|
|
if (ctx->returnValue <= 0) {
|
|
ctx->thisPar = errPar;
|
|
ctx->returnValue = UNKPAR;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
if (ctx->returnValue == 0) {
|
|
ctx->returnValue = UNKPAR;
|
|
}
|
|
iret = ParOutError(con, o);
|
|
if (logIt)
|
|
ParLogForced(o); /* log changes */
|
|
ParEnd();
|
|
return iret;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void KillLogger(ParInfo * par)
|
|
{
|
|
if (par->log != NULL && par->log != secop_logger) {
|
|
LoggerKill(par->log);
|
|
if (par->sugarStatus == 1) {
|
|
RemoveCommand(pServ->pSics, LoggerName(par->log));
|
|
par->sugarStatus = 0;
|
|
}
|
|
par->log = NULL;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int ParSwitchLog(int on, char *name)
|
|
{
|
|
char buf[80], alias[80];
|
|
|
|
KillLogger(ctx->par);
|
|
if (on) {
|
|
if (ctx->par->name[0] == '\0') {
|
|
snprintf(buf, sizeof buf, "%s", ctx->obj->name);
|
|
} else {
|
|
snprintf(buf, sizeof buf, "%s.%s", ctx->obj->name, ctx->par->name);
|
|
}
|
|
if (name == NULL) {
|
|
name = buf;
|
|
}
|
|
if (loggerDir == NULL) {
|
|
loggerDir = IFindOption(pSICSOptions, "LoggerDir");
|
|
if (loggerDir == NULL)
|
|
loggerDir = "./";
|
|
LoggerSetDir(loggerDir);
|
|
}
|
|
if (!secop_logger) {
|
|
ctx->par->log = LoggerMake(name, ctx->obj->period, ctx->exact);
|
|
if (ctx->par->log == NULL) {
|
|
return BADLOG;
|
|
}
|
|
}
|
|
if (ctx->par->sugarStatus == 0 && name != buf
|
|
&& strcmp(name, buf) != 0) {
|
|
snprintf(alias, sizeof alias, "%s %s", ctx->obj->name,
|
|
ctx->par->name);
|
|
ctx->par->sugarStatus = SugarMake(name, alias);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void ParFind(void)
|
|
{
|
|
ParInfo *p, **last, **endList;
|
|
|
|
assert(ctx);
|
|
if (ctx->par == NULL) {
|
|
last = &ctx->obj->infoList;
|
|
ctx->par = *last;
|
|
} else {
|
|
last = &ctx->par->next;
|
|
}
|
|
if (ctx->par) {
|
|
/* start search after the actual parameter */
|
|
p = ctx->par->next;
|
|
while (p != NULL && 0 != strcmp(p->name, ctx->parName)) {
|
|
p = p->next;
|
|
}
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
if (p == NULL) { /* not found: search again from list head */
|
|
p = ctx->obj->infoList;
|
|
while (p != NULL && 0 != strcmp(p->name, ctx->parName)) {
|
|
if (p == ctx->par) {
|
|
p = NULL;
|
|
break;
|
|
}
|
|
p = p->next;
|
|
}
|
|
if (p == NULL) {
|
|
p = calloc(1, sizeof *p);
|
|
if (p == NULL)
|
|
return;
|
|
p->name = strdup(ctx->parName);
|
|
p->log = NULL;
|
|
p->saveIt = 0;
|
|
p->saveLog = 0;
|
|
p->state = PAR_ALWAYS_READY;
|
|
p->node = NULL;
|
|
p->next = *last;
|
|
*last = p;
|
|
}
|
|
}
|
|
ctx->par = p;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
long ParText2Int(char *text)
|
|
{
|
|
long num = 0;
|
|
|
|
if (strcasecmp(text, "undefined") == 0 || text[0] == '\0') {
|
|
return PAR_LNAN;
|
|
}
|
|
if (ctx->enumList) {
|
|
while (ctx->enumList[num] != NULL) {
|
|
if (strcasecmp(ctx->enumList[num], text) == 0) {
|
|
return num;
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
char *ParInt2Text(int num)
|
|
{
|
|
int i;
|
|
static char buf[12];
|
|
|
|
if (num == PAR_LNAN) {
|
|
return ""; /* undefined */
|
|
}
|
|
if (!ctx->enumList)
|
|
return NULL;
|
|
for (i = 0; i <= num; i++) {
|
|
if (ctx->enumList[i] == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
return ctx->enumList[num];
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParGroup(char *groupFmt)
|
|
{
|
|
ctx->grpFmt = groupFmt;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParName(char *name)
|
|
{
|
|
|
|
if (ctx->grpFmt && *ctx->grpFmt) {
|
|
snprintf(ctx->combiName, sizeof ctx->combiName, ctx->grpFmt, name);
|
|
ctx->parName = ctx->combiName;
|
|
} else {
|
|
ctx->parName = name;
|
|
}
|
|
ParFind();
|
|
ctx->fmt = NULL;
|
|
ctx->action = ctx->act;
|
|
|
|
assert(ctx);
|
|
switch (ctx->act) {
|
|
case PAR_SHOW:
|
|
case PAR_SET:
|
|
case PAR_HDBSET:
|
|
ctx->enumList = NULL;
|
|
if (0 == strcasecmp(name, ctx->thisPar)) {
|
|
ctx->access = -1;
|
|
} else {
|
|
ctx->action = PAR_NOOP;
|
|
}
|
|
return;
|
|
case PAR_LIST:
|
|
ctx->enumList = NULL;
|
|
ctx->listTail = NULL;
|
|
ctx->doit = -1;
|
|
return;
|
|
case PAR_LOG:
|
|
return;
|
|
case PAR_LOGSWITCH:
|
|
if (0 == strcasecmp(name, ctx->thisPar)) {
|
|
ctx->access = -1;
|
|
} else {
|
|
ctx->action = PAR_NOOP;
|
|
}
|
|
return;
|
|
case PAR_SAVESWITCH:
|
|
if (0 == strcasecmp(name, ctx->thisPar)) {
|
|
ctx->access = -1;
|
|
} else {
|
|
ctx->action = PAR_NOOP;
|
|
}
|
|
return;
|
|
case PAR_INIT:
|
|
/* for save: use -1 as default value */
|
|
ctx->access = -1;
|
|
ctx->doit = -1;
|
|
ctx->logName = ""; /* log by default */
|
|
ctx->exact = 0; /* not exact by default */
|
|
return;
|
|
case PAR_GET:
|
|
if (0 != strcasecmp(name, ctx->thisPar)) {
|
|
ctx->action = PAR_NOOP;
|
|
}
|
|
return;
|
|
case PAR_UPDATE:
|
|
ctx->doit = 0; /* affects visibility */
|
|
break;
|
|
case PAR_SAVE:
|
|
case PAR_KILL:
|
|
case PAR_NOOP:
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int RestoreMode(void)
|
|
{
|
|
assert(ctx);
|
|
if (initObj == ctx->obj) {
|
|
return 1;
|
|
}
|
|
initObj = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
ParOp ParWhat(int numeric)
|
|
{
|
|
static char buf[80];
|
|
char *sp, *lname;
|
|
int i;
|
|
ParOp op;
|
|
int on;
|
|
|
|
assert(ctx);
|
|
switch (ctx->action) {
|
|
case PAR_LIST:
|
|
if (ctx->doit < 0) {
|
|
if (ctx->listTail && ctx->argc == 0) {
|
|
ctx->doit = 1;
|
|
} else {
|
|
ctx->doit = 0;
|
|
}
|
|
}
|
|
if (ctx->doit
|
|
|| (ctx->argc > 0 && 0 == strcasecmp(ctx->argv[0], "all")))
|
|
return FMT_OP;
|
|
break;
|
|
case PAR_LOG:
|
|
if (ctx->par && ctx->par->log) {
|
|
return FMT_OP;
|
|
}
|
|
break;
|
|
case PAR_LOGSWITCH:
|
|
if (ctx->argc > 1) {
|
|
ctx->returnValue = ILLARGC;
|
|
break;
|
|
}
|
|
if (ctx->returnValue) {
|
|
ctx->returnValue = AMBIGUOS;
|
|
break;
|
|
}
|
|
if (ctx->par) {
|
|
ctx->returnValue = 1;
|
|
if (ctx->argc > 0) {
|
|
lname = ctx->argv[0];
|
|
} else {
|
|
lname = NULL;
|
|
}
|
|
ctx->par->saveLog = 1;
|
|
ParSwitchLog(ctx->doit, lname);
|
|
LoggerSetNumeric(ctx->par->log, numeric);
|
|
SCparChange(ctx->con);
|
|
return NO_OP;
|
|
}
|
|
break;
|
|
case PAR_SAVESWITCH:
|
|
if (ctx->argc > 1) {
|
|
ctx->returnValue = ILLARGC;
|
|
break;
|
|
}
|
|
if (ctx->returnValue) {
|
|
ctx->returnValue = AMBIGUOS;
|
|
break;
|
|
}
|
|
if (ctx->par) {
|
|
ctx->returnValue = 1;
|
|
ctx->par->saveIt = ctx->doit;
|
|
return NO_OP;
|
|
}
|
|
break;
|
|
case PAR_INIT:
|
|
if (!RestoreMode()) {
|
|
if (ctx->access < 0) {
|
|
ctx->access = usInternal;
|
|
}
|
|
if (ctx->doit < 0) {
|
|
if (ctx->access == usInternal) {
|
|
ctx->doit = 0;
|
|
} else {
|
|
ctx->doit = 1;
|
|
}
|
|
}
|
|
if (ctx->doit) { /* set save flag */
|
|
if (ctx->par) {
|
|
ctx->par->saveIt = 1;
|
|
}
|
|
}
|
|
}
|
|
if (ctx->logName) { /* set log */
|
|
if (ctx->par) {
|
|
if (ctx->logName[0] != '\0') {
|
|
lname = ctx->logName;
|
|
} else {
|
|
lname = NULL;
|
|
}
|
|
if (secop_logger) {
|
|
ctx->par->log = secop_logger;
|
|
} else {
|
|
ParSwitchLog(1, lname);
|
|
LoggerSetNumeric(ctx->par->log, numeric);
|
|
}
|
|
}
|
|
}
|
|
return INIT_OP;
|
|
case PAR_SHOW:
|
|
if (ctx->returnValue) {
|
|
ctx->returnValue = AMBIGUOS;
|
|
break;
|
|
}
|
|
ctx->returnValue = 1;
|
|
return FMT_OP;
|
|
case PAR_HDBSET:
|
|
case PAR_SET:
|
|
if (ctx->returnValue) {
|
|
ctx->returnValue = AMBIGUOS;
|
|
break;
|
|
}
|
|
if (ctx->access < 0) {
|
|
ctx->access = usInternal;
|
|
}
|
|
if (!RestoreMode() && ctx->access < SCGetRights(ctx->con)) {
|
|
ctx->returnValue = ILLPRIV;
|
|
break;
|
|
}
|
|
ctx->returnValue = 1;
|
|
return SET_OP;
|
|
case PAR_SAVE:
|
|
if (ctx->parName[0] == '\0') {
|
|
ctx->parName = "*";
|
|
}
|
|
if (ctx->par->saveLog) {
|
|
if (ctx->par->log) {
|
|
fprintf(ctx->saveFile, "%s log %s %s\n", ctx->obj->name,
|
|
ctx->parName, LoggerName(ctx->par->log));
|
|
} else {
|
|
fprintf(ctx->saveFile, "%s unlog %s\n", ctx->obj->name,
|
|
ctx->parName);
|
|
}
|
|
}
|
|
if (ctx->par && ctx->par->saveIt == 1) {
|
|
return FMT_OP;
|
|
}
|
|
break;
|
|
case PAR_GET:
|
|
if (ctx->returnValue) {
|
|
ctx->returnValue = AMBIGUOS;
|
|
break;
|
|
}
|
|
return GET_OP;
|
|
case PAR_UPDATE:
|
|
return UPD_OP;
|
|
default:
|
|
return NO_OP;
|
|
}
|
|
ctx->action = PAR_NOOP; /* for the result of ParActionIs */
|
|
return NO_OP;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParOut(char *buf)
|
|
{
|
|
int l, i, j, m, ln, lp, iret;
|
|
char *p;
|
|
char buffer[256];
|
|
char *endp;
|
|
char *pnam;
|
|
char *sep;
|
|
char *saved, *logged;
|
|
time_t last;
|
|
|
|
assert(ctx);
|
|
assert(ctx->fmt == NULL);
|
|
switch (ctx->action) {
|
|
case PAR_LIST:
|
|
/*
|
|
if (ctx->par->log) {
|
|
snprintf(buffer, sizeof buffer, "%s", LoggerName(ctx->par->log));
|
|
} else {
|
|
*/
|
|
if (ctx->parName[0] != '\0') {
|
|
snprintf(buffer, sizeof buffer, "%s.%s", ctx->callName,
|
|
ctx->parName);
|
|
} else {
|
|
snprintf(buffer, sizeof buffer, "%s", ctx->callName);
|
|
}
|
|
|
|
if (ctx->enumList) {
|
|
i = strtol(buf, &endp, 0);
|
|
if (endp != buf) {
|
|
ctx->listTail = ParInt2Text(i); /* overwrite ctx->listTail */
|
|
}
|
|
}
|
|
p = buf;
|
|
/* find dot or end of number */
|
|
while (*p == ' ')
|
|
p++; /* skip blanks */
|
|
i = 0;
|
|
if (p[i] == '-')
|
|
i++;
|
|
j = i;
|
|
while (p[i] >= '0' && p[i] <= '9')
|
|
i++;
|
|
l = strlen(p);
|
|
ln = strlen(buffer) - strlen(ctx->callName);
|
|
if (i != j && (buf[i] == '.' || buf[i] <= ' ')) {
|
|
l += 16 - i - ln; /* decimal point or end of number at least 16 chars after object name */
|
|
lp = strlen(p);
|
|
if (l < lp)
|
|
l = lp;
|
|
m = 23 - l - ln; /* unit/comment at least 23 chars after object name */
|
|
} else { /* non numeric value */
|
|
l = 21 - ln; /* text right justified if possible */
|
|
/* m = 1; */
|
|
m = 23 - l - ln;
|
|
}
|
|
if (m < 1)
|
|
m = 1;
|
|
if (ctx->listTail == NULL)
|
|
ctx->listTail = "";
|
|
m += strlen(ctx->listTail);
|
|
if (l <= 0)
|
|
l = 1;
|
|
saved = "";
|
|
logged = "";
|
|
if (ctx->argc > 0 && 0 == strcasecmp(ctx->argv[0], "all")) {
|
|
if (!ctx->par->log) {
|
|
logged = " (not logged)";
|
|
}
|
|
if (ctx->par->saveIt == 1) {
|
|
saved = " (saved)";
|
|
} else if (ctx->par->saveIt == 2) {
|
|
saved = " (saved by driver)";
|
|
}
|
|
}
|
|
ParPrintf(NULL, eWarning, "%s %*s%*s%s%s", buffer, l, p, m,
|
|
ctx->listTail, logged, saved);
|
|
break;
|
|
case PAR_SHOW:
|
|
if (ctx->enumText) {
|
|
i = strtol(buf, &endp, 0);
|
|
if (endp != buf) {
|
|
p = ParInt2Text(i);
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
if (p == NULL)
|
|
p = ""; /* undefined */
|
|
ParPrintf(NULL, eValue, "%s", p);
|
|
break;
|
|
}
|
|
if (ctx->parName[0]) {
|
|
p = " ";
|
|
} else {
|
|
p = "";
|
|
}
|
|
ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->callName,
|
|
p, ctx->parName, buf);
|
|
break;
|
|
case PAR_HDBSET:
|
|
case PAR_SET:
|
|
if (ctx->parName[0]) {
|
|
p = " ";
|
|
} else {
|
|
p = "";
|
|
}
|
|
ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->callName, p, ctx->parName,
|
|
buf);
|
|
if (!ctx->obj->logPending) {
|
|
ctx->obj->logPending = 1;
|
|
TaskRegisterN(pServ->pTasker,"parlog", ParLog, NULL, NULL, ctx->obj, TASK_PRIO_LOW); /* schedule ParLog */
|
|
}
|
|
break;
|
|
case PAR_LOG:
|
|
if (ctx->par->log) {
|
|
if (ctx->par->state == PAR_NOW_READY) {
|
|
ctx->par->state = PAR_NOT_READY;
|
|
last = LoggerLastTime(ctx->par->log);
|
|
if (last != 0 && ctx->now - ctx->obj->period > last) {
|
|
LoggerWrite(ctx->par->log, ctx->now - ctx->obj->period,
|
|
ctx->obj->period, buf);
|
|
}
|
|
} else if (ctx->par->state != PAR_ALWAYS_READY) {
|
|
break;
|
|
}
|
|
if (showTime && ctx->obj->pCall) {
|
|
snprintf(buffer, sizeof buffer, "<time> = %ld", (long) ctx->now);
|
|
InvokeCallBack(ctx->obj->pCall, VALUECHANGE, buffer);
|
|
showTime = 0;
|
|
}
|
|
iret = LoggerWrite(ctx->par->log, ctx->now, ctx->obj->period, buf);
|
|
if (iret && ctx->obj->pCall) {
|
|
snprintf(buffer, sizeof buffer, "%s = %s",
|
|
LoggerName(ctx->par->log), buf);
|
|
InvokeCallBack(ctx->obj->pCall, VALUECHANGE, buffer);
|
|
}
|
|
}
|
|
break;
|
|
case PAR_SAVE:
|
|
if (strchr(buf, '\n') != NULL) {
|
|
fprintf(ctx->saveFile, "%s %s {%s}\n", ctx->obj->name,
|
|
ctx->parName, buf);
|
|
} else {
|
|
fprintf(ctx->saveFile, "%s %s %s\n", ctx->obj->name,
|
|
ctx->parName, buf);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParLogReady(ReadyState state)
|
|
{
|
|
if (ctx->action == PAR_LOG && ctx->par) {
|
|
ctx->par->state = state;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParFmt(char *format)
|
|
{
|
|
ctx->fmt = format; /* used for various actions */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParAccess(int accessRights)
|
|
{
|
|
ctx->access = accessRights; /* used for PAR_SET & PAR_INIT */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParEnum(char *list[])
|
|
{
|
|
ctx->enumList = list; /* used for various actions */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParSave(int saveIt)
|
|
{
|
|
if (ctx->action == PAR_INIT) {
|
|
ctx->doit = saveIt;
|
|
} else if (ctx->action == PAR_SAVE && saveIt == 2 && ctx->par) {
|
|
ctx->par->saveIt = 2;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParList(char *group)
|
|
{
|
|
if (ctx->action == PAR_LIST) {
|
|
if (group == NULL && ctx->argc == 0) {
|
|
ctx->doit = 1;
|
|
} else if (ctx->argc > 0 && group != NULL
|
|
&& 0 == strcasecmp(ctx->argv[0], group)) {
|
|
ctx->doit = 1;
|
|
} else if (ctx->doit < 0) {
|
|
ctx->doit = 0;
|
|
}
|
|
} else if (ctx->action == PAR_UPDATE) {
|
|
ctx->doit = group == NULL || group[0] != '\0';
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParTail(char *tail)
|
|
{
|
|
if (ctx->action == PAR_LIST) {
|
|
ctx->listTail = tail;
|
|
} else if (ctx->action == PAR_UPDATE) {
|
|
ctx->doit = 1; /* always visible */
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParLogAs(char *name)
|
|
{
|
|
if (ctx->action == PAR_INIT) {
|
|
ctx->logName = name;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParLogExact(int arg)
|
|
{
|
|
ctx->exact = arg;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParHasChanged(void)
|
|
{
|
|
if (ctx->par) {
|
|
if (RestoreMode()) {
|
|
ctx->par->saveIt = 1;
|
|
};
|
|
if (ctx->par->saveIt) {
|
|
SCparChange(ctx->con);
|
|
}
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static hdbCallbackReturn ParUpdateCB(pHdb node, void *userData, pHdbMessage msg) {
|
|
hdbDataMessage *setMsg;
|
|
|
|
if ((setMsg = GetHdbSetMessage(msg))){
|
|
ParBegin();
|
|
ctx->hvalue = setMsg->v;
|
|
ParDo(NULL, userData, PAR_HDBSET, node->name);
|
|
ParEnd();
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParUpdateNode(hdbValue value) {
|
|
pHdb node;
|
|
char sicscommand[128];
|
|
char path[128];
|
|
char secop_id[128];
|
|
int skip_unchanged = 1;
|
|
|
|
if (!ctx->obj->node) {
|
|
ctx->obj->secop_module = ctx->obj->name;
|
|
if (ctx->parName[0]) {
|
|
/* main node is not yet created -> assume it is of type NONE */
|
|
node = MakeHipadabaNode(ctx->obj->name, HIPNONE, 0);
|
|
if (ctx->obj->secop_module) {
|
|
SetHdbProperty(node, "secop_module", ctx->obj->secop_module);
|
|
}
|
|
} else {
|
|
node = MakeSICSHdbPar(ctx->obj->name, ctx->access, value);
|
|
if (ctx->par->log && ctx->obj->secop_module) {
|
|
snprintf(secop_id, sizeof secop_id, "%s:value", ctx->obj->secop_module);
|
|
SetHdbProperty(node, "secop_id", secop_id);
|
|
snprintf(path, sizeof path, "/%s", ctx->obj->name);
|
|
LogMakeInternal(node, path, 0); /* secop_module */
|
|
skip_unchanged = 0;
|
|
}
|
|
}
|
|
ctx->obj->node = node;
|
|
AddHipadabaChild(GetHipadabaRoot(), node, NULL);
|
|
SetHdbProperty(node, "sicscommand", ctx->obj->name);
|
|
SetHdbProperty(node, "group", "_pardef_");
|
|
}
|
|
node = ctx->par->node;
|
|
if (node == NULL) { /* node is not yet set */
|
|
if (ctx->parName[0]) {
|
|
if (strchr(ctx->parName, '/') != NULL) {
|
|
return; /* do not allow parameter names containing '/' */
|
|
}
|
|
node = AddSICSHdbPar(ctx->obj->node, ctx->parName, ctx->access, value);
|
|
if (ctx->par->log && ctx->obj->secop_module) {
|
|
snprintf(secop_id, sizeof secop_id, "%s:%s", ctx->obj->secop_module, ctx->parName);
|
|
SetHdbProperty(node, "secop_id", secop_id);
|
|
snprintf(path, sizeof path, "/%s/%s", ctx->obj->name, ctx->parName);
|
|
LogMakeInternal(node, path, 0);
|
|
skip_unchanged = 0;
|
|
}
|
|
ctx->par->node = node;
|
|
snprintf(sicscommand, sizeof sicscommand, "%s %s", ctx->obj->name, ctx->parName);
|
|
} else {
|
|
/* bare object (parameter "") */
|
|
node = ctx->obj->node;
|
|
ctx->par->node = node;
|
|
snprintf(sicscommand, sizeof sicscommand, "%s = ", ctx->obj->name);
|
|
}
|
|
SetHdbProperty(node, "sicscommand", sicscommand);
|
|
AppendHipadabaCallback(node, MakeHipadabaCallback(ParUpdateCB, ctx->obj, NULL));
|
|
}
|
|
if (ctx->action == PAR_UPDATE) {
|
|
char *visible = GetHdbProp(node, "visible");
|
|
if (ctx->doit) {
|
|
if (visible) {
|
|
SetHdbProperty(node, "visible", NULL);
|
|
}
|
|
} else {
|
|
if (!visible || strcasecmp(visible, "false") != 0) {
|
|
SetHdbProperty(node, "visible", "false");
|
|
}
|
|
}
|
|
if (GetHdbProp(node, "geterror")) skip_unchanged = 0;
|
|
switch (value.dataType) {
|
|
case HIPFLOAT:
|
|
if (value.v.doubleValue == PAR_NAN) {
|
|
if (GetHdbProp(node, "geterror") == NULL) {
|
|
SetHdbProperty(node, "geterror", "undefined");
|
|
value.v.doubleValue = 0;
|
|
UpdateHipadabaPar(node, value, ctx->con);
|
|
}
|
|
return;
|
|
}
|
|
if (skip_unchanged && node->value.v.doubleValue == value.v.doubleValue) return;
|
|
break;
|
|
case HIPINT:
|
|
if (value.v.intValue == PAR_LNAN) {
|
|
if (GetHdbProp(node, "geterror") == NULL) {
|
|
SetHdbProperty(node, "geterror", "undefined");
|
|
value.v.intValue = 0;
|
|
UpdateHipadabaPar(node, value, ctx->con);
|
|
}
|
|
return;
|
|
}
|
|
if (skip_unchanged && node->value.v.intValue == value.v.intValue) return;
|
|
break;
|
|
case HIPTEXT:
|
|
if (skip_unchanged && strcmp(node->value.v.text, value.v.text) == 0) return;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
SetHdbProperty(node, "geterror", NULL);
|
|
UpdateHipadabaPar(node, value, ctx->con);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParFloat(float *value, float defValue)
|
|
{
|
|
char *endp;
|
|
float f;
|
|
char buf[132];
|
|
|
|
switch (ParWhat(1)) {
|
|
case SET_OP:
|
|
if (ctx->action == PAR_HDBSET) {
|
|
*value = ctx->hvalue->v.doubleValue;
|
|
break;
|
|
}
|
|
if (ctx->argc > 1) {
|
|
ctx->returnValue = ILLARGC;
|
|
return;
|
|
}
|
|
if (ctx->valueArg) {
|
|
f = ParText2Int(ctx->valueArg);
|
|
if (f < 0) {
|
|
f = strtod(ctx->valueArg, &endp);
|
|
if (endp == ctx->valueArg) {
|
|
ctx->returnValue = ILLNUM;
|
|
break;
|
|
}
|
|
}
|
|
*value = f;
|
|
}
|
|
ParHasChanged();
|
|
/* fall through */
|
|
case FMT_OP:
|
|
if (*value == PAR_NAN) {
|
|
ctx->fmt = NULL;
|
|
/* ctx->returnValue = PARUNDEF; */
|
|
ParOut("");
|
|
} else {
|
|
if (ctx->fmt == NULL) {
|
|
ctx->fmt = "%.5g";
|
|
}
|
|
snprintf(buf, sizeof buf, ctx->fmt, *value);
|
|
ctx->fmt = NULL;
|
|
ParOut(buf);
|
|
}
|
|
break;
|
|
case GET_OP:
|
|
ctx->value = *value;
|
|
ctx->returnValue = 1;
|
|
break;
|
|
case INIT_OP:
|
|
*value = defValue;
|
|
ParUpdateNode(MakeHdbFloat(*value));
|
|
break;
|
|
case UPD_OP:
|
|
ParUpdateNode(MakeHdbFloat(*value));
|
|
break;
|
|
case NO_OP:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParInt(int *value, int defValue)
|
|
{
|
|
char *endp;
|
|
int i;
|
|
char buf[132];
|
|
|
|
switch (ParWhat(1)) {
|
|
case SET_OP:
|
|
if (ctx->action == PAR_HDBSET) {
|
|
*value = ctx->hvalue->v.intValue;
|
|
break;
|
|
}
|
|
if (ctx->argc > 1) {
|
|
ctx->returnValue = ILLARGC;
|
|
return;
|
|
}
|
|
if (ctx->valueArg) {
|
|
i = ParText2Int(ctx->valueArg);
|
|
if (i < 0) {
|
|
i = strtol(ctx->valueArg, &endp, 0);
|
|
if (endp == ctx->valueArg) {
|
|
ctx->returnValue = ILLNUM;
|
|
break;
|
|
}
|
|
}
|
|
*value = i;
|
|
}
|
|
ParHasChanged();
|
|
/* fall through */
|
|
case FMT_OP:
|
|
if (*value == PAR_LNAN) {
|
|
/* ctx->returnValue = PARUNDEF; */
|
|
ParOut(""); /* undefined */
|
|
} else {
|
|
snprintf(buf, sizeof buf, "%d", *value);
|
|
ParOut(buf);
|
|
}
|
|
break;
|
|
case GET_OP:
|
|
ctx->value = *value;
|
|
ctx->returnValue = 1;
|
|
break;
|
|
case INIT_OP:
|
|
*value = defValue;
|
|
ParUpdateNode(MakeHdbInt(defValue));
|
|
break;
|
|
case UPD_OP:
|
|
ParUpdateNode(MakeHdbInt(*value));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParStr(char **value, char *defValue)
|
|
{
|
|
static char *empty = "";
|
|
char *to_free;
|
|
|
|
switch (ParWhat(0)) {
|
|
case SET_OP:
|
|
to_free = *value;
|
|
if (ctx->action == PAR_HDBSET) {
|
|
if (to_free) free(to_free);
|
|
*value = strdup(ctx->hvalue->v.text);
|
|
break;
|
|
}
|
|
if (to_free) free(to_free);
|
|
if (ctx->argc > 0 && strcmp(ctx->argv[0], "=") == 0) {
|
|
*value = ParArg2Str(ctx->argc - 1, ctx->argv + 1, NULL, 0);
|
|
} else {
|
|
*value = ParArg2Str(ctx->argc, ctx->argv, NULL, 0);
|
|
}
|
|
ParHasChanged();
|
|
/* fall through */
|
|
case FMT_OP:
|
|
if (*value == NULL) {
|
|
ParOut(empty);
|
|
} else {
|
|
ParOut(*value);
|
|
}
|
|
break;
|
|
case INIT_OP:
|
|
ctx->exact = 1;
|
|
if (defValue == NULL) {
|
|
ParUpdateNode(MakeHdbText(""));
|
|
} else{
|
|
*value = strdup(defValue);
|
|
ParUpdateNode(MakeHdbText(*value));
|
|
}
|
|
break;
|
|
case UPD_OP:
|
|
if (*value == NULL) {
|
|
ParUpdateNode(MakeHdbText(""));
|
|
} else {
|
|
ParUpdateNode(MakeHdbText(*value));
|
|
}
|
|
break;
|
|
default:
|
|
if (ctx->act == PAR_KILL && *value != NULL) {
|
|
free(*value);
|
|
*value = NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParFixedStr(char *value, int maxsize, char *defValue)
|
|
{
|
|
|
|
switch (ParWhat(0)) {
|
|
case SET_OP:
|
|
if (ctx->action == PAR_HDBSET) {
|
|
snprintf(value, maxsize, "%s", ctx->hvalue->v.text);
|
|
break;
|
|
}
|
|
ParArg2Str(ctx->argc, ctx->argv, value, maxsize);
|
|
ParHasChanged();
|
|
/* fall through */
|
|
case FMT_OP:
|
|
if (value == NULL)
|
|
value = "";
|
|
ParOut(value);
|
|
break;
|
|
case INIT_OP:
|
|
ctx->exact = 1;
|
|
if (defValue == NULL) {
|
|
ParUpdateNode(MakeHdbText(""));
|
|
} else{
|
|
snprintf(value, maxsize, "%s", defValue);
|
|
ParUpdateNode(MakeHdbText(value));
|
|
}
|
|
break;
|
|
case UPD_OP:
|
|
ParUpdateNode(MakeHdbText(value));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int ParCmd(ParCommand cmd, void *userarg)
|
|
{
|
|
int iret;
|
|
|
|
if (ctx->action != PAR_SHOW && ctx->action != PAR_SET)
|
|
return 0;
|
|
if (ctx->access < 0)
|
|
ctx->access = usUser;
|
|
if (!RestoreMode() && ctx->access < SCGetRights(ctx->con)) {
|
|
ctx->returnValue = ILLPRIV;
|
|
ctx->action = PAR_NOOP;
|
|
return 0;
|
|
}
|
|
iret = cmd(ctx->obj, userarg, ctx->argc, ctx->argv);
|
|
if (iret == 0) {
|
|
ctx->returnValue = ERRCMD;
|
|
return -1;
|
|
}
|
|
ctx->returnValue = iret;
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int ParActionIs(ParAct a)
|
|
{
|
|
if (ctx->action == a)
|
|
return 1;
|
|
if (ctx->act == a)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
char *ParGetValueArg()
|
|
{
|
|
char *ret;
|
|
if (ctx->action == PAR_SET) {
|
|
ret = ctx->valueArg;
|
|
ctx->valueArg = NULL;
|
|
return ret;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void *ParObject(void)
|
|
{
|
|
return ctx->obj;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParStdDef(void)
|
|
{
|
|
ParName("verbose");
|
|
ParAccess(usUser);
|
|
ParSave(0);
|
|
ParLogAs(NULL);
|
|
ParInt(&ctx->obj->verbose, 1);
|
|
ParName("driver");
|
|
ParLogAs(NULL);
|
|
ParStr(&ctx->obj->desc->name, NULL);
|
|
ParName("creationCmd");
|
|
ParLogAs(NULL);
|
|
ParStr(&ctx->obj->creationCmd, NULL);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParGetFloat(SConnection * con, void *object, char *name, float *value)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
|
|
ParBegin();
|
|
ParDo(con, o, PAR_GET, name);
|
|
if (ctx->returnValue == 1) {
|
|
*value = ctx->value;
|
|
} else {
|
|
if (ctx->returnValue == 0) {
|
|
ctx->returnValue = UNKPAR;
|
|
}
|
|
if (con != NULL) {
|
|
ParOutError(con, o);
|
|
}
|
|
}
|
|
ParEnd();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParKillThisPar(ParInfo *p)
|
|
{
|
|
p->next = NULL;
|
|
if (p->node) {
|
|
RemoveSICSPar(p->node, NULL);
|
|
}
|
|
KillLogger(p);
|
|
if (p->name) {
|
|
free(p->name);
|
|
}
|
|
free(p);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParKillPar(void *object, char *name)
|
|
{
|
|
ParData *o = object;
|
|
ParInfo *p, **last;
|
|
|
|
last = &o->infoList;
|
|
for (p=o->infoList; p!=NULL; last=&p->next, p=p->next) {
|
|
if (strcasecmp(name, p->name) == 0) {
|
|
*last = p->next;
|
|
ParKillThisPar(p);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParKill(void *object)
|
|
{
|
|
ParData *o = ParCheck(&parClass, object);
|
|
ParInfo *p, *q;
|
|
|
|
ParBegin();
|
|
ParDo(NULL, o, PAR_KILL, NULL); /* free dynamic strings and custom content */
|
|
if (o->name)
|
|
free(o->name);
|
|
if (o->creationCmd)
|
|
free(o->creationCmd);
|
|
if (o->pCall)
|
|
DeleteCallBackInterface(o->pCall);
|
|
if (o->desc)
|
|
DeleteDescriptor(o->desc);
|
|
if (o->conn)
|
|
SCDeleteConnection(o->conn);
|
|
p = o->infoList;
|
|
while (p) {
|
|
q = p->next;
|
|
if (p->node == o->node) {
|
|
p->node = NULL; /* avoid removing the object node, this is done below */
|
|
}
|
|
ParKillThisPar(p);
|
|
p = q;
|
|
}
|
|
if (o->node) {
|
|
RemoveSICSPar(o->node, NULL); /* this deletes also all children */
|
|
o->node = NULL;
|
|
}
|
|
if (o->logPending) { /* will be free in scheduled ParLog function */
|
|
o->desc = NULL;
|
|
} else {
|
|
free(o);
|
|
}
|
|
ParEnd();
|
|
if (ctx == NULL && pServ->pSics->iDeleting) { /* finish, no more contexts nested -> free all of them */
|
|
while (freeContexts) {
|
|
ctx = freeContexts->next;
|
|
free(freeContexts);
|
|
freeContexts = ctx;
|
|
}
|
|
ctx = NULL;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParInitPar(void *object, char *name, int logged)
|
|
{
|
|
ParBegin();
|
|
ctx->obj = object;
|
|
ctx->parName = name;
|
|
ctx->par = NULL;
|
|
ParFind();
|
|
if (logged) {
|
|
if (secop_logger) {
|
|
if (ctx->par) {
|
|
ctx->par->log = secop_logger;
|
|
}
|
|
} else {
|
|
ParSwitchLog(1, NULL);
|
|
}
|
|
}
|
|
ParEnd();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void *ParMake(SConnection * con, char *name, ParClass * class,
|
|
ParDef pardef, char *creationCmd)
|
|
{
|
|
ParData *o;
|
|
int i;
|
|
|
|
assert(pardef);
|
|
o = FindCommandData(pServ->pSics, name, class->name);
|
|
if (o != NULL) {
|
|
SCPrintf(con, eWarning, "overwrite '%s'", name);
|
|
RemoveCommand(pServ->pSics, name);
|
|
}
|
|
o = calloc(1, class->size);
|
|
assert(o);
|
|
o->class = class;
|
|
ParCheck(&parClass, o);
|
|
if (!AddCommand(pServ->pSics, name, ParExecute, ParKill, o)) {
|
|
SCPrintf(con, eError, "'%s' already exists as different object", name);
|
|
free(o);
|
|
return NULL;
|
|
}
|
|
o->name = strdup(name);
|
|
assert(o->name);
|
|
o->desc = CreateDescriptor(class->name);
|
|
assert(o->desc);
|
|
o->desc->SaveStatus = ParSaveAll;
|
|
SetDescriptorKey(o->desc, "pardef", "1");
|
|
o->creationCmd = creationCmd;
|
|
o->pCall = NULL;
|
|
o->logTime = 0;
|
|
o->period = 5;
|
|
o->infoList = NULL;
|
|
o->verbose = 0;
|
|
o->logPending = 0;
|
|
o->conn = NULL;
|
|
o->node = NULL;
|
|
ParSaveConn(o, con);
|
|
o->pardef = pardef;
|
|
ParBegin();
|
|
ParDo(con, o, PAR_INIT, NULL);
|
|
SCparChange(con);
|
|
initObj = o;
|
|
ParEnd();
|
|
return o;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void ParStartup(void)
|
|
{
|
|
}
|