char *start
char *end
PREINIT:
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
char *parsetime_error = NULL;
time_t start_tmp, end_tmp;
PPCODE:
rrd_clear_error();
- if( (parsetime_error = parsetime( start, &start_tv))) {
- rrd_set_error( "start time: %s", parsetime_error);
+ if ((parsetime_error = rrd_parsetime(start, &start_tv))) {
+ rrd_set_error("start time: %s", parsetime_error);
XSRETURN_UNDEF;
}
- if( (parsetime_error = parsetime( end, &end_tv))) {
- rrd_set_error( "end time: %s", parsetime_error);
+ if ((parsetime_error = rrd_parsetime(end, &end_tv))) {
+ rrd_set_error("end time: %s", parsetime_error);
XSRETURN_UNDEF;
}
- if( proc_start_end( &start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
XSRETURN_UNDEF;
}
EXTEND(sp,2);
rrd_info(...)
PROTOTYPE: @
PREINIT:
- info_t *data,*save;
+ rrd_info_t *data,*save;
int i;
char **argv;
HV *hash;
rrd_updatev(...)
PROTOTYPE: @
PREINIT:
- info_t *data,*save;
+ rrd_info_t *data,*save;
int i;
char **argv;
HV *hash;
rrd_graphv(...)
PROTOTYPE: @
PREINIT:
- info_t *data,*save;
+ rrd_info_t *data,*save;
int i;
char **argv;
HV *hash;
}
static PyObject *PyDict_FromInfo(
- info_t *data)
+ rrd_info_t *data)
{
PyObject *r;
PyObject *r;
int argc;
char **argv;
- info_t *data;
+ rrd_info_t *data;
if (create_args("info", args, &argc, &argv) < 0)
return NULL;
return NULL;
}
r = PyDict_FromInfo(data);
- info_free(data);
+ rrd_info_free(data);
return r;
}
PyObject *r;
int argc;
char **argv;
- info_t *data;
+ rrd_info_t *data;
if (create_args("graphv", args, &argc, &argv) < 0)
return NULL;
return NULL;
}
r = PyDict_FromInfo(data);
- info_free(data);
+ rrd_info_free(data);
return r;
}
PyObject *r;
int argc;
char **argv;
- info_t *data;
+ rrd_info_t *data;
if (create_args("updatev", args, &argc, &argv) < 0)
return NULL;
return NULL;
}
r = PyDict_FromInfo(data);
- info_free(data);
+ rrd_info_free(data);
return r;
}
VALUE args)
{
string_arr a;
- info_t *p, *data;
+ rrd_info_t *p, *data;
VALUE result;
a = string_arr_new(args);
time_t last_up = time(NULL) - 10;
long int long_tmp;
unsigned long int pdp_step = 300;
- struct rrd_time_value last_up_tv;
+ rrd_time_value_t last_up_tv;
argv2 = getopt_init(argc, argv);
getopt_cleanup(argc, argv2);
return TCL_ERROR;
}
- if ((parsetime_error = parsetime(argv2[argv_i], &last_up_tv))) {
+ if ((parsetime_error = rrd_parsetime(argv2[argv_i], &last_up_tv))) {
Tcl_AppendResult(interp, "RRD Error: invalid time format: '",
argv2[argv_i], "'", (char *) NULL);
getopt_cleanup(argc, argv2);
=item *
-Do not use the C<parsetime> function!
+Do not use the C<rrd_parsetime> function!
It uses lots of global variables. You may use it in functions not designed
to be thread-safe, like in functions wrapping the C<_r> version of some
$(OBJDIR)/rrd_getopt1.o \
$(OBJDIR)/art_rgba_svp.o \
$(OBJDIR)/hash_32.o \
- $(OBJDIR)/parsetime.o \
+ $(OBJDIR)/rrd_parsetime.o \
$(OBJDIR)/pngsize.o \
$(EOLIST)
UPD_C_FILES = \
rrd_getopt.c \
rrd_getopt1.c \
- parsetime.c \
+ rrd_parsetime.c \
rrd_hw.c \
rrd_hw_math.c \
rrd_hw_update.c \
rrd_gfx.c \
rrd_dump.c \
rrd_fetch.c \
- rrd_tool.c \
rrd_resize.c \
rrd_tune.c
noinst_HEADERS = \
unused.h \
- rrd_getopt.h parsetime.h \
+ rrd_getopt.h rrd_parsetime.h \
rrd_i18n.h \
rrd_format.h rrd_tool.h rrd_xport.h rrd.h rrd_rpncalc.h \
rrd_hw.h rrd_hw_math.h rrd_hw_update.h \
librrdupd_la_LIBADD = $(CORE_LIBS) @LIB_LIBINTL@
librrd_la_SOURCES = $(RRD_C_FILES)
+librrd_la_DEPENDENCIES = librrdupd.la librrd.sym
librrd_la_LIBADD = librrdupd.la $(ALL_LIBS)
-
-# see http://sourceware.org/autobook/autobook/autobook_91.html
-
librrd_la_LDFLAGS = -version-info @LIBVERS@
+librrd_la_LDFLAGS += -export-symbols librrd.sym
librrd_th_la_SOURCES = $(UPD_C_FILES) $(RRD_C_FILES) rrd_thread_safe.c
+librrd_th_la_DEPENDENCIES = librrd.sym
librrd_th_la_CFLAGS = $(MULTITHREAD_CFLAGS)
librrd_th_la_LDFLAGS = $(MULTITHREAD_LDFLAGS) -version-info @LIBVERS@
+librrd_th_la_LDFLAGS += -export-symbols librrd.sym
librrd_th_la_LIBADD = $(ALL_LIBS)
include_HEADERS = rrd.h
rrdupdate_SOURCES = rrdupdate.c
rrdupdate_LDADD = librrdupd.la
-rrdtool_SOURCES =
-rrdtool_DEPENDENCIES = rrd_tool.o librrd.la
+rrdtool_SOURCES = rrd_tool.c
+rrdtool_DEPENDENCIES = librrd.la
rrdtool_LDADD = librrd.la
# strftime is here because we do not usually need it. unices have propper
--- /dev/null
+rrd_clear_error
+rrd_create
+rrd_create_r
+rrd_dump
+rrd_dump_r
+rrd_fetch
+rrd_fetch_r
+rrd_first
+rrd_first_r
+rrd_free_context
+rrd_get_context
+rrd_get_error
+rrd_graph
+rrd_graph_v
+rrd_info
+rrd_info_free
+rrd_info_print
+rrd_info_push
+rrd_last
+rrd_last_r
+rrd_lastupdate
+rrd_new_context
+rrd_parsetime
+rrd_proc_start_end
+rrd_resize
+rrd_restore
+rrd_set_error
+rrd_set_to_DINF
+rrd_set_to_DNAN
+rrd_strerror
+rrd_strversion
+rrd_test_error
+rrd_tune
+rrd_update
+rrd_update_r
+rrd_update_v
+rrd_version
+rrd_xport
+++ /dev/null
-/*
- * parsetime.c - parse time for at(1)
- * Copyright (C) 1993, 1994 Thomas Koenig
- *
- * modifications for English-language times
- * Copyright (C) 1993 David Parsons
- *
- * A lot of modifications and extensions
- * (including the new syntax being useful for RRDB)
- * Copyright (C) 1999 Oleg Cherevko (aka Olwi Deer)
- *
- * severe structural damage inflicted by Tobi Oetiker in 1999
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author(s) may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* NOTE: nothing in here is thread-safe!!!! Not even the localtime
- calls ... */
-
-/*
- * The BNF-like specification of the time syntax parsed is below:
- *
- * As usual, [ X ] means that X is optional, { X } means that X may
- * be either omitted or specified as many times as needed,
- * alternatives are separated by |, brackets are used for grouping.
- * (# marks the beginning of comment that extends to the end of line)
- *
- * TIME-SPECIFICATION ::= TIME-REFERENCE [ OFFSET-SPEC ] |
- * OFFSET-SPEC |
- * ( START | END ) OFFSET-SPEC
- *
- * TIME-REFERENCE ::= NOW | TIME-OF-DAY-SPEC [ DAY-SPEC-1 ] |
- * [ TIME-OF-DAY-SPEC ] DAY-SPEC-2
- *
- * TIME-OF-DAY-SPEC ::= NUMBER (':') NUMBER [am|pm] | # HH:MM
- * 'noon' | 'midnight' | 'teatime'
- *
- * DAY-SPEC-1 ::= NUMBER '/' NUMBER '/' NUMBER | # MM/DD/[YY]YY
- * NUMBER '.' NUMBER '.' NUMBER | # DD.MM.[YY]YY
- * NUMBER # Seconds since 1970
- * NUMBER # YYYYMMDD
- *
- * DAY-SPEC-2 ::= MONTH-NAME NUMBER [NUMBER] | # Month DD [YY]YY
- * 'yesterday' | 'today' | 'tomorrow' |
- * DAY-OF-WEEK
- *
- *
- * OFFSET-SPEC ::= '+'|'-' NUMBER TIME-UNIT { ['+'|'-'] NUMBER TIME-UNIT }
- *
- * TIME-UNIT ::= SECONDS | MINUTES | HOURS |
- * DAYS | WEEKS | MONTHS | YEARS
- *
- * NOW ::= 'now' | 'n'
- *
- * START ::= 'start' | 's'
- * END ::= 'end' | 'e'
- *
- * SECONDS ::= 'seconds' | 'second' | 'sec' | 's'
- * MINUTES ::= 'minutes' | 'minute' | 'min' | 'm'
- * HOURS ::= 'hours' | 'hour' | 'hr' | 'h'
- * DAYS ::= 'days' | 'day' | 'd'
- * WEEKS ::= 'weeks' | 'week' | 'wk' | 'w'
- * MONTHS ::= 'months' | 'month' | 'mon' | 'm'
- * YEARS ::= 'years' | 'year' | 'yr' | 'y'
- *
- * MONTH-NAME ::= 'jan' | 'january' | 'feb' | 'february' | 'mar' | 'march' |
- * 'apr' | 'april' | 'may' | 'jun' | 'june' | 'jul' | 'july' |
- * 'aug' | 'august' | 'sep' | 'september' | 'oct' | 'october' |
- * 'nov' | 'november' | 'dec' | 'december'
- *
- * DAY-OF-WEEK ::= 'sunday' | 'sun' | 'monday' | 'mon' | 'tuesday' | 'tue' |
- * 'wednesday' | 'wed' | 'thursday' | 'thu' | 'friday' | 'fri' |
- * 'saturday' | 'sat'
- *
- *
- * As you may note, there is an ambiguity with respect to
- * the 'm' time unit (which can mean either minutes or months).
- * To cope with this, code tries to read users mind :) by applying
- * certain heuristics. There are two of them:
- *
- * 1. If 'm' is used in context of (i.e. right after the) years,
- * months, weeks, or days it is assumed to mean months, while
- * in the context of hours, minutes, and seconds it means minutes.
- * (e.g., in -1y6m or +3w1m 'm' means 'months', while in
- * -3h20m or +5s2m 'm' means 'minutes')
- *
- * 2. Out of context (i.e. right after the '+' or '-' sign) the
- * meaning of 'm' is guessed from the number it directly follows.
- * Currently, if the number absolute value is below 25 it is assumed
- * that 'm' means months, otherwise it is treated as minutes.
- * (e.g., -25m == -25 minutes, while +24m == +24 months)
- *
- */
-
-/* System Headers */
-
-/* Local headers */
-
-#include "rrd_tool.h"
-#include <stdarg.h>
-
-/* Structures and unions */
-
-enum { /* symbols */
- MIDNIGHT, NOON, TEATIME,
- PM, AM, YESTERDAY, TODAY, TOMORROW, NOW, START, END,
- SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
- MONTHS_MINUTES,
- NUMBER, PLUS, MINUS, DOT, COLON, SLASH, ID, JUNK,
- JAN, FEB, MAR, APR, MAY, JUN,
- JUL, AUG, SEP, OCT, NOV, DEC,
- SUN, MON, TUE, WED, THU, FRI, SAT
-};
-
-/* the below is for plus_minus() */
-#define PREVIOUS_OP (-1)
-
-/* parse translation table - table driven parsers can be your FRIEND!
- */
-struct SpecialToken {
- char *name; /* token name */
- int value; /* token id */
-};
-static const struct SpecialToken VariousWords[] = {
- {"midnight", MIDNIGHT}, /* 00:00:00 of today or tomorrow */
- {"noon", NOON}, /* 12:00:00 of today or tomorrow */
- {"teatime", TEATIME}, /* 16:00:00 of today or tomorrow */
- {"am", AM}, /* morning times for 0-12 clock */
- {"pm", PM}, /* evening times for 0-12 clock */
- {"tomorrow", TOMORROW},
- {"yesterday", YESTERDAY},
- {"today", TODAY},
- {"now", NOW},
- {"n", NOW},
- {"start", START},
- {"s", START},
- {"end", END},
- {"e", END},
-
- {"jan", JAN},
- {"feb", FEB},
- {"mar", MAR},
- {"apr", APR},
- {"may", MAY},
- {"jun", JUN},
- {"jul", JUL},
- {"aug", AUG},
- {"sep", SEP},
- {"oct", OCT},
- {"nov", NOV},
- {"dec", DEC},
- {"january", JAN},
- {"february", FEB},
- {"march", MAR},
- {"april", APR},
- {"may", MAY},
- {"june", JUN},
- {"july", JUL},
- {"august", AUG},
- {"september", SEP},
- {"october", OCT},
- {"november", NOV},
- {"december", DEC},
- {"sunday", SUN},
- {"sun", SUN},
- {"monday", MON},
- {"mon", MON},
- {"tuesday", TUE},
- {"tue", TUE},
- {"wednesday", WED},
- {"wed", WED},
- {"thursday", THU},
- {"thu", THU},
- {"friday", FRI},
- {"fri", FRI},
- {"saturday", SAT},
- {"sat", SAT},
- {NULL, 0} /*** SENTINEL ***/
-};
-
-static const struct SpecialToken TimeMultipliers[] = {
- {"second", SECONDS}, /* seconds multiplier */
- {"seconds", SECONDS}, /* (pluralized) */
- {"sec", SECONDS}, /* (generic) */
- {"s", SECONDS}, /* (short generic) */
- {"minute", MINUTES}, /* minutes multiplier */
- {"minutes", MINUTES}, /* (pluralized) */
- {"min", MINUTES}, /* (generic) */
- {"m", MONTHS_MINUTES}, /* (short generic) */
- {"hour", HOURS}, /* hours ... */
- {"hours", HOURS}, /* (pluralized) */
- {"hr", HOURS}, /* (generic) */
- {"h", HOURS}, /* (short generic) */
- {"day", DAYS}, /* days ... */
- {"days", DAYS}, /* (pluralized) */
- {"d", DAYS}, /* (short generic) */
- {"week", WEEKS}, /* week ... */
- {"weeks", WEEKS}, /* (pluralized) */
- {"wk", WEEKS}, /* (generic) */
- {"w", WEEKS}, /* (short generic) */
- {"month", MONTHS}, /* week ... */
- {"months", MONTHS}, /* (pluralized) */
- {"mon", MONTHS}, /* (generic) */
- {"year", YEARS}, /* year ... */
- {"years", YEARS}, /* (pluralized) */
- {"yr", YEARS}, /* (generic) */
- {"y", YEARS}, /* (short generic) */
- {NULL, 0} /*** SENTINEL ***/
-};
-
-/* File scope variables */
-
-/* context dependent list of specials for parser to recognize,
- * required for us to be able distinguish between 'mon' as 'month'
- * and 'mon' as 'monday'
- */
-static const struct SpecialToken *Specials;
-
-static const char **scp; /* scanner - pointer at arglist */
-static char scc; /* scanner - count of remaining arguments */
-static const char *sct; /* scanner - next char pointer in current argument */
-static int need; /* scanner - need to advance to next argument */
-
-static char *sc_token = NULL; /* scanner - token buffer */
-static size_t sc_len; /* scanner - length of token buffer */
-static int sc_tokid; /* scanner - token id */
-
-/* Local functions */
-static void EnsureMemFree(
- void);
-
-static void EnsureMemFree(
- void)
-{
- if (sc_token) {
- free(sc_token);
- sc_token = NULL;
- }
-}
-
-/*
- * A hack to compensate for the lack of the C++ exceptions
- *
- * Every function func that might generate parsing "exception"
- * should return TIME_OK (aka NULL) or pointer to the error message,
- * and should be called like this: try(func(args));
- *
- * if the try is not successful it will reset the token pointer ...
- *
- * [NOTE: when try(...) is used as the only statement in the "if-true"
- * part of the if statement that also has an "else" part it should be
- * either enclosed in the curly braces (despite the fact that it looks
- * like a single statement) or NOT followed by the ";"]
- */
-#define try(b) { \
- char *_e; \
- if((_e=(b))) \
- { \
- EnsureMemFree(); \
- return _e; \
- } \
- }
-
-/*
- * The panic() function was used in the original code to die, we redefine
- * it as macro to start the chain of ascending returns that in conjunction
- * with the try(b) above will simulate a sort of "exception handling"
- */
-
-#define panic(e) { \
- return (e); \
- }
-
-/*
- * ve() and e() are used to set the return error,
- * the most appropriate use for these is inside panic(...)
- */
-#define MAX_ERR_MSG_LEN 1024
-static char errmsg[MAX_ERR_MSG_LEN];
-
-static char *ve(
- char *fmt,
- va_list ap)
-{
-#ifdef HAVE_VSNPRINTF
- vsnprintf(errmsg, MAX_ERR_MSG_LEN, fmt, ap);
-#else
- vsprintf(errmsg, fmt, ap);
-#endif
- EnsureMemFree();
- return (errmsg);
-}
-
-static char *e(
- char *fmt,
- ...)
-{
- char *err;
- va_list ap;
-
- va_start(ap, fmt);
- err = ve(fmt, ap);
- va_end(ap);
- return (err);
-}
-
-/* Compare S1 and S2, ignoring case, returning less than, equal to or
- greater than zero if S1 is lexicographically less than,
- equal to or greater than S2. -- copied from GNU libc*/
-static int mystrcasecmp(
- const char *s1,
- const char *s2)
-{
- const unsigned char *p1 = (const unsigned char *) s1;
- const unsigned char *p2 = (const unsigned char *) s2;
- unsigned char c1, c2;
-
- if (p1 == p2)
- return 0;
-
- do {
- c1 = tolower(*p1++);
- c2 = tolower(*p2++);
- if (c1 == '\0')
- break;
- }
- while (c1 == c2);
-
- return c1 - c2;
-}
-
-/*
- * parse a token, checking if it's something special to us
- */
-static int parse_token(
- char *arg)
-{
- int i;
-
- for (i = 0; Specials[i].name != NULL; i++)
- if (mystrcasecmp(Specials[i].name, arg) == 0)
- return sc_tokid = Specials[i].value;
-
- /* not special - must be some random id */
- return sc_tokid = ID;
-} /* parse_token */
-
-
-
-/*
- * init_scanner() sets up the scanner to eat arguments
- */
-static char *init_scanner(
- int argc,
- const char **argv)
-{
- scp = argv;
- scc = argc;
- need = 1;
- sc_len = 1;
- while (argc-- > 0)
- sc_len += strlen(*argv++);
-
- sc_token = (char *) malloc(sc_len * sizeof(char));
- if (sc_token == NULL)
- return "Failed to allocate memory";
- return TIME_OK;
-} /* init_scanner */
-
-/*
- * token() fetches a token from the input stream
- */
-static int token(
- void)
-{
- int idx;
-
- while (1) {
- memset(sc_token, '\0', sc_len);
- sc_tokid = EOF;
- idx = 0;
-
- /* if we need to read another argument, walk along the argument list;
- * when we fall off the arglist, we'll just return EOF forever
- */
- if (need) {
- if (scc < 1)
- return sc_tokid;
- sct = *scp;
- scp++;
- scc--;
- need = 0;
- }
- /* eat whitespace now - if we walk off the end of the argument,
- * we'll continue, which puts us up at the top of the while loop
- * to fetch the next argument in
- */
- while (isspace((unsigned char) *sct) || *sct == '_' || *sct == ',')
- ++sct;
- if (!*sct) {
- need = 1;
- continue;
- }
-
- /* preserve the first character of the new token
- */
- sc_token[0] = *sct++;
-
- /* then see what it is
- */
- if (isdigit((unsigned char) (sc_token[0]))) {
- while (isdigit((unsigned char) (*sct)))
- sc_token[++idx] = *sct++;
- sc_token[++idx] = '\0';
- return sc_tokid = NUMBER;
- } else if (isalpha((unsigned char) (sc_token[0]))) {
- while (isalpha((unsigned char) (*sct)))
- sc_token[++idx] = *sct++;
- sc_token[++idx] = '\0';
- return parse_token(sc_token);
- } else
- switch (sc_token[0]) {
- case ':':
- return sc_tokid = COLON;
- case '.':
- return sc_tokid = DOT;
- case '+':
- return sc_tokid = PLUS;
- case '-':
- return sc_tokid = MINUS;
- case '/':
- return sc_tokid = SLASH;
- default:
- /*OK, we did not make it ... */
- sct--;
- return sc_tokid = EOF;
- }
- } /* while (1) */
-} /* token */
-
-
-/*
- * expect2() gets a token and complains if it's not the token we want
- */
-static char *expect2(
- int desired,
- char *complain_fmt,
- ...)
-{
- va_list ap;
-
- va_start(ap, complain_fmt);
- if (token() != desired) {
- panic(ve(complain_fmt, ap));
- }
- va_end(ap);
- return TIME_OK;
-
-} /* expect2 */
-
-
-/*
- * plus_minus() is used to parse a single NUMBER TIME-UNIT pair
- * for the OFFSET-SPEC.
- * It also applies those m-guessing heuristics.
- */
-static char *plus_minus(
- struct rrd_time_value *ptv,
- int doop)
-{
- static int op = PLUS;
- static int prev_multiplier = -1;
- int delta;
-
- if (doop >= 0) {
- op = doop;
- try(expect2
- (NUMBER, "There should be number after '%c'",
- op == PLUS ? '+' : '-'));
- prev_multiplier = -1; /* reset months-minutes guessing mechanics */
- }
- /* if doop is < 0 then we repeat the previous op
- * with the prefetched number */
-
- delta = atoi(sc_token);
-
- if (token() == MONTHS_MINUTES) {
- /* hard job to guess what does that -5m means: -5mon or -5min? */
- switch (prev_multiplier) {
- case DAYS:
- case WEEKS:
- case MONTHS:
- case YEARS:
- sc_tokid = MONTHS;
- break;
-
- case SECONDS:
- case MINUTES:
- case HOURS:
- sc_tokid = MINUTES;
- break;
-
- default:
- if (delta < 6) /* it may be some other value but in the context
- * of RRD who needs less than 6 min deltas? */
- sc_tokid = MONTHS;
- else
- sc_tokid = MINUTES;
- }
- }
- prev_multiplier = sc_tokid;
- switch (sc_tokid) {
- case YEARS:
- ptv->tm. tm_year += (
- op == PLUS) ? delta : -delta;
-
- return TIME_OK;
- case MONTHS:
- ptv->tm. tm_mon += (
- op == PLUS) ? delta : -delta;
-
- return TIME_OK;
- case WEEKS:
- delta *= 7;
- /* FALLTHRU */
- case DAYS:
- ptv->tm. tm_mday += (
- op == PLUS) ? delta : -delta;
-
- return TIME_OK;
- case HOURS:
- ptv->offset += (op == PLUS) ? delta * 60 * 60 : -delta * 60 * 60;
- return TIME_OK;
- case MINUTES:
- ptv->offset += (op == PLUS) ? delta * 60 : -delta * 60;
- return TIME_OK;
- case SECONDS:
- ptv->offset += (op == PLUS) ? delta : -delta;
- return TIME_OK;
- default: /*default unit is seconds */
- ptv->offset += (op == PLUS) ? delta : -delta;
- return TIME_OK;
- }
- panic(e("well-known time unit expected after %d", delta));
- /* NORETURN */
- return TIME_OK; /* to make compiler happy :) */
-} /* plus_minus */
-
-
-/*
- * tod() computes the time of day (TIME-OF-DAY-SPEC)
- */
-static char *tod(
- struct rrd_time_value *ptv)
-{
- int hour, minute = 0;
- int tlen;
-
- /* save token status in case we must abort */
- int scc_sv = scc;
- const char *sct_sv = sct;
- int sc_tokid_sv = sc_tokid;
-
- tlen = strlen(sc_token);
-
- /* first pick out the time of day - we assume a HH (COLON|DOT) MM time
- */
- if (tlen > 2) {
- return TIME_OK;
- }
-
- hour = atoi(sc_token);
-
- token();
- if (sc_tokid == SLASH || sc_tokid == DOT) {
- /* guess we are looking at a date */
- scc = scc_sv;
- sct = sct_sv;
- sc_tokid = sc_tokid_sv;
- sprintf(sc_token, "%d", hour);
- return TIME_OK;
- }
- if (sc_tokid == COLON) {
- try(expect2(NUMBER,
- "Parsing HH:MM syntax, expecting MM as number, got none"));
- minute = atoi(sc_token);
- if (minute > 59) {
- panic(e("parsing HH:MM syntax, got MM = %d (>59!)", minute));
- }
- token();
- }
-
- /* check if an AM or PM specifier was given
- */
- if (sc_tokid == AM || sc_tokid == PM) {
- if (hour > 12) {
- panic(e("there cannot be more than 12 AM or PM hours"));
- }
- if (sc_tokid == PM) {
- if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
- hour += 12;
- } else {
- if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
- hour = 0;
- }
- token();
- } else if (hour > 23) {
- /* guess it was not a time then ... */
- scc = scc_sv;
- sct = sct_sv;
- sc_tokid = sc_tokid_sv;
- sprintf(sc_token, "%d", hour);
- return TIME_OK;
- }
- ptv->tm. tm_hour = hour;
- ptv->tm. tm_min = minute;
- ptv->tm. tm_sec = 0;
-
- if (ptv->tm.tm_hour == 24) {
- ptv->tm. tm_hour = 0;
- ptv->tm. tm_mday++;
- }
- return TIME_OK;
-} /* tod */
-
-
-/*
- * assign_date() assigns a date, adjusting year as appropriate
- */
-static char *assign_date(
- struct rrd_time_value *ptv,
- long mday,
- long mon,
- long year)
-{
- if (year > 138) {
- if (year > 1970)
- year -= 1900;
- else {
- panic(e("invalid year %d (should be either 00-99 or >1900)",
- year));
- }
- } else if (year >= 0 && year < 38) {
- year += 100; /* Allow year 2000-2037 to be specified as */
- }
- /* 00-37 until the problem of 2038 year will */
- /* arise for unices with 32-bit time_t :) */
- if (year < 70) {
- panic(e("won't handle dates before epoch (01/01/1970), sorry"));
- }
-
- ptv->tm. tm_mday = mday;
- ptv->tm. tm_mon = mon;
- ptv->tm. tm_year = year;
-
- return TIME_OK;
-} /* assign_date */
-
-
-/*
- * day() picks apart DAY-SPEC-[12]
- */
-static char *day(
- struct rrd_time_value *ptv)
-{
- /* using time_t seems to help portability with 64bit oses */
- time_t mday = 0, wday, mon, year = ptv->tm.tm_year;
- int tlen;
-
- switch (sc_tokid) {
- case YESTERDAY:
- ptv->tm. tm_mday--;
-
- /* FALLTRHU */
- case TODAY: /* force ourselves to stay in today - no further processing */
- token();
- break;
- case TOMORROW:
- ptv->tm. tm_mday++;
-
- token();
- break;
-
- case JAN:
- case FEB:
- case MAR:
- case APR:
- case MAY:
- case JUN:
- case JUL:
- case AUG:
- case SEP:
- case OCT:
- case NOV:
- case DEC:
- /* do month mday [year]
- */
- mon = (sc_tokid - JAN);
- try(expect2(NUMBER, "the day of the month should follow month name"));
- mday = atol(sc_token);
- if (token() == NUMBER) {
- year = atol(sc_token);
- token();
- } else
- year = ptv->tm.tm_year;
-
- try(assign_date(ptv, mday, mon, year));
- break;
-
- case SUN:
- case MON:
- case TUE:
- case WED:
- case THU:
- case FRI:
- case SAT:
- /* do a particular day of the week
- */
- wday = (sc_tokid - SUN);
- ptv->tm. tm_mday += (
- wday - ptv->tm.tm_wday);
-
- token();
- break;
- /*
- mday = ptv->tm.tm_mday;
- mday += (wday - ptv->tm.tm_wday);
- ptv->tm.tm_wday = wday;
-
- try(assign_date(ptv, mday, ptv->tm.tm_mon, ptv->tm.tm_year));
- break;
- */
-
- case NUMBER:
- /* get numeric <sec since 1970>, MM/DD/[YY]YY, or DD.MM.[YY]YY
- */
- tlen = strlen(sc_token);
- mon = atol(sc_token);
- if (mon > 10 * 365 * 24 * 60 * 60) {
- ptv->tm = *localtime(&mon);
-
- token();
- break;
- }
-
- if (mon > 19700101 && mon < 24000101) { /*works between 1900 and 2400 */
- char cmon[3], cmday[3], cyear[5];
-
- strncpy(cyear, sc_token, 4);
- cyear[4] = '\0';
- year = atol(cyear);
- strncpy(cmon, &(sc_token[4]), 2);
- cmon[2] = '\0';
- mon = atol(cmon);
- strncpy(cmday, &(sc_token[6]), 2);
- cmday[2] = '\0';
- mday = atol(cmday);
- token();
- } else {
- token();
-
- if (mon <= 31 && (sc_tokid == SLASH || sc_tokid == DOT)) {
- int sep;
-
- sep = sc_tokid;
- try(expect2(NUMBER, "there should be %s number after '%c'",
- sep == DOT ? "month" : "day",
- sep == DOT ? '.' : '/'));
- mday = atol(sc_token);
- if (token() == sep) {
- try(expect2
- (NUMBER, "there should be year number after '%c'",
- sep == DOT ? '.' : '/'));
- year = atol(sc_token);
- token();
- }
-
- /* flip months and days for European timing
- */
- if (sep == DOT) {
- long x = mday;
-
- mday = mon;
- mon = x;
- }
- }
- }
-
- mon--;
- if (mon < 0 || mon > 11) {
- panic(e("did you really mean month %d?", mon + 1));
- }
- if (mday < 1 || mday > 31) {
- panic(e("I'm afraid that %d is not a valid day of the month",
- mday));
- }
- try(assign_date(ptv, mday, mon, year));
- break;
- } /* case */
- return TIME_OK;
-} /* month */
-
-
-/* Global functions */
-
-
-/*
- * parsetime() is the external interface that takes tspec, parses
- * it and puts the result in the rrd_time_value structure *ptv.
- * It can return either absolute times (these are ensured to be
- * correct) or relative time references that are expected to be
- * added to some absolute time value and then normalized by
- * mktime() The return value is either TIME_OK (aka NULL) or
- * the pointer to the error message in the case of problems
- */
-char *parsetime(
- const char *tspec,
- struct rrd_time_value *ptv)
-{
- time_t now = time(NULL);
- int hr = 0;
-
- /* this MUST be initialized to zero for midnight/noon/teatime */
-
- Specials = VariousWords; /* initialize special words context */
-
- try(init_scanner(1, &tspec));
-
- /* establish the default time reference */
- ptv->type = ABSOLUTE_TIME;
- ptv->offset = 0;
- ptv->tm = *localtime(&now);
- ptv->tm. tm_isdst = -1; /* mk time can figure dst by default ... */
-
- token();
- switch (sc_tokid) {
- case PLUS:
- case MINUS:
- break; /* jump to OFFSET-SPEC part */
-
- case START:
- ptv->type = RELATIVE_TO_START_TIME;
- goto KeepItRelative;
- case END:
- ptv->type = RELATIVE_TO_END_TIME;
- KeepItRelative:
- ptv->tm. tm_sec = 0;
- ptv->tm. tm_min = 0;
- ptv->tm. tm_hour = 0;
- ptv->tm. tm_mday = 0;
- ptv->tm. tm_mon = 0;
- ptv->tm. tm_year = 0;
-
- /* FALLTHRU */
- case NOW:
- {
- int time_reference = sc_tokid;
-
- token();
- if (sc_tokid == PLUS || sc_tokid == MINUS)
- break;
- if (time_reference != NOW) {
- panic(e("'start' or 'end' MUST be followed by +|- offset"));
- } else if (sc_tokid != EOF) {
- panic(e("if 'now' is followed by a token it must be +|- offset"));
- }
- };
- break;
-
- /* Only absolute time specifications below */
- case NUMBER:
- {
- long hour_sv = ptv->tm.tm_hour;
- long year_sv = ptv->tm.tm_year;
-
- ptv->tm. tm_hour = 30;
- ptv->tm. tm_year = 30000;
-
- try(tod(ptv))
- try(day(ptv))
- if (ptv->tm.tm_hour == 30 && ptv->tm.tm_year != 30000) {
- try(tod(ptv))
- }
- if (ptv->tm.tm_hour == 30) {
- ptv->tm. tm_hour = hour_sv;
- }
- if (ptv->tm.tm_year == 30000) {
- ptv->tm. tm_year = year_sv;
- }
- };
- break;
- /* fix month parsing */
- case JAN:
- case FEB:
- case MAR:
- case APR:
- case MAY:
- case JUN:
- case JUL:
- case AUG:
- case SEP:
- case OCT:
- case NOV:
- case DEC:
- try(day(ptv));
- if (sc_tokid != NUMBER)
- break;
- try(tod(ptv))
- break;
-
- /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialized
- * hr to zero up above, then fall into this case in such a
- * way so we add +12 +4 hours to it for teatime, +12 hours
- * to it for noon, and nothing at all for midnight, then
- * set our rettime to that hour before leaping into the
- * month scanner
- */
- case TEATIME:
- hr += 4;
- /* FALLTHRU */
- case NOON:
- hr += 12;
- /* FALLTHRU */
- case MIDNIGHT:
- /* if (ptv->tm.tm_hour >= hr) {
- ptv->tm.tm_mday++;
- ptv->tm.tm_wday++;
- } *//* shifting does not makes sense here ... noon is noon */
- ptv->tm. tm_hour = hr;
- ptv->tm. tm_min = 0;
- ptv->tm. tm_sec = 0;
-
- token();
- try(day(ptv));
- break;
- default:
- panic(e("unparsable time: %s%s", sc_token, sct));
- break;
- } /* ugly case statement */
-
- /*
- * the OFFSET-SPEC part
- *
- * (NOTE, the sc_tokid was prefetched for us by the previous code)
- */
- if (sc_tokid == PLUS || sc_tokid == MINUS) {
- Specials = TimeMultipliers; /* switch special words context */
- while (sc_tokid == PLUS || sc_tokid == MINUS || sc_tokid == NUMBER) {
- if (sc_tokid == NUMBER) {
- try(plus_minus(ptv, PREVIOUS_OP));
- } else
- try(plus_minus(ptv, sc_tokid));
- token(); /* We will get EOF eventually but that's OK, since
- token() will return us as many EOFs as needed */
- }
- }
-
- /* now we should be at EOF */
- if (sc_tokid != EOF) {
- panic(e("unparsable trailing text: '...%s%s'", sc_token, sct));
- }
-
- if (ptv->type == ABSOLUTE_TIME)
- if (mktime(&ptv->tm) == -1) { /* normalize & check */
- /* can happen for "nonexistent" times, e.g. around 3am */
- /* when winter -> summer time correction eats a hour */
- panic(e("the specified time is incorrect (out of range?)"));
- }
- EnsureMemFree();
- return TIME_OK;
-} /* parsetime */
-
-
-int proc_start_end(
- struct rrd_time_value *start_tv,
- struct rrd_time_value *end_tv,
- time_t *start,
- time_t *end)
-{
- if (start_tv->type == RELATIVE_TO_END_TIME && /* same as the line above */
- end_tv->type == RELATIVE_TO_START_TIME) {
- rrd_set_error("the start and end times cannot be specified "
- "relative to each other");
- return -1;
- }
-
- if (start_tv->type == RELATIVE_TO_START_TIME) {
- rrd_set_error
- ("the start time cannot be specified relative to itself");
- return -1;
- }
-
- if (end_tv->type == RELATIVE_TO_END_TIME) {
- rrd_set_error("the end time cannot be specified relative to itself");
- return -1;
- }
-
- if (start_tv->type == RELATIVE_TO_END_TIME) {
- struct tm tmtmp;
-
- *end = mktime(&(end_tv->tm)) + end_tv->offset;
- tmtmp = *localtime(end); /* reinit end including offset */
- tmtmp.tm_mday += start_tv->tm.tm_mday;
- tmtmp.tm_mon += start_tv->tm.tm_mon;
- tmtmp.tm_year += start_tv->tm.tm_year;
-
- *start = mktime(&tmtmp) + start_tv->offset;
- } else {
- *start = mktime(&(start_tv->tm)) + start_tv->offset;
- }
- if (end_tv->type == RELATIVE_TO_START_TIME) {
- struct tm tmtmp;
-
- *start = mktime(&(start_tv->tm)) + start_tv->offset;
- tmtmp = *localtime(start);
- tmtmp.tm_mday += end_tv->tm.tm_mday;
- tmtmp.tm_mon += end_tv->tm.tm_mon;
- tmtmp.tm_year += end_tv->tm.tm_year;
-
- *end = mktime(&tmtmp) + end_tv->offset;
- } else {
- *end = mktime(&(end_tv->tm)) + end_tv->offset;
- }
- return 0;
-} /* proc_start_end */
+++ /dev/null
-#ifndef __PARSETIME_H__
-#define __PARSETIME_H__
-
-#include <stdio.h>
-
-#include "rrd.h"
-
-#endif
/* Formerly rrd_nan_inf.h */
#ifndef DNAN
-# define DNAN set_to_DNAN()
+# define DNAN rrd_set_to_DNAN()
#endif
#ifndef DINF
-# define DINF set_to_DINF()
+# define DINF rrd_set_to_DINF()
#endif
- double set_to_DNAN(
+ double rrd_set_to_DNAN(
void);
- double set_to_DINF(
+ double rrd_set_to_DINF(
void);
/* end of rrd_nan_inf.h */
unsigned char *ptr; /* pointer */
} rrd_blob_t;
- enum info_type { RD_I_VAL = 0,
+ typedef enum rrd_info_type { RD_I_VAL = 0,
RD_I_CNT,
RD_I_STR,
RD_I_INT,
RD_I_BLO
- };
+ } rrd_info_type_t;
- typedef union infoval {
+ typedef union rrd_infoval {
unsigned long u_cnt;
rrd_value_t u_val;
char *u_str;
int u_int;
- struct rrd_blob_t u_blo;
- } infoval;
+ rrd_blob_t u_blo;
+ } rrd_infoval_t;
- typedef struct info_t {
+ typedef struct rrd_info_t {
char *key;
- enum info_type type;
- union infoval value;
- struct info_t *next;
- } info_t;
+ rrd_info_type_t type;
+ rrd_infoval_t value;
+ struct rrd_info_t *next;
+ } rrd_info_t;
/* main function blocks */
int rrd_create(
int,
char **);
+ rrd_info_t *rrd_info(
+ int,
+ char **);
+ rrd_info_t *rrd_info_push(
+ rrd_info_t *,
+ char *,
+ rrd_info_type_t,
+ rrd_infoval_t);
+ void rrd_info_print(
+ rrd_info_t *data);
+ void rrd_info_free(
+ rrd_info_t *);
int rrd_update(
int,
char **);
+ rrd_info_t *rrd_update_v(
+ int,
+ char **);
int rrd_graph(
int,
char **,
FILE *,
double *,
double *);
- info_t *rrd_graph_v(
+ rrd_info_t *rrd_graph_v(
int,
char **);
time_t rrd_last(
int,
char **);
+ int rrd_lastupdate(
+ int argc,
+ char **argv,
+ time_t *last_update,
+ unsigned long *ds_cnt,
+ char ***ds_namv,
+ char ***last_ds);
time_t rrd_first(
int,
char **);
const char *filename,
int rraindex);
-/* Transplanted from parsetime.h */
+/* Transplanted from rrd_parsetime.h */
typedef enum {
ABSOLUTE_TIME,
RELATIVE_TO_START_TIME,
RELATIVE_TO_END_TIME
- } timetype;
+ } rrd_timetype_t;
#define TIME_OK NULL
- struct rrd_time_value {
- timetype type;
+ typedef struct rrd_time_value {
+ rrd_timetype_t type;
long offset;
struct tm tm;
- };
+ } rrd_time_value_t;
- char *parsetime(
+ char *rrd_parsetime(
const char *spec,
- struct rrd_time_value *ptv);
-/* END parsetime.h */
+ rrd_time_value_t *ptv);
+/* END rrd_parsetime.h */
- struct rrd_context {
+ typedef struct rrd_context {
char lib_errstr[256];
char rrd_error[4096];
- };
+ } rrd_context_t;
/* returns the current per-thread rrd_context */
- struct rrd_context *rrd_get_context(
+ rrd_context_t *rrd_get_context(
void);
- int proc_start_end(
- struct rrd_time_value *,
- struct rrd_time_value *,
+ int rrd_proc_start_end(
+ rrd_time_value_t *,
+ rrd_time_value_t *,
time_t *,
time_t *);
char *rrd_get_error(
void);
+ /* rrd_strerror is thread safe, but still it uses a global buffer
+ (but one per thread), thus subsequent calls within a single
+ thread overwrite the same buffer */
+ const char *rrd_strerror(
+ int err);
+
/** MULTITHREADED HELPER FUNCTIONS */
- struct rrd_context *rrd_new_context(
+ rrd_context_t *rrd_new_context(
void);
void rrd_free_context(
- struct rrd_context *buf);
-
-/* void rrd_set_error_r (struct rrd_context *, char *, ...); */
-/* void rrd_clear_error_r(struct rrd_context *); */
-/* int rrd_test_error_r (struct rrd_context *); */
-/* char *rrd_get_error_r (struct rrd_context *); */
+ rrd_context_t *buf);
- int LockRRD(
- int in_file);
+/* void rrd_set_error_r (rrd_context_t *, char *, ...); */
+/* void rrd_clear_error_r(rrd_context_t *); */
+/* int rrd_test_error_r (rrd_context_t *); */
+/* char *rrd_get_error_r (rrd_context_t *); */
#endif /* _RRDLIB_H */
return (nstr);
}
+static int readfile(
+ const char *file_name,
+ char **buffer,
+ int skipfirst)
+{
+ long writecnt = 0, totalcnt = MEMBLK;
+ long offset = 0;
+ FILE *input = NULL;
+ char c;
+
+ if ((strcmp("-", file_name) == 0)) {
+ input = stdin;
+ } else {
+ if ((input = fopen(file_name, "rb")) == NULL) {
+ rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
+ return (-1);
+ }
+ }
+ if (skipfirst) {
+ do {
+ c = getc(input);
+ offset++;
+ } while (c != '\n' && !feof(input));
+ }
+ if (strcmp("-", file_name)) {
+ fseek(input, 0, SEEK_END);
+ /* have extra space for detecting EOF without realloc */
+ totalcnt = (ftell(input) + 1) / sizeof(char) - offset;
+ if (totalcnt < MEMBLK)
+ totalcnt = MEMBLK; /* sanitize */
+ fseek(input, offset * sizeof(char), SEEK_SET);
+ }
+ if (((*buffer) = (char *) malloc((totalcnt + 4) * sizeof(char))) == NULL) {
+ perror("Allocate Buffer:");
+ exit(1);
+ };
+ do {
+ writecnt +=
+ fread((*buffer) + writecnt, 1,
+ (totalcnt - writecnt) * sizeof(char), input);
+ if (writecnt >= totalcnt) {
+ totalcnt += MEMBLK;
+ if (((*buffer) =
+ rrd_realloc((*buffer),
+ (totalcnt + 4) * sizeof(char))) == NULL) {
+ perror("Realloc Buffer:");
+ exit(1);
+ };
+ }
+ } while (!feof(input));
+ (*buffer)[writecnt] = '\0';
+ if (strcmp("-", file_name) != 0) {
+ fclose(input);
+ };
+ return writecnt;
+}
+
int main(
int argc,
char *argv[])
long argc,
const char **args)
{
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
char *parsetime_error = NULL;
char formatted[MAX_STRFTIME_SIZE];
struct tm *the_tm;
}
/* Init start and end time */
- parsetime("end-24h", &start_tv);
- parsetime("now", &end_tv);
+ rrd_parsetime("end-24h", &start_tv);
+ rrd_parsetime("now", &end_tv);
/* Parse the start and end times we were given */
- if ((parsetime_error = parsetime(args[1], &start_tv))) {
+ if ((parsetime_error = rrd_parsetime(args[1], &start_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return stralloc("");
}
- if ((parsetime_error = parsetime(args[2], &end_tv))) {
+ if ((parsetime_error = rrd_parsetime(args[2], &end_tv))) {
rrd_set_error("end time: %s", parsetime_error);
return stralloc("");
}
- if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
return stralloc("");
}
int opt;
time_t last_up = time(NULL) - 10;
unsigned long pdp_step = 300;
- struct rrd_time_value last_up_tv;
+ rrd_time_value_t last_up_tv;
char *parsetime_error = NULL;
long long_tmp;
int rc;
switch (opt) {
case 'b':
- if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return (-1);
}
context. Using these functions would require to change each and
every function containing any of the non _r versions... */
void rrd_set_error_r(
- struct rrd_context *rrd_ctx,
+ rrd_context_t *rrd_ctx,
char *fmt,
...)
{
}
int rrd_test_error_r(
- struct rrd_context *rrd_ctx)
+ rrd_context_t *rrd_ctx)
{
return rrd_ctx->rrd_error[0] != '\0';
}
void rrd_clear_error_r(
- struct rrd_context *rrd_ctx)
+ rrd_context_t *rrd_ctx)
{
rrd_ctx->rrd_error[0] = '\0';
}
char *rrd_get_error_r(
- struct rrd_context *rrd_ctx)
+ rrd_context_t *rrd_ctx)
{
return rrd_ctx->rrd_error;
}
/* PS: Should we move this to some other file? It is not really error
related. */
-struct rrd_context *rrd_new_context(
+rrd_context_t *rrd_new_context(
void)
{
- struct rrd_context *rrd_ctx =
- (struct rrd_context *) malloc(sizeof(struct rrd_context));
+ rrd_context_t *rrd_ctx =
+ (rrd_context_t *) malloc(sizeof(rrd_context_t));
if (!rrd_ctx) {
return NULL;
}
void rrd_free_context(
- struct rrd_context *rrd_ctx)
+ rrd_context_t *rrd_ctx)
{
if (rrd_ctx) {
free(rrd_ctx);
#if 0
void rrd_globalize_error(
- struct rrd_context *rrd_ctx)
+ rrd_context_t *rrd_ctx)
{
if (rrd_ctx) {
rrd_set_error(rrd_ctx->rrd_error);
time_t start_tmp = 0, end_tmp = 0;
const char *cf;
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
char *parsetime_error = NULL;
struct option long_options[] = {
{"resolution", required_argument, 0, 'r'},
opterr = 0; /* initialize getopt */
/* init start and end time */
- parsetime("end-24h", &start_tv);
- parsetime("now", &end_tv);
+ rrd_parsetime("end-24h", &start_tv);
+ rrd_parsetime("now", &end_tv);
while (1) {
int option_index = 0;
switch (opt) {
case 's':
- if ((parsetime_error = parsetime(optarg, &start_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &start_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return -1;
}
break;
case 'e':
- if ((parsetime_error = parsetime(optarg, &end_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &end_tv))) {
rrd_set_error("end time: %s", parsetime_error);
return -1;
}
}
- if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
return -1;
}
}
if (im->gdes[i].gf == GF_PRINT) {
- infoval prline;
+ rrd_infoval_t prline;
if (im->gdes[i].strftm) {
prline.u_str = malloc((FMT_LEG_LEN + 2) * sizeof(char));
int lazy = lazy_check(im);
double areazero = 0.0;
graph_desc_t *lastgdes = NULL;
- infoval info;
+ rrd_infoval_t info;
PangoFontMap *font_map = pango_cairo_font_map_get_default();
/* if we are lazy and there is nothing to PRINT ... quit now */
double *ymax)
{
int prlines = 0;
- info_t *grinfo = NULL;
- info_t *walker;
+ rrd_info_t *grinfo = NULL;
+ rrd_info_t *walker;
grinfo = rrd_graph_v(argc, argv);
if (grinfo == NULL)
/* skip anything else */
walker = walker->next;
}
- info_free(grinfo);
+ rrd_info_free(grinfo);
return 0;
}
** - options parsing now in rrd_graph_options()
** - script parsing now in rrd_graph_script()
*/
-info_t *rrd_graph_v(
+rrd_info_t *rrd_graph_v(
int argc,
char **argv)
{
image_desc_t im;
- info_t *grinfo;
+ rrd_info_t *grinfo;
rrd_graph_init(&im);
/* a dummy surface so that we can measure text sizes for placements */
im.cr = cairo_create(im.surface);
rrd_graph_options(argc, argv, &im);
if (rrd_test_error()) {
- info_free(im.grinfo);
+ rrd_info_free(im.grinfo);
im_free(&im);
return NULL;
}
if (optind >= argc) {
- info_free(im.grinfo);
+ rrd_info_free(im.grinfo);
im_free(&im);
rrd_set_error("missing filename");
return NULL;
if (strlen(argv[optind]) >= MAXPATH) {
rrd_set_error("filename (including path) too long");
- info_free(im.grinfo);
+ rrd_info_free(im.grinfo);
im_free(&im);
return NULL;
}
rrd_graph_script(argc, argv, &im, 1);
if (rrd_test_error()) {
- info_free(im.grinfo);
+ rrd_info_free(im.grinfo);
im_free(&im);
return NULL;
}
/* Everything is now read and the actual work can start */
if (graph_paint(&im) == -1) {
- info_free(im.grinfo);
+ rrd_info_free(im.grinfo);
im_free(&im);
return NULL;
}
*/
if (im.imginfo) {
- infoval info;
+ rrd_infoval_t info;
info.u_str =
sprintf_alloc(im.imginfo,
free(info.u_str);
}
if (im.rendered_image) {
- infoval img;
+ rrd_infoval_t img;
img.u_blo.size = im.rendered_image_size;
img.u_blo.ptr = im.rendered_image;
im->grid_dash_off = 1;
im->grid_dash_on = 1;
im->gridfit = 1;
- im->grinfo = (info_t *) NULL;
- im->grinfo_current = (info_t *) NULL;
+ im->grinfo = (rrd_info_t *) NULL;
+ im->grinfo_current = (rrd_info_t *) NULL;
im->imgformat = IF_PNG;
im->imginfo = NULL;
im->lazy = 0;
char scan_gtm[12], scan_mtm[12], scan_ltm[12], col_nam[12];
time_t start_tmp = 0, end_tmp = 0;
long long_tmp;
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
long unsigned int color;
char *old_locale = "";
optind = 0;
opterr = 0; /* initialize getopt */
- parsetime("end-24h", &start_tv);
- parsetime("now", &end_tv);
+ rrd_parsetime("end-24h", &start_tv);
+ rrd_parsetime("now", &end_tv);
while (1) {
int option_index = 0;
int opt;
im->with_markup = 1;
break;
case 's':
- if ((parsetime_error = parsetime(optarg, &start_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &start_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return;
}
break;
case 'e':
- if ((parsetime_error = parsetime(optarg, &end_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &end_tv))) {
rrd_set_error("end time: %s", parsetime_error);
return;
}
return;
}
- if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
- /* error string is set in parsetime.c */
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ /* error string is set in rrd_parsetime.c */
return;
}
void grinfo_push(
image_desc_t *im,
char *key,
- enum info_type type,
- infoval value)
+ rrd_info_type_t type,
+ rrd_infoval_t value)
{
- im->grinfo_current = info_push(im->grinfo_current, key, type, value);
+ im->grinfo_current = rrd_info_push(im->grinfo_current, key, type, value);
if (im->grinfo == NULL) {
im->grinfo = im->grinfo_current;
}
cairo_font_options_t *font_options; /* cairo font options */
cairo_antialias_t graph_antialias; /* antialiasing for the graph */
- info_t *grinfo; /* root pointer to extra graph info */
- info_t *grinfo_current; /* pointing to current entry */
+ rrd_info_t *grinfo; /* root pointer to extra graph info */
+ rrd_info_t *grinfo_current; /* pointing to current entry */
} image_desc_t;
/* Prototypes */
void grinfo_push(
image_desc_t *im,
char *key,
- enum info_type type,
- infoval value);
+ rrd_info_type_t type,
+ rrd_infoval_t value);
int i = 0;
char command[7]; /* step, start, end, reduce */
char tmpstr[256];
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
time_t start_tmp = 0, end_tmp = 0;
char *parsetime_error = NULL;
} else if (!strcmp("start", command)) {
i = scan_for_col(&line[*eaten], 255, tmpstr);
(*eaten) += i;
- if ((parsetime_error = parsetime(tmpstr, &start_tv))) {
+ if ((parsetime_error = rrd_parsetime(tmpstr, &start_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return 1;
}
} else if (!strcmp("end", command)) {
i = scan_for_col(&line[*eaten], 255, tmpstr);
(*eaten) += i;
- if ((parsetime_error = parsetime(tmpstr, &end_tv))) {
+ if ((parsetime_error = rrd_parsetime(tmpstr, &end_tv))) {
rrd_set_error("end time: %s", parsetime_error);
return 1;
}
}
(*eaten)++;
}
- if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
- /* error string is set in parsetime.c */
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ /* error string is set in rrd_parsetime.c */
return 1;
}
if (start_tmp < 3600 * 24 * 365 * 10) {
#include <stdarg.h>
/* proto */
-info_t *rrd_info(
+rrd_info_t *rrd_info(
int,
char **);
-info_t *rrd_info_r(
+rrd_info_t *rrd_info_r(
char *filename);
/* allocate memory for string */
return str;
}
-/* the function formerly known as push was renamed info_push because
- * it is now used outside the scope of this file */
-info_t
- *info_push(
- info_t *info,
+/* the function formerly known as push was renamed to info_push and later
+ * rrd_info_push because it is now used outside the scope of this file */
+rrd_info_t
+ *rrd_info_push(
+ rrd_info_t *info,
char *key,
- enum info_type type,
- infoval value)
+ rrd_info_type_t type,
+ rrd_infoval_t value)
{
- info_t *next;
+ rrd_info_t *next;
next = malloc(sizeof(*next));
- next->next = (info_t *) 0;
+ next->next = (rrd_info_t *) 0;
if (info)
info->next = next;
next->type = type;
}
-info_t *rrd_info(
+rrd_info_t *rrd_info(
int argc,
char **argv)
{
- info_t *info;
+ rrd_info_t *info;
if (argc < 2) {
rrd_set_error("please specify an rrd");
-info_t *rrd_info_r(
+rrd_info_t *rrd_info_r(
char *filename)
{
unsigned int i, ii = 0;
rrd_t rrd;
- info_t *data = NULL, *cd;
- infoval info;
+ rrd_info_t *data = NULL, *cd;
+ rrd_infoval_t info;
rrd_file_t *rrd_file;
enum cf_en current_cf;
enum dst_en current_ds;
goto err_free;
info.u_str = filename;
- cd = info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
+ cd = rrd_info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
data = cd;
info.u_str = rrd.stat_head->version;
- cd = info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);
+ cd = rrd_info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);
info.u_cnt = rrd.stat_head->pdp_step;
- cd = info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);
+ cd = rrd_info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);
info.u_cnt = rrd.live_head->last_up;
- cd = info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);
+ cd = rrd_info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);
for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
info.u_str = rrd.ds_def[i].dst;
- cd = info_push(cd, sprintf_alloc("ds[%s].type", rrd.ds_def[i].ds_nam),
+ cd = rrd_info_push(cd, sprintf_alloc("ds[%s].type",
+ rrd.ds_def[i].ds_nam),
RD_I_STR, info);
current_ds = dst_conv(rrd.ds_def[i].dst);
rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
rrd.ds_def, &buffer);
info.u_str = buffer;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].cdef", rrd.ds_def[i].ds_nam),
RD_I_STR, info);
free(buffer);
break;
default:
info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].minimal_heartbeat",
rrd.ds_def[i].ds_nam), RD_I_CNT,
info);
info.u_val = rrd.ds_def[i].par[DS_min_val].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].min", rrd.ds_def[i].ds_nam),
RD_I_VAL, info);
info.u_val = rrd.ds_def[i].par[DS_max_val].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].max", rrd.ds_def[i].ds_nam),
RD_I_VAL, info);
break;
}
info.u_str = rrd.pdp_prep[i].last_ds;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].last_ds", rrd.ds_def[i].ds_nam),
RD_I_STR, info);
info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].value", rrd.ds_def[i].ds_nam),
RD_I_VAL, info);
info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("ds[%s].unknown_sec",
rrd.ds_def[i].ds_nam), RD_I_CNT, info);
}
for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
info.u_str = rrd.rra_def[i].cf_nam;
- cd = info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR, info);
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR, info);
current_cf = cf_conv(rrd.rra_def[i].cf_nam);
info.u_cnt = rrd.rra_def[i].row_cnt;
- cd = info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT, info);
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT, info);
info.u_cnt = rrd.rra_ptr[i].cur_row;
- cd = info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT,
info);
info.u_cnt = rrd.rra_def[i].pdp_cnt;
- cd = info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i), RD_I_CNT,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i), RD_I_CNT,
info);
switch (current_cf) {
case CF_HWPREDICT:
case CF_MHWPREDICT:
info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].alpha", i), RD_I_VAL,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].alpha", i), RD_I_VAL,
info);
info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
info);
break;
case CF_SEASONAL:
case CF_DEVSEASONAL:
info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].gamma", i), RD_I_VAL,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].gamma", i), RD_I_VAL,
info);
if (atoi(rrd.stat_head->version) >= 4) {
info.u_val =
rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].smoothing_window", i),
RD_I_VAL, info);
}
break;
case CF_FAILURES:
info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
RD_I_VAL, info);
info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
RD_I_VAL, info);
info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt;
- cd = info_push(cd, sprintf_alloc("rra[%d].failure_threshold", i),
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].failure_threshold", i),
RD_I_CNT, info);
info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt;
- cd = info_push(cd, sprintf_alloc("rra[%d].window_length", i),
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].window_length", i),
RD_I_CNT, info);
break;
case CF_DEVPREDICT:
break;
default:
info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val;
- cd = info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
+ cd = rrd_info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
info);
break;
}
info.u_val =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_hw_intercept].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].intercept",
i, ii), RD_I_VAL, info);
info.u_val =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_hw_slope].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].slope", i,
ii), RD_I_VAL, info);
info.u_cnt =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_null_count].u_cnt;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].NaN_count",
i, ii), RD_I_CNT, info);
break;
info.u_val =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_hw_seasonal].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].seasonal",
i, ii), RD_I_VAL, info);
break;
info.u_val =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_seasonal_deviation].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].deviation",
i, ii), RD_I_VAL, info);
break;
history[j] = (violations_array[j] == 1) ? '1' : '0';
history[j] = '\0';
info.u_str = history;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].history",
i, ii), RD_I_STR, info);
}
info.u_val =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_val].u_val;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc("rra[%d].cdp_prep[%d].value", i,
ii), RD_I_VAL, info);
info.u_cnt =
rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
ii].scratch[CDP_unkn_pdp_cnt].u_cnt;
- cd = info_push(cd,
+ cd = rrd_info_push(cd,
sprintf_alloc
("rra[%d].cdp_prep[%d].unknown_datapoints", i,
ii), RD_I_CNT, info);
}
-void info_print(
- info_t *data)
+void rrd_info_print(
+ rrd_info_t *data)
{
while (data) {
printf("%s = ", data->key);
}
}
-void info_free(
- info_t *data)
+void rrd_info_free(
+ rrd_info_t *data)
{
- info_t *save;
+ rrd_info_t *save;
while (data) {
save = data;
#endif
-double set_to_DNAN(
+double rrd_set_to_DNAN(
void)
{
if (!done_nan) {
return dnan;
}
-double set_to_DINF(
+double rrd_set_to_DINF(
void)
{
if (!done_inf) {
/* The global context is very useful in the transition period to even
more thread-safe stuff, it can be used whereever we need a context
and do not need to worry about concurrency. */
-static struct rrd_context global_ctx = {
+static rrd_context_t global_ctx = {
"",
""
};
/* #include <stdarg.h> */
-struct rrd_context *rrd_get_context(
+rrd_context_t *rrd_get_context(
void)
{
return &global_ctx;
free(mem);
}
-
-/* XXX: FIXME: missing documentation. */
-/*XXX: FIXME should be renamed to rrd_readfile or _rrd_readfile */
-
-int /*_rrd_*/ readfile(
- const char *file_name,
- char **buffer,
- int skipfirst)
-{
- long writecnt = 0, totalcnt = MEMBLK;
- long offset = 0;
- FILE *input = NULL;
- char c;
-
- if ((strcmp("-", file_name) == 0)) {
- input = stdin;
- } else {
- if ((input = fopen(file_name, "rb")) == NULL) {
- rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
- return (-1);
- }
- }
- if (skipfirst) {
- do {
- c = getc(input);
- offset++;
- } while (c != '\n' && !feof(input));
- }
- if (strcmp("-", file_name)) {
- fseek(input, 0, SEEK_END);
- /* have extra space for detecting EOF without realloc */
- totalcnt = (ftell(input) + 1) / sizeof(char) - offset;
- if (totalcnt < MEMBLK)
- totalcnt = MEMBLK; /* sanitize */
- fseek(input, offset * sizeof(char), SEEK_SET);
- }
- if (((*buffer) = (char *) malloc((totalcnt + 4) * sizeof(char))) == NULL) {
- perror("Allocate Buffer:");
- exit(1);
- };
- do {
- writecnt +=
- fread((*buffer) + writecnt, 1,
- (totalcnt - writecnt) * sizeof(char), input);
- if (writecnt >= totalcnt) {
- totalcnt += MEMBLK;
- if (((*buffer) =
- rrd_realloc((*buffer),
- (totalcnt + 4) * sizeof(char))) == NULL) {
- perror("Realloc Buffer:");
- exit(1);
- };
- }
- } while (!feof(input));
- (*buffer)[writecnt] = '\0';
- if (strcmp("-", file_name) != 0) {
- fclose(input);
- };
- return writecnt;
-}
--- /dev/null
+/*
+ * rrd_parsetime.c - parse time for at(1)
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * modifications for English-language times
+ * Copyright (C) 1993 David Parsons
+ *
+ * A lot of modifications and extensions
+ * (including the new syntax being useful for RRDB)
+ * Copyright (C) 1999 Oleg Cherevko (aka Olwi Deer)
+ *
+ * severe structural damage inflicted by Tobi Oetiker in 1999
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author(s) may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* NOTE: nothing in here is thread-safe!!!! Not even the localtime
+ calls ... */
+
+/*
+ * The BNF-like specification of the time syntax parsed is below:
+ *
+ * As usual, [ X ] means that X is optional, { X } means that X may
+ * be either omitted or specified as many times as needed,
+ * alternatives are separated by |, brackets are used for grouping.
+ * (# marks the beginning of comment that extends to the end of line)
+ *
+ * TIME-SPECIFICATION ::= TIME-REFERENCE [ OFFSET-SPEC ] |
+ * OFFSET-SPEC |
+ * ( START | END ) OFFSET-SPEC
+ *
+ * TIME-REFERENCE ::= NOW | TIME-OF-DAY-SPEC [ DAY-SPEC-1 ] |
+ * [ TIME-OF-DAY-SPEC ] DAY-SPEC-2
+ *
+ * TIME-OF-DAY-SPEC ::= NUMBER (':') NUMBER [am|pm] | # HH:MM
+ * 'noon' | 'midnight' | 'teatime'
+ *
+ * DAY-SPEC-1 ::= NUMBER '/' NUMBER '/' NUMBER | # MM/DD/[YY]YY
+ * NUMBER '.' NUMBER '.' NUMBER | # DD.MM.[YY]YY
+ * NUMBER # Seconds since 1970
+ * NUMBER # YYYYMMDD
+ *
+ * DAY-SPEC-2 ::= MONTH-NAME NUMBER [NUMBER] | # Month DD [YY]YY
+ * 'yesterday' | 'today' | 'tomorrow' |
+ * DAY-OF-WEEK
+ *
+ *
+ * OFFSET-SPEC ::= '+'|'-' NUMBER TIME-UNIT { ['+'|'-'] NUMBER TIME-UNIT }
+ *
+ * TIME-UNIT ::= SECONDS | MINUTES | HOURS |
+ * DAYS | WEEKS | MONTHS | YEARS
+ *
+ * NOW ::= 'now' | 'n'
+ *
+ * START ::= 'start' | 's'
+ * END ::= 'end' | 'e'
+ *
+ * SECONDS ::= 'seconds' | 'second' | 'sec' | 's'
+ * MINUTES ::= 'minutes' | 'minute' | 'min' | 'm'
+ * HOURS ::= 'hours' | 'hour' | 'hr' | 'h'
+ * DAYS ::= 'days' | 'day' | 'd'
+ * WEEKS ::= 'weeks' | 'week' | 'wk' | 'w'
+ * MONTHS ::= 'months' | 'month' | 'mon' | 'm'
+ * YEARS ::= 'years' | 'year' | 'yr' | 'y'
+ *
+ * MONTH-NAME ::= 'jan' | 'january' | 'feb' | 'february' | 'mar' | 'march' |
+ * 'apr' | 'april' | 'may' | 'jun' | 'june' | 'jul' | 'july' |
+ * 'aug' | 'august' | 'sep' | 'september' | 'oct' | 'october' |
+ * 'nov' | 'november' | 'dec' | 'december'
+ *
+ * DAY-OF-WEEK ::= 'sunday' | 'sun' | 'monday' | 'mon' | 'tuesday' | 'tue' |
+ * 'wednesday' | 'wed' | 'thursday' | 'thu' | 'friday' | 'fri' |
+ * 'saturday' | 'sat'
+ *
+ *
+ * As you may note, there is an ambiguity with respect to
+ * the 'm' time unit (which can mean either minutes or months).
+ * To cope with this, code tries to read users mind :) by applying
+ * certain heuristics. There are two of them:
+ *
+ * 1. If 'm' is used in context of (i.e. right after the) years,
+ * months, weeks, or days it is assumed to mean months, while
+ * in the context of hours, minutes, and seconds it means minutes.
+ * (e.g., in -1y6m or +3w1m 'm' means 'months', while in
+ * -3h20m or +5s2m 'm' means 'minutes')
+ *
+ * 2. Out of context (i.e. right after the '+' or '-' sign) the
+ * meaning of 'm' is guessed from the number it directly follows.
+ * Currently, if the number absolute value is below 25 it is assumed
+ * that 'm' means months, otherwise it is treated as minutes.
+ * (e.g., -25m == -25 minutes, while +24m == +24 months)
+ *
+ */
+
+/* System Headers */
+
+/* Local headers */
+
+#include "rrd_tool.h"
+#include <stdarg.h>
+
+/* Structures and unions */
+
+enum { /* symbols */
+ MIDNIGHT, NOON, TEATIME,
+ PM, AM, YESTERDAY, TODAY, TOMORROW, NOW, START, END,
+ SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
+ MONTHS_MINUTES,
+ NUMBER, PLUS, MINUS, DOT, COLON, SLASH, ID, JUNK,
+ JAN, FEB, MAR, APR, MAY, JUN,
+ JUL, AUG, SEP, OCT, NOV, DEC,
+ SUN, MON, TUE, WED, THU, FRI, SAT
+};
+
+/* the below is for plus_minus() */
+#define PREVIOUS_OP (-1)
+
+/* parse translation table - table driven parsers can be your FRIEND!
+ */
+struct SpecialToken {
+ char *name; /* token name */
+ int value; /* token id */
+};
+static const struct SpecialToken VariousWords[] = {
+ {"midnight", MIDNIGHT}, /* 00:00:00 of today or tomorrow */
+ {"noon", NOON}, /* 12:00:00 of today or tomorrow */
+ {"teatime", TEATIME}, /* 16:00:00 of today or tomorrow */
+ {"am", AM}, /* morning times for 0-12 clock */
+ {"pm", PM}, /* evening times for 0-12 clock */
+ {"tomorrow", TOMORROW},
+ {"yesterday", YESTERDAY},
+ {"today", TODAY},
+ {"now", NOW},
+ {"n", NOW},
+ {"start", START},
+ {"s", START},
+ {"end", END},
+ {"e", END},
+
+ {"jan", JAN},
+ {"feb", FEB},
+ {"mar", MAR},
+ {"apr", APR},
+ {"may", MAY},
+ {"jun", JUN},
+ {"jul", JUL},
+ {"aug", AUG},
+ {"sep", SEP},
+ {"oct", OCT},
+ {"nov", NOV},
+ {"dec", DEC},
+ {"january", JAN},
+ {"february", FEB},
+ {"march", MAR},
+ {"april", APR},
+ {"may", MAY},
+ {"june", JUN},
+ {"july", JUL},
+ {"august", AUG},
+ {"september", SEP},
+ {"october", OCT},
+ {"november", NOV},
+ {"december", DEC},
+ {"sunday", SUN},
+ {"sun", SUN},
+ {"monday", MON},
+ {"mon", MON},
+ {"tuesday", TUE},
+ {"tue", TUE},
+ {"wednesday", WED},
+ {"wed", WED},
+ {"thursday", THU},
+ {"thu", THU},
+ {"friday", FRI},
+ {"fri", FRI},
+ {"saturday", SAT},
+ {"sat", SAT},
+ {NULL, 0} /*** SENTINEL ***/
+};
+
+static const struct SpecialToken TimeMultipliers[] = {
+ {"second", SECONDS}, /* seconds multiplier */
+ {"seconds", SECONDS}, /* (pluralized) */
+ {"sec", SECONDS}, /* (generic) */
+ {"s", SECONDS}, /* (short generic) */
+ {"minute", MINUTES}, /* minutes multiplier */
+ {"minutes", MINUTES}, /* (pluralized) */
+ {"min", MINUTES}, /* (generic) */
+ {"m", MONTHS_MINUTES}, /* (short generic) */
+ {"hour", HOURS}, /* hours ... */
+ {"hours", HOURS}, /* (pluralized) */
+ {"hr", HOURS}, /* (generic) */
+ {"h", HOURS}, /* (short generic) */
+ {"day", DAYS}, /* days ... */
+ {"days", DAYS}, /* (pluralized) */
+ {"d", DAYS}, /* (short generic) */
+ {"week", WEEKS}, /* week ... */
+ {"weeks", WEEKS}, /* (pluralized) */
+ {"wk", WEEKS}, /* (generic) */
+ {"w", WEEKS}, /* (short generic) */
+ {"month", MONTHS}, /* week ... */
+ {"months", MONTHS}, /* (pluralized) */
+ {"mon", MONTHS}, /* (generic) */
+ {"year", YEARS}, /* year ... */
+ {"years", YEARS}, /* (pluralized) */
+ {"yr", YEARS}, /* (generic) */
+ {"y", YEARS}, /* (short generic) */
+ {NULL, 0} /*** SENTINEL ***/
+};
+
+/* File scope variables */
+
+/* context dependent list of specials for parser to recognize,
+ * required for us to be able distinguish between 'mon' as 'month'
+ * and 'mon' as 'monday'
+ */
+static const struct SpecialToken *Specials;
+
+static const char **scp; /* scanner - pointer at arglist */
+static char scc; /* scanner - count of remaining arguments */
+static const char *sct; /* scanner - next char pointer in current argument */
+static int need; /* scanner - need to advance to next argument */
+
+static char *sc_token = NULL; /* scanner - token buffer */
+static size_t sc_len; /* scanner - length of token buffer */
+static int sc_tokid; /* scanner - token id */
+
+/* Local functions */
+static void EnsureMemFree(
+ void);
+
+static void EnsureMemFree(
+ void)
+{
+ if (sc_token) {
+ free(sc_token);
+ sc_token = NULL;
+ }
+}
+
+/*
+ * A hack to compensate for the lack of the C++ exceptions
+ *
+ * Every function func that might generate parsing "exception"
+ * should return TIME_OK (aka NULL) or pointer to the error message,
+ * and should be called like this: try(func(args));
+ *
+ * if the try is not successful it will reset the token pointer ...
+ *
+ * [NOTE: when try(...) is used as the only statement in the "if-true"
+ * part of the if statement that also has an "else" part it should be
+ * either enclosed in the curly braces (despite the fact that it looks
+ * like a single statement) or NOT followed by the ";"]
+ */
+#define try(b) { \
+ char *_e; \
+ if((_e=(b))) \
+ { \
+ EnsureMemFree(); \
+ return _e; \
+ } \
+ }
+
+/*
+ * The panic() function was used in the original code to die, we redefine
+ * it as macro to start the chain of ascending returns that in conjunction
+ * with the try(b) above will simulate a sort of "exception handling"
+ */
+
+#define panic(e) { \
+ return (e); \
+ }
+
+/*
+ * ve() and e() are used to set the return error,
+ * the most appropriate use for these is inside panic(...)
+ */
+#define MAX_ERR_MSG_LEN 1024
+static char errmsg[MAX_ERR_MSG_LEN];
+
+static char *ve(
+ char *fmt,
+ va_list ap)
+{
+#ifdef HAVE_VSNPRINTF
+ vsnprintf(errmsg, MAX_ERR_MSG_LEN, fmt, ap);
+#else
+ vsprintf(errmsg, fmt, ap);
+#endif
+ EnsureMemFree();
+ return (errmsg);
+}
+
+static char *e(
+ char *fmt,
+ ...)
+{
+ char *err;
+ va_list ap;
+
+ va_start(ap, fmt);
+ err = ve(fmt, ap);
+ va_end(ap);
+ return (err);
+}
+
+/* Compare S1 and S2, ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less than,
+ equal to or greater than S2. -- copied from GNU libc*/
+static int mystrcasecmp(
+ const char *s1,
+ const char *s2)
+{
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ if (p1 == p2)
+ return 0;
+
+ do {
+ c1 = tolower(*p1++);
+ c2 = tolower(*p2++);
+ if (c1 == '\0')
+ break;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+
+/*
+ * parse a token, checking if it's something special to us
+ */
+static int parse_token(
+ char *arg)
+{
+ int i;
+
+ for (i = 0; Specials[i].name != NULL; i++)
+ if (mystrcasecmp(Specials[i].name, arg) == 0)
+ return sc_tokid = Specials[i].value;
+
+ /* not special - must be some random id */
+ return sc_tokid = ID;
+} /* parse_token */
+
+
+
+/*
+ * init_scanner() sets up the scanner to eat arguments
+ */
+static char *init_scanner(
+ int argc,
+ const char **argv)
+{
+ scp = argv;
+ scc = argc;
+ need = 1;
+ sc_len = 1;
+ while (argc-- > 0)
+ sc_len += strlen(*argv++);
+
+ sc_token = (char *) malloc(sc_len * sizeof(char));
+ if (sc_token == NULL)
+ return "Failed to allocate memory";
+ return TIME_OK;
+} /* init_scanner */
+
+/*
+ * token() fetches a token from the input stream
+ */
+static int token(
+ void)
+{
+ int idx;
+
+ while (1) {
+ memset(sc_token, '\0', sc_len);
+ sc_tokid = EOF;
+ idx = 0;
+
+ /* if we need to read another argument, walk along the argument list;
+ * when we fall off the arglist, we'll just return EOF forever
+ */
+ if (need) {
+ if (scc < 1)
+ return sc_tokid;
+ sct = *scp;
+ scp++;
+ scc--;
+ need = 0;
+ }
+ /* eat whitespace now - if we walk off the end of the argument,
+ * we'll continue, which puts us up at the top of the while loop
+ * to fetch the next argument in
+ */
+ while (isspace((unsigned char) *sct) || *sct == '_' || *sct == ',')
+ ++sct;
+ if (!*sct) {
+ need = 1;
+ continue;
+ }
+
+ /* preserve the first character of the new token
+ */
+ sc_token[0] = *sct++;
+
+ /* then see what it is
+ */
+ if (isdigit((unsigned char) (sc_token[0]))) {
+ while (isdigit((unsigned char) (*sct)))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = '\0';
+ return sc_tokid = NUMBER;
+ } else if (isalpha((unsigned char) (sc_token[0]))) {
+ while (isalpha((unsigned char) (*sct)))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = '\0';
+ return parse_token(sc_token);
+ } else
+ switch (sc_token[0]) {
+ case ':':
+ return sc_tokid = COLON;
+ case '.':
+ return sc_tokid = DOT;
+ case '+':
+ return sc_tokid = PLUS;
+ case '-':
+ return sc_tokid = MINUS;
+ case '/':
+ return sc_tokid = SLASH;
+ default:
+ /*OK, we did not make it ... */
+ sct--;
+ return sc_tokid = EOF;
+ }
+ } /* while (1) */
+} /* token */
+
+
+/*
+ * expect2() gets a token and complains if it's not the token we want
+ */
+static char *expect2(
+ int desired,
+ char *complain_fmt,
+ ...)
+{
+ va_list ap;
+
+ va_start(ap, complain_fmt);
+ if (token() != desired) {
+ panic(ve(complain_fmt, ap));
+ }
+ va_end(ap);
+ return TIME_OK;
+
+} /* expect2 */
+
+
+/*
+ * plus_minus() is used to parse a single NUMBER TIME-UNIT pair
+ * for the OFFSET-SPEC.
+ * It also applies those m-guessing heuristics.
+ */
+static char *plus_minus(
+ rrd_time_value_t *ptv,
+ int doop)
+{
+ static int op = PLUS;
+ static int prev_multiplier = -1;
+ int delta;
+
+ if (doop >= 0) {
+ op = doop;
+ try(expect2
+ (NUMBER, "There should be number after '%c'",
+ op == PLUS ? '+' : '-'));
+ prev_multiplier = -1; /* reset months-minutes guessing mechanics */
+ }
+ /* if doop is < 0 then we repeat the previous op
+ * with the prefetched number */
+
+ delta = atoi(sc_token);
+
+ if (token() == MONTHS_MINUTES) {
+ /* hard job to guess what does that -5m means: -5mon or -5min? */
+ switch (prev_multiplier) {
+ case DAYS:
+ case WEEKS:
+ case MONTHS:
+ case YEARS:
+ sc_tokid = MONTHS;
+ break;
+
+ case SECONDS:
+ case MINUTES:
+ case HOURS:
+ sc_tokid = MINUTES;
+ break;
+
+ default:
+ if (delta < 6) /* it may be some other value but in the context
+ * of RRD who needs less than 6 min deltas? */
+ sc_tokid = MONTHS;
+ else
+ sc_tokid = MINUTES;
+ }
+ }
+ prev_multiplier = sc_tokid;
+ switch (sc_tokid) {
+ case YEARS:
+ ptv->tm. tm_year += (
+ op == PLUS) ? delta : -delta;
+
+ return TIME_OK;
+ case MONTHS:
+ ptv->tm. tm_mon += (
+ op == PLUS) ? delta : -delta;
+
+ return TIME_OK;
+ case WEEKS:
+ delta *= 7;
+ /* FALLTHRU */
+ case DAYS:
+ ptv->tm. tm_mday += (
+ op == PLUS) ? delta : -delta;
+
+ return TIME_OK;
+ case HOURS:
+ ptv->offset += (op == PLUS) ? delta * 60 * 60 : -delta * 60 * 60;
+ return TIME_OK;
+ case MINUTES:
+ ptv->offset += (op == PLUS) ? delta * 60 : -delta * 60;
+ return TIME_OK;
+ case SECONDS:
+ ptv->offset += (op == PLUS) ? delta : -delta;
+ return TIME_OK;
+ default: /*default unit is seconds */
+ ptv->offset += (op == PLUS) ? delta : -delta;
+ return TIME_OK;
+ }
+ panic(e("well-known time unit expected after %d", delta));
+ /* NORETURN */
+ return TIME_OK; /* to make compiler happy :) */
+} /* plus_minus */
+
+
+/*
+ * tod() computes the time of day (TIME-OF-DAY-SPEC)
+ */
+static char *tod(
+ rrd_time_value_t *ptv)
+{
+ int hour, minute = 0;
+ int tlen;
+
+ /* save token status in case we must abort */
+ int scc_sv = scc;
+ const char *sct_sv = sct;
+ int sc_tokid_sv = sc_tokid;
+
+ tlen = strlen(sc_token);
+
+ /* first pick out the time of day - we assume a HH (COLON|DOT) MM time
+ */
+ if (tlen > 2) {
+ return TIME_OK;
+ }
+
+ hour = atoi(sc_token);
+
+ token();
+ if (sc_tokid == SLASH || sc_tokid == DOT) {
+ /* guess we are looking at a date */
+ scc = scc_sv;
+ sct = sct_sv;
+ sc_tokid = sc_tokid_sv;
+ sprintf(sc_token, "%d", hour);
+ return TIME_OK;
+ }
+ if (sc_tokid == COLON) {
+ try(expect2(NUMBER,
+ "Parsing HH:MM syntax, expecting MM as number, got none"));
+ minute = atoi(sc_token);
+ if (minute > 59) {
+ panic(e("parsing HH:MM syntax, got MM = %d (>59!)", minute));
+ }
+ token();
+ }
+
+ /* check if an AM or PM specifier was given
+ */
+ if (sc_tokid == AM || sc_tokid == PM) {
+ if (hour > 12) {
+ panic(e("there cannot be more than 12 AM or PM hours"));
+ }
+ if (sc_tokid == PM) {
+ if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
+ hour += 12;
+ } else {
+ if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
+ hour = 0;
+ }
+ token();
+ } else if (hour > 23) {
+ /* guess it was not a time then ... */
+ scc = scc_sv;
+ sct = sct_sv;
+ sc_tokid = sc_tokid_sv;
+ sprintf(sc_token, "%d", hour);
+ return TIME_OK;
+ }
+ ptv->tm. tm_hour = hour;
+ ptv->tm. tm_min = minute;
+ ptv->tm. tm_sec = 0;
+
+ if (ptv->tm.tm_hour == 24) {
+ ptv->tm. tm_hour = 0;
+ ptv->tm. tm_mday++;
+ }
+ return TIME_OK;
+} /* tod */
+
+
+/*
+ * assign_date() assigns a date, adjusting year as appropriate
+ */
+static char *assign_date(
+ rrd_time_value_t *ptv,
+ long mday,
+ long mon,
+ long year)
+{
+ if (year > 138) {
+ if (year > 1970)
+ year -= 1900;
+ else {
+ panic(e("invalid year %d (should be either 00-99 or >1900)",
+ year));
+ }
+ } else if (year >= 0 && year < 38) {
+ year += 100; /* Allow year 2000-2037 to be specified as */
+ }
+ /* 00-37 until the problem of 2038 year will */
+ /* arise for unices with 32-bit time_t :) */
+ if (year < 70) {
+ panic(e("won't handle dates before epoch (01/01/1970), sorry"));
+ }
+
+ ptv->tm. tm_mday = mday;
+ ptv->tm. tm_mon = mon;
+ ptv->tm. tm_year = year;
+
+ return TIME_OK;
+} /* assign_date */
+
+
+/*
+ * day() picks apart DAY-SPEC-[12]
+ */
+static char *day(
+ rrd_time_value_t *ptv)
+{
+ /* using time_t seems to help portability with 64bit oses */
+ time_t mday = 0, wday, mon, year = ptv->tm.tm_year;
+ int tlen;
+
+ switch (sc_tokid) {
+ case YESTERDAY:
+ ptv->tm. tm_mday--;
+
+ /* FALLTRHU */
+ case TODAY: /* force ourselves to stay in today - no further processing */
+ token();
+ break;
+ case TOMORROW:
+ ptv->tm. tm_mday++;
+
+ token();
+ break;
+
+ case JAN:
+ case FEB:
+ case MAR:
+ case APR:
+ case MAY:
+ case JUN:
+ case JUL:
+ case AUG:
+ case SEP:
+ case OCT:
+ case NOV:
+ case DEC:
+ /* do month mday [year]
+ */
+ mon = (sc_tokid - JAN);
+ try(expect2(NUMBER, "the day of the month should follow month name"));
+ mday = atol(sc_token);
+ if (token() == NUMBER) {
+ year = atol(sc_token);
+ token();
+ } else
+ year = ptv->tm.tm_year;
+
+ try(assign_date(ptv, mday, mon, year));
+ break;
+
+ case SUN:
+ case MON:
+ case TUE:
+ case WED:
+ case THU:
+ case FRI:
+ case SAT:
+ /* do a particular day of the week
+ */
+ wday = (sc_tokid - SUN);
+ ptv->tm. tm_mday += (
+ wday - ptv->tm.tm_wday);
+
+ token();
+ break;
+ /*
+ mday = ptv->tm.tm_mday;
+ mday += (wday - ptv->tm.tm_wday);
+ ptv->tm.tm_wday = wday;
+
+ try(assign_date(ptv, mday, ptv->tm.tm_mon, ptv->tm.tm_year));
+ break;
+ */
+
+ case NUMBER:
+ /* get numeric <sec since 1970>, MM/DD/[YY]YY, or DD.MM.[YY]YY
+ */
+ tlen = strlen(sc_token);
+ mon = atol(sc_token);
+ if (mon > 10 * 365 * 24 * 60 * 60) {
+ ptv->tm = *localtime(&mon);
+
+ token();
+ break;
+ }
+
+ if (mon > 19700101 && mon < 24000101) { /*works between 1900 and 2400 */
+ char cmon[3], cmday[3], cyear[5];
+
+ strncpy(cyear, sc_token, 4);
+ cyear[4] = '\0';
+ year = atol(cyear);
+ strncpy(cmon, &(sc_token[4]), 2);
+ cmon[2] = '\0';
+ mon = atol(cmon);
+ strncpy(cmday, &(sc_token[6]), 2);
+ cmday[2] = '\0';
+ mday = atol(cmday);
+ token();
+ } else {
+ token();
+
+ if (mon <= 31 && (sc_tokid == SLASH || sc_tokid == DOT)) {
+ int sep;
+
+ sep = sc_tokid;
+ try(expect2(NUMBER, "there should be %s number after '%c'",
+ sep == DOT ? "month" : "day",
+ sep == DOT ? '.' : '/'));
+ mday = atol(sc_token);
+ if (token() == sep) {
+ try(expect2
+ (NUMBER, "there should be year number after '%c'",
+ sep == DOT ? '.' : '/'));
+ year = atol(sc_token);
+ token();
+ }
+
+ /* flip months and days for European timing
+ */
+ if (sep == DOT) {
+ long x = mday;
+
+ mday = mon;
+ mon = x;
+ }
+ }
+ }
+
+ mon--;
+ if (mon < 0 || mon > 11) {
+ panic(e("did you really mean month %d?", mon + 1));
+ }
+ if (mday < 1 || mday > 31) {
+ panic(e("I'm afraid that %d is not a valid day of the month",
+ mday));
+ }
+ try(assign_date(ptv, mday, mon, year));
+ break;
+ } /* case */
+ return TIME_OK;
+} /* month */
+
+
+/* Global functions */
+
+
+/*
+ * rrd_parsetime() is the external interface that takes tspec, parses
+ * it and puts the result in the rrd_time_value structure *ptv.
+ * It can return either absolute times (these are ensured to be
+ * correct) or relative time references that are expected to be
+ * added to some absolute time value and then normalized by
+ * mktime() The return value is either TIME_OK (aka NULL) or
+ * the pointer to the error message in the case of problems
+ */
+char *rrd_parsetime(
+ const char *tspec,
+ rrd_time_value_t *ptv)
+{
+ time_t now = time(NULL);
+ int hr = 0;
+
+ /* this MUST be initialized to zero for midnight/noon/teatime */
+
+ Specials = VariousWords; /* initialize special words context */
+
+ try(init_scanner(1, &tspec));
+
+ /* establish the default time reference */
+ ptv->type = ABSOLUTE_TIME;
+ ptv->offset = 0;
+ ptv->tm = *localtime(&now);
+ ptv->tm. tm_isdst = -1; /* mk time can figure dst by default ... */
+
+ token();
+ switch (sc_tokid) {
+ case PLUS:
+ case MINUS:
+ break; /* jump to OFFSET-SPEC part */
+
+ case START:
+ ptv->type = RELATIVE_TO_START_TIME;
+ goto KeepItRelative;
+ case END:
+ ptv->type = RELATIVE_TO_END_TIME;
+ KeepItRelative:
+ ptv->tm. tm_sec = 0;
+ ptv->tm. tm_min = 0;
+ ptv->tm. tm_hour = 0;
+ ptv->tm. tm_mday = 0;
+ ptv->tm. tm_mon = 0;
+ ptv->tm. tm_year = 0;
+
+ /* FALLTHRU */
+ case NOW:
+ {
+ int time_reference = sc_tokid;
+
+ token();
+ if (sc_tokid == PLUS || sc_tokid == MINUS)
+ break;
+ if (time_reference != NOW) {
+ panic(e("'start' or 'end' MUST be followed by +|- offset"));
+ } else if (sc_tokid != EOF) {
+ panic(e("if 'now' is followed by a token it must be +|- offset"));
+ }
+ };
+ break;
+
+ /* Only absolute time specifications below */
+ case NUMBER:
+ {
+ long hour_sv = ptv->tm.tm_hour;
+ long year_sv = ptv->tm.tm_year;
+
+ ptv->tm. tm_hour = 30;
+ ptv->tm. tm_year = 30000;
+
+ try(tod(ptv))
+ try(day(ptv))
+ if (ptv->tm.tm_hour == 30 && ptv->tm.tm_year != 30000) {
+ try(tod(ptv))
+ }
+ if (ptv->tm.tm_hour == 30) {
+ ptv->tm. tm_hour = hour_sv;
+ }
+ if (ptv->tm.tm_year == 30000) {
+ ptv->tm. tm_year = year_sv;
+ }
+ };
+ break;
+ /* fix month parsing */
+ case JAN:
+ case FEB:
+ case MAR:
+ case APR:
+ case MAY:
+ case JUN:
+ case JUL:
+ case AUG:
+ case SEP:
+ case OCT:
+ case NOV:
+ case DEC:
+ try(day(ptv));
+ if (sc_tokid != NUMBER)
+ break;
+ try(tod(ptv))
+ break;
+
+ /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialized
+ * hr to zero up above, then fall into this case in such a
+ * way so we add +12 +4 hours to it for teatime, +12 hours
+ * to it for noon, and nothing at all for midnight, then
+ * set our rettime to that hour before leaping into the
+ * month scanner
+ */
+ case TEATIME:
+ hr += 4;
+ /* FALLTHRU */
+ case NOON:
+ hr += 12;
+ /* FALLTHRU */
+ case MIDNIGHT:
+ /* if (ptv->tm.tm_hour >= hr) {
+ ptv->tm.tm_mday++;
+ ptv->tm.tm_wday++;
+ } *//* shifting does not makes sense here ... noon is noon */
+ ptv->tm. tm_hour = hr;
+ ptv->tm. tm_min = 0;
+ ptv->tm. tm_sec = 0;
+
+ token();
+ try(day(ptv));
+ break;
+ default:
+ panic(e("unparsable time: %s%s", sc_token, sct));
+ break;
+ } /* ugly case statement */
+
+ /*
+ * the OFFSET-SPEC part
+ *
+ * (NOTE, the sc_tokid was prefetched for us by the previous code)
+ */
+ if (sc_tokid == PLUS || sc_tokid == MINUS) {
+ Specials = TimeMultipliers; /* switch special words context */
+ while (sc_tokid == PLUS || sc_tokid == MINUS || sc_tokid == NUMBER) {
+ if (sc_tokid == NUMBER) {
+ try(plus_minus(ptv, PREVIOUS_OP));
+ } else
+ try(plus_minus(ptv, sc_tokid));
+ token(); /* We will get EOF eventually but that's OK, since
+ token() will return us as many EOFs as needed */
+ }
+ }
+
+ /* now we should be at EOF */
+ if (sc_tokid != EOF) {
+ panic(e("unparsable trailing text: '...%s%s'", sc_token, sct));
+ }
+
+ if (ptv->type == ABSOLUTE_TIME)
+ if (mktime(&ptv->tm) == -1) { /* normalize & check */
+ /* can happen for "nonexistent" times, e.g. around 3am */
+ /* when winter -> summer time correction eats a hour */
+ panic(e("the specified time is incorrect (out of range?)"));
+ }
+ EnsureMemFree();
+ return TIME_OK;
+} /* rrd_parsetime */
+
+
+int rrd_proc_start_end(
+ rrd_time_value_t *start_tv,
+ rrd_time_value_t *end_tv,
+ time_t *start,
+ time_t *end)
+{
+ if (start_tv->type == RELATIVE_TO_END_TIME && /* same as the line above */
+ end_tv->type == RELATIVE_TO_START_TIME) {
+ rrd_set_error("the start and end times cannot be specified "
+ "relative to each other");
+ return -1;
+ }
+
+ if (start_tv->type == RELATIVE_TO_START_TIME) {
+ rrd_set_error
+ ("the start time cannot be specified relative to itself");
+ return -1;
+ }
+
+ if (end_tv->type == RELATIVE_TO_END_TIME) {
+ rrd_set_error("the end time cannot be specified relative to itself");
+ return -1;
+ }
+
+ if (start_tv->type == RELATIVE_TO_END_TIME) {
+ struct tm tmtmp;
+
+ *end = mktime(&(end_tv->tm)) + end_tv->offset;
+ tmtmp = *localtime(end); /* reinit end including offset */
+ tmtmp.tm_mday += start_tv->tm.tm_mday;
+ tmtmp.tm_mon += start_tv->tm.tm_mon;
+ tmtmp.tm_year += start_tv->tm.tm_year;
+
+ *start = mktime(&tmtmp) + start_tv->offset;
+ } else {
+ *start = mktime(&(start_tv->tm)) + start_tv->offset;
+ }
+ if (end_tv->type == RELATIVE_TO_START_TIME) {
+ struct tm tmtmp;
+
+ *start = mktime(&(start_tv->tm)) + start_tv->offset;
+ tmtmp = *localtime(start);
+ tmtmp.tm_mday += end_tv->tm.tm_mday;
+ tmtmp.tm_mon += end_tv->tm.tm_mon;
+ tmtmp.tm_year += end_tv->tm.tm_year;
+
+ *end = mktime(&tmtmp) + end_tv->offset;
+ } else {
+ *end = mktime(&(end_tv->tm)) + end_tv->offset;
+ }
+ return 0;
+} /* rrd_proc_start_end */
--- /dev/null
+#ifndef __PARSETIME_H__
+#define __PARSETIME_H__
+
+#include <stdio.h>
+
+#include "rrd.h"
+
+#endif
rrd_free(&rrdold);
return (-1);
}
- if (LockRRD(rrd_file->fd) != 0) {
+ if (rrd_lock(rrd_file) != 0) {
rrd_set_error("could not lock original RRD");
rrd_free(&rrdold);
rrd_close(rrd_file);
rrd_free(&rrdnew);
return (-1);
}
- if (LockRRD(rrd_out_file->fd) != 0) {
+ if (rrd_lock(rrd_out_file) != 0) {
rrd_set_error("could not lock new RRD");
rrd_free(&rrdold);
rrd_close(rrd_file);
static void context_destroy_context(
void *ctx_)
{
- struct rrd_context *ctx = ctx_;
+ rrd_context_t *ctx = ctx_;
if (ctx)
rrd_free_context(ctx);
pthread_key_create(&context_key, context_destroy_context);
}
-struct rrd_context *rrd_get_context(
+rrd_context_t *rrd_get_context(
void)
{
- struct rrd_context *ctx;
+ rrd_context_t *ctx;
pthread_once(&context_key_once, context_get_key);
ctx = pthread_getspecific(context_key);
const char *rrd_strerror(
int err)
{
- struct rrd_context *ctx = rrd_get_context();
+ rrd_context_t *ctx = rrd_get_context();
if (strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr)))
return "strerror_r failed. sorry!";
int err)
{
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
- struct rrd_context *ctx;
+ rrd_context_t *ctx;
ctx = rrd_get_context();
pthread_mutex_lock(&mtx);
atexit(context_destroy_context);
}
}
-struct rrd_context *rrd_get_context(
+rrd_context_t *rrd_get_context(
void)
{
- struct rrd_context *ctx;
+ rrd_context_t *ctx;
context_init_context();
const char *rrd_strerror(
int err)
{
- struct rrd_context *ctx;
+ rrd_context_t *ctx;
context_init_context();
else if (strcmp("dump", argv[1]) == 0)
rrd_dump(argc - 1, &argv[1]);
else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
- info_t *data;
+ rrd_info_t *data;
if (strcmp("info", argv[1]) == 0)
data = rrd_info(argc - 1, &argv[1]);
else
data = rrd_update_v(argc - 1, &argv[1]);
- info_print(data);
- info_free(data);
+ rrd_info_print(data);
+ rrd_info_free(data);
}
else if (strcmp("--version", argv[1]) == 0 ||
}
} else if (strcmp("graphv", argv[1]) == 0) {
- info_t *grinfo = NULL; /* 1 to distinguish it from the NULL that rrd_graph sends in */
+ rrd_info_t *grinfo = NULL; /* 1 to distinguish it from the NULL that rrd_graph sends in */
grinfo = rrd_graph_v(argc - 1, &argv[1]);
if (grinfo) {
- info_print(grinfo);
- info_free(grinfo);
+ rrd_info_print(grinfo);
+ rrd_info_free(grinfo);
}
} else if (strcmp("tune", argv[1]) == 0)
#define DIM(x) (sizeof(x)/sizeof(x[0]))
- info_t *rrd_info(
- int,
- char **);
- int rrd_lastupdate(
- int argc,
- char **argv,
- time_t *last_update,
- unsigned long *ds_cnt,
- char ***ds_namv,
- char ***last_ds);
- info_t *rrd_update_v(
- int,
- char **);
char *sprintf_alloc(
char *,
...);
- info_t *info_push(
- info_t *,
- char *,
- enum info_type,
- infoval);
- void info_print(
- info_t *data);
- void info_free(
- info_t *);
/* HELPER FUNCTIONS */
int whence);
off_t rrd_tell(
rrd_file_t *rrd_file);
- int readfile(
- const char *file,
- char **buffer,
- int skipfirst);
+ int rrd_lock(
+ rrd_file_t *file);
#define RRD_READONLY (1<<0)
#define RRD_READWRITE (1<<1)
char *a,
char *b);
- /* rrd_strerror is thread safe, but still it uses a global buffer
- (but one per thread), thus subsequent calls within a single
- thread overwrite the same buffer */
- const char *rrd_strerror(
- int err);
-
#endif
#ifdef __cplusplus
const char *tmplt,
int argc,
const char **argv,
- info_t *);
+ rrd_info_t *);
static int allocate_data_structures(
rrd_t *rrd,
char **updvals,
long *tmpl_idx,
unsigned long tmpl_cnt,
- info_t **pcdp_summary,
+ rrd_info_t **pcdp_summary,
int version,
unsigned long *skip_update,
int *schedule_smooth);
unsigned long *rra_current,
time_t current_time,
unsigned long *skip_update,
- info_t **pcdp_summary);
+ rrd_info_t **pcdp_summary);
static int write_RRA_row(
rrd_file_t *rrd_file,
unsigned long rra_idx,
unsigned long *rra_current,
unsigned short CDP_scratch_idx,
- info_t **pcdp_summary,
+ rrd_info_t **pcdp_summary,
time_t rra_time);
static int smooth_all_rras(
#define IFDNAN(X,Y) (isnan(X) ? (Y) : (X));
-info_t *rrd_update_v(
+rrd_info_t *rrd_update_v(
int argc,
char **argv)
{
char *tmplt = NULL;
- info_t *result = NULL;
- infoval rc;
+ rrd_info_t *result = NULL;
+ rrd_infoval_t rc;
struct option long_options[] = {
{"template", required_argument, 0, 't'},
{0, 0, 0, 0}
goto end_tag;
}
rc.u_int = 0;
- result = info_push(NULL, sprintf_alloc("return_value"), RD_I_INT, rc);
+ result = rrd_info_push(NULL, sprintf_alloc("return_value"), RD_I_INT, rc);
rc.u_int = _rrd_update(argv[optind], tmplt,
argc - optind - 1,
(const char **) (argv + optind + 1), result);
const char *tmplt,
int argc,
const char **argv,
- info_t *pcdp_summary)
+ rrd_info_t *pcdp_summary)
{
int arg_i = 2;
/* get exclusive lock to whole file.
* lock gets removed when we close the file.
*/
- if (LockRRD(rrd_file->fd) != 0) {
+ if (rrd_lock(rrd_file) != 0) {
rrd_set_error("could not lock RRD");
goto err_close;
}
*
* returns 0 on success
*/
-int LockRRD(
- int in_file)
+int rrd_lock(
+ rrd_file_t *file)
{
int rcstat;
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
struct _stat st;
- if (_fstat(in_file, &st) == 0) {
- rcstat = _locking(in_file, _LK_NBLCK, st.st_size);
+ if (_fstat(file->fd, &st) == 0) {
+ rcstat = _locking(file->fd, _LK_NBLCK, st.st_size);
} else {
rcstat = -1;
}
lock.l_start = 0; /* start of file */
lock.l_whence = SEEK_SET; /* end of file */
- rcstat = fcntl(in_file, F_SETLK, &lock);
+ rcstat = fcntl(file->fd, F_SETLK, &lock);
#endif
}
char **updvals,
long *tmpl_idx,
unsigned long tmpl_cnt,
- info_t **pcdp_summary,
+ rrd_info_t **pcdp_summary,
int version,
unsigned long *skip_update,
int *schedule_smooth)
double tmp;
char *parsetime_error = NULL;
char *old_locale;
- struct rrd_time_value ds_tv;
+ rrd_time_value_t ds_tv;
struct timeval tmp_time; /* used for time conversion */
/* get the time from the reading ... handle N */
if (timesyntax == '@') { /* at-style */
- if ((parsetime_error = parsetime(updvals[0], &ds_tv))) {
+ if ((parsetime_error = rrd_parsetime(updvals[0], &ds_tv))) {
rrd_set_error("ds time: %s: %s", updvals[0], parsetime_error);
return -1;
}
unsigned long *rra_current,
time_t current_time,
unsigned long *skip_update,
- info_t **pcdp_summary)
+ rrd_info_t **pcdp_summary)
{
unsigned long rra_idx;
unsigned long rra_start;
unsigned long rra_idx,
unsigned long *rra_current,
unsigned short CDP_scratch_idx,
- info_t **pcdp_summary,
+ rrd_info_t **pcdp_summary,
time_t rra_time)
{
unsigned long ds_idx, cdp_idx;
- infoval iv;
+ rrd_infoval_t iv;
for (ds_idx = 0; ds_idx < rrd->stat_head->ds_cnt; ds_idx++) {
/* compute the cdp index */
if (*pcdp_summary != NULL) {
iv.u_val = rrd->cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val;
/* append info to the return hash */
- *pcdp_summary = info_push(*pcdp_summary,
+ *pcdp_summary = rrd_info_push(*pcdp_summary,
sprintf_alloc("[%d]RRA[%s][%lu]DS[%s]",
rra_time,
rrd->rra_def[rra_idx].
image_desc_t im;
time_t start_tmp = 0, end_tmp = 0;
- struct rrd_time_value start_tv, end_tv;
+ rrd_time_value_t start_tv, end_tv;
char *parsetime_error = NULL;
struct option long_options[] = {
{"start", required_argument, 0, 's'},
rrd_graph_init(&im);
- parsetime("end-24h", &start_tv);
- parsetime("now", &end_tv);
+ rrd_parsetime("end-24h", &start_tv);
+ rrd_parsetime("now", &end_tv);
while (1) {
int option_index = 0;
case 262:
break;
case 's':
- if ((parsetime_error = parsetime(optarg, &start_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &start_tv))) {
rrd_set_error("start time: %s", parsetime_error);
return -1;
}
break;
case 'e':
- if ((parsetime_error = parsetime(optarg, &end_tv))) {
+ if ((parsetime_error = rrd_parsetime(optarg, &end_tv))) {
rrd_set_error("end time: %s", parsetime_error);
return -1;
}
}
}
- if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+ if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
return -1;
}
# End Source File\r
# Begin Source File\r
\r
-SOURCE=..\src\parsetime.c\r
+SOURCE=..\src\rrd_parsetime.c\r
# End Source File\r
# Begin Source File\r
\r
</FileConfiguration>\r
</File>\r
<File\r
- RelativePath="parsetime.c">\r
+ RelativePath="rrd_parsetime.c">\r
<FileConfiguration\r
Name="Release|Win32">\r
<Tool\r