255 } |
255 } |
256 return 1; |
256 return 1; |
257 } |
257 } |
258 |
258 |
259 // TODO: use scstr_t after update to UCX 2.0 |
259 // TODO: use scstr_t after update to UCX 2.0 |
260 static sstr_t rtrimskip(sstr_t str, size_t skip) { |
260 static size_t rtrimskip(sstr_t str, size_t skip) { |
261 while (skip < str.length && isspace(str.ptr[skip])) skip++; |
261 while (skip < str.length && isspace(str.ptr[skip])) skip++; |
262 return sstrsubs(str, skip); |
262 return skip; |
263 } |
263 } |
264 |
264 |
265 static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) { |
265 static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) { |
266 size_t csvlen; |
266 size_t csvlen; |
267 for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) { |
267 for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) { |
270 fs.length = csvlen; |
270 fs.length = csvlen; |
271 |
271 |
272 tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length); |
272 tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length); |
273 |
273 |
274 return csvlen; |
274 return csvlen; |
|
275 } |
|
276 |
|
277 static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter); |
|
278 |
|
279 static size_t parse_tagfilter_filter(sstr_t fs, SyncTagFilter* tagfilter) { |
|
280 |
|
281 size_t consumed = rtrimskip(fs, 0); |
|
282 fs = sstrsubs(fs, consumed); |
|
283 |
|
284 if (fs.length == 0) { |
|
285 memset(tagfilter, 0, sizeof(SyncTagFilter)); |
|
286 return consumed; |
|
287 } else { |
|
288 |
|
289 // optional operator |
|
290 int hasop = 0; |
|
291 if (fs.ptr[0] == '&') { |
|
292 tagfilter->mode = DAV_SYNC_TAGFILTER_AND; |
|
293 hasop = 1; |
|
294 } else if (fs.ptr[0] == '|') { |
|
295 tagfilter->mode = DAV_SYNC_TAGFILTER_OR; |
|
296 hasop = 1; |
|
297 } else if (fs.ptr[0] == '0') { |
|
298 tagfilter->mode = DAV_SYNC_TAGFILTER_NONE; |
|
299 hasop = 1; |
|
300 } else if (fs.ptr[0] == '1') { |
|
301 tagfilter->mode = DAV_SYNC_TAGFILTER_ONE; |
|
302 hasop = 1; |
|
303 } else { |
|
304 // default operator is AND |
|
305 tagfilter->mode = DAV_SYNC_TAGFILTER_AND; |
|
306 } |
|
307 |
|
308 if (hasop) { |
|
309 size_t skip = rtrimskip(fs, 1); |
|
310 consumed += skip; |
|
311 fs = sstrsubs(fs, skip); |
|
312 } |
|
313 |
|
314 if (fs.length > 0 && fs.ptr[0] == '(') { |
|
315 consumed += parse_tagfilter_subfilters(fs, tagfilter); |
|
316 } else { |
|
317 tagfilter->subfilter_count = 0; |
|
318 tagfilter->subfilters = NULL; |
|
319 consumed += parse_tagfilter_taglist(fs, tagfilter); |
|
320 } |
|
321 |
|
322 return consumed; |
|
323 } |
275 } |
324 } |
276 |
325 |
277 /* |
326 /* |
278 * Parses: ( "(" , filter , ")" )+ |
327 * Parses: ( "(" , filter , ")" )+ |
279 */ |
328 */ |
291 memset(tagfilter, 0, sizeof(SyncTagFilter)); |
340 memset(tagfilter, 0, sizeof(SyncTagFilter)); |
292 return tagfilter; |
341 return tagfilter; |
293 } |
342 } |
294 |
343 |
295 // TODO: use scstr_t after update to UCX 2.0 |
344 // TODO: use scstr_t after update to UCX 2.0 |
296 sstr_t fs = sstrtrim(sstr((char*) filterstring)); |
345 sstr_t fs = sstr((char*) filterstring); |
297 |
346 size_t consumed = parse_tagfilter_filter(fs, tagfilter); |
298 if (fs.length == 0) { |
347 |
299 memset(tagfilter, 0, sizeof(SyncTagFilter)); |
348 // consume trailing white spaces |
300 return tagfilter; |
349 consumed = rtrimskip(fs, consumed); |
301 } else { |
350 |
302 |
351 // sanity check: have we consumed the whole string? |
303 // optional operator |
352 if (consumed != fs.length) { |
304 if (fs.ptr[0] == '&') { |
353 free_tagfilter(tagfilter); |
305 tagfilter->mode = DAV_SYNC_TAGFILTER_AND; |
354 return NULL; |
306 fs = rtrimskip(fs, 1); |
|
307 } else if (fs.ptr[0] == '|') { |
|
308 tagfilter->mode = DAV_SYNC_TAGFILTER_OR; |
|
309 fs = rtrimskip(fs, 1); |
|
310 } else if (fs.ptr[0] == '0') { |
|
311 tagfilter->mode = DAV_SYNC_TAGFILTER_NONE; |
|
312 fs = rtrimskip(fs, 1); |
|
313 } else if (fs.ptr[0] == '1') { |
|
314 tagfilter->mode = DAV_SYNC_TAGFILTER_ONE; |
|
315 fs = rtrimskip(fs, 1); |
|
316 } else { |
|
317 // default operator is AND |
|
318 tagfilter->mode = DAV_SYNC_TAGFILTER_AND; |
|
319 } |
|
320 |
|
321 size_t consumed; |
|
322 if (fs.length > 0 && fs.ptr[0] == '(') { |
|
323 consumed = parse_tagfilter_subfilters(fs, tagfilter); |
|
324 } else { |
|
325 tagfilter->subfilter_count = 0; |
|
326 tagfilter->subfilters = NULL; |
|
327 consumed = parse_tagfilter_taglist(fs, tagfilter); |
|
328 } |
|
329 |
|
330 if (consumed != fs.length) { |
|
331 free(tagfilter->subfilters); |
|
332 free(tagfilter); |
|
333 return NULL; |
|
334 } |
|
335 } |
355 } |
336 |
356 |
337 return tagfilter; |
357 return tagfilter; |
|
358 } |
|
359 |
|
360 void free_tagfilter(SyncTagFilter* filter) { |
|
361 for (size_t i = 0 ; i < filter->subfilter_count ; i++) { |
|
362 free_tagfilter(filter->subfilters[i]); |
|
363 } |
|
364 free(filter->subfilters); |
|
365 free(filter); |
338 } |
366 } |
339 |
367 |
340 static int matches_tags_and(UcxList *dav_tags, UcxList *tags, int ignorecase) { |
368 static int matches_tags_and(UcxList *dav_tags, UcxList *tags, int ignorecase) { |
341 UCX_FOREACH(e, tags) { |
369 UCX_FOREACH(e, tags) { |
342 if (!ucx_list_contains(dav_tags, e->data, |
370 if (!ucx_list_contains(dav_tags, e->data, |
385 static int matches_tags(UcxList *dav_tags, SyncTagFilter *tagfilter) { |
413 static int matches_tags(UcxList *dav_tags, SyncTagFilter *tagfilter) { |
386 |
414 |
387 if (tagfilter->subfilter_count > 0) { |
415 if (tagfilter->subfilter_count > 0) { |
388 int ret = 1; |
416 int ret = 1; |
389 for (size_t i = 0 ; i < tagfilter->subfilter_count ; i++) { |
417 for (size_t i = 0 ; i < tagfilter->subfilter_count ; i++) { |
390 ret &= matches_tags(dav_tags, &(tagfilter->subfilters[i])); |
418 ret &= matches_tags(dav_tags, tagfilter->subfilters[i]); |
391 } |
419 } |
392 return ret; |
420 return ret; |
393 } else { |
421 } else { |
394 int ignorecase = 0; // TODO: maybe add support later |
422 int ignorecase = 0; // TODO: maybe add support later |
395 switch (tagfilter->mode) { |
423 switch (tagfilter->mode) { |
487 SyncTagFilter* tagfilter = parse_tagfilter_string(cmd_getoption(a, "tags")); |
515 SyncTagFilter* tagfilter = parse_tagfilter_string(cmd_getoption(a, "tags")); |
488 if (!tagfilter) { |
516 if (!tagfilter) { |
489 fprintf(stderr, "Malformed tag filter\n"); |
517 fprintf(stderr, "Malformed tag filter\n"); |
490 return -1; |
518 return -1; |
491 } |
519 } |
|
520 // TODO: tons of memory leaks... |
|
521 // call free_tagfilter() before each return |
492 |
522 |
493 SyncDirectory *dir = scfg_get_dir(a->argv[0]); |
523 SyncDirectory *dir = scfg_get_dir(a->argv[0]); |
494 if(!dir) { |
524 if(!dir) { |
495 fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]); |
525 fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]); |
496 return -1; |
526 return -1; |