417 lp, prev.ptr, |
417 lp, prev.ptr, |
418 sfmtarg(tokenstr), |
418 sfmtarg(tokenstr), |
419 ln, pn).ptr; |
419 ln, pn).ptr; |
420 } |
420 } |
421 |
421 |
422 // TODO: this macro results in a memory leak - we return without freeing memory |
|
423 #define dqlsec_alloc_failed(ptr, stmt) \ |
422 #define dqlsec_alloc_failed(ptr, stmt) \ |
424 if (!(ptr)) { \ |
423 if (!(ptr)) do { \ |
425 (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \ |
424 (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \ |
426 return 0; \ |
425 return 0; \ |
427 } |
426 } while(0) |
428 #define dqlsec_malloc(stmt, ptr, type) ptr = malloc(sizeof(type)); \ |
427 #define dqlsec_malloc(stmt, ptr, type) \ |
429 dqlsec_alloc_failed(ptr, stmt); |
428 dqlsec_alloc_failed(ptr = malloc(sizeof(type)), stmt) |
430 #define dqlsec_mallocz(stmt, ptr, type) ptr = calloc(1, sizeof(type)); \ |
429 #define dqlsec_mallocz(stmt, ptr, type) \ |
431 dqlsec_alloc_failed(ptr, stmt); |
430 dqlsec_alloc_failed(ptr = calloc(1, sizeof(type)), stmt) |
432 |
431 |
433 #define dqlsec_list_append(stmt, list, data) \ |
432 #define dqlsec_list_append_or_free(stmt, list, data) \ |
434 { \ |
433 do { \ |
435 UcxList *_dqlsecbak_ = list; \ |
434 UcxList *_dqlsecbak_ = list; \ |
436 list = ucx_list_append(list, data); \ |
435 list = ucx_list_append(list, data); \ |
437 if (!list) { \ |
436 if (!list) { \ |
|
437 free(data); \ |
|
438 data = NULL; \ |
438 (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \ |
439 (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \ |
439 list = _dqlsecbak_; \ |
440 list = _dqlsecbak_; \ |
|
441 return 0; \ |
440 } \ |
442 } \ |
441 } |
443 } while(0) |
442 |
444 |
443 // special symbols are single tokens - the % sign MUST NOT be a special symbol |
445 // special symbols are single tokens - the % sign MUST NOT be a special symbol |
444 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; |
446 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; |
445 |
447 |
446 static _Bool iskeyword(DavQLToken *token) { |
448 static _Bool iskeyword(DavQLToken *token) { |
529 return NULL; |
531 return NULL; |
530 } |
532 } |
531 } |
533 } |
532 |
534 |
533 static UcxList* dav_parse_tokenize(sstr_t src) { |
535 static UcxList* dav_parse_tokenize(sstr_t src) { |
534 #define alloc_token token = malloc(sizeof(DavQLToken));\ |
536 #define alloc_token() do {token = malloc(sizeof(DavQLToken));\ |
535 if(!token) {ucx_list_free(tokens); return NULL;} |
537 if(!token) {ucx_list_free(tokens); return NULL;}} while(0) |
536 #define add_token tokens = dav_parse_add_token(tokens, token); \ |
538 #define add_token() do {tokens = dav_parse_add_token(tokens, token); \ |
537 if(!tokens) {return NULL;} |
539 if(!tokens) {return NULL;}} while(0) |
538 UcxList *tokens = NULL; |
540 UcxList *tokens = NULL; |
539 |
541 |
540 DavQLToken *token = NULL; |
542 DavQLToken *token = NULL; |
541 char insequence = '\0'; |
543 char insequence = '\0'; |
542 for (size_t i = 0 ; i < src.length ; i++) { |
544 for (size_t i = 0 ; i < src.length ; i++) { |
549 token->value.length += 3; |
551 token->value.length += 3; |
550 i += 2; |
552 i += 2; |
551 } else { |
553 } else { |
552 // add quoted token to list |
554 // add quoted token to list |
553 token->value.length++; |
555 token->value.length++; |
554 add_token |
556 add_token(); |
555 token = NULL; |
557 token = NULL; |
556 insequence = '\0'; |
558 insequence = '\0'; |
557 } |
559 } |
558 } else if (insequence == '\0') { |
560 } else if (insequence == '\0') { |
559 insequence = src.ptr[i]; |
561 insequence = src.ptr[i]; |
560 // always create new token for quoted strings |
562 // always create new token for quoted strings |
561 if (token) { |
563 if (token) { |
562 add_token |
564 add_token(); |
563 } |
565 } |
564 alloc_token |
566 alloc_token(); |
565 token->value.ptr = src.ptr + i; |
567 token->value.ptr = src.ptr + i; |
566 token->value.length = 1; |
568 token->value.length = 1; |
567 } else { |
569 } else { |
568 // add other kind of quotes to token |
570 // add other kind of quotes to token |
569 token->value.length++; |
571 token->value.length++; |
571 } else if (insequence) { |
573 } else if (insequence) { |
572 token->value.length++; |
574 token->value.length++; |
573 } else if (isspace(src.ptr[i])) { |
575 } else if (isspace(src.ptr[i])) { |
574 // add token before spaces to list (if any) |
576 // add token before spaces to list (if any) |
575 if (token) { |
577 if (token) { |
576 add_token |
578 add_token(); |
577 token = NULL; |
579 token = NULL; |
578 } |
580 } |
579 } else if (strchr(special_token_symbols, src.ptr[i])) { |
581 } else if (strchr(special_token_symbols, src.ptr[i])) { |
580 // add token before special symbol to list (if any) |
582 // add token before special symbol to list (if any) |
581 if (token) { |
583 if (token) { |
582 add_token |
584 add_token(); |
583 token = NULL; |
585 token = NULL; |
584 } |
586 } |
585 // add special symbol as single token to list |
587 // add special symbol as single token to list |
586 alloc_token |
588 alloc_token(); |
587 token->value.ptr = src.ptr + i; |
589 token->value.ptr = src.ptr + i; |
588 token->value.length = 1; |
590 token->value.length = 1; |
589 add_token |
591 add_token(); |
590 // set tokenizer ready to read more tokens |
592 // set tokenizer ready to read more tokens |
591 token = NULL; |
593 token = NULL; |
592 } else { |
594 } else { |
593 // if this is a new token, create memory for it |
595 // if this is a new token, create memory for it |
594 if (!token) { |
596 if (!token) { |
595 alloc_token |
597 alloc_token(); |
596 token->value.ptr = src.ptr + i; |
598 token->value.ptr = src.ptr + i; |
597 token->value.length = 0; |
599 token->value.length = 0; |
598 } |
600 } |
599 // extend token length when reading more bytes |
601 // extend token length when reading more bytes |
600 token->value.length++; |
602 token->value.length++; |
601 } |
603 } |
602 } |
604 } |
603 |
605 |
604 if (token) { |
606 if (token) { |
605 add_token |
607 add_token(); |
606 } |
608 } |
607 |
609 |
608 alloc_token |
610 alloc_token(); |
609 token->tokenclass = DAVQL_TOKEN_END; |
611 token->tokenclass = DAVQL_TOKEN_END; |
610 token->value = S(""); |
612 token->value = S(""); |
611 UcxList *ret = ucx_list_append(tokens, token); |
613 UcxList *ret = ucx_list_append(tokens, token); |
612 if (ret) { |
614 if (ret) { |
613 return ret; |
615 return ret; |
996 |
998 |
997 // RULE: "-" |
999 // RULE: "-" |
998 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) { |
1000 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) { |
999 DavQLField *field; |
1001 DavQLField *field; |
1000 dqlsec_malloc(stmt, field, DavQLField); |
1002 dqlsec_malloc(stmt, field, DavQLField); |
|
1003 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
1001 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1004 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1002 field->expr->type = DAVQL_IDENTIFIER; |
1005 field->expr->type = DAVQL_IDENTIFIER; |
1003 field->expr->srctext = field->name = token_sstr(token); |
1006 field->expr->srctext = field->name = token_sstr(token); |
1004 dqlsec_list_append(stmt, stmt->fields, field); |
|
1005 return 1; |
1007 return 1; |
1006 } |
1008 } |
1007 |
1009 |
1008 // RULE: "*", {",", NamedExpression} |
1010 // RULE: "*", {",", NamedExpression} |
1009 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) { |
1011 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) { |
1010 DavQLField *field; |
1012 DavQLField *field; |
1011 dqlsec_malloc(stmt, field, DavQLField); |
1013 dqlsec_malloc(stmt, field, DavQLField); |
|
1014 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
1012 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1015 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1013 field->expr->type = DAVQL_IDENTIFIER; |
1016 field->expr->type = DAVQL_IDENTIFIER; |
1014 field->expr->srctext = field->name = token_sstr(token); |
1017 field->expr->srctext = field->name = token_sstr(token); |
1015 dqlsec_list_append(stmt, stmt->fields, field); |
|
1016 |
1018 |
1017 int total_consumed = 0; |
1019 int total_consumed = 0; |
1018 int consumed = 1; |
1020 int consumed = 1; |
1019 |
1021 |
1020 do { |
1022 do { |
1027 consumed = dav_parse_named_field(stmt, token, &localfield); |
1029 consumed = dav_parse_named_field(stmt, token, &localfield); |
1028 if (!stmt->errorcode && consumed) { |
1030 if (!stmt->errorcode && consumed) { |
1029 DavQLField *field; |
1031 DavQLField *field; |
1030 dqlsec_malloc(stmt, field, DavQLField); |
1032 dqlsec_malloc(stmt, field, DavQLField); |
1031 memcpy(field, &localfield, sizeof(DavQLField)); |
1033 memcpy(field, &localfield, sizeof(DavQLField)); |
1032 dqlsec_list_append(stmt, stmt->fields, field); |
1034 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
1033 } |
1035 } |
1034 } else { |
1036 } else { |
1035 consumed = 0; |
1037 consumed = 0; |
1036 } |
1038 } |
1037 } while (consumed > 0); |
1039 } while (consumed > 0); |
1048 consumed = dav_parse_named_field(stmt, token, &localfield); |
1050 consumed = dav_parse_named_field(stmt, token, &localfield); |
1049 if (consumed) { |
1051 if (consumed) { |
1050 DavQLField *field; |
1052 DavQLField *field; |
1051 dqlsec_malloc(stmt, field, DavQLField); |
1053 dqlsec_malloc(stmt, field, DavQLField); |
1052 memcpy(field, &localfield, sizeof(DavQLField)); |
1054 memcpy(field, &localfield, sizeof(DavQLField)); |
1053 dqlsec_list_append(stmt, stmt->fields, field); |
1055 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
1054 token = ucx_list_get(token, consumed); |
1056 token = ucx_list_get(token, consumed); |
1055 total_consumed += consumed; |
1057 total_consumed += consumed; |
1056 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER) |
1058 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER) |
1057 // look ahead, if the field is JUST the identifier |
1059 // look ahead, if the field is JUST the identifier |
1058 && (token_is(token->next, DAVQL_TOKEN_COMMA) || |
1060 && (token_is(token->next, DAVQL_TOKEN_COMMA) || |
1061 DavQLField *field; |
1063 DavQLField *field; |
1062 dqlsec_malloc(stmt, field, DavQLField); |
1064 dqlsec_malloc(stmt, field, DavQLField); |
1063 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1065 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
1064 field->expr->type = DAVQL_IDENTIFIER; |
1066 field->expr->type = DAVQL_IDENTIFIER; |
1065 field->expr->srctext = field->name = token_sstr(token); |
1067 field->expr->srctext = field->name = token_sstr(token); |
1066 dqlsec_list_append(stmt, stmt->fields, field); |
1068 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
1067 |
1069 |
1068 consumed = 1; |
1070 consumed = 1; |
1069 total_consumed++; |
1071 total_consumed++; |
1070 token = token->next; |
1072 token = token->next; |
1071 |
1073 |
1445 total_consumed += consumed; |
1447 total_consumed += consumed; |
1446 |
1448 |
1447 DavQLOrderCriterion *criterion; |
1449 DavQLOrderCriterion *criterion; |
1448 dqlsec_malloc(stmt, criterion, DavQLOrderCriterion); |
1450 dqlsec_malloc(stmt, criterion, DavQLOrderCriterion); |
1449 memcpy(criterion, &crit, sizeof(DavQLOrderCriterion)); |
1451 memcpy(criterion, &crit, sizeof(DavQLOrderCriterion)); |
1450 dqlsec_list_append(stmt, stmt->orderby, criterion); |
1452 dqlsec_list_append_or_free(stmt, stmt->orderby, criterion); |
1451 |
1453 |
1452 if (token_is(token, DAVQL_TOKEN_COMMA)) { |
1454 if (token_is(token, DAVQL_TOKEN_COMMA)) { |
1453 total_consumed++; |
1455 total_consumed++; |
1454 token = token->next; |
1456 token = token->next; |
1455 } else { |
1457 } else { |