diff options
author | anonimal <anonimal@i2pmail.org> | 2017-06-28 21:07:24 +0000 |
---|---|---|
committer | anonimal <anonimal@i2pmail.org> | 2018-03-18 15:52:19 +0000 |
commit | 84c5a9ba481d7a33cc0fd0ca43867b61d127d907 (patch) | |
tree | f05d3d3f107da02005b4a61f0e5074c113a7165c /external/unbound/testcode/replay.c | |
parent | Merge pull request #3416 (diff) | |
download | monero-84c5a9ba481d7a33cc0fd0ca43867b61d127d907.tar.xz |
Unbound: remove unbound from in-tree source
We'll instead use a git submodule to pull from our unbound repo.
Diffstat (limited to '')
-rw-r--r-- | external/unbound/testcode/replay.c | 1034 |
1 files changed, 0 insertions, 1034 deletions
diff --git a/external/unbound/testcode/replay.c b/external/unbound/testcode/replay.c deleted file mode 100644 index b45bde806..000000000 --- a/external/unbound/testcode/replay.c +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * testcode/replay.c - store and use a replay of events for the DNS resolver. - * - * Copyright (c) 2007, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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, WHETHER 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. - */ - -/** - * \file - * Store and use a replay of events for the DNS resolver. - * Used to test known scenarios to get known outcomes. - */ - -#include "config.h" -/* for strtod prototype */ -#include <math.h> -#include <ctype.h> -#include <time.h> -#include "util/log.h" -#include "util/net_help.h" -#include "util/config_file.h" -#include "testcode/replay.h" -#include "testcode/testpkts.h" -#include "testcode/fake_event.h" -#include "sldns/str2wire.h" - -/** max length of lines in file */ -#define MAX_LINE_LEN 10240 - -/** - * Expand a macro - * @param store: value storage - * @param runtime: replay runtime for other stuff. - * @param text: the macro text, after the ${, Updated to after the } when - * done (successfully). - * @return expanded text, malloced. NULL on failure. - */ -static char* macro_expand(rbtree_type* store, - struct replay_runtime* runtime, char** text); - -/** compare of time values */ -static int -timeval_smaller(const struct timeval* x, const struct timeval* y) -{ -#ifndef S_SPLINT_S - if(x->tv_sec < y->tv_sec) - return 1; - else if(x->tv_sec == y->tv_sec) { - if(x->tv_usec <= y->tv_usec) - return 1; - else return 0; - } - else return 0; -#endif -} - -/** parse keyword in string. - * @param line: if found, the line is advanced to after the keyword. - * @param keyword: string. - * @return: true if found, false if not. - */ -static int -parse_keyword(char** line, const char* keyword) -{ - size_t len = (size_t)strlen(keyword); - if(strncmp(*line, keyword, len) == 0) { - *line += len; - return 1; - } - return 0; -} - -/** delete moment */ -static void -replay_moment_delete(struct replay_moment* mom) -{ - if(!mom) - return; - if(mom->match) { - delete_entry(mom->match); - } - free(mom->autotrust_id); - free(mom->string); - free(mom->variable); - config_delstrlist(mom->file_content); - free(mom); -} - -/** delete range */ -static void -replay_range_delete(struct replay_range* rng) -{ - if(!rng) - return; - delete_entry(rng->match); - free(rng); -} - -/** strip whitespace from end of string */ -static void -strip_end_white(char* p) -{ - size_t i; - for(i = strlen(p); i > 0; i--) { - if(isspace((unsigned char)p[i-1])) - p[i-1] = 0; - else return; - } -} - -/** - * Read a range from file. - * @param remain: Rest of line (after RANGE keyword). - * @param in: file to read from. - * @param name: name to print in errors. - * @param pstate: read state structure with - * with lineno : incremented as lines are read. - * ttl, origin, prev for readentry. - * @param line: line buffer. - * @return: range object to add to list, or NULL on error. - */ -static struct replay_range* -replay_range_read(char* remain, FILE* in, const char* name, - struct sldns_file_parse_state* pstate, char* line) -{ - struct replay_range* rng = (struct replay_range*)malloc( - sizeof(struct replay_range)); - off_t pos; - char *parse; - struct entry* entry, *last = NULL; - if(!rng) - return NULL; - memset(rng, 0, sizeof(*rng)); - /* read time range */ - if(sscanf(remain, " %d %d", &rng->start_step, &rng->end_step)!=2) { - log_err("Could not read time range: %s", line); - free(rng); - return NULL; - } - /* read entries */ - pos = ftello(in); - while(fgets(line, MAX_LINE_LEN-1, in)) { - pstate->lineno++; - parse = line; - while(isspace((unsigned char)*parse)) - parse++; - if(!*parse || *parse == ';') { - pos = ftello(in); - continue; - } - if(parse_keyword(&parse, "ADDRESS")) { - while(isspace((unsigned char)*parse)) - parse++; - strip_end_white(parse); - if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen)) { - log_err("Line %d: could not read ADDRESS: %s", - pstate->lineno, parse); - free(rng); - return NULL; - } - pos = ftello(in); - continue; - } - if(parse_keyword(&parse, "RANGE_END")) { - return rng; - } - /* set position before line; read entry */ - pstate->lineno--; - fseeko(in, pos, SEEK_SET); - entry = read_entry(in, name, pstate, 1); - if(!entry) - fatal_exit("%d: bad entry", pstate->lineno); - entry->next = NULL; - if(last) - last->next = entry; - else rng->match = entry; - last = entry; - - pos = ftello(in); - } - replay_range_delete(rng); - return NULL; -} - -/** Read FILE match content */ -static void -read_file_content(FILE* in, int* lineno, struct replay_moment* mom) -{ - char line[MAX_LINE_LEN]; - char* remain = line; - struct config_strlist** last = &mom->file_content; - line[MAX_LINE_LEN-1]=0; - if(!fgets(line, MAX_LINE_LEN-1, in)) - fatal_exit("FILE_BEGIN expected at line %d", *lineno); - if(!parse_keyword(&remain, "FILE_BEGIN")) - fatal_exit("FILE_BEGIN expected at line %d", *lineno); - while(fgets(line, MAX_LINE_LEN-1, in)) { - (*lineno)++; - if(strncmp(line, "FILE_END", 8) == 0) { - return; - } - if(line[0]) line[strlen(line)-1] = 0; /* remove newline */ - if(!cfg_strlist_insert(last, strdup(line))) - fatal_exit("malloc failure"); - last = &( (*last)->next ); - } - fatal_exit("no FILE_END in input file"); -} - -/** read assign step info */ -static void -read_assign_step(char* remain, struct replay_moment* mom) -{ - char buf[1024]; - char eq; - int skip; - buf[sizeof(buf)-1]=0; - if(sscanf(remain, " %1023s %c %n", buf, &eq, &skip) != 2) - fatal_exit("cannot parse assign: %s", remain); - mom->variable = strdup(buf); - if(eq != '=') - fatal_exit("no '=' in assign: %s", remain); - remain += skip; - if(remain[0]) remain[strlen(remain)-1]=0; /* remove newline */ - mom->string = strdup(remain); - if(!mom->variable || !mom->string) - fatal_exit("out of memory"); -} - -/** - * Read a replay moment 'STEP' from file. - * @param remain: Rest of line (after STEP keyword). - * @param in: file to read from. - * @param name: name to print in errors. - * @param pstate: with lineno, ttl, origin, prev for parse state. - * lineno is incremented. - * @return: range object to add to list, or NULL on error. - */ -static struct replay_moment* -replay_moment_read(char* remain, FILE* in, const char* name, - struct sldns_file_parse_state* pstate) -{ - struct replay_moment* mom = (struct replay_moment*)malloc( - sizeof(struct replay_moment)); - int skip = 0; - int readentry = 0; - if(!mom) - return NULL; - memset(mom, 0, sizeof(*mom)); - if(sscanf(remain, " %d%n", &mom->time_step, &skip) != 1) { - log_err("%d: cannot read number: %s", pstate->lineno, remain); - free(mom); - return NULL; - } - remain += skip; - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "NOTHING")) { - mom->evt_type = repevt_nothing; - } else if(parse_keyword(&remain, "QUERY")) { - mom->evt_type = repevt_front_query; - readentry = 1; - if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen)) - fatal_exit("internal error"); - } else if(parse_keyword(&remain, "CHECK_ANSWER")) { - mom->evt_type = repevt_front_reply; - readentry = 1; - } else if(parse_keyword(&remain, "CHECK_OUT_QUERY")) { - mom->evt_type = repevt_back_query; - readentry = 1; - } else if(parse_keyword(&remain, "REPLY")) { - mom->evt_type = repevt_back_reply; - readentry = 1; - } else if(parse_keyword(&remain, "TIMEOUT")) { - mom->evt_type = repevt_timeout; - } else if(parse_keyword(&remain, "TIME_PASSES")) { - mom->evt_type = repevt_time_passes; - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "EVAL")) { - while(isspace((unsigned char)*remain)) - remain++; - mom->string = strdup(remain); - if(!mom->string) fatal_exit("out of memory"); - if(strlen(mom->string)>0) - mom->string[strlen(mom->string)-1]=0; - remain += strlen(mom->string); - } - } else if(parse_keyword(&remain, "CHECK_AUTOTRUST")) { - mom->evt_type = repevt_autotrust_check; - while(isspace((unsigned char)*remain)) - remain++; - if(strlen(remain)>0 && remain[strlen(remain)-1]=='\n') - remain[strlen(remain)-1] = 0; - mom->autotrust_id = strdup(remain); - if(!mom->autotrust_id) fatal_exit("out of memory"); - read_file_content(in, &pstate->lineno, mom); - } else if(parse_keyword(&remain, "ERROR")) { - mom->evt_type = repevt_error; - } else if(parse_keyword(&remain, "TRAFFIC")) { - mom->evt_type = repevt_traffic; - } else if(parse_keyword(&remain, "ASSIGN")) { - mom->evt_type = repevt_assign; - read_assign_step(remain, mom); - } else if(parse_keyword(&remain, "INFRA_RTT")) { - char *s, *m; - mom->evt_type = repevt_infra_rtt; - while(isspace((unsigned char)*remain)) - remain++; - s = remain; - remain = strchr(s, ' '); - if(!remain) fatal_exit("expected three args for INFRA_RTT"); - remain[0] = 0; - remain++; - while(isspace((unsigned char)*remain)) - remain++; - m = strchr(remain, ' '); - if(!m) fatal_exit("expected three args for INFRA_RTT"); - m[0] = 0; - m++; - while(isspace((unsigned char)*m)) - m++; - if(!extstrtoaddr(s, &mom->addr, &mom->addrlen)) - fatal_exit("bad infra_rtt address %s", s); - if(strlen(m)>0 && m[strlen(m)-1]=='\n') - m[strlen(m)-1] = 0; - mom->variable = strdup(remain); - mom->string = strdup(m); - if(!mom->string) fatal_exit("out of memory"); - if(!mom->variable) fatal_exit("out of memory"); - } else { - log_err("%d: unknown event type %s", pstate->lineno, remain); - free(mom); - return NULL; - } - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "ADDRESS")) { - while(isspace((unsigned char)*remain)) - remain++; - if(strlen(remain) > 0) /* remove \n */ - remain[strlen(remain)-1] = 0; - if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) { - log_err("line %d: could not parse ADDRESS: %s", - pstate->lineno, remain); - free(mom); - return NULL; - } - } - if(parse_keyword(&remain, "ELAPSE")) { - double sec; - errno = 0; - sec = strtod(remain, &remain); - if(sec == 0. && errno != 0) { - log_err("line %d: could not parse ELAPSE: %s (%s)", - pstate->lineno, remain, strerror(errno)); - free(mom); - return NULL; - } -#ifndef S_SPLINT_S - mom->elapse.tv_sec = (int)sec; - mom->elapse.tv_usec = (int)((sec - (double)mom->elapse.tv_sec) - *1000000. + 0.5); -#endif - } - - if(readentry) { - mom->match = read_entry(in, name, pstate, 1); - if(!mom->match) { - free(mom); - return NULL; - } - } - - return mom; -} - -/** makes scenario with title on rest of line */ -static struct replay_scenario* -make_scenario(char* line) -{ - struct replay_scenario* scen; - while(isspace((unsigned char)*line)) - line++; - if(!*line) { - log_err("scenario: no title given"); - return NULL; - } - scen = (struct replay_scenario*)malloc(sizeof(struct replay_scenario)); - if(!scen) - return NULL; - memset(scen, 0, sizeof(*scen)); - scen->title = strdup(line); - if(!scen->title) { - free(scen); - return NULL; - } - return scen; -} - -struct replay_scenario* -replay_scenario_read(FILE* in, const char* name, int* lineno) -{ - char line[MAX_LINE_LEN]; - char *parse; - struct replay_scenario* scen = NULL; - struct sldns_file_parse_state pstate; - line[MAX_LINE_LEN-1]=0; - memset(&pstate, 0, sizeof(pstate)); - pstate.default_ttl = 3600; - pstate.lineno = *lineno; - - while(fgets(line, MAX_LINE_LEN-1, in)) { - parse=line; - pstate.lineno++; - (*lineno)++; - while(isspace((unsigned char)*parse)) - parse++; - if(!*parse) - continue; /* empty line */ - if(parse_keyword(&parse, ";")) - continue; /* comment */ - if(parse_keyword(&parse, "SCENARIO_BEGIN")) { - scen = make_scenario(parse); - if(!scen) - fatal_exit("%d: could not make scen", *lineno); - continue; - } - if(!scen) - fatal_exit("%d: expected SCENARIO", *lineno); - if(parse_keyword(&parse, "RANGE_BEGIN")) { - struct replay_range* newr = replay_range_read(parse, - in, name, &pstate, line); - if(!newr) - fatal_exit("%d: bad range", pstate.lineno); - *lineno = pstate.lineno; - newr->next_range = scen->range_list; - scen->range_list = newr; - } else if(parse_keyword(&parse, "STEP")) { - struct replay_moment* mom = replay_moment_read(parse, - in, name, &pstate); - if(!mom) - fatal_exit("%d: bad moment", pstate.lineno); - *lineno = pstate.lineno; - if(scen->mom_last && - scen->mom_last->time_step >= mom->time_step) - fatal_exit("%d: time goes backwards", *lineno); - if(scen->mom_last) - scen->mom_last->mom_next = mom; - else scen->mom_first = mom; - scen->mom_last = mom; - } else if(parse_keyword(&parse, "SCENARIO_END")) { - struct replay_moment *p = scen->mom_first; - int num = 0; - while(p) { - num++; - p = p->mom_next; - } - log_info("Scenario has %d steps", num); - return scen; - } - } - replay_scenario_delete(scen); - return NULL; -} - -void -replay_scenario_delete(struct replay_scenario* scen) -{ - struct replay_moment* mom, *momn; - struct replay_range* rng, *rngn; - if(!scen) - return; - free(scen->title); - mom = scen->mom_first; - while(mom) { - momn = mom->mom_next; - replay_moment_delete(mom); - mom = momn; - } - rng = scen->range_list; - while(rng) { - rngn = rng->next_range; - replay_range_delete(rng); - rng = rngn; - } - free(scen); -} - -/** fetch oldest timer in list that is enabled */ -static struct fake_timer* -first_timer(struct replay_runtime* runtime) -{ - struct fake_timer* p, *res = NULL; - for(p=runtime->timer_list; p; p=p->next) { - if(!p->enabled) - continue; - if(!res) - res = p; - else if(timeval_smaller(&p->tv, &res->tv)) - res = p; - } - return res; -} - -struct fake_timer* -replay_get_oldest_timer(struct replay_runtime* runtime) -{ - struct fake_timer* t = first_timer(runtime); - if(t && timeval_smaller(&t->tv, &runtime->now_tv)) - return t; - return NULL; -} - -int -replay_var_compare(const void* a, const void* b) -{ - struct replay_var* x = (struct replay_var*)a; - struct replay_var* y = (struct replay_var*)b; - return strcmp(x->name, y->name); -} - -rbtree_type* -macro_store_create(void) -{ - return rbtree_create(&replay_var_compare); -} - -/** helper function to delete macro values */ -static void -del_macro(rbnode_type* x, void* ATTR_UNUSED(arg)) -{ - struct replay_var* v = (struct replay_var*)x; - free(v->name); - free(v->value); - free(v); -} - -void -macro_store_delete(rbtree_type* store) -{ - if(!store) - return; - traverse_postorder(store, del_macro, NULL); - free(store); -} - -/** return length of macro */ -static size_t -macro_length(char* text) -{ - /* we are after ${, looking for } */ - int depth = 0; - size_t len = 0; - while(*text) { - len++; - if(*text == '}') { - if(depth == 0) - break; - depth--; - } else if(text[0] == '$' && text[1] == '{') { - depth++; - } - text++; - } - return len; -} - -/** insert new stuff at start of buffer */ -static int -do_buf_insert(char* buf, size_t remain, char* after, char* inserted) -{ - char* save = strdup(after); - size_t len; - if(!save) return 0; - if(strlen(inserted) > remain) { - free(save); - return 0; - } - len = strlcpy(buf, inserted, remain); - buf += len; - remain -= len; - (void)strlcpy(buf, save, remain); - free(save); - return 1; -} - -/** do macro recursion */ -static char* -do_macro_recursion(rbtree_type* store, struct replay_runtime* runtime, - char* at, size_t remain) -{ - char* after = at+2; - char* expand = macro_expand(store, runtime, &after); - if(!expand) - return NULL; /* expansion failed */ - if(!do_buf_insert(at, remain, after, expand)) { - free(expand); - return NULL; - } - free(expand); - return at; /* and parse over the expanded text to see if again */ -} - -/** get var from store */ -static struct replay_var* -macro_getvar(rbtree_type* store, char* name) -{ - struct replay_var k; - k.node.key = &k; - k.name = name; - return (struct replay_var*)rbtree_search(store, &k); -} - -/** do macro variable */ -static char* -do_macro_variable(rbtree_type* store, char* buf, size_t remain) -{ - struct replay_var* v; - char* at = buf+1; - char* name = at; - char sv; - if(at[0]==0) - return NULL; /* no variable name after $ */ - while(*at && (isalnum((unsigned char)*at) || *at=='_')) { - at++; - } - /* terminator, we are working in macro_expand() buffer */ - sv = *at; - *at = 0; - v = macro_getvar(store, name); - *at = sv; - - if(!v) { - log_err("variable is not defined: $%s", name); - return NULL; /* variable undefined is error for now */ - } - - /* insert the variable contents */ - if(!do_buf_insert(buf, remain, at, v->value)) - return NULL; - return buf; /* and expand the variable contents */ -} - -/** do ctime macro on argument */ -static char* -do_macro_ctime(char* arg) -{ - char buf[32]; - time_t tt = (time_t)atoi(arg); - if(tt == 0 && strcmp(arg, "0") != 0) { - log_err("macro ctime: expected number, not: %s", arg); - return NULL; - } - ctime_r(&tt, buf); - if(buf[0]) buf[strlen(buf)-1]=0; /* remove trailing newline */ - return strdup(buf); -} - -/** perform arithmetic operator */ -static double -perform_arith(double x, char op, double y, double* res) -{ - switch(op) { - case '+': - *res = x+y; - break; - case '-': - *res = x-y; - break; - case '/': - *res = x/y; - break; - case '*': - *res = x*y; - break; - default: - return 0; - } - - return 1; -} - -/** do macro arithmetic on two numbers and operand */ -static char* -do_macro_arith(char* orig, size_t remain, char** arithstart) -{ - double x, y, result; - char operator; - int skip; - char buf[32]; - char* at; - /* not yet done? we want number operand number expanded first. */ - if(!*arithstart) { - /* remember start pos of expr, skip the first number */ - at = orig; - *arithstart = at; - while(*at && (isdigit((unsigned char)*at) || *at == '.')) - at++; - return at; - } - /* move back to start */ - remain += (size_t)(orig - *arithstart); - at = *arithstart; - - /* parse operands */ - if(sscanf(at, " %lf %c %lf%n", &x, &operator, &y, &skip) != 3) { - *arithstart = NULL; - return do_macro_arith(orig, remain, arithstart); - } - if(isdigit((unsigned char)operator)) { - *arithstart = orig; - return at+skip; /* do nothing, but setup for later number */ - } - - /* calculate result */ - if(!perform_arith(x, operator, y, &result)) { - log_err("unknown operator: %s", at); - return NULL; - } - - /* put result back in buffer */ - snprintf(buf, sizeof(buf), "%.12g", result); - if(!do_buf_insert(at, remain, at+skip, buf)) - return NULL; - - /* the result can be part of another expression, restart that */ - *arithstart = NULL; - return at; -} - -/** Do range macro on expanded buffer */ -static char* -do_macro_range(char* buf) -{ - double x, y, z; - if(sscanf(buf, " %lf %lf %lf", &x, &y, &z) != 3) { - log_err("range func requires 3 args: %s", buf); - return NULL; - } - if(x <= y && y <= z) { - char res[1024]; - snprintf(res, sizeof(res), "%.24g", y); - return strdup(res); - } - fatal_exit("value %.24g not in range [%.24g, %.24g]", y, x, z); - return NULL; -} - -static char* -macro_expand(rbtree_type* store, struct replay_runtime* runtime, char** text) -{ - char buf[10240]; - char* at = *text; - size_t len = macro_length(at); - int dofunc = 0; - char* arithstart = NULL; - if(len >= sizeof(buf)) - return NULL; /* too long */ - buf[0] = 0; - (void)strlcpy(buf, at, len+1-1); /* do not copy last '}' character */ - at = buf; - - /* check for functions */ - if(strcmp(buf, "time") == 0) { - snprintf(buf, sizeof(buf), ARG_LL "d", (long long)runtime->now_secs); - *text += len; - return strdup(buf); - } else if(strcmp(buf, "timeout") == 0) { - time_t res = 0; - struct fake_timer* t = first_timer(runtime); - if(t && (time_t)t->tv.tv_sec >= runtime->now_secs) - res = (time_t)t->tv.tv_sec - runtime->now_secs; - snprintf(buf, sizeof(buf), ARG_LL "d", (long long)res); - *text += len; - return strdup(buf); - } else if(strncmp(buf, "ctime ", 6) == 0 || - strncmp(buf, "ctime\t", 6) == 0) { - at += 6; - dofunc = 1; - } else if(strncmp(buf, "range ", 6) == 0 || - strncmp(buf, "range\t", 6) == 0) { - at += 6; - dofunc = 1; - } - - /* actual macro text expansion */ - while(*at) { - size_t remain = sizeof(buf)-strlen(buf); - if(strncmp(at, "${", 2) == 0) { - at = do_macro_recursion(store, runtime, at, remain); - } else if(*at == '$') { - at = do_macro_variable(store, at, remain); - } else if(isdigit((unsigned char)*at)) { - at = do_macro_arith(at, remain, &arithstart); - } else { - /* copy until whitespace or operator */ - if(*at && (isalnum((unsigned char)*at) || *at=='_')) { - at++; - while(*at && (isalnum((unsigned char)*at) || *at=='_')) - at++; - } else at++; - } - if(!at) return NULL; /* failure */ - } - *text += len; - if(dofunc) { - /* post process functions, buf has the argument(s) */ - if(strncmp(buf, "ctime", 5) == 0) { - return do_macro_ctime(buf+6); - } else if(strncmp(buf, "range", 5) == 0) { - return do_macro_range(buf+6); - } - } - return strdup(buf); -} - -char* -macro_process(rbtree_type* store, struct replay_runtime* runtime, char* text) -{ - char buf[10240]; - char* next, *expand; - char* at = text; - if(!strstr(text, "${")) - return strdup(text); /* no macros */ - buf[0] = 0; - buf[sizeof(buf)-1]=0; - while( (next=strstr(at, "${")) ) { - /* copy text before next macro */ - if((size_t)(next-at) >= sizeof(buf)-strlen(buf)) - return NULL; /* string too long */ - (void)strlcpy(buf+strlen(buf), at, (size_t)(next-at+1)); - /* process the macro itself */ - next += 2; - expand = macro_expand(store, runtime, &next); - if(!expand) return NULL; /* expansion failed */ - (void)strlcpy(buf+strlen(buf), expand, sizeof(buf)-strlen(buf)); - free(expand); - at = next; - } - /* copy remainder fixed text */ - (void)strlcpy(buf+strlen(buf), at, sizeof(buf)-strlen(buf)); - return strdup(buf); -} - -char* -macro_lookup(rbtree_type* store, char* name) -{ - struct replay_var* x = macro_getvar(store, name); - if(!x) return strdup(""); - return strdup(x->value); -} - -void macro_print_debug(rbtree_type* store) -{ - struct replay_var* x; - RBTREE_FOR(x, struct replay_var*, store) { - log_info("%s = %s", x->name, x->value); - } -} - -int -macro_assign(rbtree_type* store, char* name, char* value) -{ - struct replay_var* x = macro_getvar(store, name); - if(x) { - free(x->value); - } else { - x = (struct replay_var*)malloc(sizeof(*x)); - if(!x) return 0; - x->node.key = x; - x->name = strdup(name); - if(!x->name) { - free(x); - return 0; - } - (void)rbtree_insert(store, &x->node); - } - x->value = strdup(value); - return x->value != NULL; -} - -/* testbound assert function for selftest. counts the number of tests */ -#define tb_assert(x) \ - do { if(!(x)) fatal_exit("%s:%d: %s: assertion %s failed", \ - __FILE__, __LINE__, __func__, #x); \ - num_asserts++; \ - } while(0); - -void testbound_selftest(void) -{ - /* test the macro store */ - rbtree_type* store = macro_store_create(); - char* v; - int r; - int num_asserts = 0; - tb_assert(store); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "") == 0); - free(v); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "") == 0); - free(v); - - r = macro_assign(store, "bla", "waarde1"); - tb_assert(r); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "") == 0); - free(v); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "waarde1") == 0); - free(v); - - r = macro_assign(store, "vlerk", "kanteel"); - tb_assert(r); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "waarde1") == 0); - free(v); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "kanteel") == 0); - free(v); - - r = macro_assign(store, "bla", "ww"); - tb_assert(r); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "ww") == 0); - free(v); - - tb_assert( macro_length("}") == 1); - tb_assert( macro_length("blabla}") == 7); - tb_assert( macro_length("bla${zoink}bla}") == 7+8); - tb_assert( macro_length("bla${zoink}${bla}bla}") == 7+8+6); - - v = macro_process(store, NULL, ""); - tb_assert( v && strcmp(v, "") == 0); - free(v); - - v = macro_process(store, NULL, "${}"); - tb_assert( v && strcmp(v, "") == 0); - free(v); - - v = macro_process(store, NULL, "blabla ${} dinges"); - tb_assert( v && strcmp(v, "blabla dinges") == 0); - free(v); - - v = macro_process(store, NULL, "1${$bla}2${$bla}3"); - tb_assert( v && strcmp(v, "1ww2ww3") == 0); - free(v); - - v = macro_process(store, NULL, "it is ${ctime 123456}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - r = macro_assign(store, "t1", "123456"); - tb_assert(r); - v = macro_process(store, NULL, "it is ${ctime ${$t1}}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - v = macro_process(store, NULL, "it is ${ctime $t1}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - r = macro_assign(store, "x", "1"); - tb_assert(r); - r = macro_assign(store, "y", "2"); - tb_assert(r); - v = macro_process(store, NULL, "${$x + $x}"); - tb_assert( v && strcmp(v, "2") == 0); - free(v); - v = macro_process(store, NULL, "${$x - $x}"); - tb_assert( v && strcmp(v, "0") == 0); - free(v); - v = macro_process(store, NULL, "${$y * $y}"); - tb_assert( v && strcmp(v, "4") == 0); - free(v); - v = macro_process(store, NULL, "${32 / $y + $x + $y}"); - tb_assert( v && strcmp(v, "19") == 0); - free(v); - - v = macro_process(store, NULL, "${32 / ${$y+$y} + ${${100*3}/3}}"); - tb_assert( v && strcmp(v, "108") == 0); - free(v); - - v = macro_process(store, NULL, "${1 2 33 2 1}"); - tb_assert( v && strcmp(v, "1 2 33 2 1") == 0); - free(v); - - v = macro_process(store, NULL, "${123 3 + 5}"); - tb_assert( v && strcmp(v, "123 8") == 0); - free(v); - - v = macro_process(store, NULL, "${123 glug 3 + 5}"); - tb_assert( v && strcmp(v, "123 glug 8") == 0); - free(v); - - macro_store_delete(store); - printf("selftest successful (%d checks).\n", num_asserts); -} |