Mercurial > libavcodec.hg
diff eval.c @ 11801:026edf66e3a9 libavcodec
Make ff_parse_expr() and ff_parse_and_eval_expr() return an int
containing an error code.
Allow these functions to convey the reason of the failure to the
calling function, failure which is not always due to a parsing error
but it may depend for example on a memory problem.
Also fix several potential memleaks.
author | stefano |
---|---|
date | Tue, 01 Jun 2010 08:07:07 +0000 |
parents | c6368258b694 |
children | 5880d90f2b99 |
line wrap: on
line diff
--- a/eval.c Mon May 31 22:01:31 2010 +0000 +++ b/eval.c Tue Jun 01 08:07:07 2010 +0000 @@ -167,7 +167,7 @@ return NAN; } -static AVExpr * parse_expr(Parser *p); +static int parse_expr(AVExpr **e, Parser *p); void ff_free_expr(AVExpr * e) { if (!e) return; @@ -176,20 +176,22 @@ av_freep(&e); } -static AVExpr * parse_primary(Parser *p) { +static int parse_primary(AVExpr **e, Parser *p) +{ AVExpr * d = av_mallocz(sizeof(AVExpr)); char *next= p->s; - int i; + int ret, i; if (!d) - return NULL; + return AVERROR(ENOMEM); /* number */ d->value = av_strtod(p->s, &next); if(next != p->s){ d->type = e_value; p->s= next; - return d; + *e = d; + return 0; } d->value = 1; @@ -199,7 +201,8 @@ p->s+= strlen(p->const_name[i]); d->type = e_const; d->a.const_index = i; - return d; + *e = d; + return 0; } } @@ -208,29 +211,34 @@ av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); p->s= next; ff_free_expr(d); - return NULL; + return AVERROR(EINVAL); } p->s++; // "(" if (*next == '(') { // special case do-nothing av_freep(&d); - d = parse_expr(p); + if ((ret = parse_expr(&d, p)) < 0) + return ret; if(p->s[0] != ')'){ av_log(p, AV_LOG_ERROR, "missing )\n"); ff_free_expr(d); - return NULL; + return AVERROR(EINVAL); } p->s++; // ")" - return d; + *e = d; + return 0; } - d->param[0] = parse_expr(p); + if ((ret = parse_expr(&(d->param[0]), p)) < 0) { + ff_free_expr(d); + return ret; + } if(p->s[0]== ','){ p->s++; // "," - d->param[1] = parse_expr(p); + parse_expr(&d->param[1], p); } if(p->s[0] != ')'){ av_log(p, AV_LOG_ERROR, "missing )\n"); ff_free_expr(d); - return NULL; + return AVERROR(EINVAL); } p->s++; // ")" @@ -265,7 +273,8 @@ if(strmatch(next, p->func1_name[i])){ d->a.func1 = p->func1[i]; d->type = e_func1; - return d; + *e = d; + return 0; } } @@ -273,16 +282,18 @@ if(strmatch(next, p->func2_name[i])){ d->a.func2 = p->func2[i]; d->type = e_func2; - return d; + *e = d; + return 0; } } av_log(p, AV_LOG_ERROR, "unknown function\n"); ff_free_expr(d); - return NULL; + return AVERROR(EINVAL); } - return d; + *e = d; + return 0; } static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){ @@ -296,67 +307,116 @@ return e; } -static AVExpr * parse_pow(Parser *p, int *sign){ +static int parse_pow(AVExpr **e, Parser *p, int *sign) +{ *sign= (*p->s == '+') - (*p->s == '-'); p->s += *sign&1; - return parse_primary(p); + return parse_primary(e, p); } -static AVExpr * parse_factor(Parser *p){ - int sign, sign2; - AVExpr * e = parse_pow(p, &sign); +static int parse_factor(AVExpr **e, Parser *p) +{ + int sign, sign2, ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_pow(&e0, p, &sign)) < 0) + return ret; while(p->s[0]=='^'){ + e1 = e0; p->s++; - e= new_eval_expr(e_pow, 1, e, parse_pow(p, &sign2)); - if (!e) - return NULL; - if (e->param[1]) e->param[1]->value *= (sign2|1); + if ((ret = parse_pow(&e2, p, &sign2)) < 0) { + ff_free_expr(e1); + return ret; + } + e0 = new_eval_expr(e_pow, 1, e1, e2); + if (!e0) { + ff_free_expr(e1); + ff_free_expr(e2); + return AVERROR(ENOMEM); + } + if (e0->param[1]) e0->param[1]->value *= (sign2|1); } - if (e) e->value *= (sign|1); - return e; + if (e0) e0->value *= (sign|1); + + *e = e0; + return 0; } -static AVExpr * parse_term(Parser *p){ - AVExpr * e = parse_factor(p); +static int parse_term(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_factor(&e0, p)) < 0) + return ret; while(p->s[0]=='*' || p->s[0]=='/'){ int c= *p->s++; - e= new_eval_expr(c == '*' ? e_mul : e_div, 1, e, parse_factor(p)); - if (!e) - return NULL; + e1 = e0; + if ((ret = parse_factor(&e2, p)) < 0) { + ff_free_expr(e1); + return ret; + } + e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2); + if (!e0) { + ff_free_expr(e1); + ff_free_expr(e2); + return AVERROR(ENOMEM); + } } - return e; + *e = e0; + return 0; } -static AVExpr * parse_subexpr(Parser *p) { - AVExpr * e = parse_term(p); +static int parse_subexpr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_term(&e0, p)) < 0) + return ret; while(*p->s == '+' || *p->s == '-') { - e= new_eval_expr(e_add, 1, e, parse_term(p)); - if (!e) - return NULL; + e1 = e0; + if ((ret = parse_term(&e2, p)) < 0) { + ff_free_expr(e1); + return ret; + } + e0 = new_eval_expr(e_add, 1, e1, e2); + if (!e0) { + ff_free_expr(e1); + ff_free_expr(e2); + return AVERROR(ENOMEM); + } }; - return e; + *e = e0; + return 0; } -static AVExpr * parse_expr(Parser *p) { - AVExpr * e; - +static int parse_expr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; if(p->stack_index <= 0) //protect against stack overflows - return NULL; + return AVERROR(EINVAL); p->stack_index--; - e = parse_subexpr(p); - + if ((ret = parse_subexpr(&e0, p)) < 0) + return ret; while(*p->s == ';') { + e1 = e0; + if ((ret = parse_subexpr(&e2, p)) < 0) { + ff_free_expr(e1); + return ret; + } p->s++; - e= new_eval_expr(e_last, 1, e, parse_subexpr(p)); - if (!e) - return NULL; + e0 = new_eval_expr(e_last, 1, e1, e2); + if (!e0) { + ff_free_expr(e1); + ff_free_expr(e2); + return AVERROR(ENOMEM); + } }; p->stack_index++; - - return e; + *e = e0; + return 0; } static int verify_expr(AVExpr * e) { @@ -373,7 +433,7 @@ } } -AVExpr *ff_parse_expr(const char *s, +int ff_parse_expr(AVExpr **expr, const char *s, const char * const *const_name, const char * const *func1_name, double (* const *func1)(void *, double), const char * const *func2_name, double (* const *func2)(void *, double, double), @@ -383,9 +443,10 @@ AVExpr *e = NULL; char *w = av_malloc(strlen(s) + 1); char *wp = w; + int ret = 0; if (!w) - goto end; + return AVERROR(ENOMEM); while (*s) if (!isspace(*s++)) *wp++ = s[-1]; @@ -402,14 +463,17 @@ p.log_offset = log_offset; p.log_ctx = log_ctx; - e = parse_expr(&p); + if ((ret = parse_expr(&e, &p)) < 0) + goto end; if (!verify_expr(e)) { ff_free_expr(e); - e = NULL; + ret = AVERROR(EINVAL); + goto end; } + *expr = e; end: av_free(w); - return e; + return ret; } double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) { @@ -420,18 +484,22 @@ return eval_expr(&p, e); } -double ff_parse_and_eval_expr(const char *s, +int ff_parse_and_eval_expr(double *d, const char *s, const char * const *const_name, const double *const_value, const char * const *func1_name, double (* const *func1)(void *, double), const char * const *func2_name, double (* const *func2)(void *, double, double), void *opaque, int log_offset, void *log_ctx) { - AVExpr *e = ff_parse_expr(s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); - double d; - if (!e) return NAN; - d = ff_eval_expr(e, const_value, opaque); + AVExpr *e = NULL; + int ret = ff_parse_expr(&e, s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); + + if (ret < 0) { + *d = NAN; + return ret; + } + *d = ff_eval_expr(e, const_value, opaque); ff_free_expr(e); - return d; + return isnan(*d) ? AVERROR(EINVAL) : 0; } #ifdef TEST @@ -448,12 +516,15 @@ }; int main(void){ int i; - printf("%f == 12.7\n", ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL)); - printf("%f == 0.931322575\n", ff_parse_and_eval_expr("80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL)); + double d; + ff_parse_and_eval_expr(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); + printf("%f == 12.7\n", d); + ff_parse_and_eval_expr(&d, "80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL); + printf("%f == 0.931322575\n", d); for(i=0; i<1050; i++){ START_TIMER - ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); + ff_parse_and_eval_expr(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); STOP_TIMER("ff_parse_and_eval_expr") } return 0;