Mercurial > libavcodec.hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
11800:966aa6b53dcf | 11801:026edf66e3a9 |
---|---|
165 } | 165 } |
166 } | 166 } |
167 return NAN; | 167 return NAN; |
168 } | 168 } |
169 | 169 |
170 static AVExpr * parse_expr(Parser *p); | 170 static int parse_expr(AVExpr **e, Parser *p); |
171 | 171 |
172 void ff_free_expr(AVExpr * e) { | 172 void ff_free_expr(AVExpr * e) { |
173 if (!e) return; | 173 if (!e) return; |
174 ff_free_expr(e->param[0]); | 174 ff_free_expr(e->param[0]); |
175 ff_free_expr(e->param[1]); | 175 ff_free_expr(e->param[1]); |
176 av_freep(&e); | 176 av_freep(&e); |
177 } | 177 } |
178 | 178 |
179 static AVExpr * parse_primary(Parser *p) { | 179 static int parse_primary(AVExpr **e, Parser *p) |
180 { | |
180 AVExpr * d = av_mallocz(sizeof(AVExpr)); | 181 AVExpr * d = av_mallocz(sizeof(AVExpr)); |
181 char *next= p->s; | 182 char *next= p->s; |
182 int i; | 183 int ret, i; |
183 | 184 |
184 if (!d) | 185 if (!d) |
185 return NULL; | 186 return AVERROR(ENOMEM); |
186 | 187 |
187 /* number */ | 188 /* number */ |
188 d->value = av_strtod(p->s, &next); | 189 d->value = av_strtod(p->s, &next); |
189 if(next != p->s){ | 190 if(next != p->s){ |
190 d->type = e_value; | 191 d->type = e_value; |
191 p->s= next; | 192 p->s= next; |
192 return d; | 193 *e = d; |
194 return 0; | |
193 } | 195 } |
194 d->value = 1; | 196 d->value = 1; |
195 | 197 |
196 /* named constants */ | 198 /* named constants */ |
197 for(i=0; p->const_name && p->const_name[i]; i++){ | 199 for(i=0; p->const_name && p->const_name[i]; i++){ |
198 if(strmatch(p->s, p->const_name[i])){ | 200 if(strmatch(p->s, p->const_name[i])){ |
199 p->s+= strlen(p->const_name[i]); | 201 p->s+= strlen(p->const_name[i]); |
200 d->type = e_const; | 202 d->type = e_const; |
201 d->a.const_index = i; | 203 d->a.const_index = i; |
202 return d; | 204 *e = d; |
205 return 0; | |
203 } | 206 } |
204 } | 207 } |
205 | 208 |
206 p->s= strchr(p->s, '('); | 209 p->s= strchr(p->s, '('); |
207 if(p->s==NULL){ | 210 if(p->s==NULL){ |
208 av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); | 211 av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); |
209 p->s= next; | 212 p->s= next; |
210 ff_free_expr(d); | 213 ff_free_expr(d); |
211 return NULL; | 214 return AVERROR(EINVAL); |
212 } | 215 } |
213 p->s++; // "(" | 216 p->s++; // "(" |
214 if (*next == '(') { // special case do-nothing | 217 if (*next == '(') { // special case do-nothing |
215 av_freep(&d); | 218 av_freep(&d); |
216 d = parse_expr(p); | 219 if ((ret = parse_expr(&d, p)) < 0) |
220 return ret; | |
217 if(p->s[0] != ')'){ | 221 if(p->s[0] != ')'){ |
218 av_log(p, AV_LOG_ERROR, "missing )\n"); | 222 av_log(p, AV_LOG_ERROR, "missing )\n"); |
219 ff_free_expr(d); | 223 ff_free_expr(d); |
220 return NULL; | 224 return AVERROR(EINVAL); |
221 } | 225 } |
222 p->s++; // ")" | 226 p->s++; // ")" |
223 return d; | 227 *e = d; |
224 } | 228 return 0; |
225 d->param[0] = parse_expr(p); | 229 } |
230 if ((ret = parse_expr(&(d->param[0]), p)) < 0) { | |
231 ff_free_expr(d); | |
232 return ret; | |
233 } | |
226 if(p->s[0]== ','){ | 234 if(p->s[0]== ','){ |
227 p->s++; // "," | 235 p->s++; // "," |
228 d->param[1] = parse_expr(p); | 236 parse_expr(&d->param[1], p); |
229 } | 237 } |
230 if(p->s[0] != ')'){ | 238 if(p->s[0] != ')'){ |
231 av_log(p, AV_LOG_ERROR, "missing )\n"); | 239 av_log(p, AV_LOG_ERROR, "missing )\n"); |
232 ff_free_expr(d); | 240 ff_free_expr(d); |
233 return NULL; | 241 return AVERROR(EINVAL); |
234 } | 242 } |
235 p->s++; // ")" | 243 p->s++; // ")" |
236 | 244 |
237 d->type = e_func0; | 245 d->type = e_func0; |
238 if( strmatch(next, "sinh" ) ) d->a.func0 = sinh; | 246 if( strmatch(next, "sinh" ) ) d->a.func0 = sinh; |
263 else { | 271 else { |
264 for(i=0; p->func1_name && p->func1_name[i]; i++){ | 272 for(i=0; p->func1_name && p->func1_name[i]; i++){ |
265 if(strmatch(next, p->func1_name[i])){ | 273 if(strmatch(next, p->func1_name[i])){ |
266 d->a.func1 = p->func1[i]; | 274 d->a.func1 = p->func1[i]; |
267 d->type = e_func1; | 275 d->type = e_func1; |
268 return d; | 276 *e = d; |
277 return 0; | |
269 } | 278 } |
270 } | 279 } |
271 | 280 |
272 for(i=0; p->func2_name && p->func2_name[i]; i++){ | 281 for(i=0; p->func2_name && p->func2_name[i]; i++){ |
273 if(strmatch(next, p->func2_name[i])){ | 282 if(strmatch(next, p->func2_name[i])){ |
274 d->a.func2 = p->func2[i]; | 283 d->a.func2 = p->func2[i]; |
275 d->type = e_func2; | 284 d->type = e_func2; |
276 return d; | 285 *e = d; |
286 return 0; | |
277 } | 287 } |
278 } | 288 } |
279 | 289 |
280 av_log(p, AV_LOG_ERROR, "unknown function\n"); | 290 av_log(p, AV_LOG_ERROR, "unknown function\n"); |
281 ff_free_expr(d); | 291 ff_free_expr(d); |
282 return NULL; | 292 return AVERROR(EINVAL); |
283 } | 293 } |
284 | 294 |
285 return d; | 295 *e = d; |
296 return 0; | |
286 } | 297 } |
287 | 298 |
288 static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){ | 299 static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){ |
289 AVExpr * e = av_mallocz(sizeof(AVExpr)); | 300 AVExpr * e = av_mallocz(sizeof(AVExpr)); |
290 if (!e) | 301 if (!e) |
294 e->param[0] =p0 ; | 305 e->param[0] =p0 ; |
295 e->param[1] =p1 ; | 306 e->param[1] =p1 ; |
296 return e; | 307 return e; |
297 } | 308 } |
298 | 309 |
299 static AVExpr * parse_pow(Parser *p, int *sign){ | 310 static int parse_pow(AVExpr **e, Parser *p, int *sign) |
311 { | |
300 *sign= (*p->s == '+') - (*p->s == '-'); | 312 *sign= (*p->s == '+') - (*p->s == '-'); |
301 p->s += *sign&1; | 313 p->s += *sign&1; |
302 return parse_primary(p); | 314 return parse_primary(e, p); |
303 } | 315 } |
304 | 316 |
305 static AVExpr * parse_factor(Parser *p){ | 317 static int parse_factor(AVExpr **e, Parser *p) |
306 int sign, sign2; | 318 { |
307 AVExpr * e = parse_pow(p, &sign); | 319 int sign, sign2, ret; |
320 AVExpr *e0, *e1, *e2; | |
321 if ((ret = parse_pow(&e0, p, &sign)) < 0) | |
322 return ret; | |
308 while(p->s[0]=='^'){ | 323 while(p->s[0]=='^'){ |
324 e1 = e0; | |
309 p->s++; | 325 p->s++; |
310 e= new_eval_expr(e_pow, 1, e, parse_pow(p, &sign2)); | 326 if ((ret = parse_pow(&e2, p, &sign2)) < 0) { |
311 if (!e) | 327 ff_free_expr(e1); |
312 return NULL; | 328 return ret; |
313 if (e->param[1]) e->param[1]->value *= (sign2|1); | 329 } |
314 } | 330 e0 = new_eval_expr(e_pow, 1, e1, e2); |
315 if (e) e->value *= (sign|1); | 331 if (!e0) { |
316 return e; | 332 ff_free_expr(e1); |
317 } | 333 ff_free_expr(e2); |
318 | 334 return AVERROR(ENOMEM); |
319 static AVExpr * parse_term(Parser *p){ | 335 } |
320 AVExpr * e = parse_factor(p); | 336 if (e0->param[1]) e0->param[1]->value *= (sign2|1); |
337 } | |
338 if (e0) e0->value *= (sign|1); | |
339 | |
340 *e = e0; | |
341 return 0; | |
342 } | |
343 | |
344 static int parse_term(AVExpr **e, Parser *p) | |
345 { | |
346 int ret; | |
347 AVExpr *e0, *e1, *e2; | |
348 if ((ret = parse_factor(&e0, p)) < 0) | |
349 return ret; | |
321 while(p->s[0]=='*' || p->s[0]=='/'){ | 350 while(p->s[0]=='*' || p->s[0]=='/'){ |
322 int c= *p->s++; | 351 int c= *p->s++; |
323 e= new_eval_expr(c == '*' ? e_mul : e_div, 1, e, parse_factor(p)); | 352 e1 = e0; |
324 if (!e) | 353 if ((ret = parse_factor(&e2, p)) < 0) { |
325 return NULL; | 354 ff_free_expr(e1); |
326 } | 355 return ret; |
327 return e; | 356 } |
328 } | 357 e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2); |
329 | 358 if (!e0) { |
330 static AVExpr * parse_subexpr(Parser *p) { | 359 ff_free_expr(e1); |
331 AVExpr * e = parse_term(p); | 360 ff_free_expr(e2); |
361 return AVERROR(ENOMEM); | |
362 } | |
363 } | |
364 *e = e0; | |
365 return 0; | |
366 } | |
367 | |
368 static int parse_subexpr(AVExpr **e, Parser *p) | |
369 { | |
370 int ret; | |
371 AVExpr *e0, *e1, *e2; | |
372 if ((ret = parse_term(&e0, p)) < 0) | |
373 return ret; | |
332 while(*p->s == '+' || *p->s == '-') { | 374 while(*p->s == '+' || *p->s == '-') { |
333 e= new_eval_expr(e_add, 1, e, parse_term(p)); | 375 e1 = e0; |
334 if (!e) | 376 if ((ret = parse_term(&e2, p)) < 0) { |
335 return NULL; | 377 ff_free_expr(e1); |
378 return ret; | |
379 } | |
380 e0 = new_eval_expr(e_add, 1, e1, e2); | |
381 if (!e0) { | |
382 ff_free_expr(e1); | |
383 ff_free_expr(e2); | |
384 return AVERROR(ENOMEM); | |
385 } | |
336 }; | 386 }; |
337 | 387 |
338 return e; | 388 *e = e0; |
339 } | 389 return 0; |
340 | 390 } |
341 static AVExpr * parse_expr(Parser *p) { | 391 |
342 AVExpr * e; | 392 static int parse_expr(AVExpr **e, Parser *p) |
343 | 393 { |
394 int ret; | |
395 AVExpr *e0, *e1, *e2; | |
344 if(p->stack_index <= 0) //protect against stack overflows | 396 if(p->stack_index <= 0) //protect against stack overflows |
345 return NULL; | 397 return AVERROR(EINVAL); |
346 p->stack_index--; | 398 p->stack_index--; |
347 | 399 |
348 e = parse_subexpr(p); | 400 if ((ret = parse_subexpr(&e0, p)) < 0) |
349 | 401 return ret; |
350 while(*p->s == ';') { | 402 while(*p->s == ';') { |
403 e1 = e0; | |
404 if ((ret = parse_subexpr(&e2, p)) < 0) { | |
405 ff_free_expr(e1); | |
406 return ret; | |
407 } | |
351 p->s++; | 408 p->s++; |
352 e= new_eval_expr(e_last, 1, e, parse_subexpr(p)); | 409 e0 = new_eval_expr(e_last, 1, e1, e2); |
353 if (!e) | 410 if (!e0) { |
354 return NULL; | 411 ff_free_expr(e1); |
412 ff_free_expr(e2); | |
413 return AVERROR(ENOMEM); | |
414 } | |
355 }; | 415 }; |
356 | 416 |
357 p->stack_index++; | 417 p->stack_index++; |
358 | 418 *e = e0; |
359 return e; | 419 return 0; |
360 } | 420 } |
361 | 421 |
362 static int verify_expr(AVExpr * e) { | 422 static int verify_expr(AVExpr * e) { |
363 if (!e) return 0; | 423 if (!e) return 0; |
364 switch (e->type) { | 424 switch (e->type) { |
371 case e_gauss: return verify_expr(e->param[0]); | 431 case e_gauss: return verify_expr(e->param[0]); |
372 default: return verify_expr(e->param[0]) && verify_expr(e->param[1]); | 432 default: return verify_expr(e->param[0]) && verify_expr(e->param[1]); |
373 } | 433 } |
374 } | 434 } |
375 | 435 |
376 AVExpr *ff_parse_expr(const char *s, | 436 int ff_parse_expr(AVExpr **expr, const char *s, |
377 const char * const *const_name, | 437 const char * const *const_name, |
378 const char * const *func1_name, double (* const *func1)(void *, double), | 438 const char * const *func1_name, double (* const *func1)(void *, double), |
379 const char * const *func2_name, double (* const *func2)(void *, double, double), | 439 const char * const *func2_name, double (* const *func2)(void *, double, double), |
380 int log_offset, void *log_ctx) | 440 int log_offset, void *log_ctx) |
381 { | 441 { |
382 Parser p; | 442 Parser p; |
383 AVExpr *e = NULL; | 443 AVExpr *e = NULL; |
384 char *w = av_malloc(strlen(s) + 1); | 444 char *w = av_malloc(strlen(s) + 1); |
385 char *wp = w; | 445 char *wp = w; |
446 int ret = 0; | |
386 | 447 |
387 if (!w) | 448 if (!w) |
388 goto end; | 449 return AVERROR(ENOMEM); |
389 | 450 |
390 while (*s) | 451 while (*s) |
391 if (!isspace(*s++)) *wp++ = s[-1]; | 452 if (!isspace(*s++)) *wp++ = s[-1]; |
392 *wp++ = 0; | 453 *wp++ = 0; |
393 | 454 |
400 p.func2 = func2; | 461 p.func2 = func2; |
401 p.func2_name = func2_name; | 462 p.func2_name = func2_name; |
402 p.log_offset = log_offset; | 463 p.log_offset = log_offset; |
403 p.log_ctx = log_ctx; | 464 p.log_ctx = log_ctx; |
404 | 465 |
405 e = parse_expr(&p); | 466 if ((ret = parse_expr(&e, &p)) < 0) |
467 goto end; | |
406 if (!verify_expr(e)) { | 468 if (!verify_expr(e)) { |
407 ff_free_expr(e); | 469 ff_free_expr(e); |
408 e = NULL; | 470 ret = AVERROR(EINVAL); |
409 } | 471 goto end; |
472 } | |
473 *expr = e; | |
410 end: | 474 end: |
411 av_free(w); | 475 av_free(w); |
412 return e; | 476 return ret; |
413 } | 477 } |
414 | 478 |
415 double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) { | 479 double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) { |
416 Parser p; | 480 Parser p; |
417 | 481 |
418 p.const_value= const_value; | 482 p.const_value= const_value; |
419 p.opaque = opaque; | 483 p.opaque = opaque; |
420 return eval_expr(&p, e); | 484 return eval_expr(&p, e); |
421 } | 485 } |
422 | 486 |
423 double ff_parse_and_eval_expr(const char *s, | 487 int ff_parse_and_eval_expr(double *d, const char *s, |
424 const char * const *const_name, const double *const_value, | 488 const char * const *const_name, const double *const_value, |
425 const char * const *func1_name, double (* const *func1)(void *, double), | 489 const char * const *func1_name, double (* const *func1)(void *, double), |
426 const char * const *func2_name, double (* const *func2)(void *, double, double), | 490 const char * const *func2_name, double (* const *func2)(void *, double, double), |
427 void *opaque, int log_offset, void *log_ctx) | 491 void *opaque, int log_offset, void *log_ctx) |
428 { | 492 { |
429 AVExpr *e = ff_parse_expr(s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); | 493 AVExpr *e = NULL; |
430 double d; | 494 int ret = ff_parse_expr(&e, s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); |
431 if (!e) return NAN; | 495 |
432 d = ff_eval_expr(e, const_value, opaque); | 496 if (ret < 0) { |
497 *d = NAN; | |
498 return ret; | |
499 } | |
500 *d = ff_eval_expr(e, const_value, opaque); | |
433 ff_free_expr(e); | 501 ff_free_expr(e); |
434 return d; | 502 return isnan(*d) ? AVERROR(EINVAL) : 0; |
435 } | 503 } |
436 | 504 |
437 #ifdef TEST | 505 #ifdef TEST |
438 #undef printf | 506 #undef printf |
439 static double const_values[]={ | 507 static double const_values[]={ |
446 "E", | 514 "E", |
447 0 | 515 0 |
448 }; | 516 }; |
449 int main(void){ | 517 int main(void){ |
450 int i; | 518 int i; |
451 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)); | 519 double d; |
452 printf("%f == 0.931322575\n", ff_parse_and_eval_expr("80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL)); | 520 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); |
521 printf("%f == 12.7\n", d); | |
522 ff_parse_and_eval_expr(&d, "80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL); | |
523 printf("%f == 0.931322575\n", d); | |
453 | 524 |
454 for(i=0; i<1050; i++){ | 525 for(i=0; i<1050; i++){ |
455 START_TIMER | 526 START_TIMER |
456 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); | 527 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); |
457 STOP_TIMER("ff_parse_and_eval_expr") | 528 STOP_TIMER("ff_parse_and_eval_expr") |
458 } | 529 } |
459 return 0; | 530 return 0; |
460 } | 531 } |
461 #endif | 532 #endif |