Exemple #1
0
/**
 * Find common prefix from the edges of the node.
 *
 * Some cases of the common prefix:
 *
 * 1.  "/foo/{slug}" vs "/foo/bar"                      => common prefix = "/foo/"
 * 2.  "{slug}/hate" vs "{slug}/bar"                    => common prefix = "{slug}/"
 * 2.  "/z/{slug}/hate" vs "/z/{slog}/bar"              => common prefix = "/z/"
 * 3.  "{slug:xxx}/hate" vs "{slug:yyy}/bar"            => common prefix = ""
 * 4.  "aaa{slug:xxx}/hate" vs "aab{slug:yyy}/bar"      => common prefix = "aa"
 * 5.  "/foo/{slug}/hate" vs "/fo{slug}/bar"            => common prefix = "/fo"
 */
edge * r3_node_find_common_prefix(node *n, const char *path, int path_len, int *prefix_len, char **errstr) {
    int i = 0;
    int prefix = 0;
    *prefix_len = 0;
    edge *e = NULL;
    for(i = 0 ; i < n->edge_len ; i++ ) {
        // ignore all edges with slug
        prefix = strndiff( (char*) path, n->edges[i]->pattern, n->edges[i]->pattern_len);

        // no common, consider insert a new edge
        if ( prefix > 0 ) {
            e = n->edges[i];
            break;
        }
    }

    // found common prefix edge
    if (prefix > 0) {
        r3_slug_t *slug;
        int ret = 0;
        const char *offset = path;
        const char *p = path + prefix;

        slug = r3_slug_new(path, path_len);

        do {
            ret = r3_slug_parse(slug, path, path_len, offset, errstr);
            // found slug
            if (ret == 1) {
                // inside slug, backtrace to the begin of the slug
                if ( p >= slug->begin && p <= slug->end ) {
                    prefix = slug->begin - path - 1;
                    break;
                } else if ( p < slug->begin ) {
                    break;
                } else if ( p >= slug->end && p < (path + path_len) ) {
                    offset = slug->end + 1;
                    prefix = p - path;
                    continue;
                } else {
                    break;
                }
            } else if (ret == -1) {
                r3_slug_free(slug);
                return NULL;
            } else {
                break;
            }
        } while(ret == 1);

        // free the slug
        r3_slug_free(slug);
    }

    *prefix_len = prefix;
    return e;
}
Exemple #2
0
/**
 * 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;
}
Exemple #3
0
Fichier : node.c Projet : SciTeX/r3
/**
 * 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 ( count_slug(path, path_len) > 1 ) {
            char *p = find_slug_placeholder(path, NULL);

#ifdef DEBUG
            assert(p);
#endif

            // find the next one
            p = find_slug_placeholder(p + 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, strndup(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 {
            node * child = r3_tree_create(3);
            r3_node_add_child(n, strndup(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) {
                // 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 ) {
        // printf("branch the edge prefix_len: %d\n", prefix_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;
}
Exemple #4
0
/**
 * 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 offset = 0;
    for( int i = 0 ; i < n->edge_len ; i++ ) {
        offset = strndiff(path, n->edges[i]->pattern, n->edges[i]->pattern_len);

        // printf("offset: %d   %s vs %s\n", offset, path, n->edges[i]->pattern );

        // no common, consider insert a new edge
        if ( offset > 0 ) {
            e = n->edges[i];
            break;
        }
    }

    // branch the edge at correct position (avoid broken slugs)
    char *slug_s = strchr(path, '{');
    char *slug_e = strchr(path, '}');
    if ( slug_s && slug_e ) {
        if ( offset > (slug_s - path) && offset < (slug_e - path) ) {
            // break before '{'
            offset = slug_s - path;
        }
    }

    if ( offset == 0 ) {
        // not found, we should just insert a whole new edge
        node * child = r3_tree_create(3);
        r3_node_add_child(n, strndup(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 ( offset == e->pattern_len ) {    // fully-equal to the pattern of the edge

        char * subpath = path + offset;
        int    subpath_len = path_len - offset;

        // there are something more we can insert
        if ( subpath_len > 0 ) {
            return r3_tree_insert_pathl(e->child, subpath, subpath_len, route, data);
        } else {
            // no more path to insert
            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 ( offset < e->pattern_len ) {
        // printf("branch the edge offset: %d\n", offset);


        /* it's partially matched with the pattern,
         * we should split the end point and make a branch here...
         */
        node *c2; // child 1, child 2
        edge *e2; // edge 1, edge 2
        char * s2 = path + offset;
        int s2_len = 0;

        r3_edge_branch(e, offset);

        // here is the new edge from.
        c2 = r3_tree_create(3);
        s2_len = path_len - offset;
        e2 = r3_edge_create(strndup(s2, s2_len), s2_len, c2);
        // printf("edge right: %s\n", e2->pattern);
        r3_node_append_edge(e->child, e2);


        char *op = e->pattern;
        // truncate the original edge pattern 
        e->pattern = strndup(e->pattern, offset);
        e->pattern_len = offset;
        free(op);

        // move n->edges to c1
        c2->endpoint++;
        c2->data = data;

        if (route) {
            route->data = data;
            r3_node_append_route(c2, route);
        }
        return c2;
    } else {
        printf("unexpected route.");
        return NULL;
    }
    return n;
}