From c52639c4319cb8b71c7a13c3caaf611a468e2055 Mon Sep 17 00:00:00 2001 From: c9s Date: Mon, 2 Jun 2014 01:01:29 +0800 Subject: [PATCH] slug parser --- include/r3.h | 38 ++++++++++++++++++++++ src/str.c | 79 +++++++++++++++++++++++++++++++++++++++++++++- tests/check_slug.c | 37 ++++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) diff --git a/include/r3.h b/include/r3.h index b2562c9..c68559b 100644 --- a/include/r3.h +++ b/include/r3.h @@ -180,6 +180,44 @@ enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE }; enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH, OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA }; +typedef struct { + /** + * source path + */ + char * path; + + int path_len; + + /** + * slug start pointer + */ + char * begin; + + /** + * slug end pointer + */ + char * end; + + /** + * slug length + */ + int len; + + // slug pattern pointer if we have one + char * pattern; + + // the length of custom pattern, if the pattern is found. + int pattern_len; + +} r3_slug_t; + + +r3_slug_t * r3_slug_parse(const char *needle, int needle_len, char **errstr); + +char * r3_slug_to_str(r3_slug_t *s); + +void r3_slug_free(r3_slug_t * s); + #ifdef ENABLE_JSON json_object * r3_edge_to_json_object(const edge * e); json_object * r3_node_to_json_object(const node * n); diff --git a/src/str.c b/src/str.c index 939d067..a3ae55b 100644 --- a/src/str.c +++ b/src/str.c @@ -38,6 +38,83 @@ int r3_pattern_to_opcode(const char * pattern, int len) { } +r3_slug_t * r3_slug_new(char * path, int path_len) { + r3_slug_t * s = zmalloc(sizeof(r3_slug_t)); + s->path = path; + s->path_len = path_len; + + s->begin = NULL; + s->end = NULL; + s->len = 0; + + s->pattern = NULL; + s->pattern_len = 0; + return s; +} + +void r3_slug_free(r3_slug_t * s) { + zfree(s); +} + +int r3_slug_check(r3_slug_t *s, char **errstr) { + if (s->begin == NULL) { + return 1; + } + if (s->end == NULL) { + return 1; + } + return 0; +} + + +char * r3_slug_to_str(r3_slug_t *s) { + char *str = NULL; + asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path); + return str; +} + + +r3_slug_t * r3_slug_parse(const char *needle, int needle_len, char **errstr) { + r3_slug_t * s = r3_slug_new(needle, needle_len); + + int cnt = 0; + int state = 0; + char * p = (char*) needle; + + while( (p-needle) < needle_len) { + + if (*p == '\\' ) { + p++; p++; + } + if (state == 0 && *p == '{') { + s->begin = p+1; + } + + if (state == 1 && *p == ':') { + // start from next + s->pattern = p+1; + } + + // closing slug + if (state == 1 && *p == '}') { + s->end = p; + s->len = s->end - s->begin; + if (s->pattern) { + s->pattern_len = p - s->pattern; + } + cnt++; + break; + } + + if ( *p == '{' ) { + state++; + } else if ( *p == '}' ) { + state--; + } + p++; + }; + return s; +} /** * provide a quick way to count slugs, simply search for '{' @@ -66,7 +143,7 @@ int slug_count(const char * needle, int len, char **errstr) { info("FOUND PATTERN: '%s' (%d), STATE: %d\n", needle, len, state); if (state != 0) { if (errstr) { - asprintf(errstr, "incomplete slug pattern. PATTERN (%d): '%s' (%d), OFFSET: %d, STATE: %d", len, needle, p - needle, state); + asprintf(errstr, "incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state); } return 0; } diff --git a/tests/check_slug.c b/tests/check_slug.c index 0919487..36a555a 100644 --- a/tests/check_slug.c +++ b/tests/check_slug.c @@ -94,6 +94,41 @@ START_TEST (test_incomplete_slug) } END_TEST + +START_TEST (test_slug_parse_with_pattern) +{ + char * pattern = "/user/{name:\\d{3}}"; + char * errstr = NULL; + r3_slug_t *s = r3_slug_parse(pattern, strlen(pattern), &errstr); + + char * out = r3_slug_to_str(s); + printf("%s\n",out); + zfree(out); + + r3_slug_free(s); +} +END_TEST + + +START_TEST (test_slug_parse_without_pattern) +{ + char * pattern = "/user/{name}"; + char * errstr = NULL; + r3_slug_t *s = r3_slug_parse(pattern, strlen(pattern), &errstr); + + char * out = r3_slug_to_str(s); + printf("%s\n",out); + zfree(out); + + r3_slug_free(s); +} +END_TEST + + + + + + START_TEST (test_slug_count) { int cnt = 0; @@ -134,6 +169,8 @@ Suite* r3_suite (void) { tcase_add_test(tcase, test_slug_compile); tcase_add_test(tcase, test_pattern_to_opcode); tcase_add_test(tcase, test_incomplete_slug); + tcase_add_test(tcase, test_slug_parse_with_pattern); + tcase_add_test(tcase, test_slug_parse_without_pattern); suite_add_tcase(suite, tcase); return suite;