Files
sicspsi/pardef.c
2006-08-17 15:39:37 +00:00

1280 lines
33 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 <ctype.h>
#include "logger.h"
#include "pardef.h"
#include "sugar.h"
#include "commandlog.h"
#define ILLNUM -2
#define ILLARGC -3
#define AMBIGUOS -4
#define ILLPRIV -5
#define BADLOG -6
#define UNKPAR -7
typedef enum { NO_OP, FMT_OP, SET_OP, GET_OP, INIT_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;
} 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 = SCLoad(&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 = eStatus;
}
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) {
WriteToCommandLog(">", 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;
}
/*-------------------------------------------------------------------------*/
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;
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;
}
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;
assert(0==strcasecmp(o->name, name));
if (o->creationCmd) {
fprintf(fil, "if {[catch { %s }] == 0} {\n", o->creationCmd);
}
ParDo(0, o, PAR_SAVE, NULL);
if (o->creationCmd) {
fprintf(fil, " %s endinit\n}\n", name);
}
ctx->saveFile = NULL;
ret = ctx->returnValue;
ParEnd();
return ret;
}
/*--------------------------------------------------------------------------*/
FILE *ParSaveFile(void) {
if (ctx) {
return ctx->saveFile;
}
return NULL;
}
/*--------------------------------------------------------------------------*/
int ParLog(void *object) {
ParData *o = ParCheck(&parClass, object);
int next;
ParBegin();
ctx->now = time(NULL);
next = ctx->now - (o->logTime / o->period + 1) * o->period;
if (next >= 0) {
showTime = 1;
ParDo(0, o, PAR_LOG, NULL);
o->logTime = ctx->now;
o->logPending = 0;
}
ParEnd();
return next;
}
/*--------------------------------------------------------------------------*/
void ParLogForced(void *object) {
ParData *o = ParCheck(&parClass, object);
int next;
ParBegin();
ctx->now = time(NULL);
showTime = 1;
ParDo(0, o, PAR_LOG, NULL);
o->logTime = ctx->now;
o->logPending = 0;
ParEnd();
}
/*-------------------------------------------------------------------------*/
static int ParCallBack(int event, void *eventData, void *userData,
commandContext cc) {
char *pBuf = (char *)eventData;
SConnection *con = (SConnection *)userData;
if (event == VALUECHANGE) {
SCPushContext2(con,cc);
SCWrite(con,pBuf,eValue);
SCPopContext(con);
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", 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 BUSY:
SCPrintf(con, eError, "ERROR: %s busy", o->name);
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, eStatus);
}
/*----------------------------------------------------------------------------*/
void ParSaveConn(void *object, SConnection *con) {
ParData *o = ParCheck(&parClass, object);
int rights;
rights = SCGetRights(con);
if (rights >= usMugger && rights <= usUser && con->pSock != NULL) {
SCSave(&o->conn, con);
}
}
/*----------------------------------------------------------------------------*/
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];
ParBegin();
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 */
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 {
ctx->argc = argc - 3;
ctx->argv = argv + 3;
ctx->doit = toupper(argv[1][0]) != 'U';
ctx->exact = 1;
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 {
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, SCGetContext(con),VALUECHANGE, ParCallBack, con, NULL);
SCRegister(con, pServ->pSics, o->pCall, id);
SCSendOK(con);
ParEnd();
return 1;
} else if (strcmp(argv[1],"uninterest") == 0) {
if (o->pCall) {
RemoveCallback2(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], "=") == 0) {
ctx->argc = argc - 2;
ctx->argv = argv + 2;
ctx->valueArg = argv[2];
ParDo(con, o, PAR_SET, "");
logIt = 1;
} else {
if (argc == 2) {
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) {
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);
}
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 = ctx->parName;
p->log = NULL;
p->saveIt = 0;
p->saveLog = 0;
p->state = PAR_ALWAYS_READY;
p->next = *last;
*last = p;
}
}
ctx->par = p;
}
/*--------------------------------------------------------------------------*/
long ParText2Int(char *text) {
long num = 0;
if (strcasecmp(text, "undefined") == 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:
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 = 1; /* exact by default */
return;
case PAR_GET:
if (0 != strcasecmp(name, ctx->thisPar)) {
ctx->action = PAR_NOOP;
}
return;
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;
}
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_SET:
if (ctx->returnValue) {
ctx->returnValue = AMBIGUOS;
break;
}
if (ctx->access < 0) {
ctx->access = usInternal;
}
if (ctx->access < SCGetRights(ctx->con) && !RestoreMode()) {
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) {
return FMT_OP;
}
break;
case PAR_GET:
if (ctx->returnValue) {
ctx->returnValue = AMBIGUOS;
break;
}
return GET_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->obj->name, ctx->parName);
} else {
snprintf(buffer, sizeof buffer, "%s", ctx->obj->name);
}
}
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->obj->name);
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) {
saved = " (saved)";
}
}
ParPrintf(NULL, eWarning, "%s %*s%*s%s%s", buffer, l, p, m, ctx->listTail, logged, saved);
break;
case PAR_SHOW:
if (ctx->parName[0]) { p=" "; } else { p=""; }
ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->obj->name, p, ctx->parName, buf);
break;
case PAR_SET:
if (ctx->parName[0]) { p=" "; } else { p=""; }
ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->obj->name, p, ctx->parName, buf);
if (!ctx->obj->logPending) {
ctx->obj->logPending = 1;
TaskRegister(pServ->pTasker, ParLog, NULL, NULL, ctx->obj, 0); /* 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:
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;
}
}
/*----------------------------------------------------------------------------*/
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;
}
}
}
/*----------------------------------------------------------------------------*/
void ParTail(char *tail) {
if (ctx->action == PAR_LIST) {
ctx->listTail = tail;
}
}
/*----------------------------------------------------------------------------*/
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);
}
}
}
/*----------------------------------------------------------------------------*/
void ParFloat(float *value, float defValue) {
char *endp;
float f;
char buf[132];
switch (ParWhat(1)) {
case SET_OP:
if (ctx->argc > 1) {
ctx->returnValue = ILLARGC;
return;
}
if (ctx->valueArg) {
f = strtod(ctx->valueArg, &endp);
if (endp == ctx->valueArg) {
f = ParText2Int(ctx->valueArg);
if (f < 0) {
ctx->returnValue = ILLNUM;
break;
}
}
*value = f;
}
ParHasChanged();
/* fall through */
case FMT_OP:
if (*value == PAR_NAN) {
ctx->fmt = NULL;
ParOut("undefined");
} 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;
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->argc > 1) {
ctx->returnValue = ILLARGC;
return;
}
if (ctx->valueArg) {
i = strtol(ctx->valueArg, &endp, 0);
if (endp == ctx->valueArg) {
i = ParText2Int(ctx->valueArg);
if (i < 0) {
ctx->returnValue = ILLNUM;
break;
}
}
*value = i;
}
ParHasChanged();
/* fall through */
case FMT_OP:
if (*value == PAR_LNAN) {
ParOut("undefined");
} else {
snprintf(buf, sizeof buf, "%d", *value);
ParOut(buf);
}
break;
case INIT_OP:
*value = defValue;
break;
default: break;
}
}
/*----------------------------------------------------------------------------*/
void ParStr(char **value, char *defValue) {
static char *empty="";
switch (ParWhat(0)) {
case SET_OP:
if (*value != NULL) free(*value);
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) value = &empty;
ParOut(*value);
break;
case INIT_OP:
if (defValue != NULL) {
*value = strdup(defValue);
}
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:
ParArg2Str(ctx->argc, ctx->argv, value, maxsize);
ParHasChanged();
/* fall through */
case FMT_OP:
if (value == NULL) value = "";
ParOut(value);
break;
case INIT_OP:
if (defValue != NULL) {
snprintf(value, maxsize, "%s", defValue);
}
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 (ctx->access < SCGetRights(ctx->con) && !RestoreMode()) {
ctx->returnValue = ILLPRIV;
ctx->action = PAR_NOOP;
return 0;
}
ctx->returnValue = 1;
return cmd(ctx->obj, userarg, ctx->argc, ctx->argv);
}
/*----------------------------------------------------------------------------*/
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;
}
/*----------------------------------------------------------------------------*/
static int ParEndInit(void *object, void *arg, int argc, char *argv[]) {
initObj = NULL;
return 1;
}
/*----------------------------------------------------------------------------*/
void ParStdDef(void) {
ParName("endinit"); ParCmd(ParEndInit, NULL);
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 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);
p = o->infoList;
while (p) {
q = p->next;
p->next = NULL;
KillLogger(p);
free(p);
p = q;
}
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) {
ParBegin();
ctx->obj = object;
ctx->parName = name;
ctx->par = NULL;
ParFind();
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;
o->creationCmd = creationCmd;
o->pCall = NULL;
o->logTime = 0;
o->period = 5;
o->infoList = NULL;
o->verbose = 0;
ParSaveConn(o, con);
o->pardef = pardef;
ParBegin();
ParDo(con, o, PAR_INIT, NULL);
SCparChange(con);
initObj = o;
ParEnd();
return o;
}
/*----------------------------------------------------------------------------*/
void ParStartup(void) {
}