diff --git a/include/node.h b/include/node.h index d92d71c..6656542 100644 --- a/include/node.h +++ b/include/node.h @@ -49,6 +49,8 @@ rnode * rnode_lookup(rnode * tree, char * path, int path_len); redge * redge_create(char * pattern, int pattern_len, rnode * child); +void redge_branch(redge *e, int dl); + void redge_free(redge * edge); #endif /* !NODE_H */ diff --git a/include/str.h b/include/str.h index d58218a..4963da8 100644 --- a/include/str.h +++ b/include/str.h @@ -12,7 +12,9 @@ int strndiff(char * d1, char * d2, unsigned int n); int strdiff(char * d1, char * d2); -char * slug_to_pcre(char * slug, char sep); +char * compile_slug(char * str, int len); + +char * contains_slug(char * str); char * ltrim_slash(char* str); diff --git a/src/node.c b/src/node.c index 44ae5b6..384f2f4 100644 --- a/src/node.c +++ b/src/node.c @@ -236,13 +236,13 @@ rnode * rnode_insert_routel(rnode *tree, char *route, int route_len) // branch the edge at correct position (avoid broken slugs) char *slug_s = strchr(route, '{'); char *slug_e = strchr(route, '}'); - if ( dl > (slug_s - route) && dl < (slug_e - route) ) { - // break before '{' - dl = slug_s - route; + if ( slug_s && slug_e ) { + if ( dl > (slug_s - route) && dl < (slug_e - route) ) { + // break before '{' + dl = slug_s - route; + } } - - /* it's partically matched with the pattern, * we should split the end point and make a branch here... */ @@ -252,26 +252,7 @@ rnode * rnode_insert_routel(rnode *tree, char *route, int route_len) char * s2 = route + dl; int s1_len = 0, s2_len = 0; - redge **tmp_edges = e->child->edges; - int **tmp_edge_len = e->child->edge_len; - - // the suffix edge of the leaf - c1 = rnode_create(3); - s1_len = e->pattern_len - dl; - e1 = redge_create(strndup(s1, s1_len), s1_len, c1); - // printf("edge left: %s\n", e1->pattern); - - // Migrate the child edges to the new edge we just created. - for ( int i = 0 ; i < tmp_edge_len ; i++ ) { - rnode_append_edge(c1, tmp_edges[i]); - e->child->edges[i] = NULL; - } - e->child->edge_len = 0; - - rnode_append_edge(e->child, e1); - - - + redge_branch(e, dl); // here is the new edge from. c2 = rnode_create(3); @@ -286,15 +267,7 @@ rnode * rnode_insert_routel(rnode *tree, char *route, int route_len) e->pattern_len = dl; - - // Move the child edges to the new suffix edge child - /* - e->child->edge_len = 0; - */ - - // move n->edges to c1 - c1->endpoint++; c2->endpoint++; return c2; } else if ( dl > 0 ) { @@ -309,6 +282,32 @@ rnode * rnode_insert_routel(rnode *tree, char *route, int route_len) return n; } +void redge_branch(redge *e, int dl) { + rnode *c1; // child 1, child 2 + redge *e1; // edge 1, edge 2 + char * s1 = e->pattern + dl; + int s1_len = 0; + + redge **tmp_edges = e->child->edges; + int tmp_edge_len = e->child->edge_len; + + // the suffix edge of the leaf + c1 = rnode_create(3); + s1_len = e->pattern_len - dl; + e1 = redge_create(strndup(s1, s1_len), s1_len, c1); + // printf("edge left: %s\n", e1->pattern); + + // Migrate the child edges to the new edge we just created. + for ( int i = 0 ; i < tmp_edge_len ; i++ ) { + rnode_append_edge(c1, tmp_edges[i]); + e->child->edges[i] = NULL; + } + e->child->edge_len = 0; + + rnode_append_edge(e->child, e1); + c1->endpoint++; +} + void rnode_dump(rnode * n, int level) { if ( n->edge_len ) { print_indent(level); diff --git a/src/str.c b/src/str.c index a204f4d..7e6b615 100644 --- a/src/str.c +++ b/src/str.c @@ -32,29 +32,71 @@ int strdiff(char * d1, char * d2) { +char * contains_slug(char * str) { + return strchr(str, '}'); +} + /** * @param char * sep separator */ -char * slug_to_pcre(char * slug, char sep) +char * compile_slug(char * str, int len) { - char * p = NULL; - char * pat = NULL; - char * end = NULL; + char *s1 = NULL, *s2 = NULL, *i = NULL, *o = NULL; + char *pat = NULL; + char sep = '/'; - if ( NULL != (p = strchr(slug, ':')) ) { - // this slug contains a pattern - end = strchr(p, '}'); + // find '{' + s1 = strchr(str, '{'); - // start after ':' - return strndup( (p + 1) , (end - p - 1) ); - } else { - if ((pat = malloc(128)) == NULL) { - return (NULL); - } - // should return a '[^/]+' pattern - snprintf(pat, 128, "[^%c]+", sep); + if ( s1 == NULL ) { + return strdup(str); } - return pat; + + if ( (s1 - str) > 0 ) { + sep = *(s1-1); + } + + char * out = NULL; + if ((out = calloc(sizeof(char),128)) == NULL) { + return (NULL); + } + + // append prefix + o = out; + strncat(o, str, s1 - str); + o += (s1 - str); + + // start after ':' + if ( NULL != (pat = strchr(s1, ':')) ) { + pat++; + + // this slug contains a pattern + s2 = strchr(pat, '}'); + + *o = '('; + o++; + + strncat(o, pat, (s2 - pat) ); + o += (s2 - pat); + + *o = ')'; + o++; + + } else { + // should return a '[^/]+' pattern + // strncat(c, "([^%c]+)", strlen("([^%c]+)") ); + // snprintf(pat, 128, "([^%c]+)", sep); + sprintf(o, "([^%c]+)", sep); + o+= sizeof("([^%c]+)"); + } + + s2++; + while( (s2 - str) > len ) { + *o = *s2; + s2++; + o++; + } + return out; } diff --git a/tests/test_tree.c b/tests/test_tree.c index ea769bb..84f7f6f 100644 --- a/tests/test_tree.c +++ b/tests/test_tree.c @@ -62,20 +62,37 @@ START_TEST (test_combine_patterns) } END_TEST -START_TEST (test_slug_to_pcre) +START_TEST (test_compile_slug) { + /* char * pattern; - pattern = slug_to_pcre("{id}", '/'); - fail_if( strcmp(pattern, "[^/]+") != 0 , "as [^/]+" ); + pattern = compile_slug("{id}", strlen("{id}")); + ck_assert_str_eq( pattern, "([^/]+)" ); free(pattern); - pattern = slug_to_pcre("{id:[a-z]+}", '/'); - fail_if( strcmp(pattern, "[a-z]+") != 0 , "as [a-z]+" ); + pattern = compile_slug("/{id}", strlen("/{id}")); + ck_assert_str_eq( pattern, "/([^/]+)" ); + free(pattern); + + pattern = compile_slug("-{id}", strlen("-{id}")); + ck_assert_str_eq( pattern, "-([^-]+)" ); + free(pattern); + + pattern = compile_slug("{id}-{title}", strlen("{id}-{title}")); + ck_assert_str_eq( pattern, "([^/]+)-([^-]+)" ); free(pattern); + pattern = compile_slug("{id:[a-z]+}", strlen("{id:[a-z]+}") ); + ck_assert_str_eq( pattern, "([a-z]+)" ); + free(pattern); + pattern = compile_slug("/path/{id:[a-z]+}", strlen("/path/{id:[a-z]+}") ); + ck_assert_str_eq( pattern, "/path/([a-z]+)" ); + free(pattern); + */ + /* char * p = malloc(sizeof(char) * 10); strncat(p, "foo", 3); @@ -221,7 +238,7 @@ Suite* r3_suite (void) { tcase_add_test(tcase, test_rnode_construct_uniq); tcase_add_test(tcase, test_rnode_find_edge); tcase_add_test(tcase, test_rnode_insert_routel); - tcase_add_test(tcase, test_slug_to_pcre); + tcase_add_test(tcase, test_compile_slug); tcase_add_test(tcase, test_combine_patterns); suite_add_tcase(suite, tcase);