diff options
| -rw-r--r-- | src/template-parser.c | 136 | ||||
| -rw-r--r-- | src/template-parser.h | 3 | ||||
| -rw-r--r-- | tests/check_renderer.c | 14 | ||||
| -rw-r--r-- | tests/check_template_parser.c | 41 | 
4 files changed, 171 insertions, 23 deletions
diff --git a/src/template-parser.c b/src/template-parser.c index d25ea0f..6eb65b6 100644 --- a/src/template-parser.c +++ b/src/template-parser.c @@ -25,8 +25,12 @@ typedef enum {      TEMPLATE_BLOCK_TYPE,      TEMPLATE_BLOCK_BLOCK_TYPE_START,      TEMPLATE_BLOCK_BLOCK_TYPE, -    TEMPLATE_BLOCK_IFDEF_START, -    TEMPLATE_BLOCK_IFDEF_VARIABLE, +    TEMPLATE_BLOCK_IF_START, +    TEMPLATE_BLOCK_IF_VARIABLE, +    TEMPLATE_BLOCK_IF_OPERATOR_START, +    TEMPLATE_BLOCK_IF_OPERATOR, +    TEMPLATE_BLOCK_IF_OPERAND_START, +    TEMPLATE_BLOCK_IF_OPERAND,      TEMPLATE_BLOCK_END,      TEMPLATE_VARIABLE_START,      TEMPLATE_VARIABLE, @@ -52,6 +56,10 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)      size_t current = 0;      size_t start = 0;      size_t end = 0; +    size_t op_start = 0; +    size_t op_end = 0; +    size_t start2 = 0; +    size_t end2 = 0;      unsigned int if_count = 0; @@ -73,6 +81,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                      stmt = b_malloc(sizeof(blogc_template_stmt_t));                      stmt->type = type;                      stmt->value = b_strndup(src + start, src_len - start); +                    stmt->op = NULL; +                    stmt->value2 = NULL;                      stmts = b_slist_append(stmts, stmt);                      stmt = NULL;                  } @@ -92,6 +102,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                          stmt = b_malloc(sizeof(blogc_template_stmt_t));                          stmt->type = type;                          stmt->value = b_strndup(src + start, end - start); +                        stmt->op = NULL; +                        stmt->value2 = NULL;                          stmts = b_slist_append(stmts, stmt);                          stmt = NULL;                      } @@ -117,7 +129,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                  if (c >= 'a' && c <= 'z')                      break;                  if (c == ' ') { -                    if (0 == strncmp("block", src + start, current - start)) { +                    if ((current - start == 5) && +                        (0 == strncmp("block", src + start, current - start))) +                    {                          if (block_state == BLOCK_CLOSED) {                              state = TEMPLATE_BLOCK_BLOCK_TYPE_START;                              type = BLOGC_TEMPLATE_BLOCK_STMT; @@ -128,7 +142,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                              src, src_len, current, "Blocks can't be nested.");                          break;                      } -                    else if (0 == strncmp("endblock", src + start, current - start)) { +                    else if ((current - start == 8) && +                        (0 == strncmp("endblock", src + start, current - start))) +                    {                          if (block_state != BLOCK_CLOSED) {                              state = TEMPLATE_BLOCK_END;                              type = BLOGC_TEMPLATE_ENDBLOCK_STMT; @@ -140,21 +156,36 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                              "'endblock' statement without an open 'block' statement.");                          break;                      } -                    else if (0 == strncmp("ifdef", src + start, current - start)) { -                        state = TEMPLATE_BLOCK_IFDEF_START; +                    else if ((current - start == 5) && +                        (0 == strncmp("ifdef", src + start, current - start))) +                    { +                        state = TEMPLATE_BLOCK_IF_START;                          type = BLOGC_TEMPLATE_IFDEF_STMT;                          start = current;                          if_count++;                          break;                      } -                    else if (0 == strncmp("ifndef", src + start, current - start)) { -                        state = TEMPLATE_BLOCK_IFDEF_START; +                    else if ((current - start == 6) && +                        (0 == strncmp("ifndef", src + start, current - start))) +                    { +                        state = TEMPLATE_BLOCK_IF_START;                          type = BLOGC_TEMPLATE_IFNDEF_STMT;                          start = current;                          if_count++;                          break;                      } -                    else if (0 == strncmp("endif", src + start, current - start)) { +                    else if ((current - start == 2) && +                        (0 == strncmp("if", src + start, current - start))) +                    { +                        state = TEMPLATE_BLOCK_IF_START; +                        type = BLOGC_TEMPLATE_IF_STMT; +                        start = current; +                        if_count++; +                        break; +                    } +                    else if ((current - start == 5) && +                        (0 == strncmp("endif", src + start, current - start))) +                    {                          if (if_count > 0) {                              state = TEMPLATE_BLOCK_END;                              type = BLOGC_TEMPLATE_ENDIF_STMT; @@ -216,11 +247,11 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                      "and 'listing_once'.");                  break; -            case TEMPLATE_BLOCK_IFDEF_START: +            case TEMPLATE_BLOCK_IF_START:                  if (c == ' ')                      break;                  if (c >= 'A' && c <= 'Z') { -                    state = TEMPLATE_BLOCK_IFDEF_VARIABLE; +                    state = TEMPLATE_BLOCK_IF_VARIABLE;                      start = current;                      break;                  } @@ -229,12 +260,15 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                      "Invalid variable name. Must begin with uppercase letter.");                  break; -            case TEMPLATE_BLOCK_IFDEF_VARIABLE: +            case TEMPLATE_BLOCK_IF_VARIABLE:                  if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')                      break;                  if (c == ' ') {                      end = current; -                    state = TEMPLATE_BLOCK_END; +                    if (type == BLOGC_TEMPLATE_IF_STMT) +                        state = TEMPLATE_BLOCK_IF_OPERATOR_START; +                    else +                        state = TEMPLATE_BLOCK_END;                      break;                  }                  *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src, @@ -243,6 +277,45 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)                      "or '_'.");                  break; +            case TEMPLATE_BLOCK_IF_OPERATOR_START: +                if (c == ' ') { +                    break; +                } +                state = TEMPLATE_BLOCK_IF_OPERATOR; +                op_start = current; +                break; + +            case TEMPLATE_BLOCK_IF_OPERATOR: +                if (c != ' ') +                    break; +                state = TEMPLATE_BLOCK_IF_OPERAND_START; +                op_end = current; +                break; + +            case TEMPLATE_BLOCK_IF_OPERAND_START: +                if (c == ' ') +                    break; +                if (c != '"') { +                    op_start = 0; +                    op_end = 0; +                    *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src, +                        src_len, current, +                        "Invalid 'if' operand. Must be double-quoted static string."); +                    break; +                } +                state = TEMPLATE_BLOCK_IF_OPERAND; +                start2 = current + 1; +                break; + +            case TEMPLATE_BLOCK_IF_OPERAND: +                if (c != '"') +                    break; +                if (c == '"' && src[current - 1] == '\\') +                    break; +                state = TEMPLATE_BLOCK_END; +                end2 = current; +                break; +              case TEMPLATE_BLOCK_END:                  if (c == ' ')                      break; @@ -302,11 +375,44 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)              case TEMPLATE_CLOSE_BRACKET:                  if (c == '}') { +                    if (op_end > op_start) { +                        if ((!((op_end - op_start == 1) && +                               (0 == strncmp("<", src + op_start, op_end - op_start)))) && +                            (!((op_end - op_start == 1) && +                               (0 == strncmp(">", src + op_start, op_end - op_start)))) && +                            (!((op_end - op_start == 2) && +                               (0 == strncmp("<=", src + op_start, op_end - op_start)))) && +                            (!((op_end - op_start == 2) && +                               (0 == strncmp(">=", src + op_start, op_end - op_start)))) && +                            (!((op_end - op_start == 2) && +                               (0 == strncmp("==", src + op_start, op_end - op_start)))) && +                            (!((op_end - op_start == 2) && +                               (0 == strncmp("!=", src + op_start, op_end - op_start))))) +                        { +                            *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, +                                src, src_len, op_start, +                                "Invalid 'if' operator. Must be '<', '>', " +                                "'<=', '>=', '==' or '!='."); +                            break; +                        } +                    }                      stmt = b_malloc(sizeof(blogc_template_stmt_t));                      stmt->type = type;                      stmt->value = NULL; +                    stmt->op = NULL; +                    stmt->value2 = NULL; +                    if (op_end > op_start) { +                        stmt->op = b_strndup(src + op_start, op_end - op_start); +                        op_start = 0; +                        op_end = 0; +                    }                      if (end > start)                          stmt->value = b_strndup(src + start, end - start); +                    if (end2 > start2) { +                        stmt->value2 = b_strndup(src + start2, end2 - start2); +                        start2 = 0; +                        end2 = 0; +                    }                      stmts = b_slist_append(stmts, stmt);                      stmt = NULL;                      state = TEMPLATE_START; @@ -355,7 +461,11 @@ blogc_template_free_stmts(b_slist_t *stmts)  {      for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) {          blogc_template_stmt_t *data = tmp->data; +        if (data == NULL) +            continue;          free(data->value); +        free(data->op); +        free(data->value2);          free(data);      }      b_slist_free(stmts); diff --git a/src/template-parser.h b/src/template-parser.h index 88c9ccf..b9213e2 100644 --- a/src/template-parser.h +++ b/src/template-parser.h @@ -15,6 +15,7 @@  typedef enum {      BLOGC_TEMPLATE_IFDEF_STMT = 1,      BLOGC_TEMPLATE_IFNDEF_STMT, +    BLOGC_TEMPLATE_IF_STMT,      BLOGC_TEMPLATE_ENDIF_STMT,      BLOGC_TEMPLATE_BLOCK_STMT,      BLOGC_TEMPLATE_ENDBLOCK_STMT, @@ -25,6 +26,8 @@ typedef enum {  typedef struct {      blogc_template_stmt_type_t type;      char *value; +    char *value2; +    char *op;  } blogc_template_stmt_t;  b_slist_t* blogc_template_parse(const char *src, size_t src_len, diff --git a/tests/check_renderer.c b/tests/check_renderer.c index 0244e30..e238610 100644 --- a/tests/check_renderer.c +++ b/tests/check_renderer.c @@ -63,9 +63,9 @@ test_render_entry(void **state)          "{% block listing_once %}fuuu{% endblock %}\n"          "{% block entry %}\n"          "{{ DATE }}\n" -        "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" -        "{% if GUDA %}{{ GUDA }}{% endif %}\n" -        "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" +        "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" +        "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n" +        "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n"          "{% endblock %}\n"          "{% block listing %}lol{% endblock %}\n";      blogc_error_t *err = NULL; @@ -98,12 +98,12 @@ test_render_listing(void **state)          "foo\n"          "{% block listing_once %}fuuu{% endblock %}\n"          "{% block entry %}\n" -        "{% if GUDA %}{{ GUDA }}{% endif %}\n" -        "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" +        "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n" +        "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n"          "{% endblock %}\n"          "{% block listing %}\n" -        "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" -        "bola: {% if BOLA %}{{ BOLA }}{% endif %}\n" +        "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" +        "bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"          "{% endblock %}\n";      blogc_error_t *err = NULL;      b_slist_t *l = blogc_template_parse(str, strlen(str), &err); diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c index 3479ca5..06161a7 100644 --- a/tests/check_template_parser.c +++ b/tests/check_template_parser.c @@ -34,6 +34,18 @@ blogc_assert_template_stmt(b_slist_t *l, const char *value,  static void +blogc_assert_template_if_stmt(b_slist_t *l, const char *variable, +    const char *operator, const char *operand) +{ +    blogc_template_stmt_t *stmt = l->data; +    assert_string_equal(stmt->value, variable); +    assert_string_equal(stmt->op, operator); +    assert_string_equal(stmt->value2, operand); +    assert_int_equal(stmt->type, BLOGC_TEMPLATE_IF_STMT); +} + + +static void  test_template_parse(void **state)  {      const char *a = @@ -48,7 +60,8 @@ test_template_parse(void **state)          "{% endif %}\n"          "{% endblock %}\n"          "{% block listing %}{{ BOLA }}{% endblock %}\n" -        "{% block listing_once %}asd{% endblock %}\n"; +        "{% block listing_once %}asd{% endblock %}\n" +        "{% if BOLA == \"10\" %}aee{% endif %}";      blogc_error_t *err = NULL;      b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);      assert_null(err); @@ -92,7 +105,12 @@ test_template_parse(void **state)          NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);      blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,          "\n", BLOGC_TEMPLATE_CONTENT_STMT); -    assert_null(tmp->next->next->next->next->next->next->next->next->next->next); +    tmp = tmp->next->next->next->next->next->next->next->next->next->next; +    blogc_assert_template_if_stmt(tmp, "BOLA", "==", "10"); +    blogc_assert_template_stmt(tmp->next, "aee", BLOGC_TEMPLATE_CONTENT_STMT); +    blogc_assert_template_stmt(tmp->next->next, NULL, +        BLOGC_TEMPLATE_ENDIF_STMT); +    assert_null(tmp->next->next->next);      blogc_template_free_stmts(stmts);  } @@ -407,6 +425,22 @@ test_template_parse_invalid_ifdef_variable(void **state)  static void +test_template_parse_invalid_if_operator(void **state) +{ +    const char *a = "{% block entry %}{% if BOLA = \"asd\" %}\n"; +    blogc_error_t *err = NULL; +    b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err); +    assert_non_null(err); +    assert_null(stmts); +    assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); +    assert_string_equal(err->msg, +        "Invalid 'if' operator. Must be '<', '>', '<=', '>=', '==' or '!='.\n" +        "Error occurred near to '= \"asd\" %}'"); +    blogc_error_free(err); +} + + +static void  test_template_parse_invalid_block_end(void **state)  {      const char *a = "{% block entry }}\n"; @@ -505,7 +539,7 @@ test_template_parse_invalid_close2(void **state)  static void  test_template_parse_invalid_if_not_closed(void **state)  { -    const char *a = "{% block entry %}{% if BOLA %}{% endblock %}\n"; +    const char *a = "{% block entry %}{% ifdef BOLA %}{% endblock %}\n";      blogc_error_t *err = NULL;      b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);      assert_non_null(err); @@ -547,6 +581,7 @@ main(void)          unit_test(test_template_parse_invalid_block_type),          unit_test(test_template_parse_invalid_ifdef_start),          unit_test(test_template_parse_invalid_ifdef_variable), +        unit_test(test_template_parse_invalid_if_operator),          unit_test(test_template_parse_invalid_block_end),          unit_test(test_template_parse_invalid_variable_name),          unit_test(test_template_parse_invalid_variable_name2),  | 
