b2/db.c |
296 | 296 | } |
297 | 297 | |
298 | 298 | |
| 299 | /* ----- Part search (by characteristics) ---------------------------------- */ |
299 | 300 | |
| 301 | |
| 302 | struct sel_prm_data { |
| 303 | struct param *param; |
| 304 | const struct part **res; |
| 305 | int n_res; |
| 306 | }; |
| 307 | |
| 308 | |
| 309 | static struct param *convert_vars(struct param *vars, const struct action *act) |
| 310 | { |
| 311 | struct param *res = NULL, **last = &res; |
| 312 | |
| 313 | convert_params(&vars, act->fields, &last); |
| 314 | convert_params(&vars, act->rules, &last); |
| 315 | free_vars(vars); |
| 316 | return res; |
| 317 | } |
| 318 | |
| 319 | |
| 320 | /* |
| 321 | * @@@ By matching fields (and not field names), we avoid having to check for |
| 322 | * field compatibility. However, this also means that only fields that appear |
| 323 | * in the same place in the hierarchy can be matched. |
| 324 | * |
| 325 | * For example, a tolerance TOL in T=R could thus never match the tolerance TOL |
| 326 | * in T=C. This seems reasonable, but may need some more pondering. |
| 327 | */ |
| 328 | |
| 329 | /* |
| 330 | * @@@ We require all fields specified in the query to exist (and to match). |
| 331 | * Could there be cases where this doesn't make sense ? |
| 332 | */ |
| 333 | |
| 334 | static int params_match(const struct param *query, const struct param *part) |
| 335 | { |
| 336 | const struct param *q, *p; |
| 337 | |
| 338 | for (q = query; q; q = q->next) { |
| 339 | for (p = part; p; p = p->next) { |
| 340 | if (q->u.field != p->u.field) |
| 341 | continue; |
| 342 | if (compare(q->u.field->fmt, &p->value, q->op, |
| 343 | &q->value)) |
| 344 | goto next; |
| 345 | return 0; |
| 346 | } |
| 347 | return 0; |
| 348 | next: ; |
| 349 | } |
| 350 | return 1; |
| 351 | } |
| 352 | |
| 353 | |
| 354 | static gboolean sel_prm_traverse(gpointer key, gpointer value, gpointer data) |
| 355 | { |
| 356 | struct part *p = key; |
| 357 | struct sel_prm_data *d = data; |
| 358 | |
| 359 | if (!params_match(d->param, p->param)) |
| 360 | return FALSE; |
| 361 | d->res = realloc(d->res, sizeof(const struct part *)*(d->n_res+1)); |
| 362 | if (!d->res) |
| 363 | abort(); |
| 364 | d->res[d->n_res++] = key; |
| 365 | return FALSE; |
| 366 | } |
| 367 | |
| 368 | |
| 369 | const struct part **select_parametric(struct param *vars, |
| 370 | const struct action *act) |
| 371 | { |
| 372 | struct sel_prm_data data = { |
| 373 | .param = convert_vars(vars, act), |
| 374 | .res = NULL, |
| 375 | .n_res = 0, |
| 376 | }; |
| 377 | |
| 378 | g_tree_foreach(tree, sel_prm_traverse, (void *) &data); |
| 379 | if (data.n_res) |
| 380 | data.res[data.n_res] = NULL; |
| 381 | return data.res; |
| 382 | } |