node * r3_tree_insert_pathl(node *tree, char *path, int path_len, void * data) { return r3_tree_insert_pathl_(tree, path, path_len, NULL , data); }
/** * Return the last inserted node. */ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route, void * data) { node * n = tree; edge * e = NULL; /* length of common prefix */ int prefix_len = 0; for( int i = 0 ; i < n->edge_len ; i++ ) { prefix_len = strndiff(path, n->edges[i]->pattern, n->edges[i]->pattern_len); // printf("prefix_len: %d %s vs %s\n", prefix_len, path, n->edges[i]->pattern ); // no common, consider insert a new edge if ( prefix_len > 0 ) { e = n->edges[i]; break; } } // branch the edge at correct position (avoid broken slugs) char *slug_s; if ( (slug_s = inside_slug(path, path_len, path + prefix_len)) != NULL ) { prefix_len = slug_s - path; } // common prefix not found, insert a new edge for this pattern if ( prefix_len == 0 ) { // there are two more slugs, we should break them into several parts int slug_cnt = slug_count(path, path_len); if ( slug_cnt > 1 ) { int slug_len; char *p = slug_find_placeholder(path, &slug_len); #ifdef DEBUG assert(p); #endif // find the next one '{', then break there if(p) { p = slug_find_placeholder(p + slug_len + 1, NULL); } #ifdef DEBUG assert(p); #endif // insert the first one edge, and break at "p" node * child = r3_tree_create(3); r3_node_connect(n, zstrndup(path, (int)(p - path)), child); // and insert the rest part to the child return r3_tree_insert_pathl_(child, p, path_len - (int)(p - path), route, data); } else { if (slug_cnt == 1) { // there is one slug, let's see if it's optimiz-able by opcode int slug_len = 0; char *slug_p = slug_find_placeholder(path, &slug_len); int slug_pattern_len = 0; char *slug_pattern = slug_find_pattern(slug_p, &slug_pattern_len); int opcode = 0; // if there is a pattern defined. if (slug_pattern) { char *cpattern = slug_compile(slug_pattern, slug_pattern_len); opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern)); zfree(cpattern); } else { opcode = OP_EXPECT_NOSLASH; } // found opcode if (opcode) { // if the slug starts after one+ charactor, for example foo{slug} node *c1; if (slug_p > path) { c1 = r3_tree_create(3); r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate } else { c1 = n; } node * c2 = r3_tree_create(3); edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2); op_edge->opcode = opcode; // insert rest int restlen = (path_len - (slug_p - path)) - slug_len; if (restlen) { return r3_tree_insert_pathl_(c2, slug_p + slug_len, restlen, route, data); } c2->data = data; c2->endpoint++; if (route) { route->data = data; r3_node_append_route(c2, route); } return c2; } } // only one slug node * child = r3_tree_create(3); r3_node_connect(n, zstrndup(path, path_len) , child); child->data = data; child->endpoint++; if (route) { route->data = data; r3_node_append_route(child, route); } return child; } } else if ( prefix_len == e->pattern_len ) { // fully-equal to the pattern of the edge char * subpath = path + prefix_len; int subpath_len = path_len - prefix_len; // there are something more we can insert if ( subpath_len > 0 ) { return r3_tree_insert_pathl_(e->child, subpath, subpath_len, route, data); } else { // there are no more path to insert // see if there is an endpoint already if (e->child->endpoint > 0) { // XXX: return an error code instead of NULL return NULL; } e->child->endpoint++; // make it as an endpoint e->child->data = data; if (route) { route->data = data; r3_node_append_route(e->child, route); } return e->child; } } else if ( prefix_len < e->pattern_len ) { /* it's partially matched with the pattern, * we should split the end point and make a branch here... */ char * s2 = path + prefix_len; int s2_len = path_len - prefix_len; r3_edge_branch(e, prefix_len); return r3_tree_insert_pathl_(e->child, s2 , s2_len, route , data); } else { printf("unexpected route."); return NULL; } return n; }
/** * Return the last inserted node. */ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route, void * data) { node * n = tree; edge * e = NULL; /* length of common prefix */ int prefix_len = 0; for( int i = 0 ; i < n->edge_len ; i++ ) { prefix_len = strndiff(path, n->edges[i]->pattern, n->edges[i]->pattern_len); // printf("prefix_len: %d %s vs %s\n", prefix_len, path, n->edges[i]->pattern ); // no common, consider insert a new edge if ( prefix_len > 0 ) { e = n->edges[i]; break; } } // branch the edge at correct position (avoid broken slugs) char *slug_s; if ( (slug_s = inside_slug(path, path_len, path + prefix_len)) != NULL ) { prefix_len = slug_s - path; } // common prefix not found, insert a new edge for this pattern if ( prefix_len == 0 ) { // there are two more slugs, we should break them into several parts if ( slug_count(path, path_len) > 1 ) { int slug_len; char *p = find_slug_placeholder(path, &slug_len); #ifdef DEBUG assert(p); #endif // find the next one if(p) { p = find_slug_placeholder(p + slug_len + 1, NULL); } #ifdef DEBUG assert(p); #endif // insert the first one edge, and break at "p" node * child = r3_tree_create(3); r3_node_add_child(n, zstrndup(path, (int)(p - path)), child); child->endpoint = 0; // and insert the rest part to the child return r3_tree_insert_pathl_(child, p, path_len - (int)(p - path), route, data); } else { node * child = r3_tree_create(3); r3_node_add_child(n, zstrndup(path, path_len) , child); // info("edge not found, insert one: %s\n", path); child->data = data; child->endpoint++; if (route) { route->data = data; r3_node_append_route(child, route); } return child; } } else if ( prefix_len == e->pattern_len ) { // fully-equal to the pattern of the edge char * subpath = path + prefix_len; int subpath_len = path_len - prefix_len; // there are something more we can insert if ( subpath_len > 0 ) { return r3_tree_insert_pathl_(e->child, subpath, subpath_len, route, data); } else { // there are no more path to insert // see if there is an endpoint already if (e->child->endpoint > 0) { // XXX: return an error code instead of NULL return NULL; } e->child->endpoint++; // make it as an endpoint e->child->data = data; if (route) { route->data = data; r3_node_append_route(e->child, route); } return e->child; } } else if ( prefix_len < e->pattern_len ) { /* it's partially matched with the pattern, * we should split the end point and make a branch here... */ char * s2 = path + prefix_len; int s2_len = path_len - prefix_len; r3_edge_branch(e, prefix_len); return r3_tree_insert_pathl_(e->child, s2 , s2_len, route , data); } else { printf("unexpected route."); return NULL; } return n; }