int bool_expr(bool op,oprtype *addr) { oprtype x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!(TREF(expr_depth))++) TREF(expr_start) = TREF(expr_start_orig) = NULL; if (!eval_expr(&x)) { TREF(expr_depth) = 0; return FALSE; } coerce(&x, OCT_BOOL); if (!(--(TREF(expr_depth)))) TREF(shift_side_effects) = FALSE; assert(x.oprclass == TRIP_REF); bx_tail(x.oprval.tref, op, addr); return TRUE; }
/// Evaluates the expression str using the vim internal expression /// evaluator (see |expression|). /// Dictionaries and lists are recursively expanded. /// /// @param str The expression str /// @param[out] err Details of an error that may have occurred /// @return The expanded object Object vim_eval(String str, Error *err) { Object rv; // Evaluate the expression try_start(); typval_T *expr_result = eval_expr((char_u *) str.data, NULL); if (!expr_result) { set_api_error("Failed to eval expression", err); } if (!try_end(err)) { // No errors, convert the result rv = vim_to_object(expr_result); } // Free the vim object free_tv(expr_result); return rv; }
void main(void) { struct eval_state_t *es; /* set up test variables */ an_int.type = et_int; an_int.value.as_int = 1; a_uint.type = et_uint; a_uint.value.as_uint = 2; a_float.type = et_float; a_float.value.as_float = 3.0f; a_double.type = et_double; a_double.value.as_double = 4.0; a_symbol.type = et_symbol; a_symbol.value.as_symbol = "testing 1 2 3..."; /* instantiate an evaluator */ es = eval_new(my_eval_ident, NULL); while (1) { struct eval_value_t val; char expr_buf[1024]; fgets(expr_buf, 1024, stdin); /* chop */ if (expr_buf[strlen(expr_buf)-1] == '\n') expr_buf[strlen(expr_buf)-1] = '\0'; if (expr_buf[0] == '\0') exit(0); val = eval_expr(es, expr_buf, NULL); if (eval_error) fprintf(stdout, "eval error: %s\n", eval_err_str[eval_error]); else { fprintf(stdout, "%s == ", expr_buf); eval_print(stdout, val); fprintf(stdout, "\n"); } } }
void print_expr (LISTNODE *p) { #if 0 LISTNODE *q = p; size_t len = 0; char *s; long e; /* Calculate the length of the expr. */ for (q = p; q != NULL_LIST; q = q->next) len = len + strlen(q->text); /* Allocate a string buffer. */ s = (char *) xmalloc(len+1); /* Print the expr in the string buffer. */ *s = '\0'; for (q = p; q != NULL_LIST; q = q->next) { strcat(s, q->text); strcat(s, " "); } printf("\""); /* If possible, simplify the expression. */ if (eval_expr(s, &e)) printf("%ld", e); else printf("%s", s); printf("\""); #else printf("\""); do { printf("%s ", p->text); p = p->next; } while (p != NULL_LIST); printf("\""); #endif }
bool eval_qual_set(int nquals, ExprState **qual_ary) { int i; for (i = 0; i < nquals; i++) { ExprState *qual_state = qual_ary[i]; Datum result; /* * Sanity check: we already require the return type of qual * expressions to be boolean in the analysis phase */ ASSERT(qual_state->expr->type == TYPE_BOOL); result = eval_expr(qual_state); if (result.b == false) return false; } return true; }
int main(int ac, char **av) { char *buff; t_nbr res; if (ac != 4) { my_putstr("usage : "); my_putstr(av[0]); my_putstr("base ops\"()+-*/%\" exp_len\n"); return (1); } check_size(av); buff = buffer(av[3]); global_error(av, buff); trad_base_to_ascii(av, buff); my_init_zero(&res); eval_expr(buff, &res, my_strlen(av[1])); trad_ascii_to_base(av, &res); free(res.str); free(buff); return (0); }
/* ** Main function. Given by the subject. ** When you use this program to compute very large numbers, use the -p ** parramater to enable progress bar display. ** Ex : ./calc "01" "()+-x/%" 999999999 -p */ int main(int ac, char **av) { unsigned int size; char *expr; int p; p = 0; if (ac != 4 && ac != 5) { my_putstr("Usage : "); my_putstr(av[0]); my_putstr(" base (\"0123456789\") ops (\"()+-*/%\") exp_len\n"); exit(1); } else if (ac == 5 && strcmp(av[4], "-p") == 0) p = 1; check_base(av[1]); check_ops(av[2]); size = my_atoi(av[3]); expr = get_expr(size); eval_expr(av[1], av[2], expr, size, p); free(expr); exit(0); }
int main(int ac, char **av) { char *expr; unsigned int size; if (ac != 4) { my_putstr("Usage : "); my_putstr(av[0]); my_putstr(" base ops\"()+-*/%\" exp_len\n"); return (0); } if (check_base(av[1]) == 1) return (0); if (check_ops(av[2]) == 1) return (0); size = my_atoi(av[3]); expr = get_expr(size); if (expr == NULL) return (0); my_putstr(eval_expr(av[1], av[2], expr, size)); my_putstr("\n"); return (0); }
double eval(FILE* stream, char allowed_nums[4], char* ok) { int i, c; double result; struct eval_ctx ctx; ctx.stream = stream; ctx.err = NULL; /* we make a copy instead of pointing to the original array so that the can remove the numbers when we see them in the expression */ memcpy(ctx.allowed_nums, allowed_nums, sizeof allowed_nums); result = eval_expr(&ctx); if((c = getc(stream)) != '\n' && c != EOF) { /* still got characters in the stream */ if(!ctx.err) ctx.err = "Unexpected character"; consume_line(stream); } for (i = 0; !ctx.err && i < 4; i++) if(ctx.allowed_nums[i] != -1) ctx.err = "Not all numbers were used"; if (ctx.err) { puts(ctx.err); *ok = 0; return 0.; } *ok = 1; return result; }
static double eval_value(struct eval_ctx* ctx) { char tok; double res; if (eval_consume(ctx, "(")) { /* got a parenthesis, evaluate its contents and use it as value */ res = eval_expr(ctx); if (!eval_consume(ctx, ")")) { ctx->err = "Parenthesis not closed"; return 0.; } return res; } if ((tok = eval_consume(ctx, "123456789"))) { /* got a number (we only support single-digit numbers) */ char num = tok - '0'; /* convert from character to number */ if (mark_number(ctx->allowed_nums, num)) { res = (double) num; return res; } else { ctx->err = "Number not allowed"; /*ctx->cur--; /* report error at right spot */ return 0.; } } /* got something we can't parse as a value */ ctx->err = "Unexpected character"; return 0.; }
/* execute assignment operation */ int do_assign(struct sip_msg* msg, struct action* a) { int ret; pv_value_t val; pv_spec_p dspec; ret = -1; dspec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(dspec)) { LM_ERR("read only PV in left expression\n"); goto error; } memset(&val, 0, sizeof(pv_value_t)); if(a->elem[1].type != NULLV_ST) { ret = eval_expr((struct expr*)a->elem[1].u.data, msg, &val); if(!((val.flags&PV_VAL_STR)||(val.flags&PV_VAL_INT))) { LM_ERR("no value in right expression\n"); goto error; } } switch ((unsigned char)a->type){ case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: script_trace("assign", (unsigned char)a->type == EQ_T ? "equal" : (unsigned char)a->type == COLONEQ_T ? "colon-eq" : (unsigned char)a->type == PLUSEQ_T ? "plus-eq" : (unsigned char)a->type == MINUSEQ_T ? "minus-eq" : (unsigned char)a->type == DIVEQ_T ? "div-eq" : (unsigned char)a->type == MULTEQ_T ? "mult-eq" : (unsigned char)a->type == MODULOEQ_T? "modulo-eq" : (unsigned char)a->type == BANDEQ_T ? "b-and-eq" : (unsigned char)a->type == BOREQ_T ? "b-or-eq":"b-xor-eq", msg, a->line); if(a->elem[1].type == NULLV_ST) { if(pv_set_value(msg, dspec, (int)a->type, 0)<0) { LM_ERR("setting PV failed\n"); goto error; } } else { if(pv_set_value(msg, dspec, (int)a->type, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } } ret = 1; break; default: LM_ALERT("BUG -> unknown op type %d\n", a->type); goto error; } pv_value_destroy(&val); return ret; error: LM_ERR("error at line: %d\n", a->line); pv_value_destroy(&val); return -1; }
LONG_DOUBLE eval_expr_func(eval_context *ctx, ast_node *tree) { expr_func_data *func_data = (expr_func_data*)tree->data; if (strcmp(func_data->name, "sin") == 0) return sinl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "cos") == 0) return cosl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "tan") == 0) return tanl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "acos") == 0) return acosl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "asin") == 0) return asinl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "atan") == 0) return atanl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "cosh") == 0) return coshl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "sinh") == 0) return sinhl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "tanh") == 0) return tanhl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "log") == 0) return logl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "log10") == 0) return log10l(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "ceil") == 0) return ceill(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "fabs") == 0) return fabsl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "floor") == 0) return floorl(eval_expr(ctx, func_data->rhs)); else if (strcmp(func_data->name, "sqrt") == 0) return sqrtl(eval_expr(ctx, func_data->rhs)); else return eval_emit_error(ctx, "Unknown function %s.", func_data->name); }
LONG_DOUBLE eval_expr_binop(eval_context *ctx, ast_node *tree) { expr_binop_data *binop_data = (expr_binop_data*)tree->data; switch (binop_data->op) { case OP_ADD: return eval_expr(ctx, binop_data->lhs) + eval_expr(ctx, binop_data->rhs); case OP_SUB: return eval_expr(ctx, binop_data->lhs) - eval_expr(ctx, binop_data->rhs); case OP_MUL: return eval_expr(ctx, binop_data->lhs) * eval_expr(ctx, binop_data->rhs); case OP_DIV: return eval_expr(ctx, binop_data->lhs) / eval_expr(ctx, binop_data->rhs); case OP_MOD: { // Knuthsche "floored division" LONG_DOUBLE a = eval_expr(ctx, binop_data->lhs); LONG_DOUBLE n = eval_expr(ctx, binop_data->rhs); return a-n*floor(a/n); } case OP_EXP: return pow(eval_expr(ctx, binop_data->lhs), eval_expr(ctx, binop_data->rhs)); case OP_ASS: { if (binop_data->lhs->type != EXPR_VAR) return eval_emit_error(ctx, "Cannot assign to a non-variable."); else { expr_var_data *var_data = (expr_var_data*)binop_data->lhs->data; LONG_DOUBLE rhs_res = eval_expr(ctx, binop_data->rhs); store_var(store_get(), var_data->name, rhs_res); return rhs_res; } } default: return eval_emit_error(ctx, "Operator not implemented."); } }
// Starts the algorithm with the required parameters void startGenerations(int targetNumber, uint maxGenerations, uint geneCountMin, uint geneCountMax, uint logThreshold) { bool solutionFound = false; int generation = 0; Chromosome *fittestChromosome = NULL; float bestFitness = 0; // Run the simulation until a solution has been found or the maximum number of generations has been reached for (unsigned int i = 0; !solutionFound && (maxGenerations == 0 || i < maxGenerations); ++i) { bool writeLog = logThreshold && (generation % logThreshold == 0); if (writeLog) std::cout << "Generation " << generation << '\n'; Chromosome *newChromosome = NULL; if (fittestChromosome) newChromosome = new Chromosome(*fittestChromosome); else newChromosome = new Chromosome(geneCountMin, geneCountMax); int result = 0; eval_expr(newChromosome->getSanitized(), result); if (writeLog) std::cout << "Chromosome result: " << result << '\n'; if (result != targetNumber) // Solution not yet found { float fitness = getFitness(result, targetNumber); if (writeLog) std::cout << "Chromosome fitness: " << fitness; if (fitness > bestFitness) { if (writeLog) std::cout << " -> selected\n"; if (fittestChromosome) delete fittestChromosome; fittestChromosome = newChromosome; bestFitness = fitness; } else { if (writeLog) std::cout << " -> rejected\n"; delete newChromosome; } } else // Solution found { if (fittestChromosome) delete fittestChromosome; fittestChromosome = newChromosome; solutionFound = true; } if (writeLog) std::cout << std::endl; ++generation; } std::cout << "Target number: " << targetNumber << '\n' << "Solution " << (solutionFound ? "" : "not ") << "found after " << generation << " generations" << std::endl; if (fittestChromosome) { if (solutionFound) fittestChromosome->displayInfo(); delete fittestChromosome; } }
LONG_DOUBLE eval_expr_nop(eval_context *ctx, ast_node *tree) { expr_nop_data *nop_data = (expr_nop_data*)tree->data; return eval_expr(ctx, nop_data->next); }
static void assemble(void) { section *sec; atom *p; char *attr; int bss; final_pass=1; for(sec=first_section; sec; sec=sec->next) { source *lasterrsrc=NULL; int lasterrline=0; sec->pc=sec->org; attr=sec->attr; bss=0; while(*attr) { if(*attr++=='u') { bss=1; break; } } for(p=sec->first; p; p=p->next) { sec->pc=(sec->pc+p->align-1)/p->align*p->align; cur_src=p->src; cur_src->line=p->line; if(p->list&&p->list->atom==p) { p->list->sec=sec; p->list->pc=sec->pc; } if(p->type==INSTRUCTION) { dblock *db; cur_listing=p->list; db=eval_instruction(p->content.inst,sec,sec->pc); if(pic_check) do_pic_check(db->relocs); cur_listing=0; if(DEBUG) { if(db->size!=instruction_size(p->content.inst,sec,sec->pc)) ierror(0); } /*FIXME: sauber freigeben */ myfree(p->content.inst); p->content.db=db; p->type=DATA; } else if(p->type==DATADEF) { dblock *db; cur_listing=p->list; db=eval_data(p->content.defb->op,p->content.defb->bitsize,sec,sec->pc); if(pic_check) do_pic_check(db->relocs); cur_listing=0; /*FIXME: sauber freigeben */ myfree(p->content.defb); p->content.db=db; p->type=DATA; } else if(p->type==RORG) { sblock *sb; taddr space; if(eval_expr(p->content.roffs,&space,sec,sec->pc)) { space=sec->org+space-sec->pc; if (space>=0) { sb=new_sblock(number_expr(space),1,0); p->content.sb=sb; p->type=SPACE; } else general_error(20); /* rorg is lower than current pc */ } else general_error(30); /* expression must be constant */ } else if(p->type==DATA&&bss) { if(lasterrsrc!=p->src||lasterrline!=p->line) { general_error(31); /* initialized data in bss */ lasterrsrc=p->src; lasterrline=p->line; } } #ifdef HAVE_CPU_OPTS else if(p->type==OPTS) cpu_opts(p->content.opts); #endif else if(p->type==PRINTTEXT) printf("%s\n",p->content.ptext); else if (p->type==PRINTEXPR) { taddr val; eval_expr(p->content.pexpr,&val,sec,sec->pc); printf("%ld (0x%lx)\n",(long)val,(unsigned long)val); } sec->pc+=atom_size(p,sec,sec->pc); } } }
static int parse_arith(char **word, size_t * word_length, size_t * max_length, const char *words, size_t * offset, int flags, int bracket) { /* We are poised just after "$((" or "$[" */ int error; int paren_depth = 1; size_t expr_length; size_t expr_maxlen; char *expr; expr = w_newword(&expr_length, &expr_maxlen); for (; words[*offset]; ++(*offset)) { switch (words[*offset]) { case '$': error = parse_dollars(&expr, &expr_length, &expr_maxlen, words, offset, flags, NULL, NULL, NULL, 1); /* The ``1'' here is to tell parse_dollars not to * split the fields. */ if (error) { free(expr); return error; } break; case '`': (*offset)++; error = parse_backtick(&expr, &expr_length, &expr_maxlen, words, offset, flags, NULL, NULL, NULL); /* The first NULL here is to tell parse_backtick not to * split the fields. */ if (error) { free(expr); return error; } break; case '\\': error = parse_qtd_backslash(&expr, &expr_length, &expr_maxlen, words, offset); if (error) { free(expr); return error; } /* I think that a backslash within an * arithmetic expansion is bound to * cause an error sooner or later anyway though. */ break; case ')': if (--paren_depth == 0) { char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ long int numresult = 0; long long int convertme; if (bracket || words[1 + *offset] != ')') { free(expr); return WRDE_SYNTAX; } ++(*offset); /* Go - evaluate. */ if (*expr && eval_expr(expr, &numresult) != 0) { free(expr); return WRDE_SYNTAX; } if (numresult < 0) { convertme = -numresult; *word = w_addchar(*word, word_length, max_length, '-'); if (!*word) { free(expr); return WRDE_NOSPACE; } } else convertme = numresult; result[20] = '\0'; *word = w_addstr(*word, word_length, max_length, _itoa(convertme, &result[20])); free(expr); return *word ? 0 : WRDE_NOSPACE; } expr = w_addchar(expr, &expr_length, &expr_maxlen, words[*offset]); if (expr == NULL) return WRDE_NOSPACE; break; case ']': if (bracket && paren_depth == 1) { char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ long int numresult = 0; /* Go - evaluate. */ if (*expr && eval_expr(expr, &numresult) != 0) { free(expr); return WRDE_SYNTAX; } result[20] = '\0'; *word = w_addstr(*word, word_length, max_length, _itoa(numresult, &result[20])); free(expr); return *word ? 0 : WRDE_NOSPACE; } free(expr); return WRDE_SYNTAX; case '\n': case ';': case '{': case '}': free(expr); return WRDE_BADCHAR; case '(': ++paren_depth; default: expr = w_addchar(expr, &expr_length, &expr_maxlen, words[*offset]); if (expr == NULL) return WRDE_NOSPACE; } } /* Premature end */ free(expr); return WRDE_SYNTAX; }
int main(int argc, char **argv) { Atom expr; Atom result; Atom env; Error err; char input[MAXLINE]; char *end = input; env_init(&env); //print_expr(env); FILE *fp = NULL; /* no arguments were passed */ if(argc < 2) fp = stdin; else { fp = fopen(argv[1], "r"); if(fp == NULL) { fprintf(stderr, "Cannot open file %s\n", argv[1]); return -1; } const char * file_extension = get_filename_extension(argv[1]); if(strcmp(file_extension, "liuyong") != 0) { fprintf(stderr, "file extension must be .liuyong\n"); return -1; } } printf("> "); while(fgets(input, MAXLINE, fp) != NULL) { err = read_expr(input, &end, &expr); //print_expr(expr); if(!err) err = eval_expr(expr, env, &result); switch(err) { case ERROR_OK: print_expr(result); printf("\n"); break; case ERROR_SYNTAX: printf("Syntax Error\n"); break; case ERROR_UNBOUND: printf("Symbol Not Bound\n"); break; case ERROR_TYPE: printf("Wrong Type\n"); break; case ERROR_ARGS: printf("Wrong Nomber Of Arguments\n"); break; } printf("> "); } }
/* evaluate a stat as an expression */ struct eval_value_t stat_eval_ident(struct eval_state_t *es)/* an expression evaluator */ { struct stat_sdb_t *sdb = es->user_ptr; struct stat_stat_t *stat; static struct eval_value_t err_value = { et_int, { 0 } }; struct eval_value_t val; /* locate the stat variable */ for (stat = sdb->stats; stat != NULL; stat = stat->next) { if (!strcmp(stat->name, es->tok_buf)) { /* found it! */ break; } } if (!stat) { /* could not find stat variable */ eval_error = ERR_UNDEFVAR; return err_value; } /* else, return the value of stat */ /* convert the stat variable value to a typed expression value */ switch (stat->sc) { case sc_int: val.type = et_int; val.value.as_int = *stat->variant.for_int.var; break; case sc_uint: val.type = et_uint; val.value.as_uint = *stat->variant.for_uint.var; break; #ifdef HOST_HAS_QWORD case sc_qword: /* FIXME: cast to double, eval package doesn't support long long's */ val.type = et_double; #ifdef _MSC_VER /* FIXME: MSC does not implement qword_t to dbl conversion */ val.value.as_double = (double)(sqword_t)*stat->variant.for_qword.var; #else /* !_MSC_VER */ val.value.as_double = (double)*stat->variant.for_qword.var; #endif /* _MSC_VER */ break; case sc_sqword: /* FIXME: cast to double, eval package doesn't support long long's */ val.type = et_double; val.value.as_double = (double)*stat->variant.for_sqword.var; break; #endif /* HOST_HAS_QWORD */ case sc_float: val.type = et_float; val.value.as_float = *stat->variant.for_float.var; break; case sc_double: val.type = et_double; val.value.as_double = *stat->variant.for_double.var; break; case sc_dist: case sc_sdist: fatal("stat distributions not allowed in formula expressions"); break; case sc_formula: { /* instantiate a new evaluator to avoid recursion problems */ struct eval_state_t *es = eval_new(stat_eval_ident, sdb); char *endp; val = eval_expr(es, stat->variant.for_formula.formula, &endp); if (eval_error != ERR_NOERR || *endp != '\0') { /* pass through eval_error */ val = err_value; } /* else, use value returned */ eval_delete(es); } break; default: panic("bogus stat class"); } return val; }
static double eval_item(const char *buf, int *pos) /* item = -item | +item | int | var | (expr) */ { double rv = 0.0; void *data; int tlen, nargs, xargs; DB(int i); FunctionPtr fn; DB(char *fname); Token tok; DB(printf("-- eval_item(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos)); tok = pull_token(buf, pos); if(G_eval_error) return rv; DB(printf("-- item token type '%c' = ", tok.type)); switch(tok.type) { case '+': /* positive */ DB(printf("positive\n")); rv = eval_fact(buf, pos); break; case '-': /* negative */ DB(printf("negative\n")); rv = -eval_fact(buf, pos); break; case 'v': /* variable */ DB(printf("variable name '%s'=%f\n", tok.str, tok.value)); rv = tok.value; break; case 'f': /* function */ DB(printf("function name '%s'=%p(%d)\n", tok.str, tok.fn, tok.args)); tlen = tok.args; nargs = tok.args; xargs = nargs; data = tok.data; fn = tok.fn; DB(fname = tok.str); tok = pull_token(buf, pos); if(G_eval_error == 0) { if(tok.type != '(') G_eval_error = EVAL_SYNTAX_ERROR; else { double *targ = NULL; if(tlen > 0) { targ = (double*)lalloc(sizeof(double)*tlen); if(targ == NULL) { G_eval_error = EVAL_MEM_ERROR; break; } }else tlen = 0; if(eval_args(buf, pos, &nargs, &targ, &tlen, 0)) break; DB(printf("-- item %d arguments\n", nargs)); if(xargs < 0) { if(nargs < 1) { DB(printf("-- item too few arguments\n")); G_eval_error = EVAL_ARGS_ERROR; break; } }else if(nargs != xargs) { DB(printf("-- item bad argument count (%d) need %d\n", nargs, xargs)); G_eval_error = EVAL_ARGS_ERROR; break; } tok = pull_token(buf, pos); if(tok.type != ')') G_eval_error = EVAL_SYNTAX_ERROR; else if(G_eval_error == 0) { DB(printf("-- call function [%p] with %d args [%p]\n", fn, nargs, targ)); DB(printf("-- %s(%f", fname, targ[0])); DB(for(i=1;i<nargs;i++)printf(",%f",targ[i])); DB(printf(")\n")); if(fn(nargs, targ, &rv, data) != 0) G_eval_error = EVAL_FUNCTION_ERROR; DB(printf("-- rv = %f\n", rv)); } } } break; case 'n': /* number */ DB(printf("number value '%s'=%f\n", tok.str, tok.value)); rv = tok.value; break; case '(': DB(printf("start grouping\n")); rv = eval_expr(buf, pos); tok = pull_token(buf, pos); if(tok.type != ')') G_eval_error = EVAL_SYNTAX_ERROR; break; default: DB(printf("PUSHBACK\n")); push_token(tok); }
/* * Take a command string and break it up into an argc, argv list while * handling quoting and wildcards. The returned argument list and * strings are in static memory, and so are overwritten on each call. * The argument list is ended with a NULL pointer for convenience. * Returns TRUE if successful, or FALSE on an error with a message * already output. */ BOOL makeArgs(const char * cmd, int * retArgc, const char *** retArgv) { const char * argument; char * cp; char * cpOut; char * newStrings; const char ** fileTable; const char ** newArgTable; int newArgTableSize; int fileCount; int len; int ch; int quote; BOOL quotedWildCards; BOOL unquotedWildCards; static int stringsLength; static char * strings; static int argCount; static int argTableSize; static const char ** argTable; /* * Clear the returned values until we know them. */ argCount = 0; *retArgc = 0; *retArgv = NULL; /* * Copy the command string into a buffer that we can modify, * reallocating it if necessary. */ len = strlen(cmd) + 1; if (len > stringsLength) { newStrings = realloc(strings, len); if (newStrings == NULL) { fprintf(stderr, "Cannot allocate string\n"); return FALSE; } strings = newStrings; stringsLength = len; } memcpy(strings, cmd, len); cp = strings; /* * Keep parsing the command string as long as there are any * arguments left. */ while (*cp) { /* * Save the beginning of this argument. */ argument = cp; cpOut = cp; /* * Reset quoting and wildcarding for this argument. */ quote = '\0'; quotedWildCards = FALSE; unquotedWildCards = FALSE; /* * Loop over the string collecting the next argument while * looking for quoted strings or quoted characters, and * remembering whether there are any wildcard characters * in the argument. */ while (*cp) { ch = *cp++; /* * If we are not in a quote and we see a blank then * this argument is done. */ if (isBlank(ch) && (quote == '\0')) break; /* * If we see a backslash then accept the next * character no matter what it is. */ if (ch == '\\') { ch = *cp++; /* * Make sure there is a next character. */ if (ch == '\0') { fprintf(stderr, "Bad quoted character\n"); return FALSE; } /* * Remember whether the quoted character * is a wildcard. */ if (isWildCard(ch)) quotedWildCards = TRUE; *cpOut++ = ch; continue; } /* * If we see one of the wildcard characters then * remember whether it was seen inside or outside * of quotes. */ if (isWildCard(ch)) { if (quote) quotedWildCards = TRUE; else unquotedWildCards = TRUE; } /* * If we were in a quote and we saw the same quote * character again then the quote is done. */ if (ch == quote) { quote = '\0'; continue; } /* * If we weren't in a quote and we see either type * of quote character, then remember that we are * now inside of a quote. */ if ((quote == '\0') && ((ch == '\'') || (ch == '"'))) { quote = ch; continue; } /* * Store the character. */ *cpOut++ = ch; } /* * Make sure that quoting is terminated properly. */ if (quote) { fprintf(stderr, "Unmatched quote character\n"); return FALSE; } /* * Null terminate the argument if it had shrunk, and then * skip over all blanks to the next argument, nulling them * out too. */ if (cp != cpOut) *cpOut = '\0'; while (isBlank(*cp)) *cp++ = '\0'; /* * If both quoted and unquoted wildcards were used then * complain since we don't handle them properly. */ if (quotedWildCards && unquotedWildCards) { fprintf(stderr, "Cannot use quoted and unquoted wildcards\n"); return FALSE; } /* * Expand the argument into the matching filenames or accept * it as is depending on whether there were any unquoted * wildcard characters in it. */ if (unquotedWildCards) { /* * Expand the argument into the matching filenames. */ fileCount = expandWildCards(argument, &fileTable); /* * Return an error if the wildcards failed to match. */ if (fileCount < 0) return FALSE; if (fileCount == 0) { fprintf(stderr, "Wildcard expansion error\n"); return FALSE; } } else { /* * Set up to only store the argument itself. */ fileTable = &argument; fileCount = 1; } /* * Now reallocate the argument table to hold the file name. */ if (argCount + fileCount >= argTableSize) { newArgTableSize = argCount + fileCount + 1; newArgTable = (const char **) realloc(argTable, (sizeof(const char *) * newArgTableSize)); if (newArgTable == NULL) { fprintf(stderr, "No memory for arg list\n"); return FALSE; } argTable = newArgTable; argTableSize = newArgTableSize; } /* * Copy the new arguments to the end of the old ones. */ memcpy((void *) &argTable[argCount], (const void *) fileTable, (sizeof(const char **) * fileCount)); /* * Add to the argument count. */ argCount += fileCount; } /* * Null terminate the argument list and return it. */ argTable[argCount] = NULL; /*arithmetic part code*/ int i; int j; int flag = 1; int res; char *env; static char *result = NULL; if (result == NULL) { result = malloc(sizeof (char) * 256); if (result == NULL) { fprintf(stderr, "Memory error\n"); return FALSE; } } for ( i = 0; i < argCount; i++) { if (argTable[i][0] == '$') { if (argTable[i][1] == '(') { memcpy(result, argTable[i], strlen(argTable[i])); for (j = 2; argTable[i][j] != '\0'; j++) { if (isdigit(result[j])) flag = 0; else if (result[j] == '+' || result[j] == '-' || result[j] == 'x' || result[j] == '/') { if (flag == 1) { fprintf(stderr, "Wrong arithmetic expression\n"); return FALSE; } flag = 1; } else if (result[j] == ')') { result[j] = '\0'; if (result[j + 1] != '\0') { fprintf(stderr, "Wrong arithmetic expression\n"); return FALSE; } } else { fprintf(stderr, "Wrong arithmetic expression\n"); return FALSE; } } res = eval_expr(&result[2]); sprintf(result, "%d", res); argTable[i] = result; } else { env = getenv(&argTable[i][1]); if (env != NULL) argTable[i] = env; else argTable[i] = "\0"; } } } *retArgc = argCount; *retArgv = argTable; return TRUE; }
/** Evaluate an expression in a given frame */ value_t eval_expr( heapptr_t expr, clos_t* clos, value_t* locals ) { //printf("eval_expr\n"); // Get the shape of the AST node // Note: AST nodes must match the shapes defined in init_parser, // otherwise this interpreter can't handle it shapeidx_t shape = get_shape(expr); // Variable or constant declaration (let/var) if (shape == SHAPE_AST_DECL) { ast_decl_t* decl = (ast_decl_t*)expr; // Let declarations should be initialized assert (decl->cst == false); return VAL_FALSE; } // Variable reference (read) if (shape == SHAPE_AST_REF) { ast_ref_t* ref = (ast_ref_t*)expr; assert (ref->decl != NULL); //printf("evaluating ref to %s\n", string_cstr(ref->name)); // If this is a variable from an outer function if (ref->decl->fun != clos->fun) { //printf("ref from outer fun\n"); assert (ref->idx < clos->fun->free_vars->len); cell_t* cell = clos->cells[ref->idx]; assert (cell != NULL); value_t value; value.word = cell->word; value.tag = cell->tag; return value; } // Check that the ref index is valid if (ref->idx > clos->fun->local_decls->len) { printf("invalid variable reference\n"); printf("ref->name=%s\n", string_cstr(ref->name)); printf("ref->idx=%d\n", ref->idx); printf("local_decls->len=%d\n", clos->fun->local_decls->len); exit(-1); } // If this an escaping variable (captured by a closure) if (ref->decl->esc) { // Free variables are stored in mutable cells // Pointers to the cells are found on the closure object cell_t* cell = locals[ref->idx].word.cell; value_t value; value.word = cell->word; value.tag = cell->tag; //printf("read value from cell\n"); return value; } /* printf("reading normal local\n"); string_print(ref->name); printf("\n"); */ // Read directly from the stack frame return locals[ref->idx]; } if (shape == SHAPE_AST_CONST) { //printf("constant\n"); ast_const_t* cst = (ast_const_t*)expr; return cst->val; } if (shape == SHAPE_STRING) { return value_from_heapptr(expr, TAG_STRING); } // Array literal expression if (shape == SHAPE_ARRAY) { array_t* array_expr = (array_t*)expr; // Array of values to be produced array_t* val_array = array_alloc(array_expr->len); for (size_t i = 0; i < array_expr->len; ++i) { heapptr_t expr = array_get(array_expr, i).word.heapptr; value_t value = eval_expr(expr, clos, locals); array_set(val_array, i, value); } return value_from_heapptr((heapptr_t)val_array, TAG_ARRAY); } // Object literal expression if (shape == SHAPE_AST_OBJ) { //printf("obj literal expr\n"); ast_obj_t* obj_expr = (ast_obj_t*)expr; object_t* obj = object_alloc(OBJ_MIN_CAP); // TODO: set prototype // Do this in object_alloc? for (size_t i = 0; i < obj_expr->name_strs->len; ++i) { string_t* prop_name = array_get(obj_expr->name_strs, i).word.string; heapptr_t val_expr = array_get(obj_expr->val_exprs, i).word.heapptr; value_t value = eval_expr(val_expr, clos, locals); object_set_prop( obj, prop_name, value, ATTR_DEFAULT ); } return value_from_obj((heapptr_t)obj); } // Binary operator (e.g. a + b) if (shape == SHAPE_AST_BINOP) { //printf("binop\n"); ast_binop_t* binop = (ast_binop_t*)expr; // Assignment if (binop->op == &OP_ASSIGN) { value_t val = eval_expr(binop->right_expr, clos, locals); return eval_assign( binop->left_expr, val, clos, locals ); } value_t v0 = eval_expr(binop->left_expr, clos, locals); value_t v1 = eval_expr(binop->right_expr, clos, locals); int64_t i0 = v0.word.int64; int64_t i1 = v1.word.int64; string_t* s0 = v0.word.string; string_t* s1 = v1.word.string; if (binop->op == &OP_MEMBER) return eval_get_prop(v0, v1); if (binop->op == &OP_INDEX) return eval_get_index(v0, v1); if (binop->op == &OP_ADD) return value_from_int64(i0 + i1); if (binop->op == &OP_SUB) return value_from_int64(i0 - i1); if (binop->op == &OP_MUL) return value_from_int64(i0 * i1); if (binop->op == &OP_DIV) return value_from_int64(i0 / i1); if (binop->op == &OP_MOD) return value_from_int64(i0 % i1); if (binop->op == &OP_LT) return (i0 < i1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_LE) { if (v0.tag == TAG_STRING && v1.tag == TAG_STRING) return (strcmp(string_cstr(s0), string_cstr(s1)) <= 0)? VAL_TRUE:VAL_FALSE; if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64) return (i0 <= i1)? VAL_TRUE:VAL_FALSE; assert (false); } if (binop->op == &OP_GT) return (i0 > i1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_GE) { if (v0.tag == TAG_STRING && v1.tag == TAG_STRING) return (strcmp(string_cstr(s0), string_cstr(s1)) >= 0)? VAL_TRUE:VAL_FALSE; if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64) return (i0 >= i1)? VAL_TRUE:VAL_FALSE; assert (false); } if (binop->op == &OP_EQ) return value_equals(v0, v1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_NE) return value_equals(v0, v1)? VAL_FALSE:VAL_TRUE; printf("unimplemented binary operator: %s\n", binop->op->str); return VAL_FALSE; } // Unary operator (e.g.: -x, not a) if (shape == SHAPE_AST_UNOP) { ast_unop_t* unop = (ast_unop_t*)expr; value_t v0 = eval_expr(unop->expr, clos, locals); if (unop->op == &OP_NEG) return value_from_int64(-v0.word.int64); if (unop->op == &OP_NOT) return eval_truth(v0)? VAL_FALSE:VAL_TRUE; printf("unimplemented unary operator: %s\n", unop->op->str); return VAL_FALSE; } // Sequence/block expression if (shape == SHAPE_AST_SEQ) { ast_seq_t* seqexpr = (ast_seq_t*)expr; array_t* expr_list = seqexpr->expr_list; value_t value = VAL_TRUE; for (size_t i = 0; i < expr_list->len; ++i) { heapptr_t expr = array_get(expr_list, i).word.heapptr; value = eval_expr(expr, clos, locals); } // Return the value of the last expression return value; } // If expression if (shape == SHAPE_AST_IF) { ast_if_t* ifexpr = (ast_if_t*)expr; value_t t = eval_expr(ifexpr->test_expr, clos, locals); if (eval_truth(t)) return eval_expr(ifexpr->then_expr, clos, locals); else return eval_expr(ifexpr->else_expr, clos, locals); } // Function/closure expression if (shape == SHAPE_AST_FUN) { //printf("creating closure\n"); ast_fun_t* nested = (ast_fun_t*)expr; // Allocate a closure of the nested function clos_t* new_clos = clos_alloc(nested); // For each free (closure) variable of the nested function for (size_t i = 0; i < nested->free_vars->len; ++i) { ast_decl_t* decl = array_get(nested->free_vars, i).word.decl; // If the variable is from this function if (decl->fun == clos->fun) { new_clos->cells[i] = locals[decl->idx].word.cell; } else { uint32_t free_idx = array_indexof_ptr(clos->fun->free_vars, (heapptr_t)decl); assert (free_idx < clos->fun->free_vars->len); new_clos->cells[i] = clos->cells[free_idx]; } } assert (new_clos->fun == nested); return value_from_heapptr((heapptr_t)new_clos, TAG_CLOS); } // Call expression if (shape == SHAPE_AST_CALL) { //printf("evaluating call\n"); ast_call_t* callexpr = (ast_call_t*)expr; // Evaluate the closure expression value_t callee_clos = eval_expr(callexpr->fun_expr, clos, locals); if (callee_clos.tag == TAG_CLOS) { return eval_call( callee_clos.word.clos, callexpr->arg_exprs, clos, locals ); } if (callee_clos.tag == TAG_HOSTFN) { return eval_host_call( callee_clos.word.hostfn, callexpr->arg_exprs, clos, locals ); } printf("invalid callee in function call\n"); exit(-1); } printf("eval error, unknown expression type, shapeidx=%d\n", get_shape(expr)); exit(-1); }
/** Evaluate a host function call */ value_t eval_host_call( hostfn_t* callee, array_t* arg_exprs, clos_t* caller, value_t* caller_locals ) { value_t* arg_vals = alloca(sizeof(value_t) * arg_exprs->len); if (arg_exprs->len != callee->num_params) { printf( "argument count mismatch in call to %s, got %d, expected %d\n", string_cstr(callee->name), arg_exprs->len, callee->num_params ); exit(-1); } // Evaluate the argument values for (size_t i = 0; i < arg_exprs->len; ++i) { //printf("evaluating arg %ld\n", i); // Evaluate the parameter value arg_vals[i] = eval_expr( array_get_ptr(arg_exprs, i), caller, caller_locals ); } // Type test signature if (callee->sig_str == vm_get_cstr("bool(tag)")) { bool (*fptr)(tag_t) = callee->fptr; return fptr(arg_vals[0].tag)? VAL_TRUE:VAL_FALSE; } if (callee->sig_str == vm_get_cstr("void(int)")) { void (*fptr)(int) = callee->fptr; fptr(arg_vals[0].word.int32); return VAL_TRUE; } if (callee->sig_str == vm_get_cstr("void(int64)")) { void (*fptr)(int64_t) = callee->fptr; fptr(arg_vals[0].word.int64); return VAL_TRUE; } if (callee->sig_str == vm_get_cstr("void(string)")) { void (*fptr)(string_t*) = callee->fptr; fptr(arg_vals[0].word.string); return VAL_TRUE; } if (callee->sig_str == vm_get_cstr("string()")) { string_t* (*fptr)() = callee->fptr; string_t* str = fptr(); return value_from_heapptr((heapptr_t)str, TAG_STRING); } if (callee->sig_str == vm_get_cstr("string(string)")) { string_t* (*fptr)(string_t*) = callee->fptr; string_t* str = fptr(arg_vals[0].word.string); return value_from_heapptr((heapptr_t)str, TAG_STRING); } printf("unsupported host function signature\n"); exit(-1); }
/** Evaluate an assignment of a value to an expression */ value_t eval_assign( heapptr_t lhs_expr, value_t val, clos_t* clos, value_t* locals ) { shapeidx_t shape = get_shape(lhs_expr); // Assignment to variable declaration if (shape == SHAPE_AST_DECL) { ast_decl_t* decl = (ast_decl_t*)lhs_expr; // If this an escaping variable if (decl->esc) { // Escaping variables are stored in mutable cells // Pointers to the cells are found on the closure object cell_t* cell = locals[decl->idx].word.cell; cell->word = val.word; cell->tag = val.tag; return val; } // Assign to the stack frame slot directly locals[decl->idx] = val; return val; } // Assignment to a variable if (shape == SHAPE_AST_REF) { ast_ref_t* ref = (ast_ref_t*)lhs_expr; assert (ref->decl != NULL); // If this is a variable from an outer function if (ref->decl->fun != clos->fun) { assert (ref->idx < clos->fun->free_vars->len); cell_t* cell = clos->cells[ref->idx]; cell->word = val.word; cell->tag = val.tag; return val; } // Check that the ref index is valid if (ref->idx > clos->fun->local_decls->len) { printf("assignment to invalid index\n"); exit(-1); } // If this an escaping variable (captured by a closure) if (ref->decl->esc) { // Escaping variables are stored in mutable cells // Pointers to the cells are found on the closure object cell_t* cell = locals[ref->idx].word.cell; cell->word = val.word; cell->tag = val.tag; return val; } // Assign to the stack frame slot directly locals[ref->idx] = val; return val; } // Binary operator (e.g. a.b) if (shape == SHAPE_AST_BINOP) { ast_binop_t* binop = (ast_binop_t*)lhs_expr; value_t v0 = eval_expr(binop->left_expr, clos, locals); value_t v1 = eval_expr(binop->right_expr, clos, locals); if (binop->op == &OP_MEMBER) { if (v0.tag != TAG_OBJECT) { printf("non-object base in property write\n"); exit(-1); } if (v1.tag != TAG_STRING) { printf("non-string property name in property write\n"); exit(-1); } object_set_prop( v0.word.object, v1.word.string, val, ATTR_DEFAULT ); return val; } } printf("invalid lhs expression in assignment\n"); exit(-1); }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; int sec,usec; union sockaddr_union* to; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len,i; int user = 0; int expires = 0; str vals[5]; str result; struct sip_uri uri, next_hop; struct sip_uri *u; unsigned short port; int cmatch; struct action *aitem; struct action *adefault; pv_spec_t *spec; pv_elem_p model; pv_value_t val; pv_elem_t *pve; str name_s; struct timeval start; int end_time; action_elem_t *route_params_bak; int route_params_number_bak; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; start_expire_timer(start,execmsgthreshold); ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: script_trace("core", "drop", msg, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: script_trace("core", "exit", msg, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: script_trace("core", "return", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL)) { ret=-1; } else { if(!(val.flags&PV_VAL_INT)) ret = 1; else ret = val.ri; } pv_value_destroy(&val); } else { ret=a->elem[0].u.number; } action_flags |= ACT_FL_RETURN; break; case FORWARD_T: script_trace("core", "forward", msg, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LM_ERR("forward: bad_uri dropping packet\n"); break; } /* create a temporary proxy*/ p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host, u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 ); if (p==0){ LM_ERR("bad host name in uri, dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; } break; case SEND_T: script_trace("core", "send", msg, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->elem[1].u.data) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST){ LM_ALERT("BUG in send() header type %d\n",a->elem[1].type); ret=E_BUG; break; } else { pve = (pv_elem_t *)a->elem[1].u.data; } } else { pve = NULL; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->elem[0].u.data; ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_UNSPEC; break; } /* build new msg */ tmp = pkg_malloc(msg->len + name_s.len); if (!tmp) { LM_ERR("memory allocation failure\n"); ret = E_OUT_OF_MEM; break; } LM_DBG("searching for first line %d\n", msg->first_line.len); /* search first line of previous msg */ /* copy headers */ len = msg->first_line.len; memcpy(tmp, msg->buf, len); memcpy(tmp + len, name_s.s, name_s.len); memcpy(tmp + len + name_s.len, msg->buf + len, msg->len - len); ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, tmp, msg->len + name_s.len); pkg_free(tmp); } else { ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, msg->buf, msg->len); } if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } pkg_free(to); if (ret==0) ret=1; break; case LOG_T: script_trace("core", "log", msg, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string); ret=1; break; case APPEND_BRANCH_T: script_trace("core", "append_branch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); ret=E_BUG; break; } if (a->elem[0].u.s.s==NULL) { ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec, get_ruri_q(), getb0flags(), msg->force_send_socket); /* reset all branch info */ msg->force_send_socket = 0; setb0flags(0); set_ruri_q(Q_UNSPECIFIED); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } else { ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: script_trace("core", "remove_branch", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) { ret=-1; break; } i = val.ri; } else { i=a->elem[0].u.number; } ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: script_trace("core", "len_gt", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); ret=E_BUG; break; } ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: script_trace("core", "set_debug", msg, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else reset_proc_debug_level(); ret = 1; break; case SETFLAG_T: script_trace("core", "setflag", msg, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: script_trace("core", "resetflag", msg, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: script_trace("core", "isflagset", msg, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: script_trace("core", "setsflag", msg, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: script_trace("core", "resetsflag", msg, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: script_trace("core", "issflagset", msg, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: script_trace("core", "setbflag", msg, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: script_trace("core", "resetbflag", msg, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: script_trace("core", "isbflagset", msg, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: script_trace("core", "error", msg, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_ERR("error(\"%s\", \"%s\") not implemented yet\n", a->elem[0].u.string, a->elem[1].u.string); ret=1; break; case ROUTE_T: script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); ret=E_BUG; break; } if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){ LM_ALERT("BUG - invalid routing table number in" "route(%lu)\n", a->elem[0].u.number); ret=E_CFG; break; } /* check if the route has parameters */ if (a->elem[1].type != 0) { if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in route() type %d/%d\n", a->elem[1].type, a->elem[2].type); ret=E_BUG; break; } route_params_bak = route_params; route_params = (action_elem_t *)a->elem[2].u.data; route_params_number_bak = route_params_number; route_params_number = a->elem[1].u.number; return_code=run_actions(rlist[a->elem[0].u.number].a, msg); route_params = route_params_bak; route_params_number = route_params_number_bak; } else { return_code=run_actions(rlist[a->elem[0].u.number].a, msg); } ret=return_code; break; case REVERT_URI_T: script_trace("core", "revert_uri", msg, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", msg, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); break; } } else if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->type==SET_URI_T) { if (set_ruri( msg, &a->elem[0].u.s) ) { LM_ERR("failed to set new RURI\n"); ret=E_OUT_OF_MEM; break; } ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; if (a->type==PREFIX_T) { if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else if (a->type==STRIP_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip asked; " " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->elem[0].u.number; len=uri.user.len - a->elem[0].u.number; } } else if (a->type==STRIP_TAIL_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip_tail asked;" " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->elem[0].u.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp && len>0){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ /* include in param string the starting ';' */ len=uri.params.len+1; tmp--; if(crt+len+1>end) goto error_uri; /* if a maddr param is present, strip it out */ if (uri.maddr.len && (a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) { memcpy(crt,tmp,uri.maddr.s-tmp-1); crt+=uri.maddr.s-tmp-1; memcpy(crt,uri.maddr_val.s+uri.maddr_val.len, tmp+len-uri.maddr_val.s-uri.maddr_val.len); crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len; } else { memcpy(crt,tmp,len);crt+=len; } } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case SET_DSTURI_T: script_trace("core", "set_dsturi", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); ret=E_BUG; break; } if(set_dst_uri(msg, &a->elem[0].u.s)!=0) ret = -1; else ret = 1; break; case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? "set_dsturi" : "set_dstport", msg, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); ret=E_BUG; break; } tmp = msg->dst_uri.s; len = msg->dst_uri.len; if (tmp == NULL || len == 0) { LM_ERR("failure - null uri\n"); ret = E_UNSPEC; break; } if (a->type == SET_DSTHOST_T && (a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) { LM_ERR("cannot set a null uri domain\n"); break; } if (parse_uri(tmp, len, &uri)<0) { LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri == NULL) { LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; /* user */ tmp = uri.user.s; len = uri.user.len; if (tmp) { if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; user = 1; } /* passwd */ tmp = uri.passwd.s; len = uri.passwd.len; if (user || tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* host */ if (a->type==SET_DSTHOST_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.host.s; len = uri.host.len; } if (tmp) { if (user) { if (crt+1>end) goto error_uri; *crt++='@'; } if (crt+len+1>end) goto error_uri; memcpy(crt, tmp, len); crt += len; } /* port */ if (a->type==SET_DSTPORT_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.port.s; len = uri.port.len; } if (tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt++=';'; memcpy(crt,tmp,len); crt += len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt++='?'; memcpy(crt,tmp,len); crt += len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ pkg_free(msg->dst_uri.s); msg->dst_uri.s=new_uri; msg->dst_uri.len=crt-new_uri; ret = 1; break; case RESET_DSTURI_T: script_trace("core", "reset_dsturi", msg, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; ret = 1; break; case ISDSTURISET_T: script_trace("core", "isdsturiset", msg, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: script_trace("core", "if", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); return_code = ret; } else return_code = v; }else{ if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){ ret=run_action_list( (struct action*)a->elem[2].u.data,msg); return_code = ret; } else return_code = v; } } break; case WHILE_T: script_trace("core", "while", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; while(1) { if(len++ >= max_while_loops) { LM_INFO("max while loops are encountered\n"); break; } v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) &&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); /* check if return was done */ if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ break; } return_code = ret; } else { /* we should not get here */ return_code = v; break; } } else { /* condition was false */ return_code = v; break; } } } break; case CACHE_STORE_T: script_trace("core", "cache_store", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } if ((a->elem[2].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - third argument not of type" " string%d\n", a->elem[2].type ); ret=E_BUG; break; } str val_s; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* get the expires value */ if ( a->elem[3].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[3].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_store\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n", val.rs.len, val.rs.s); } expires = val.ri; } else if ( a->elem[3].type == NUMBER_ST ) { expires = (int)a->elem[3].u.number; } ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires); break; case CACHE_REMOVE_T: script_trace("core", "cache_remove", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: script_trace("core", "cache_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux); if(ret > 0) { val.rs = aux; val.flags = PV_VAL_STR; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } pkg_free(aux.s); } break; case CACHE_COUNTER_FETCH_T: script_trace("core", "cache_counter_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } int aux_counter; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter); if(ret > 0) { val.ri = aux_counter; val.flags = PV_TYPE_INT|PV_VAL_INT; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } } break; case CACHE_ADD_T: script_trace("core", "cache_add", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int increment=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_add\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n", val.rs.len, val.rs.s); } increment = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { increment = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return the new value to script ? */ ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); break; case CACHE_SUB_T: script_trace("core", "cache_sub", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int decrement=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_sub\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n", val.rs.len, val.rs.s); } decrement = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { decrement = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return new value to script ? */ ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } cdb_raw_entry **cdb_reply; int val_number=0,i,j; int key_number=0; pvname_list_t *cdb_res,*it; int_str avp_val; int_str avp_name; unsigned short avp_type; if (a->elem[2].u.data) { cdb_res = (pvname_list_t*)a->elem[2].u.data; for (it=cdb_res;it;it=it->next) val_number++; LM_DBG("The query expects %d results back\n",val_number); ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number); if (ret >= 0 && val_number > 0) { for (i=key_number-1; i>=0;i--) { it=cdb_res; for (j=0;j < val_number;j++) { avp_type = 0; if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n, &avp_type) != 0) { LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } switch (cdb_reply[i][j].type) { case CDB_INT: avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; avp_val.s = cdb_reply[i][j].val.s; break; default: LM_WARN("Unknown type %d\n",cdb_reply[i][j].type); goto next_avp; } if (add_avp(avp_type,avp_name.n,avp_val) != 0) { LM_ERR("Unable to add AVP\n"); free_raw_fetch(cdb_reply,val_number,key_number); return -1; } next_avp: if (it) { it = it->next; if (it==NULL); break; } } } free_raw_fetch(cdb_reply,val_number,key_number); } } else ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: script_trace("core", "xdbg", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print message"); break; } } else { LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type); ret=E_BUG; } break; case XLOG_T: script_trace("core", "xlog", msg, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } else { if (a->elem[0].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } break; case RAISE_EVENT_T: script_trace("core", "raise_event", msg, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { /* three parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, a->elem[1].u.data, a->elem[2].u.data); } else { /* two parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, NULL, a->elem[1].u.data); } if (ret <= 0) { LM_ERR("cannot raise event\n"); ret=E_UNSPEC; break; } break; case SUBSCRIBE_EVENT_T: script_trace("core", "subscribe_event", msg, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { if (a->elem[2].type != NUMBER_ST) { LM_ERR("BUG in subscribe expiration time\n"); ret=E_BUG; break; } else { i = a->elem[2].u.number; } } else { i = 0; } name_s.s = a->elem[0].u.data; name_s.len = strlen(name_s.s); /* result should be the socket */ result.s = a->elem[1].u.data; result.len = strlen(result.s); ret = evi_event_subscribe(name_s, result, i, 0); break; case CONSTRUCT_URI_T: script_trace("core", "construct_uri", msg, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { if ( pv_printf_s(msg, pve, &vals[i])!=0 || vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; return -1; } } else vals[i] = pve->text; } result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); if (result.s) { int_str res; int avp_name; unsigned short avp_type; spec = (pv_spec_t*)a->elem[5].u.data; if (pv_get_avp_name( msg, &(spec->pvp), &avp_name, &avp_type)!=0){ LM_CRIT("BUG in getting AVP name\n"); return -1; } res.s = result; if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){ LM_ERR("cannot add AVP\n"); return -1; } } break; case GET_TIMESTAMP_T: script_trace("core", "get_timestamp", msg, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; unsigned short avp_type; spec = (pv_spec_t*)a->elem[0].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = sec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } spec = (pv_spec_t*)a->elem[1].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = usec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } } else { LM_ERR("failed to get time\n"); return -1; } break; case SWITCH_T: script_trace("core", "switch", msg, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); ret=E_BUG; break; } spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0) { LM_ALERT("BUG - no value in switch()\n"); ret=E_BUG; break; } /* get the value of pvar */ if(a->elem[1].type!=ACTIONS_ST) { LM_ALERT("BUG in switch() actions\n"); ret=E_BUG; break; } return_code=1; adefault = NULL; aitem = (struct action*)a->elem[1].u.data; cmatch=0; while(aitem) { if((unsigned char)aitem->type==DEFAULT_T) adefault=aitem; if(cmatch==0) { if(aitem->elem[0].type==STR_ST) { if(val.flags&PV_VAL_STR && val.rs.len==aitem->elem[0].u.s.len && strncasecmp(val.rs.s, aitem->elem[0].u.s.s, val.rs.len)==0) cmatch = 1; } else { /* number */ if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } } if(cmatch==1) { if(aitem->elem[1].u.data) { return_code=run_action_list( (struct action*)aitem->elem[1].u.data, msg); if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT)) break; } if(aitem->elem[2].u.number==1) break; } aitem = aitem->next; } if((cmatch==0) && (adefault!=NULL)) { LM_DBG("switch: running default statement\n"); if(adefault->elem[0].u.data) return_code=run_action_list( (struct action*)adefault->elem[0].u.data, msg); } ret=return_code; break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, msg, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, (char*)a->elem[3].u.data, (char*)a->elem[4].u.data, (char*)a->elem[5].u.data, (char*)a->elem[6].u.data); }else{ LM_ALERT("BUG in module call\n"); } break; case FORCE_RPORT_T: script_trace("core", "force_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: script_trace("core", "force_local_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: script_trace("core", "set_adv_addr", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_address() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } str adv_addr; pve = (pv_elem_t *)a->elem[0].u.data; if ( pv_printf_s(msg, pve, &adv_addr)!=0 || adv_addr.len == 0 || adv_addr.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); msg->set_global_address=adv_addr; ret=1; /* continue processing */ break; case SET_ADV_PORT_T: script_trace("core", "set_adv_port", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_port() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->elem[0].u.data); ret=1; /* continue processing */ break; #ifdef USE_TCP case FORCE_TCP_ALIAS_T: script_trace("core", "force_tcp_alias", msg, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; else{ LM_ALERT("BUG in force_tcp_alias" " port type %d\n", a->elem[0].type); ret=E_BUG; break; } if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); ret=E_UNSPEC; break; } } #endif ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: script_trace("core", "force_send_socket", msg, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } msg->force_send_socket=(struct socket_info*)a->elem[0].u.data; ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: script_trace("core", "serialize_branches", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) { LM_ERR("serialize_branches failed\n"); ret=E_UNSPEC; break; } ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: script_trace("core", "next_branches", msg, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; break; } /* continue processing */ break; case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: ret = do_assign(msg, a); break; case USE_BLACKLIST_T: script_trace("core", "use_blacklist", msg, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: script_trace("core", "unuse_blacklist", msg, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: script_trace("core", "pv_printf", msg, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) { LM_ERR("read only PV in first parameter of pv_printf\n"); goto error; } model = (pv_elem_p)a->elem[1].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_printf_s(msg, model, &val.rs)!=0) { LM_ERR("cannot eval second parameter\n"); goto error; } val.flags = PV_VAL_STR; if(pv_set_value(msg, spec, EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } ret = 1; break; case SCRIPT_TRACE_T: script_trace("core", "script_trace", msg, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { use_script_trace = 1; if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ERR("BUG in use_script_trace() arguments\n"); ret=E_BUG; break; } if (a->elem[2].type!=NOSUBTYPE) { script_trace_info = (char *)a->elem[2].u.data; } else { script_trace_info = NULL; } script_trace_log_level = (int)a->elem[0].u.number; script_trace_elem = *(pv_elem_p)a->elem[1].u.data; } break; default: LM_ALERT("BUG - unknown type %d\n", a->type); goto error; } if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T) return_code = ret; /*skip:*/ update_longest_action(); return ret; error: LM_ERR("error at line: %d\n", a->line); update_longest_action(); return ret; error_uri: LM_ERR("set*: uri too long\n"); if (new_uri) pkg_free(new_uri); update_longest_action(); return E_UNSPEC; error_fwd_uri: update_longest_action(); return ret; }
/*! \brief * \return 0/1 (false/true) or -1 on error, -127 EXPR_DROP */ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) { struct sip_uri uri; int ret; int retl; int retr; int ival; pv_value_t lval; pv_value_t rval; char *p; int i,n; ret=E_BUG; if (e->type!=ELEM_T){ LM_CRIT("invalid type\n"); goto error; } if(val) memset(val, 0, sizeof(pv_value_t)); switch(e->left.type){ case METHOD_O: ret=comp_strval(msg, e->op, &msg->first_line.u.request.method, &e->right); break; case URI_O: if(msg->new_uri.s){ if (e->right.type==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &msg->new_uri, &e->right); } }else{ if (e->right.type==MYSELF_ST){ if (parse_sip_msg_uri(msg)<0) ret=-1; else ret=check_self_op(e->op, &msg->parsed_uri.host, msg->parsed_uri.port_no? msg->parsed_uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &msg->first_line.u.request.uri, &e->right); } } break; case FROM_URI_O: if (parse_from_header(msg)<0){ LM_ERR("bad or missing From: header\n"); goto error; } if (e->right.type==MYSELF_ST){ if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len, &uri) < 0){ LM_ERR("bad uri in From:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &get_from(msg)->uri, &e->right); } break; case TO_URI_O: if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) || (msg->to==0))){ LM_ERR("bad or missing To: header\n"); goto error; } /* to content is parsed automatically */ if (e->right.type==MYSELF_ST){ if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len, &uri) < 0){ LM_ERR("bad uri in To:\n"); goto error; } ret=check_self_op(e->op, &uri.host, uri.port_no?uri.port_no:SIP_PORT); }else{ ret=comp_strval(msg, e->op, &get_to(msg)->uri, &e->right); } break; case SRCIP_O: ret=comp_ip(msg, e->op, &msg->rcv.src_ip, &e->right); break; case DSTIP_O: ret=comp_ip(msg, e->op, &msg->rcv.dst_ip, &e->right); break; case NUMBER_O: ret=!(!e->right.v.n); /* !! to transform it in {0,1} */ break; case ACTION_O: ret=run_action_list( (struct action*)e->right.v.data, msg); if(val) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = ret; } if (ret<=0) ret=(ret==0)?EXPR_DROP:0; else ret=1; return ret; case EXPR_O: retl = retr = 0; memset(&lval, 0, sizeof(pv_value_t)); memset(&rval, 0, sizeof(pv_value_t)); if(e->left.v.data) retl=eval_expr((struct expr*)e->left.v.data,msg,&lval); if(lval.flags == PV_VAL_NONE) { pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(e->op == BNOT_OP) { if(lval.flags&PV_VAL_INT) { if(val!=NULL) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = ~lval.ri; } pv_value_destroy(&lval); pv_value_destroy(&rval); return (val->ri)?1:0; } LM_ERR("binary NOT on non-numeric value\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(e->right.v.data) retr=eval_expr((struct expr*)e->right.v.data,msg,&rval); if(lval.flags&PV_TYPE_INT) { if( (rval.flags&PV_VAL_NULL) ) { rval.ri = 0; } else if(!(rval.flags&PV_VAL_INT)) { LM_ERR("invalid numeric operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } if(val!=NULL) val->flags = PV_TYPE_INT|PV_VAL_INT; ival = 0; switch(e->op) { case PLUS_OP: ival = lval.ri + rval.ri; break; case MINUS_OP: ival = lval.ri - rval.ri; break; case DIV_OP: if(rval.ri==0) { LM_ERR("divide by 0\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } else ival = lval.ri / rval.ri; break; case MULT_OP: ival = lval.ri * rval.ri; break; case MODULO_OP: if(rval.ri==0) { LM_ERR("divide by 0\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } else ival = lval.ri % rval.ri; break; case BAND_OP: ival = lval.ri & rval.ri; break; case BOR_OP: ival = lval.ri | rval.ri; break; case BXOR_OP: ival = lval.ri ^ rval.ri; break; case BLSHIFT_OP: ival = lval.ri << rval.ri; break; case BRSHIFT_OP: ival = lval.ri >> rval.ri; break; default: LM_ERR("invalid int op %d\n", e->op); val->ri = 0; pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } pv_value_destroy(&lval); pv_value_destroy(&rval); if(val!=NULL) val->ri = ival; return (ival)?1:0; } else if (e->op == PLUS_OP) { if( (rval.flags&PV_VAL_NULL) || (val==NULL)) { if (val) val->flags|=PV_VAL_STR; ret = (lval.rs.len>0 || rval.rs.len>0); pv_value_destroy(&lval); pv_value_destroy(&rval); return ret; } if(!(rval.flags&PV_VAL_STR)) { LM_ERR("invalid string operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->rs.s=(char*)pkg_malloc((lval.rs.len+rval.rs.len+1) *sizeof(char)); if(val->rs.s==0) { LM_ERR("no more memory\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->flags = PV_VAL_PKG|PV_VAL_STR; memcpy(val->rs.s, lval.rs.s, lval.rs.len); memcpy(val->rs.s+lval.rs.len, rval.rs.s, rval.rs.len); val->rs.len = lval.rs.len + rval.rs.len; val->rs.s[val->rs.len] = '\0'; pv_value_destroy(&lval); pv_value_destroy(&rval); return 1; } else if ((lval.flags & PV_VAL_STR) && (rval.flags & PV_VAL_STR)) { if (lval.rs.len != rval.rs.len) { LM_ERR("Different length string operands\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } n = lval.rs.len; val->rs.s = pkg_malloc(n+1); if (!val->rs.s) { LM_ERR("no more memory\n"); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } switch(e->op) { case BAND_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] & rval.rs.s[i]; break; case BOR_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] | rval.rs.s[i]; break; case BXOR_OP: for (i=0;i<n;i++) val->rs.s[i] = lval.rs.s[i] ^ rval.rs.s[i]; break; default: LM_ERR("Only bitwise operations can be applied on strings\n"); val->ri = 0; pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } val->flags = PV_VAL_PKG|PV_VAL_STR; val->rs.len = n; val->rs.s[n] = '\0'; pv_value_destroy(&lval); pv_value_destroy(&rval); return 1; } else { LM_ERR("Invalid operator : %d \n",e->op); pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; } break; case SRCPORT_O: ret=comp_no(msg->rcv.src_port, e->right.v.data, /* e.g., 5060 */ e->op, /* e.g. == */ e->right.type /* 5060 is number */); break; case DSTPORT_O: ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op, e->right.type); break; case PROTO_O: ret=comp_no(msg->rcv.proto, e->right.v.data, e->op, e->right.type); break; case AF_O: ret=comp_no(msg->rcv.src_ip.af, e->right.v.data, e->op, e->right.type); break; case RETCODE_O: ret=comp_no(return_code, e->right.v.data, e->op, e->right.type); break; case MSGLEN_O: ret=comp_no(msg->len, e->right.v.data, e->op, e->right.type); break; case STRINGV_O: if(val) { val->flags = PV_VAL_STR; val->rs = e->left.v.s; } /* optimization for no dup ?!?! */ return (e->left.v.s.len>0)?1:0; case NUMBERV_O: if(val) { val->flags = PV_TYPE_INT|PV_VAL_INT; val->ri = e->left.v.n; } ret=!(!e->left.v.n); /* !! to transform it in {0,1} */ return ret; case SCRIPTVAR_O: if(e->op==NO_OP) { memset(&rval, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, e->right.v.spec, &rval)==0) { if(rval.flags==PV_VAL_NONE || (rval.flags&PV_VAL_NULL) || (rval.flags&PV_VAL_EMPTY) || ((rval.flags&PV_TYPE_INT)&&rval.ri==0)) { pv_value_destroy(&rval); return 0; } if(rval.flags&PV_TYPE_INT) { pv_value_destroy(&rval); return 1; } if(rval.rs.len!=0) { pv_value_destroy(&rval); return 1; } pv_value_destroy(&rval); } return 0; } if(e->op==VALUE_OP) { if(pv_get_spec_value(msg, e->left.v.spec, &lval)==0) { if(val!=NULL) memcpy(val, &lval, sizeof(pv_value_t)); if(lval.flags&PV_VAL_STR) { if(!((lval.flags&PV_VAL_PKG) || (lval.flags&PV_VAL_SHM))) { if(val!=NULL) { /* do pkg duplicate */ p = (char*)pkg_malloc((val->rs.len+1) *sizeof(char)); if(p==0) { LM_ERR("no more pkg memory\n"); memset(val, 0, sizeof(pv_value_t)); return 0; } memcpy(p, val->rs.s, val->rs.len); p[val->rs.len] = 0; val->rs.s = p; val->flags|= PV_VAL_PKG; } } return 1; } if(lval.flags==PV_VAL_NONE || (lval.flags & PV_VAL_NULL) || (lval.flags & PV_VAL_EMPTY)) return 0; if(lval.flags&PV_TYPE_INT) return (lval.ri!=0); else return (lval.rs.len>0); } return 0; } ret=comp_scriptvar(msg, e->op, &e->left, &e->right); break; default: LM_CRIT("invalid operand %d\n", e->left.type); }
void do_if (int sharp) { char c; char d; #ifdef DEBUG_IF if (debugging) { outputc('<'); outputc(sharp ? '#' : '@'); outputs("if: "); // fflush(outfile); } #endif if (in_false_if()) { n_skipped_ifs ++; #ifdef DEBUG_IF if (debugging) { outputs("in-false, skipped>"); // fflush(outfile); } #endif if (sharp) { d = '\0'; do { c = d; d = Get(); } while ((c == '\\') || (d != '\n')); } return ; } if (! sharp) { c = getnonspace(); if (c != '(') { err_head(); fprintf(stderr, "@if must have ()s\n"); Push(c); iffalse(); #ifdef DEBUG_IF if (debugging) { outputc('>'); // fflush(outfile); } #endif return ; } } if (eval_expr(sharp, 0)) { iftrue(); } else { iffalse(); } #ifdef DEBUG_IF if (debugging) { outputc('>'); // fflush(outfile); } #endif }
/* print the value of stat variable STAT */ void stat_print_stat(struct stat_sdb_t *sdb, /* stat database */ struct stat_stat_t *stat,/* stat variable */ FILE *fd) /* output stream */ { struct eval_value_t val; switch (stat->sc) { case sc_int: fprintf(fd, "%-22s ", stat->name); myfprintf(fd, stat->format, *stat->variant.for_int.var); fprintf(fd, " # %s", stat->desc); break; case sc_uint: fprintf(fd, "%-22s ", stat->name); myfprintf(fd, stat->format, *stat->variant.for_uint.var); fprintf(fd, " # %s", stat->desc); break; #ifdef HOST_HAS_QWORD case sc_qword: { char buf[128]; fprintf(fd, "%-22s ", stat->name); mysprintf(buf, stat->format, *stat->variant.for_qword.var); fprintf(fd, "%s # %s", buf, stat->desc); } break; case sc_sqword: { char buf[128]; fprintf(fd, "%-22s ", stat->name); mysprintf(buf, stat->format, *stat->variant.for_sqword.var); fprintf(fd, "%s # %s", buf, stat->desc); } break; #endif /* HOST_HAS_QWORD */ case sc_float: fprintf(fd, "%-22s ", stat->name); myfprintf(fd, stat->format, (double)*stat->variant.for_float.var); fprintf(fd, " # %s", stat->desc); break; case sc_double: fprintf(fd, "%-22s ", stat->name); myfprintf(fd, stat->format, *stat->variant.for_double.var); fprintf(fd, " # %s", stat->desc); break; case sc_dist: print_dist(stat, fd); break; case sc_sdist: print_sdist(stat, fd); break; case sc_formula: { /* instantiate a new evaluator to avoid recursion problems */ struct eval_state_t *es = eval_new(stat_eval_ident, sdb); char *endp; fprintf(fd, "%-22s ", stat->name); val = eval_expr(es, stat->variant.for_formula.formula, &endp); if (eval_error != ERR_NOERR || *endp != '\0') fprintf(fd, "<error: %s>", eval_err_str[eval_error]); else myfprintf(fd, stat->format, eval_as_double(val)); fprintf(fd, " # %s", stat->desc); /* done with the evaluator */ eval_delete(es); } break; default: panic("bogus stat class"); } fprintf(fd, "\n"); }
static struct block *postfix_expression(struct block *block) { struct var root; block = primary_expression(block); root = block->expr; while (1) { const struct member *field; const struct typetree *type; struct var expr, copy, *arg; struct token tok; int i, j; switch ((tok = peek()).token) { case '[': do { /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic * takes care of multiplying b with the correct width. */ consume('['); block = expression(block); root = eval_expr(block, IR_OP_ADD, root, block->expr); root = eval_deref(block, root); consume(']'); } while (peek().token == '['); break; case '(': type = root.type; if (is_pointer(root.type) && is_function(root.type->next)) type = type_deref(root.type); else if (!is_function(root.type)) { error("Expression must have type pointer to function, was %t.", root.type); exit(1); } consume('('); arg = calloc(nmembers(type), sizeof(*arg)); for (i = 0; i < nmembers(type); ++i) { if (peek().token == ')') { error("Too few arguments, expected %d but got %d.", nmembers(type), i); exit(1); } block = assignment_expression(block); arg[i] = block->expr; /* todo: type check here. */ if (i < nmembers(type) - 1) { consume(','); } } while (is_vararg(type) && peek().token != ')') { consume(','); arg = realloc(arg, (i + 1) * sizeof(*arg)); block = assignment_expression(block); arg[i] = block->expr; i++; } consume(')'); for (j = 0; j < i; ++j) param(block, arg[j]); free(arg); root = eval_call(block, root); break; case '.': consume('.'); tok = consume(IDENTIFIER); field = find_type_member(root.type, tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } root.type = field->type; root.offset += field->offset; break; case ARROW: consume(ARROW); tok = consume(IDENTIFIER); if (is_pointer(root.type) && is_struct_or_union(root.type->next)) { field = find_type_member(type_deref(root.type), tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } /* Make it look like a pointer to the field type, then perform * normal dereferencing. */ root.type = type_init(T_POINTER, field->type); root = eval_deref(block, root); root.offset = field->offset; } else { error("Invalid field access."); exit(1); } break; case INCREMENT: consume(INCREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_ADD, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; case DECREMENT: consume(DECREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_SUB, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; default: block->expr = root; return block; } } }
static struct block *unary_expression(struct block *block) { struct var value; switch (peek().token) { case '&': consume('&'); block = cast_expression(block); block->expr = eval_addr(block, block->expr); break; case '*': consume('*'); block = cast_expression(block); block->expr = eval_deref(block, block->expr); break; case '!': consume('!'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr); break; case '~': consume('~'); block = cast_expression(block); block->expr = eval_expr(block, IR_NOT, block->expr); break; case '+': consume('+'); block = cast_expression(block); block->expr.lvalue = 0; break; case '-': consume('-'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr); break; case SIZEOF: { struct typetree *type; struct block *head = cfg_block_init(), *tail; consume(SIZEOF); if (peek().token == '(') { switch (peekn(2).token) { case FIRST(type_name): consume('('); type = declaration_specifiers(NULL); if (peek().token != ')') { type = declarator(type, NULL); } consume(')'); break; default: tail = unary_expression(head); type = (struct typetree *) tail->expr.type; break; } } else { tail = unary_expression(head); type = (struct typetree *) tail->expr.type; } if (is_function(type)) { error("Cannot apply 'sizeof' to function type."); } if (!size_of(type)) { error("Cannot apply 'sizeof' to incomplete type."); } block->expr = var_int(size_of(type)); break; } case INCREMENT: consume(INCREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; case DECREMENT: consume(DECREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; default: block = postfix_expression(block); break; } return block; }