/*--------------------------------------------------------------------------- pardef.c my way to define and handle object parameters Markus Zolliker, March 2005 ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #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= 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, "