359 #endif |
359 #endif |
360 |
360 |
361 |
361 |
362 /* ----------- ----------- tag filter ---------------------- */ |
362 /* ----------- ----------- tag filter ---------------------- */ |
363 |
363 |
364 // TODO: use scstr_t after update to UCX 2.0 |
364 static size_t rtrimskip(scstr_t str, size_t skip) { |
365 static size_t rtrimskip(sstr_t str, size_t skip) { |
|
366 while (skip < str.length && isspace(str.ptr[skip])) skip++; |
365 while (skip < str.length && isspace(str.ptr[skip])) skip++; |
367 return skip; |
366 return skip; |
368 } |
367 } |
369 |
368 |
370 static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) { |
369 static size_t parse_tagfilter_taglist(scstr_t fs, SyncTagFilter* tagfilter) { |
371 size_t csvlen; |
370 size_t csvlen; |
372 for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) { |
371 for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) { |
373 if (fs.ptr[csvlen] == ')') break; |
372 if (fs.ptr[csvlen] == ')') break; |
374 } |
373 } |
375 fs.length = csvlen; |
374 fs.length = csvlen; |
377 tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length); |
376 tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length); |
378 |
377 |
379 return csvlen; |
378 return csvlen; |
380 } |
379 } |
381 |
380 |
382 static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter); |
381 static size_t parse_tagfilter_subfilters(scstr_t fs, SyncTagFilter* tagfilter); |
383 |
382 |
384 static size_t parse_tagfilter_filter(sstr_t fs, SyncTagFilter* tagfilter) { |
383 static size_t parse_tagfilter_filter(scstr_t fs, SyncTagFilter* tagfilter) { |
385 |
384 |
386 size_t consumed = rtrimskip(fs, 0); |
385 size_t consumed = rtrimskip(fs, 0); |
387 fs = sstrsubs(fs, consumed); |
386 fs = scstrsubs(fs, consumed); |
388 |
387 |
389 if (fs.length == 0) { |
388 if (fs.length == 0) { |
390 return consumed; |
389 return consumed; |
391 } else { |
390 } else { |
392 |
391 |
410 } |
409 } |
411 |
410 |
412 if (hasop) { |
411 if (hasop) { |
413 size_t skip = rtrimskip(fs, 1); |
412 size_t skip = rtrimskip(fs, 1); |
414 consumed += skip; |
413 consumed += skip; |
415 fs = sstrsubs(fs, skip); |
414 fs = scstrsubs(fs, skip); |
416 } |
415 } |
417 |
416 |
418 if (fs.length > 0 && fs.ptr[0] == '(') { |
417 if (fs.length > 0 && fs.ptr[0] == '(') { |
419 size_t c = parse_tagfilter_subfilters(fs, tagfilter); |
418 size_t c = parse_tagfilter_subfilters(fs, tagfilter); |
420 if (c) { |
419 if (c) { |
431 } |
430 } |
432 |
431 |
433 /* |
432 /* |
434 * Parses: ( "(" , filter , ")" )+ |
433 * Parses: ( "(" , filter , ")" )+ |
435 */ |
434 */ |
436 static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* f) { |
435 static size_t parse_tagfilter_subfilters(scstr_t fs, SyncTagFilter* f) { |
437 |
436 |
438 // strategy: allocate much and give back later (instead of reallocs in loop) |
437 // strategy: allocate much and give back later (instead of reallocs in loop) |
439 size_t subfilter_cap = 8; |
438 size_t subfilter_cap = 8; |
440 f->subfilters = calloc(subfilter_cap, sizeof(SyncTagFilter*)); |
439 f->subfilters = calloc(subfilter_cap, sizeof(SyncTagFilter*)); |
441 f->subfilter_count = 0; |
440 f->subfilter_count = 0; |
443 size_t total_consumed = 0; |
442 size_t total_consumed = 0; |
444 size_t c; |
443 size_t c; |
445 do { |
444 do { |
446 // skip leading parenthesis (and white spaces) |
445 // skip leading parenthesis (and white spaces) |
447 c = rtrimskip(fs, 1); |
446 c = rtrimskip(fs, 1); |
448 fs = sstrsubs(fs, c); |
447 fs = scstrsubs(fs, c); |
449 total_consumed += c; |
448 total_consumed += c; |
450 |
449 |
451 // increase array capacity, if necessary |
450 // increase array capacity, if necessary |
452 if (f->subfilter_count >= subfilter_cap) { |
451 if (f->subfilter_count >= subfilter_cap) { |
453 subfilter_cap *= 2; |
452 subfilter_cap *= 2; |
470 if (c > 0 && fs.ptr[c] == ')') { |
469 if (c > 0 && fs.ptr[c] == ')') { |
471 f->subfilters[f->subfilter_count++] = subf; |
470 f->subfilters[f->subfilter_count++] = subf; |
472 |
471 |
473 // consume ')' and find the next parenthesis or the end-of-string |
472 // consume ')' and find the next parenthesis or the end-of-string |
474 c = rtrimskip(fs, 1+c); |
473 c = rtrimskip(fs, 1+c); |
475 fs = sstrsubs(fs, c); |
474 fs = scstrsubs(fs, c); |
476 total_consumed += c; |
475 total_consumed += c; |
477 |
476 |
478 if (fs.length == 0 || fs.ptr[0] == ')') { |
477 if (fs.length == 0 || fs.ptr[0] == ')') { |
479 // our job is done |
478 // our job is done |
480 break; |
479 break; |
509 tagfilter->scope = scope; |
508 tagfilter->scope = scope; |
510 if (!filterstring) { |
509 if (!filterstring) { |
511 return tagfilter; |
510 return tagfilter; |
512 } |
511 } |
513 |
512 |
514 // TODO: use scstr_t after update to UCX 2.0 |
513 scstr_t fs = scstr(filterstring); |
515 sstr_t fs = sstr((char*) filterstring); |
|
516 size_t consumed = parse_tagfilter_filter(fs, tagfilter); |
514 size_t consumed = parse_tagfilter_filter(fs, tagfilter); |
517 if (!consumed) { |
515 if (!consumed) { |
518 free_tagfilter(tagfilter); |
516 free_tagfilter(tagfilter); |
519 return NULL; |
517 return NULL; |
520 } |
518 } |