310 consumed += skip; |
309 consumed += skip; |
311 fs = sstrsubs(fs, skip); |
310 fs = sstrsubs(fs, skip); |
312 } |
311 } |
313 |
312 |
314 if (fs.length > 0 && fs.ptr[0] == '(') { |
313 if (fs.length > 0 && fs.ptr[0] == '(') { |
315 consumed += parse_tagfilter_subfilters(fs, tagfilter); |
314 size_t c = parse_tagfilter_subfilters(fs, tagfilter); |
|
315 if (c) { |
|
316 return consumed + c; |
|
317 } else { |
|
318 return 0; |
|
319 } |
316 } else { |
320 } else { |
317 tagfilter->subfilter_count = 0; |
321 tagfilter->subfilter_count = 0; |
318 tagfilter->subfilters = NULL; |
322 tagfilter->subfilters = NULL; |
319 consumed += parse_tagfilter_taglist(fs, tagfilter); |
323 return consumed + parse_tagfilter_taglist(fs, tagfilter); |
320 } |
324 } |
321 |
|
322 return consumed; |
|
323 } |
325 } |
324 } |
326 } |
325 |
327 |
326 /* |
328 /* |
327 * Parses: ( "(" , filter , ")" )+ |
329 * Parses: ( "(" , filter , ")" )+ |
328 */ |
330 */ |
329 static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter) { |
331 static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* f) { |
330 // TODO: implement |
332 |
331 tagfilter->subfilter_count = 0; |
333 // strategy: allocate much and give back later (instead of reallocs in loop) |
332 tagfilter->subfilters = NULL; |
334 size_t subfilter_cap = 8; |
333 |
335 f->subfilters = calloc(subfilter_cap, sizeof(SyncTagFilter*)); |
334 return 0; |
336 f->subfilter_count = 0; |
|
337 |
|
338 size_t total_consumed = 0; |
|
339 size_t c; |
|
340 do { |
|
341 // skip leading parenthesis (and white spaces) |
|
342 c = rtrimskip(fs, 1); |
|
343 fs = sstrsubs(fs, c); |
|
344 total_consumed += c; |
|
345 |
|
346 // increase array capacity, if necessary |
|
347 if (f->subfilter_count >= subfilter_cap) { |
|
348 subfilter_cap *= 2; |
|
349 SyncTagFilter** newarr = realloc(f->subfilters, |
|
350 subfilter_cap * sizeof(SyncTagFilter*)); |
|
351 if (newarr) { |
|
352 f->subfilters = newarr; |
|
353 } else { |
|
354 abort(); // no error handling reachable, so we are fucked |
|
355 } |
|
356 } |
|
357 |
|
358 // allocate space for a new filter |
|
359 SyncTagFilter* subf = calloc(1, sizeof(SyncTagFilter)); |
|
360 |
|
361 // parse that filter |
|
362 c = parse_tagfilter_filter(fs, subf); |
|
363 |
|
364 // sanity check: we must end with a closing parenthesis |
|
365 if (c > 0 && fs.ptr[c] == ')') { |
|
366 f->subfilters[f->subfilter_count++] = subf; |
|
367 |
|
368 // consume ')' and find the next parenthesis or the end-of-string |
|
369 c = rtrimskip(fs, 1+c); |
|
370 fs = sstrsubs(fs, c); |
|
371 total_consumed += c; |
|
372 |
|
373 if (fs.length == 0 || fs.ptr[0] == ')') { |
|
374 // our job is done |
|
375 break; |
|
376 } else if (fs.ptr[0] != '(') { |
|
377 // anything else than a parenthesis or end-of-string is an error |
|
378 return 0; |
|
379 } |
|
380 } else { |
|
381 free(subf); |
|
382 break; |
|
383 } |
|
384 |
|
385 } while(1); |
|
386 |
|
387 // try to shrink the array |
|
388 if (f->subfilter_count > 0) { |
|
389 SyncTagFilter** shrinked_array = realloc(f->subfilters, |
|
390 f->subfilter_count * sizeof(SyncTagFilter*)); |
|
391 if (shrinked_array) { |
|
392 f->subfilters = shrinked_array; |
|
393 } |
|
394 } else { |
|
395 free(f->subfilters); |
|
396 f->subfilters = NULL; |
|
397 } |
|
398 |
|
399 return total_consumed; |
335 } |
400 } |
336 |
401 |
337 SyncTagFilter* parse_tagfilter_string(const char* filterstring) { |
402 SyncTagFilter* parse_tagfilter_string(const char* filterstring) { |
338 SyncTagFilter* tagfilter = malloc(sizeof(SyncTagFilter)); |
403 SyncTagFilter* tagfilter = calloc(1, sizeof(SyncTagFilter)); |
339 if (!filterstring) { |
404 if (!filterstring) { |
340 memset(tagfilter, 0, sizeof(SyncTagFilter)); |
|
341 return tagfilter; |
405 return tagfilter; |
342 } |
406 } |
343 |
407 |
344 // TODO: use scstr_t after update to UCX 2.0 |
408 // TODO: use scstr_t after update to UCX 2.0 |
345 sstr_t fs = sstr((char*) filterstring); |
409 sstr_t fs = sstr((char*) filterstring); |
346 size_t consumed = parse_tagfilter_filter(fs, tagfilter); |
410 size_t consumed = parse_tagfilter_filter(fs, tagfilter); |
|
411 if (!consumed) { |
|
412 free_tagfilter(tagfilter); |
|
413 return NULL; |
|
414 } |
347 |
415 |
348 // consume trailing white spaces |
416 // consume trailing white spaces |
349 consumed = rtrimskip(fs, consumed); |
417 consumed = rtrimskip(fs, consumed); |
350 |
418 |
351 // sanity check: have we consumed the whole string? |
419 // sanity check: have we consumed the whole string? |