diff --git a/logreader.c b/logreader.c new file mode 100644 index 0000000..5781473 --- /dev/null +++ b/logreader.c @@ -0,0 +1,414 @@ +#include +#include +#include +#include +#include +#include +#include "logger.h" +#include "sics.h" + +#define LOGGER_NAN -999999. +#define ONE_YEAR (366*24*3600) + +typedef enum { NUMERIC, TEXT } CompType; + +typedef struct { + SConnection *pCon; + char *var; + int exact; + CompType type; + time_t step; + time_t tlim; + time_t tmin, tmax, tlast, told; + float ymin, ymax, ylast, yold; + char slast[256]; + char set[256]; + int np; +} Compressor; + +static char *dir = NULL; +static char *dir2 = NULL; + +static void InitCompressor(Compressor *c, SConnection *pCon, time_t step) { + c->pCon = pCon; + c->step = step; + c->tmin = -2; + c->tmax = 0; + c->tlast = 0; + c->tlim = 0; + c->told = 0; + c->slast[0]='\0'; + c->ylast = LOGGER_NAN; +} + +static void OutString(Compressor *c, time_t t, char *str) { + char line[256]; + + /* printf("out %ld %g\n", t, y); */ + if (0 != strcmp(str, c->slast)) { + snprintf(line, sizeof line, "%ld %s\n", (long)(t - c->tlast), str); + c->tlast = t; + c->slast[0]='\0'; + strncat(c->slast, str, sizeof c->slast - 1); + SCWrite(c->pCon, line, eWarning); + c->np--; + } +} + +static void OutFloat(Compressor *c, time_t t, float y) { + char line[80]; + + /* printf("out %ld %g\n", t, y); */ + if (y != c->ylast || !c->exact) { + c->ylast = y; + if (y == LOGGER_NAN) { + snprintf(line, sizeof line, "%ld\n", (long)(t - c->tlast)); + } else { + snprintf(line, sizeof line, "%ld %g\n", (long)(t - c->tlast), y); + } + /* printf("-%s\n", line); */ + c->tlast = t; + SCWrite(c->pCon, line, eWarning); + c->np--; + } +} + +static void PutValue(Compressor *c, time_t t, char *value) { + char *p; + double y; + + if (c->var) { + SCPrintf(c->pCon, eWarning, "*%s exact %d\n", c->var, c->exact); + c->var = NULL; + } + if (c->type == NUMERIC) { + if (t == 0) { /* finish */ + t = c->tlim + 3 * c->step; + y = 0; + } else { + y = strtod(value, &p); + if (p == value) { + y = LOGGER_NAN; + } else { + if (y == LOGGER_NAN) y *= 1.0000002; + } + } + /* printf("put %ld %g\n", t, y); */ + if (c->tlim == 0) goto first; + if (t >= c->tlim) { + c->tlim += c->step; + if (c->tmin > c->tmax) { + OutFloat(c, c->tmax, c->ymax); + c->ymax = c->ymin; + c->tmax = c->tmin; + } else { + OutFloat(c, c->tmin, c->ymin); + if (c->tmin == c->tmax) goto first; + c->ymin = c->ymax; + c->tmin = c->tmax; + } + if (t >= c->tlim) { + OutFloat(c, c->tmin, c->ymin); + if (t >= c->tlim + c->step) { + OutFloat(c, c->told, c->yold); + } + goto first; + } + } + if (y <= c->ymin) { + c->ymin = y; + c->tmin = t; + } else if (y > c->ymax) { + c->ymax = y; + c->tmax = t; + } + c->yold = y; + c->told = t; + return; + first: + c->tlim = t + 2 * c->step; + c->tmin = t; + c->tmax = t; + c->ymin = y; + c->ymax = y; + return; + } else if (c->type == TEXT) { + if (t != 0) OutString(c, t, value); + } +} +/*--------------------------------------------------------------------------*/ +static long getOpt(char *line, int *isdst, int *exact) { + long lxs; + char *opt; + + opt = strstr(line, "isdst"); + if (opt) { + sscanf(opt, "isdst %d", isdst); + } + opt = strstr(line, "exact"); + if (opt) { + sscanf(opt, "exact %d", exact); + } + opt = strstr(line, "period"); + if (opt) { + sscanf(opt, "period %ld", &lxs); + return lxs; + } else { + return -1; + } +} +/*--------------------------------------------------------------------------*/ +static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + time_t from, to, step, xs, lastt, now; + long lxs; + char *p; + int i, iarg0, l, iret, loss, np; + int inRange; + int yday=0; + time_t t, startim; + struct tm tm; + char stim[32], path[256], line[256], lastval[256]; + char *lin, *val, *stp; + FILE *fil; + Compressor c; + float yy, lasty; + CompType type0; + DIR *dr; + char *opt; + int isdst; + int overflow; + + /* argtolower(argc, argv); */ + if (argc < 4) goto illarg; + now = time(NULL); + from = strtol(argv[1], &p, 0); /* unix time, not year 2038 safe */ + if (p == argv[1]) goto illarg; + to = strtol(argv[2], NULL, 0); + if (p == argv[2]) goto illarg; + if (from < ONE_YEAR) { + from += now; + } + if (to < ONE_YEAR) { + to += now; + } + iarg0 = 4; + if (strcasecmp(argv[3],"text") == 0) { /* non-numeric values */ + step = 1; + type0 = TEXT; + np = from - to + 2; + } else if (strcasecmp(argv[3],"np") == 0) { /* max. number of points */ + type0 = NUMERIC; + iarg0 = 5; + np = strtol(argv[4], NULL, 0); + if (to <= from) { + step = 1; + } else if (np <= 2) { + step = to - from; + } else { + step = (to - from) / (np - 2) + 1; + } + } else { + step = strtol(argv[3], NULL, 0); + if (step <= 0) step = 1; + type0 = NUMERIC; + np = (from - to) / step + 2; + } + if (p == argv[3]) goto illarg; + if (step <= 0) step = 1; + + snprintf(line, sizeof line, "%ld\n", (long)now); + SCWrite(pCon, line, eWarning); + + if (dir == NULL) { + dir = IFindOption(pSICSOptions, "LoggerDir"); + if (dir == NULL) { + SCWrite(pCon, "LoggerDir not found", eError); + return 0; + } + LoggerSetDir(dir); + } + if (dir2 == NULL) { + dir2 = IFindOption(pSICSOptions, "LoggerDir2"); + if (dir2 == NULL) dir2=""; + } + + loss = 0; + overflow = 0; + for (i=iarg0; i= 0) { + if (lxs == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = lxs; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + } + } + } + if (fil == NULL) { + lin = NULL; + } else { + do { + lin = fgets(line, sizeof line, fil); + /* printf("%s\n", line); */ + if (lin == NULL) break; + if (line[0] == '#') { + lxs = getOpt(line, &isdst, &c.exact); + if (lxs >= 0) { + if (lxs == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = lxs; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + lin[0]='\0'; + } else { + p = strchr(line, '\n'); if (p) *p='\0'; + p = strchr(line, '#'); if (p) *p='\0'; + } + } while (lin[0] == '\0'); + } + if (lin != NULL) { + /* printf(" %s\n", line); */ + p = strchr(line, '\t'); + if (p) { + *p='\0'; + val = p+1; + } else { + val = ""; + } + p = strchr(val, '\t'); + if (p) { + stp = p+1; + *p='\0'; + iret = sscanf(stp, "%ld", &lxs); + if (iret == 1) { + if (lxs == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = lxs; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + } + iret = sscanf(line, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if (iret != 3) { + lin = NULL; + } else { + tm.tm_isdst = isdst; + t=mktime(&tm); + if (!inRange) { + if (t < startim) { + lastval[0]='\0'; + strncat(lastval, val, sizeof lastval - 1); + lastt = t; + } else { + inRange=1; + if (lastt != 0) { + PutValue(&c, lastt, lastval); + } + PutValue(&c, t, val); + } + } else { + PutValue(&c, t, val); + } + } + } + if (lin == NULL) { + tm.tm_hour = 24; /* try next day */ + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + startim=mktime(&tm); + continue; + } + } + if (!inRange) { + if (lastt != 0) { + PutValue(&c, lastt, lastval); + } + } + c.ylast = LOGGER_NAN; /* force output of last value */ + PutValue(&c, 0, ""); /* finish */ + if (fil) { + fclose(fil); + fil = NULL; + } + if (c.np < 0) overflow = 1; + } + snprintf(line, sizeof line, "*%d %d\n", loss, overflow); + SCWrite(pCon, line, eWarning); + return 1; +illarg: + SCWrite(pCon, "illegal argument(s)", eError); + return 0; +} +/*--------------------------------------------------------------------------*/ +static void KillLogReader(void *data) { + Logger *p, *next; + + KillDummy(data); + LoggerFreeAll(); +} +/*--------------------------------------------------------------------------*/ +void LogReaderInit(void) { + AddCommand(pServ->pSics,"Graph",LogReader,KillLogReader,NULL); +}