2014-05-14 22:08:42 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2014-05-14 12:47:52 -04:00
|
|
|
|
2014-05-14 22:08:42 -04:00
|
|
|
// Jemalloc memory management
|
|
|
|
#include <jemalloc/jemalloc.h>
|
|
|
|
|
2014-05-15 01:39:50 -04:00
|
|
|
// PCRE
|
|
|
|
#include <pcre.h>
|
|
|
|
|
2014-05-14 22:08:42 -04:00
|
|
|
// Judy array
|
|
|
|
#include <Judy.h>
|
|
|
|
|
2014-05-15 06:26:41 -04:00
|
|
|
#include "str.h"
|
2014-05-15 01:39:50 -04:00
|
|
|
#include "node.h"
|
|
|
|
#include "token.h"
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
struct _rnode {
|
|
|
|
redge ** children;
|
|
|
|
int children_len;
|
|
|
|
int children_cap;
|
|
|
|
|
|
|
|
/* the combined regexp pattern string from pattern_tokens */
|
2014-05-15 09:17:30 -04:00
|
|
|
char * combined_pattern;
|
|
|
|
int combined_pattern_len;
|
2014-05-15 06:26:41 -04:00
|
|
|
|
2014-05-15 09:17:30 -04:00
|
|
|
int endpoint;
|
2014-05-15 06:02:10 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _redge {
|
|
|
|
char * pattern;
|
|
|
|
int pattern_len;
|
2014-05-15 09:17:30 -04:00
|
|
|
bool is_slug;
|
2014-05-15 06:02:10 -04:00
|
|
|
rnode * child;
|
|
|
|
};
|
|
|
|
|
2014-05-14 22:08:42 -04:00
|
|
|
// String value as the index http://judy.sourceforge.net/doc/JudySL_3x.htm
|
2014-05-15 01:39:50 -04:00
|
|
|
|
2014-05-15 06:26:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a rnode object
|
|
|
|
*/
|
2014-05-15 01:39:50 -04:00
|
|
|
rnode * rnode_create(int cap) {
|
2014-05-15 09:17:30 -04:00
|
|
|
rnode * n = (rnode*) malloc( sizeof(rnode) );
|
2014-05-15 01:39:50 -04:00
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
n->children = (redge**) malloc( sizeof(redge*) * 10 );
|
2014-05-15 01:39:50 -04:00
|
|
|
n->children_len = 0;
|
|
|
|
n->children_cap = 10;
|
2014-05-15 06:26:41 -04:00
|
|
|
n->endpoint = 0;
|
2014-05-15 09:17:30 -04:00
|
|
|
n->combined_pattern = NULL;
|
2014-05-15 06:02:10 -04:00
|
|
|
// n->edge_patterns = token_array_create(10);
|
2014-05-15 01:39:50 -04:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rnode_free(rnode * tree) {
|
|
|
|
for (int i = 0 ; i < tree->children_len ; i++ ) {
|
2014-05-15 06:02:10 -04:00
|
|
|
redge_free(tree->children[ i ]);
|
2014-05-15 01:39:50 -04:00
|
|
|
}
|
|
|
|
free(tree->children);
|
2014-05-15 06:02:10 -04:00
|
|
|
// token_array_free(tree->edge_patterns);
|
2014-05-15 01:39:50 -04:00
|
|
|
free(tree);
|
|
|
|
tree = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
|
2014-05-15 01:39:50 -04:00
|
|
|
/* parent node, edge pattern, child */
|
2014-05-15 06:02:10 -04:00
|
|
|
bool rnode_add_child(rnode * n, char * pat , rnode *child) {
|
2014-05-15 01:39:50 -04:00
|
|
|
// find the same sub-pattern, if it does not exist, create one
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
redge * e;
|
|
|
|
|
|
|
|
e = rnode_find_edge(n, pat);
|
|
|
|
if (e) {
|
2014-05-15 01:39:50 -04:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
e = redge_create( pat, strlen(pat), child);
|
|
|
|
rnode_append_edge(n, e);
|
|
|
|
// token_array_append(n->edge_patterns, pat);
|
|
|
|
// assert( token_array_len(n->edge_patterns) == n->children_len );
|
2014-05-15 01:39:50 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
|
|
|
|
void rnode_append_edge(rnode *n, redge *e) {
|
2014-05-15 01:39:50 -04:00
|
|
|
if (n->children_len >= n->children_cap) {
|
|
|
|
n->children_cap *= 2;
|
2014-05-15 06:02:10 -04:00
|
|
|
n->children = realloc(n->children, sizeof(redge) * n->children_cap);
|
2014-05-15 01:39:50 -04:00
|
|
|
}
|
2014-05-15 06:02:10 -04:00
|
|
|
n->children[ n->children_len++ ] = e;
|
2014-05-15 01:39:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
redge * rnode_find_edge(rnode * n, char * pat) {
|
|
|
|
redge * e;
|
|
|
|
for (int i = 0 ; i < n->children_len ; i++ ) {
|
|
|
|
e = n->children[i];
|
|
|
|
if ( strcmp(e->pattern, pat) == 0 ) {
|
|
|
|
return e;
|
2014-05-15 01:39:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-05-15 09:17:30 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function combines ['/foo', '/bar', '/{slug}'] into (/foo)|(/bar)|/([^/]+)}
|
|
|
|
*
|
|
|
|
*/
|
2014-05-15 08:38:07 -04:00
|
|
|
void rnode_combine_patterns(rnode * n) {
|
2014-05-15 09:17:30 -04:00
|
|
|
char * cpat;
|
|
|
|
char * p;
|
|
|
|
|
|
|
|
cpat = malloc(128);
|
|
|
|
if (cpat==NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p = cpat;
|
|
|
|
|
2014-05-15 08:38:07 -04:00
|
|
|
redge *e = NULL;
|
|
|
|
for ( int i = 0 ; i < n->children_len ; i++ ) {
|
|
|
|
e = n->children[i];
|
2014-05-15 09:17:30 -04:00
|
|
|
strncat(p++,"(", 1);
|
|
|
|
strncat(p, e->pattern, e->pattern_len);
|
|
|
|
|
|
|
|
p += e->pattern_len;
|
|
|
|
|
|
|
|
strncat(p++,")", 1);
|
|
|
|
|
|
|
|
if ( i + 1 < n->children_len ) {
|
|
|
|
strncat(p++,"|",1);
|
|
|
|
}
|
2014-05-15 08:38:07 -04:00
|
|
|
}
|
2014-05-15 09:17:30 -04:00
|
|
|
n->combined_pattern = cpat;
|
|
|
|
n->combined_pattern_len = p - cpat;
|
2014-05-15 08:38:07 -04:00
|
|
|
}
|
|
|
|
|
2014-05-15 06:26:41 -04:00
|
|
|
|
|
|
|
rnode * rnode_lookup(rnode * tree, char * path, int path_len) {
|
|
|
|
token_array * tokens = split_route_pattern(path, path_len);
|
|
|
|
|
|
|
|
rnode * n = tree;
|
|
|
|
redge * e = NULL;
|
|
|
|
for ( int i = 0 ; i < tokens->len ; i++ ) {
|
|
|
|
e = rnode_find_edge(n, token_array_fetch(tokens, i) );
|
|
|
|
if (!e) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
n = e->child;
|
|
|
|
}
|
|
|
|
if (n->endpoint) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
rnode * rnode_insert_tokens(rnode * tree, token_array * tokens) {
|
|
|
|
rnode * n = tree;
|
|
|
|
redge * e = NULL;
|
|
|
|
for ( int i = 0 ; i < tokens->len ; i++ ) {
|
|
|
|
e = rnode_find_edge(n, token_array_fetch(tokens, i) );
|
|
|
|
if (e) {
|
|
|
|
n = e->child;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// insert node
|
|
|
|
rnode * child = rnode_create(3);
|
2014-05-15 06:26:41 -04:00
|
|
|
rnode_add_child(n, strdup(token_array_fetch(tokens,i)) , child);
|
2014-05-15 06:02:10 -04:00
|
|
|
n = child;
|
|
|
|
}
|
2014-05-15 06:26:41 -04:00
|
|
|
n->endpoint++;
|
2014-05-15 06:02:10 -04:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2014-05-15 06:26:41 -04:00
|
|
|
rnode * rnode_insert_route(rnode *tree, char *route)
|
|
|
|
{
|
|
|
|
return rnode_insert_routel(tree, route, strlen(route) );
|
|
|
|
}
|
|
|
|
|
|
|
|
rnode * rnode_insert_routel(rnode *tree, char *route, int route_len)
|
|
|
|
{
|
|
|
|
token_array * t = split_route_pattern(route, strlen(route));
|
|
|
|
return rnode_insert_tokens(tree, t);
|
|
|
|
}
|
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
void rnode_dump(rnode * n, int level) {
|
|
|
|
if ( n->children_len ) {
|
|
|
|
print_indent(level);
|
|
|
|
printf("*\n");
|
|
|
|
for ( int i = 0 ; i < n->children_len ; i++ ) {
|
|
|
|
redge * e = n->children[i];
|
|
|
|
print_indent(level + 1);
|
|
|
|
printf("+ \"%s\"\n", e->pattern);
|
|
|
|
rnode_dump( e->child, level + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-15 01:39:50 -04:00
|
|
|
|
2014-05-15 06:02:10 -04:00
|
|
|
redge * redge_create(char * pattern, int pattern_len, rnode * child) {
|
|
|
|
redge * edge = (redge*) malloc( sizeof(redge) );
|
|
|
|
edge->pattern = pattern;
|
|
|
|
edge->pattern_len = pattern_len;
|
|
|
|
edge->child = child;
|
2014-05-15 09:17:30 -04:00
|
|
|
edge->is_slug = 0;
|
2014-05-15 06:02:10 -04:00
|
|
|
return edge;
|
2014-05-15 01:39:50 -04:00
|
|
|
}
|
2014-05-15 06:02:10 -04:00
|
|
|
|
|
|
|
void redge_free(redge * e) {
|
|
|
|
free(e->pattern);
|
|
|
|
if ( e->child ) {
|
|
|
|
rnode_free(e->child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|