Merge branch 'master' into feature/stats
Conflicts: bench.html bench_str.csv config.h config.h.in include/r3.h src/node.c
This commit is contained in:
commit
76e4b15787
23 changed files with 382 additions and 1152 deletions
|
@ -28,7 +28,7 @@ script:
|
|||
- make V=1
|
||||
- sudo make install
|
||||
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
|
||||
- if [ "x$VALGRIND" == xyes ]; then valgrind ./tests/.libs/* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
|
||||
- if [ "x$VALGRIND" == xyes ]; then valgrind ./tests/.libs/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
|
||||
|
||||
after_success:
|
||||
- if [ x$COVERALLS == xyes ]; then coveralls ; fi
|
||||
|
|
42
README.md
42
README.md
|
@ -120,9 +120,35 @@ r3_route_free(r1);
|
|||
r3_tree_free(n);
|
||||
```
|
||||
|
||||
Slug
|
||||
-----------------------
|
||||
A slug is a placeholder, which captures the string from the URL as a variable.
|
||||
Slugs will be compiled into regular expression patterns.
|
||||
|
||||
Slugs without specified pattern (like `/user/{userId}`) will be compiled with the `[^/]+` pattern.
|
||||
|
||||
To specify the pattern of a slug, you may write a colon to separate the slug name and the pattern:
|
||||
|
||||
"/user/{userId:\\d+}"
|
||||
|
||||
The above route will use `\d+` as its pattern.
|
||||
|
||||
|
||||
Benchmark
|
||||
Optimization
|
||||
-----------------------
|
||||
Simple regular expressions are optimized through a regexp pattern to opcode
|
||||
compiler, which translates simple patterns into small & fast scanners.
|
||||
|
||||
By using this method, r3 reduces the matching overhead of pcre library.
|
||||
|
||||
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+` or `[^-]+`
|
||||
|
||||
slugs without specified regular expression will be compiled with a `[^/]+` pattern. therefore, it's optimized too.
|
||||
|
||||
Complex regular expressions will still use libpcre to match URL (partially).
|
||||
|
||||
|
||||
Performance
|
||||
-----------------------
|
||||
The routing benchmark from stevegraham/rails' PR <https://github.com/stevegraham/rails/pull/1>:
|
||||
|
||||
|
@ -151,6 +177,19 @@ paths.each do |path|
|
|||
end
|
||||
```
|
||||
|
||||
Function prefix mapping
|
||||
-----------------------
|
||||
|
||||
|Function Prefix |Description |
|
||||
|------------------|------------------------------------------------------------------------------------|
|
||||
|`r3_tree_*` |Tree related operations, which require a node to operate a whole tree |
|
||||
|`r3_node_*` |Single node related operations, which do not go through its own children or parent. |
|
||||
|`r3_edge_*` |Edge related operations |
|
||||
|`r3_route_*` |Route related operations, which are needed only when the tree is defined by routes |
|
||||
|`match_entry_*` |Match entry related operations, a `match_entry` is just like the request parameters |
|
||||
|
||||
|
||||
|
||||
|
||||
Rendering routes with graphviz
|
||||
-------------------------------
|
||||
|
@ -176,6 +215,7 @@ digraph g {
|
|||
|
||||
Use case in PHP
|
||||
-----------------------
|
||||
**not implemented yet**
|
||||
|
||||
```php
|
||||
// Here is the paths data structure
|
||||
|
|
20
bench.html
20
bench.html
|
@ -9,7 +9,7 @@
|
|||
<script src="http://code.highcharts.com/modules/exporting.js"></script>
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
|
||||
<script>
|
||||
$.get('tests/bench_str.csv', function(data) {
|
||||
$.get('bench_str.csv', function(data) {
|
||||
|
||||
var options = {
|
||||
chart: {
|
||||
|
@ -145,7 +145,7 @@
|
|||
},
|
||||
{
|
||||
type: 'area',
|
||||
name: '/post/{year}/{month}',
|
||||
name: 'simple pattern matching',
|
||||
pointInterval: 1000,
|
||||
lineWidth: 1,
|
||||
marker: {
|
||||
|
@ -164,6 +164,17 @@
|
|||
},
|
||||
pointStart: Date.UTC(2014, 5, 16),
|
||||
data: []
|
||||
},
|
||||
{
|
||||
type: 'area',
|
||||
name: 'match_entry with str',
|
||||
pointInterval: 1000,
|
||||
lineWidth: 1,
|
||||
marker: {
|
||||
radius: 3
|
||||
},
|
||||
pointStart: Date.UTC(2014, 5, 16),
|
||||
data: []
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -179,9 +190,8 @@
|
|||
}
|
||||
*/
|
||||
var columns = line.split(/,/);
|
||||
|
||||
var commentText = columns[4];
|
||||
for (var i = 1; i < 4; i++ ) {
|
||||
var commentText = columns[5];
|
||||
for (var i = 1; i < 5; i++ ) {
|
||||
var a = parseInt(columns[i]);
|
||||
var args = a ?
|
||||
(commentText ? { y: a, comment: commentText } : a)
|
||||
|
|
|
@ -461,7 +461,70 @@
|
|||
1400750512,10126746.58
|
||||
1400750536,10568568.26
|
||||
1400762875,10472029.42
|
||||
1400764426,10066458.45,1590373.41,0,flag
|
||||
1400765068,10657617.64,2131810.12,0,flag
|
||||
1400766518,10259200.94,1878279.25,96697.86,flag1
|
||||
1400766623,11057429.08,2113683.19,95835.70,flag2
|
||||
1400764426,10066458.45,1590373.41
|
||||
1400765068,10657617.64,2131810.12
|
||||
1400766518,10259200.94,1878279.25,96697.86
|
||||
1400766623,11057429.08,2113683.19,95835.70
|
||||
1400815975,11316714.26,2165050.14,55188.21
|
||||
1400815990,10826986.93,1780938.43,55188.21
|
||||
1400816005,10584527.76,1707721.44,55924.05
|
||||
1400816427,9376611.56,2006568.41,53092.46
|
||||
1400816438,9096902.53,2108994.21,59074.70
|
||||
1400816448,9260790.48,2131479.91,55188.21
|
||||
1400816458,9303957.38,2110797.39,55924.05
|
||||
1400816525,9330370.85,1985782.06,59074.70
|
||||
1400816594,9389101.94,1989498.64,34663.67
|
||||
1400816645,9201251.49,2105517.01,43240.25
|
||||
1400816815,9228390.29,2097606.06,23301.69
|
||||
1400817268,9242018.45,2109706.16,38479.85
|
||||
1400817280,9320308.27,1891100.64,47662.55
|
||||
1400817392,6448229.88,1994875.02,34663.67
|
||||
1400817671,8654311.52,2094510.75,47662.55
|
||||
1400817706,9362050.27,1981074.38,62601.55
|
||||
1400818067,9247601.69,1944615.34,35848.75
|
||||
1400818654,10797650.12,2550647.32,52428.80
|
||||
1400818717,10964008.21,2607023.59,59074.70
|
||||
1400818725,11160125.46,2574373.69,47127.01
|
||||
1400818732,10829199.02,2557782.44,67650.06
|
||||
1400818739,10859734.88,2538368.71,41527.76
|
||||
1400820693,12547680.62,2375764.20,55924.05
|
||||
1400820703,12815067.19,2375474.47,34379.54
|
||||
1400820719,11693810.54,2231143.55,47662.55
|
||||
1400820728,12612875.15,2357108.19,49932.19
|
||||
1400820868,12158497.75,2598723.80,62601.55
|
||||
1400820877,12254639.62,2583601.86,77672.30
|
||||
1400820886,12274457.34,2393445.83,55188.21
|
||||
1400820922,12218386.22,2604565.56,77672.30
|
||||
1400820933,12443155.46,2361317.46,45590.26
|
||||
1400829105,12110496.08,4797414.85,38479.85
|
||||
1400829117,12258758.55,4129968.45,59074.70
|
||||
1400829143,12339827.27,4775224.01,55924.05
|
||||
1400831278,11421287.15,4742488.93,39945.75
|
||||
1400832805,11676305.28,4832961.50,58254.22
|
||||
1400832811,11785948.52,4137657.27,45590.26
|
||||
1400832831,11918383.46,4859275.06,47662.55
|
||||
1400832837,11650937.22,4734982.85,61680.94
|
||||
1400832892,11728021.34,4274247.24,45590.26
|
||||
1400832912,11580034.68,4752494.99,62601.55
|
||||
1400833017,11890578.32,4501803.27,29330.80
|
||||
1400833024,11715363.55,4726544.41,59074.70
|
||||
1400833045,11813359.08,4828190.72,53092.46
|
||||
1400833051,11082009.03,4721512.49,62601.55
|
||||
1400837359,2709622.75,4773140.52,71089.90
|
||||
1400837501,11958680.82,4777890.52,45590.26
|
||||
1400837621,11423775.75,4679207.46,59074.70,2459430.07
|
||||
1400837636,11534281.98,4192617.73,66576.25,2968590.57
|
||||
1400837657,11693260.66,4815393.82,77672.30,2856236.96
|
||||
1400837667,11834338.05,4822006.81,47662.55,3015821.63
|
||||
1400837677,11999462.15,4854783.73,49932.19,3008349.32
|
||||
1400837696,11814938.63,4740948.30,55188.21,3007002.06
|
||||
1400837706,11535595.30,4712420.14,62601.55,2865728.03
|
||||
1400837716,11928552.18,4833449.01,35848.75,2990344.18
|
||||
1400837725,11873673.72,4275934.73,45590.26,3024045.98
|
||||
1400837735,11805064.50,4855078.95,47662.55,3016256.98
|
||||
1400837744,12041094.07,4815428.09,61680.94,2991090.14
|
||||
1400837754,11766504.83,4848425.07,47662.55,2986385.66
|
||||
1400837764,11979089.24,4257134.48,47662.55,3015693.70
|
||||
1400837774,11190990.08,4331119.44,45590.26,2587281.10
|
||||
1400837785,10306507.50,3909290.89,47662.55,2827471.10
|
||||
1400837797,10323334.38,4221122.48,55924.05,2294463.55
|
Can't render this file because it has a wrong number of fields in line 464.
|
|
@ -1,54 +0,0 @@
|
|||
# - Try to find the CHECK libraries
|
||||
# Once done this will define
|
||||
#
|
||||
# CHECK_FOUND - system has check
|
||||
# CHECK_INCLUDE_DIRS - the check include directory
|
||||
# CHECK_LIBRARIES - check library
|
||||
#
|
||||
# Copyright (c) 2007 Daniel Gollub <gollub@b1-systems.de>
|
||||
# Copyright (c) 2007-2009 Bjoern Ricks <bjoern.ricks@gmail.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
INCLUDE( FindPkgConfig )
|
||||
|
||||
IF ( Check_FIND_REQUIRED )
|
||||
SET( _pkgconfig_REQUIRED "REQUIRED" )
|
||||
ELSE( Check_FIND_REQUIRED )
|
||||
SET( _pkgconfig_REQUIRED "" )
|
||||
ENDIF ( Check_FIND_REQUIRED )
|
||||
|
||||
IF ( CHECK_MIN_VERSION )
|
||||
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
|
||||
ELSE ( CHECK_MIN_VERSION )
|
||||
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
|
||||
ENDIF ( CHECK_MIN_VERSION )
|
||||
|
||||
# Look for CHECK include dir and libraries
|
||||
IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
|
||||
|
||||
FIND_PATH( CHECK_INCLUDE_DIRS check.h )
|
||||
|
||||
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
|
||||
|
||||
IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
||||
SET( CHECK_FOUND 1 )
|
||||
IF ( NOT Check_FIND_QUIETLY )
|
||||
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
|
||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
||||
ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
||||
IF ( Check_FIND_REQUIRED )
|
||||
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
|
||||
ELSE ( Check_FIND_REQUIRED )
|
||||
IF ( NOT Check_FIND_QUIETLY )
|
||||
MESSAGE( STATUS "Could NOT find CHECK" )
|
||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
||||
ENDIF ( Check_FIND_REQUIRED )
|
||||
ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
||||
ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
|
||||
|
||||
# Hide advanced variables from CMake GUIs
|
||||
MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES )
|
|
@ -1,44 +0,0 @@
|
|||
# - Try to find jemalloc headers and libraries.
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(JeMalloc)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# JEMALLOC_ROOT_DIR Set this variable to the root installation of
|
||||
# jemalloc if the module has problems finding
|
||||
# the proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# JEMALLOC_FOUND System has jemalloc libs/headers
|
||||
# JEMALLOC_LIBRARIES The jemalloc library/libraries
|
||||
# JEMALLOC_INCLUDE_DIR The location of jemalloc headers
|
||||
|
||||
find_path(JEMALLOC_ROOT_DIR
|
||||
NAMES include/jemalloc/jemalloc.h
|
||||
)
|
||||
|
||||
find_library(JEMALLOC_LIBRARIES
|
||||
NAMES jemalloc
|
||||
HINTS ${JEMALLOC_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
find_path(JEMALLOC_INCLUDE_DIR
|
||||
NAMES jemalloc/jemalloc.h
|
||||
HINTS ${JEMALLOC_ROOT_DIR}/include
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(JeMalloc DEFAULT_MSG
|
||||
JEMALLOC_LIBRARIES
|
||||
JEMALLOC_INCLUDE_DIR
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
JEMALLOC_ROOT_DIR
|
||||
JEMALLOC_LIBRARIES
|
||||
JEMALLOC_INCLUDE_DIR
|
||||
)
|
|
@ -1,37 +0,0 @@
|
|||
# Copyright (C) 2007-2009 LuaDist.
|
||||
# Created by Peter Kapec <kapecp@gmail.com>
|
||||
# Redistribution and use of this file is allowed according to the terms of the MIT license.
|
||||
# For details see the COPYRIGHT file distributed with LuaDist.
|
||||
# Note:
|
||||
# Searching headers and libraries is very simple and is NOT as powerful as scripts
|
||||
# distributed with CMake, because LuaDist defines directories to search for.
|
||||
# Everyone is encouraged to contact the author with improvements. Maybe this file
|
||||
# becomes part of CMake distribution sometimes.
|
||||
|
||||
# - Find judy
|
||||
# Find the native Judy headers and libraries.
|
||||
#
|
||||
# Judy_INCLUDE_DIRS - where to find judy.h, etc.
|
||||
# Judy_LIBRARIES - List of libraries when using judy.
|
||||
# Judy_FOUND - True if judy found.
|
||||
|
||||
# Look for the header file.
|
||||
FIND_PATH(Judy_INCLUDE_DIR NAMES Judy.h)
|
||||
|
||||
# Look for the library.
|
||||
FIND_LIBRARY(Judy_LIBRARY NAMES judy)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set Judy_FOUND to TRUE if all listed variables are TRUE.
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Judy DEFAULT_MSG Judy_LIBRARY Judy_INCLUDE_DIR)
|
||||
|
||||
# Copy the results to the output variables.
|
||||
IF(Judy_FOUND)
|
||||
SET(Judy_LIBRARIES ${Judy_LIBRARY})
|
||||
SET(Judy_INCLUDE_DIRS ${Judy_INCLUDE_DIR})
|
||||
ELSE(Judy_FOUND)
|
||||
SET(Judy_LIBRARIES)
|
||||
SET(Judy_INCLUDE_DIRS)
|
||||
ENDIF(Judy_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(Judy_INCLUDE_DIRS Judy_LIBRARIES)
|
|
@ -1,37 +0,0 @@
|
|||
# Copyright (C) 2007-2009 LuaDist.
|
||||
# Created by Peter Kapec <kapecp@gmail.com>
|
||||
# Redistribution and use of this file is allowed according to the terms of the MIT license.
|
||||
# For details see the COPYRIGHT file distributed with LuaDist.
|
||||
# Note:
|
||||
# Searching headers and libraries is very simple and is NOT as powerful as scripts
|
||||
# distributed with CMake, because LuaDist defines directories to search for.
|
||||
# Everyone is encouraged to contact the author with improvements. Maybe this file
|
||||
# becomes part of CMake distribution sometimes.
|
||||
|
||||
# - Find pcre
|
||||
# Find the native PCRE headers and libraries.
|
||||
#
|
||||
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
|
||||
# PCRE_LIBRARIES - List of libraries when using pcre.
|
||||
# PCRE_FOUND - True if pcre found.
|
||||
|
||||
# Look for the header file.
|
||||
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
|
||||
|
||||
# Look for the library.
|
||||
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
|
||||
|
||||
# Copy the results to the output variables.
|
||||
IF(PCRE_FOUND)
|
||||
SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
|
||||
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
|
||||
ELSE(PCRE_FOUND)
|
||||
SET(PCRE_LIBRARIES)
|
||||
SET(PCRE_INCLUDE_DIRS)
|
||||
ENDIF(PCRE_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)
|
122
config.h
122
config.h
|
@ -1,122 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* "whether graphviz is enable" */
|
||||
#define ENABLE_GRAPHVIZ test "x$enable_graphviz" = "xyes"
|
||||
<<<<<<< HEAD
|
||||
|
||||
/* "whether statistics is enable" */
|
||||
#define ENABLE_STATS test "x$enable_stats" = "xyes"
|
||||
=======
|
||||
>>>>>>> master
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <jemalloc/jemalloc.h> header file. */
|
||||
/* #undef HAVE_JEMALLOC_JEMALLOC_H */
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#define HAVE_MALLOC 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#define HAVE_REALLOC 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#define HAVE_STRNDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#define HAVE_STRSTR 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "r3"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "r3"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "r3 1.0.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "r3"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.0.0"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if you have the PATH_MAX macro. */
|
||||
/* #undef USE_JEMALLOC */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.0.0"
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
/* #undef malloc */
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
/* #undef realloc */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
25
include/r3.h
25
include/r3.h
|
@ -53,10 +53,8 @@ struct _node {
|
|||
/** compile-time variables here.... **/
|
||||
|
||||
/* the combined regexp pattern string from pattern_tokens */
|
||||
int compare_type;
|
||||
char * combined_pattern;
|
||||
int combined_pattern_len;
|
||||
int ov_cnt;
|
||||
int * ov;
|
||||
pcre * pcre_pattern;
|
||||
pcre_extra * pcre_extra;
|
||||
|
||||
|
@ -76,7 +74,7 @@ struct _edge {
|
|||
|
||||
char * pattern;
|
||||
int pattern_len;
|
||||
|
||||
int opcode;
|
||||
float score;
|
||||
bool has_slug:1;
|
||||
};
|
||||
|
@ -120,7 +118,9 @@ void r3_tree_free(node * tree);
|
|||
|
||||
void r3_edge_free(edge * edge);
|
||||
|
||||
edge * r3_node_add_child(node * n, char * pat , node *child);
|
||||
edge * r3_node_connectl(node * n, char * pat, int len, int strdup, node *child);
|
||||
|
||||
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
|
||||
|
||||
edge * r3_node_find_edge(node * n, char * pat);
|
||||
|
||||
|
@ -190,7 +190,18 @@ void r3_tree_feedback(node *tree, node *end);
|
|||
|
||||
#define METHOD_GET 2
|
||||
#define METHOD_POST 2<<1
|
||||
#define METHOD_PUT 2<<1
|
||||
#define METHOD_DELETE 2<<1
|
||||
#define METHOD_PUT 2<<2
|
||||
#define METHOD_DELETE 2<<3
|
||||
#define METHOD_PATCH 2<<4
|
||||
#define METHOD_HEAD 2<<5
|
||||
#define METHOD_OPTIONS 2<<6
|
||||
|
||||
|
||||
|
||||
int r3_pattern_to_opcode(char * pattern, int pattern_len);
|
||||
|
||||
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 };
|
||||
|
||||
#endif /* !R3_NODE_H */
|
||||
|
|
|
@ -16,9 +16,9 @@ char * slug_compile(char * str, int len);
|
|||
|
||||
bool contains_slug(char * str);
|
||||
|
||||
char * find_slug_pattern(char *s1, int *len);
|
||||
char * slug_find_pattern(char *s1, int *len);
|
||||
|
||||
char * find_slug_placeholder(char *s1, int *len);
|
||||
char * slug_find_placeholder(char *s1, int *len);
|
||||
|
||||
char * inside_slug(char * needle, int needle_len, char *offset);
|
||||
|
||||
|
|
527
install-sh
527
install-sh
|
@ -1,527 +0,0 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2011-11-20.07; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -1,17 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
|
||||
|
||||
set(R3_SRCS node.c str.c list.c token.c edge.c zmalloc.c)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -pipe -g3 -funroll-loops -O0")
|
||||
|
||||
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
||||
set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
||||
|
||||
# add_library(r3 SHARED ${R3_SRCS})
|
||||
add_library(r3 STATIC ${R3_SRCS})
|
||||
target_link_libraries(r3 ${LIBS})
|
||||
install (TARGETS r3 DESTINATION lib)
|
||||
# target_link_libraries(r3 cblas)
|
||||
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
|
|
@ -28,6 +28,7 @@ edge * r3_edge_create(char * pattern, int pattern_len, node * child) {
|
|||
edge * e = (edge*) zmalloc( sizeof(edge) );
|
||||
e->pattern = pattern;
|
||||
e->pattern_len = pattern_len;
|
||||
e->opcode = 0;
|
||||
e->child = child;
|
||||
e->parent = NULL;
|
||||
|
||||
|
@ -81,17 +82,16 @@ node * r3_edge_branch(edge *e, int dl) {
|
|||
e->child->data = NULL;
|
||||
|
||||
// truncate the original edge pattern
|
||||
char *op = e->pattern;
|
||||
char *oldpattern = e->pattern;
|
||||
e->pattern = zstrndup(e->pattern, dl);
|
||||
e->pattern_len = dl;
|
||||
zfree(oldpattern);
|
||||
|
||||
return new_child;
|
||||
}
|
||||
|
||||
void r3_edge_free(edge * e) {
|
||||
if (e->pattern) {
|
||||
zfree(e->pattern);
|
||||
}
|
||||
if ( e->child ) {
|
||||
r3_tree_free(e->child);
|
||||
}
|
||||
|
|
214
src/node.c
214
src/node.c
|
@ -1,20 +1,14 @@
|
|||
#include <config.h>
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Jemalloc memory management
|
||||
// #include <jemalloc/jemalloc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// PCRE
|
||||
#include <pcre.h>
|
||||
|
||||
// Judy array
|
||||
// #include <Judy.h>
|
||||
|
||||
#include "r3.h"
|
||||
#include "r3_define.h"
|
||||
#include "r3_str.h"
|
||||
#include "str_array.h"
|
||||
#include "zmalloc.h"
|
||||
|
@ -61,8 +55,6 @@ node * r3_tree_create(int cap) {
|
|||
n->combined_pattern = NULL;
|
||||
n->pcre_pattern = NULL;
|
||||
n->pcre_extra = NULL;
|
||||
n->ov_cnt = 0;
|
||||
n->ov = NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -72,12 +64,9 @@ void r3_tree_free(node * tree) {
|
|||
r3_edge_free(tree->edges[ i ]);
|
||||
}
|
||||
}
|
||||
if (tree->edges) {
|
||||
zfree(tree->edges);
|
||||
}
|
||||
if (tree->routes) {
|
||||
zfree(tree->routes);
|
||||
}
|
||||
|
||||
if (tree->pcre_pattern) {
|
||||
pcre_free(tree->pcre_pattern);
|
||||
}
|
||||
|
@ -86,21 +75,13 @@ void r3_tree_free(node * tree) {
|
|||
pcre_free_study(tree->pcre_extra);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tree->combined_pattern)
|
||||
zfree(tree->combined_pattern);
|
||||
if (tree->ov)
|
||||
zfree(tree->ov);
|
||||
zfree(tree);
|
||||
tree = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* parent node, edge pattern, child */
|
||||
edge * r3_node_add_child(node * n, char * pat , node *child) {
|
||||
edge * r3_node_connectl(node * n, char * pat, int len, int dupl, node *child) {
|
||||
// find the same sub-pattern, if it does not exist, create one
|
||||
|
||||
edge * e;
|
||||
|
||||
e = r3_node_find_edge(n, pat);
|
||||
|
@ -108,10 +89,11 @@ edge * r3_node_add_child(node * n, char * pat , node *child) {
|
|||
return e;
|
||||
}
|
||||
|
||||
e = r3_edge_create( pat, strlen(pat), child);
|
||||
if (dupl) {
|
||||
pat = zstrndup(pat, len);
|
||||
}
|
||||
e = r3_edge_create(pat, len, child);
|
||||
r3_node_append_edge(n, e);
|
||||
// str_array_append(n->edge_patterns, pat);
|
||||
// assert( str_array_len(n->edge_patterns) == n->edge_len );
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -197,9 +179,15 @@ void r3_tree_compile_patterns(node * n) {
|
|||
p++;
|
||||
|
||||
edge *e = NULL;
|
||||
int opcode_cnt = 0;
|
||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
||||
e = n->edges[i];
|
||||
|
||||
if ( e->opcode )
|
||||
opcode_cnt++;
|
||||
|
||||
if ( e->has_slug ) {
|
||||
// compile "foo/{slug}" to "foo/[^/]+"
|
||||
char * slug_pat = slug_compile(e->pattern, e->pattern_len);
|
||||
strcat(p, slug_pat);
|
||||
} else {
|
||||
|
@ -218,13 +206,15 @@ void r3_tree_compile_patterns(node * n) {
|
|||
|
||||
info("pattern: %s\n",cpat);
|
||||
|
||||
n->ov_cnt = (1 + n->edge_len) * 3;
|
||||
n->ov = (int*) zcalloc(sizeof(int) * n->ov_cnt);
|
||||
|
||||
// if all edges use opcode, we should skip the combined_pattern.
|
||||
if ( opcode_cnt == n->edge_len ) {
|
||||
// zfree(cpat);
|
||||
n->compare_type = NODE_COMPARE_OPCODE;
|
||||
} else {
|
||||
n->compare_type = NODE_COMPARE_PCRE;
|
||||
}
|
||||
|
||||
n->combined_pattern = cpat;
|
||||
n->combined_pattern_len = p - cpat;
|
||||
|
||||
|
||||
const char *error;
|
||||
int erroffset;
|
||||
|
@ -290,47 +280,93 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
|||
edge *e;
|
||||
int rc;
|
||||
int i;
|
||||
int ov_cnt;
|
||||
int restlen;
|
||||
char *pp;
|
||||
char *pp_end = path + path_len;
|
||||
|
||||
if (n->compare_type == NODE_COMPARE_OPCODE) {
|
||||
for (i = 0; i < n->edge_len ; i++ ) {
|
||||
pp = path;
|
||||
e = n->edges[i];
|
||||
switch(e->opcode) {
|
||||
case OP_EXPECT_NOSLASH:
|
||||
while (*pp != '/' && pp < pp_end) pp++;
|
||||
break;
|
||||
case OP_EXPECT_MORE_ALPHA:
|
||||
while ( isalpha(*pp) && pp < pp_end) pp++;
|
||||
break;
|
||||
case OP_EXPECT_MORE_DIGITS:
|
||||
while ( isdigit(*pp) && pp < pp_end) pp++;
|
||||
break;
|
||||
case OP_EXPECT_MORE_WORDS:
|
||||
while ( (isdigit(*pp) || isalpha(*pp)) && pp < pp_end) pp++;
|
||||
break;
|
||||
case OP_EXPECT_NODASH:
|
||||
while (*pp != '-' && pp < pp_end) pp++;
|
||||
break;
|
||||
}
|
||||
// check match
|
||||
if ( (pp - path) > 0) {
|
||||
restlen = pp_end - pp;
|
||||
if (entry) {
|
||||
str_array_append(entry->vars , zstrndup(path, pp - path));
|
||||
}
|
||||
if (restlen == 0) {
|
||||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||
}
|
||||
return r3_tree_matchl(e->child, pp, pp_end - pp, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the pcre_pattern is found, and the pointer is not NULL, then it's
|
||||
// pcre pattern node, we use pcre_exec to match the nodes
|
||||
if (n->pcre_pattern) {
|
||||
info("pcre matching %s on %s\n", n->combined_pattern, path);
|
||||
ov_cnt = (1 + n->edge_len) * 3;
|
||||
int ov[ ov_cnt ];
|
||||
|
||||
rc = pcre_exec(
|
||||
n->pcre_pattern, /* the compiled pattern */
|
||||
|
||||
// PCRE Study makes this slow
|
||||
NULL, // n->pcre_extra, /* no extra data - we didn't study the pattern */
|
||||
n->pcre_extra,
|
||||
path, /* the subject string */
|
||||
path_len, /* the length of the subject */
|
||||
0, /* start at offset 0 in the subject */
|
||||
0, /* default options */
|
||||
n->ov, /* output vector for substring information */
|
||||
n->ov_cnt); /* number of elements in the output vector */
|
||||
ov, /* output vector for substring information */
|
||||
ov_cnt); /* number of elements in the output vector */
|
||||
|
||||
// info("rc: %d\n", rc );
|
||||
// does not match all edges, return NULL;
|
||||
if (rc < 0) {
|
||||
#ifdef DEBUG
|
||||
printf("pcre rc: %d\n", rc );
|
||||
switch(rc)
|
||||
{
|
||||
case PCRE_ERROR_NOMATCH: printf("pcre: no match\n"); break;
|
||||
/*
|
||||
Handle other special cases if you like
|
||||
*/
|
||||
default: printf("pcre matching error '%d' on pattern '%s'\n", rc, n->combined_pattern); break;
|
||||
case PCRE_ERROR_NOMATCH:
|
||||
printf("pcre: no match '%s' on pattern '%s'\n", path, n->combined_pattern);
|
||||
break;
|
||||
|
||||
// Handle other special cases if you like
|
||||
default:
|
||||
printf("pcre matching error '%d' '%s' on pattern '%s'\n", rc, path, n->combined_pattern);
|
||||
break;
|
||||
}
|
||||
// does not match all edges, return NULL;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *substring_start;
|
||||
int substring_length;
|
||||
for (i = 1; i < rc; i++)
|
||||
{
|
||||
char *substring_start = path + n->ov[2*i];
|
||||
int substring_length = n->ov[2*i+1] - n->ov[2*i];
|
||||
substring_start = path + ov[2*i];
|
||||
substring_length = ov[2*i+1] - ov[2*i];
|
||||
// info("%2d: %.*s\n", i, substring_length, substring_start);
|
||||
|
||||
if ( substring_length > 0) {
|
||||
int restlen = path_len - n->ov[1]; // fully match to the end
|
||||
restlen = path_len - ov[1]; // fully match to the end
|
||||
// info("matched item => restlen:%d edges:%d i:%d\n", restlen, n->edge_len, i);
|
||||
|
||||
e = n->edges[i - 1];
|
||||
|
@ -343,7 +379,7 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
|||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||
}
|
||||
// get the length of orginal string: $0
|
||||
return r3_tree_matchl( e->child, path + (n->ov[1] - n->ov[0]), restlen, entry);
|
||||
return r3_tree_matchl( e->child, path + (ov[1] - ov[0]), restlen, entry);
|
||||
}
|
||||
}
|
||||
// does not match
|
||||
|
@ -351,7 +387,7 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
|||
}
|
||||
|
||||
if ( (e = r3_node_find_edge_str(n, path, path_len)) != NULL ) {
|
||||
int restlen = path_len - e->pattern_len;
|
||||
restlen = path_len - e->pattern_len;
|
||||
if (restlen == 0) {
|
||||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||
}
|
||||
|
@ -376,23 +412,19 @@ route * r3_tree_match_route(const node *tree, match_entry * entry) {
|
|||
|
||||
inline edge * r3_node_find_edge_str(const node * n, char * str, int str_len) {
|
||||
int i = 0;
|
||||
int matched_idx = 0;
|
||||
int matched_idx = -1;
|
||||
char firstbyte = *str;
|
||||
for (; i < n->edge_len ; i++ ) {
|
||||
if ( firstbyte == *(n->edges[i]->pattern) ) {
|
||||
matched_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info("matching '%s' with '%s'\n", str, node_edge_pattern(n,i) );
|
||||
if ( strncmp( node_edge_pattern(n,matched_idx), str, node_edge_pattern_len(n,matched_idx) ) == 0 ) {
|
||||
return n->edges[matched_idx];
|
||||
if ( strncmp( node_edge_pattern(n,i), str, node_edge_pattern_len(n,i) ) == 0 ) {
|
||||
return n->edges[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
node * r3_node_create() {
|
||||
node * n = (node*) zmalloc( sizeof(node) );
|
||||
|
@ -474,17 +506,18 @@ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route
|
|||
// 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_cnt = slug_count(path, path_len);
|
||||
if ( slug_cnt > 1 ) {
|
||||
int slug_len;
|
||||
char *p = find_slug_placeholder(path, &slug_len);
|
||||
char *p = slug_find_placeholder(path, &slug_len);
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(p);
|
||||
#endif
|
||||
|
||||
// find the next one
|
||||
// find the next one '{', then break there
|
||||
if(p) {
|
||||
p = find_slug_placeholder(p + slug_len + 1, NULL);
|
||||
p = slug_find_placeholder(p + slug_len + 1, NULL);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
assert(p);
|
||||
|
@ -492,18 +525,62 @@ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route
|
|||
|
||||
// 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;
|
||||
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_add_child(n, zstrndup(path, path_len) , child);
|
||||
// info("edge not found, insert one: %s\n", path);
|
||||
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);
|
||||
|
@ -587,6 +664,9 @@ void r3_tree_dump(node * n, int level) {
|
|||
|
||||
// printf(" hits:%lld score:%.1f ", e->hits, e->score);
|
||||
printf(" score:%.1f ", e->score);
|
||||
if (e->opcode ) {
|
||||
printf(" opcode:%d", e->opcode);
|
||||
}
|
||||
|
||||
if ( e->child ) {
|
||||
printf("\n");
|
||||
|
|
35
src/str.c
35
src/str.c
|
@ -13,6 +13,33 @@
|
|||
#include "str_array.h"
|
||||
#include "zmalloc.h"
|
||||
|
||||
int r3_pattern_to_opcode(char * pattern, int len) {
|
||||
if ( strncmp(pattern, "\\w+",len) == 0 ) {
|
||||
return OP_EXPECT_MORE_WORDS;
|
||||
}
|
||||
if ( strncmp(pattern, "[0-9a-z]+",len) == 0 || strncmp(pattern, "[a-z0-9]+",len) == 0 ) {
|
||||
return OP_EXPECT_MORE_WORDS;
|
||||
}
|
||||
if ( strncmp(pattern, "[a-z]+",len) == 0 ) {
|
||||
return OP_EXPECT_MORE_ALPHA;
|
||||
}
|
||||
if ( strncmp(pattern, "\\d+", len) == 0 ) {
|
||||
return OP_EXPECT_MORE_DIGITS;
|
||||
}
|
||||
if ( strncmp(pattern, "[0-9]+", len) == 0 ) {
|
||||
return OP_EXPECT_MORE_DIGITS;
|
||||
}
|
||||
if ( strncmp(pattern, "[^/]+", len) == 0 ) {
|
||||
return OP_EXPECT_NOSLASH;
|
||||
}
|
||||
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
|
||||
return OP_EXPECT_NODASH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* provide a quick way to count slugs, simply search for '{'
|
||||
*/
|
||||
|
@ -66,7 +93,7 @@ char * inside_slug(char * needle, int needle_len, char *offset) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char * find_slug_placeholder(char *s1, int *len) {
|
||||
char * slug_find_placeholder(char *s1, int *len) {
|
||||
char *c;
|
||||
char *s2;
|
||||
int cnt = 0;
|
||||
|
@ -98,7 +125,7 @@ char * find_slug_placeholder(char *s1, int *len) {
|
|||
/**
|
||||
* given a slug string, duplicate the pattern string of the slug
|
||||
*/
|
||||
char * find_slug_pattern(char *s1, int *len) {
|
||||
char * slug_find_pattern(char *s1, int *len) {
|
||||
char *c;
|
||||
char *s2;
|
||||
int cnt = 1;
|
||||
|
@ -136,7 +163,7 @@ char * slug_compile(char * str, int len)
|
|||
|
||||
// append prefix
|
||||
int s1_len;
|
||||
s1 = find_slug_placeholder(str, &s1_len);
|
||||
s1 = slug_find_placeholder(str, &s1_len);
|
||||
|
||||
if ( s1 == NULL ) {
|
||||
return zstrdup(str);
|
||||
|
@ -153,7 +180,7 @@ char * slug_compile(char * str, int len)
|
|||
|
||||
|
||||
int pat_len;
|
||||
pat = find_slug_pattern(s1, &pat_len);
|
||||
pat = slug_find_pattern(s1, &pat_len);
|
||||
|
||||
if (pat) {
|
||||
*o = '(';
|
||||
|
|
139
test-driver
139
test-driver
|
@ -1,139 +0,0 @@
|
|||
#! /bin/sh
|
||||
# test-driver - basic testsuite driver script.
|
||||
|
||||
scriptversion=2013-07-13.22; # UTC
|
||||
|
||||
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$0: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--]
|
||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=no
|
||||
color_tests=no
|
||||
enable_hard_errors=yes
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
missing_opts=
|
||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
||||
if test x"$missing_opts" != x; then
|
||||
usage_error "the following mandatory options are missing:$missing_opts"
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
usage_error "missing argument"
|
||||
fi
|
||||
|
||||
if test $color_tests = yes; then
|
||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
||||
red='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # No color.
|
||||
else
|
||||
red= grn= lgn= blu= mgn= std=
|
||||
fi
|
||||
|
||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
||||
trap "st=129; $do_exit" 1
|
||||
trap "st=130; $do_exit" 2
|
||||
trap "st=141; $do_exit" 13
|
||||
trap "st=143; $do_exit" 15
|
||||
|
||||
# Test script is run here.
|
||||
"$@" >$log_file 2>&1
|
||||
estatus=$?
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
estatus=1
|
||||
fi
|
||||
|
||||
case $estatus:$expect_failure in
|
||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
||||
esac
|
||||
|
||||
# Report outcome to console.
|
||||
echo "${col}${res}${std}: $test_name"
|
||||
|
||||
# Register the test result, and other relevant metadata.
|
||||
echo ":test-result: $res" > $trs_file
|
||||
echo ":global-test-result: $res" >> $trs_file
|
||||
echo ":recheck: $recheck" >> $trs_file
|
||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -1,24 +0,0 @@
|
|||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||
find_package(Check REQUIRED)
|
||||
find_package(PCRE REQUIRED)
|
||||
# find_package(Judy REQUIRED)
|
||||
|
||||
if (NOT CHECK_FOUND)
|
||||
message(STATUS "Skipping unit tests, Check library not found!")
|
||||
else (NOT CHECK_FOUND)
|
||||
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3)
|
||||
|
||||
include_directories(${CHECK_INCLUDE_DIRS})
|
||||
# include_directories("${PROJECT_SOURCE_DIR}/include/r2")
|
||||
add_executable(test_r3 test_tree.c)
|
||||
target_link_libraries(test_r3 ${TEST_LIBS})
|
||||
|
||||
add_custom_command(
|
||||
TARGET test_r3 POST_BUILD
|
||||
COMMENT "Running unit tests"
|
||||
COMMAND test_r3
|
||||
)
|
||||
endif (NOT CHECK_FOUND)
|
||||
|
||||
|
|
@ -14,7 +14,6 @@ noinst_HEADERS = \
|
|||
$(NULL)
|
||||
|
||||
dist_noinst_DATA = \
|
||||
bench_str.csv \
|
||||
$(NULL)
|
||||
|
||||
if USE_JEMALLOC
|
||||
|
|
|
@ -450,10 +450,18 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
|||
assert( *((int*) m->data) == 999 );
|
||||
|
||||
|
||||
BENCHMARK(string_dispatch)
|
||||
|
||||
BENCHMARK(str_dispatch)
|
||||
r3_tree_matchl(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
|
||||
END_BENCHMARK(string_dispatch)
|
||||
BENCHMARK_SUMMARY(string_dispatch);
|
||||
END_BENCHMARK(str_dispatch)
|
||||
BENCHMARK_SUMMARY(str_dispatch);
|
||||
|
||||
BENCHMARK(str_match_entry)
|
||||
match_entry * e = match_entry_createl("/qux/bar/corge", strlen("/qux/bar/corge") );
|
||||
r3_tree_match_entry(n , e);
|
||||
zfree(e);
|
||||
END_BENCHMARK(str_match_entry)
|
||||
BENCHMARK_SUMMARY(str_match_entry);
|
||||
|
||||
|
||||
node * tree2 = r3_tree_create(1);
|
||||
|
@ -465,6 +473,6 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
|||
END_BENCHMARK(pcre_dispatch)
|
||||
BENCHMARK_SUMMARY(pcre_dispatch);
|
||||
|
||||
BENCHMARK_RECORD_CSV("bench_str.csv", 3, BR(string_dispatch), BR(pcre_dispatch), BR(tree_compile) );
|
||||
BENCHMARK_RECORD_CSV("bench_str.csv", 4, BR(str_dispatch), BR(pcre_dispatch), BR(tree_compile), BR(str_match_entry) );
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -65,23 +65,4 @@ void bench_append_csv(char *filename, int countOfB, ...);
|
|||
|
||||
#define BR(b) &b
|
||||
|
||||
|
||||
#define BENCHMARK(B) \
|
||||
bench B; B.N = 5000000; B.R = 3; \
|
||||
bench_start(&B); \
|
||||
for (int _r = 0; _r < B.R ; _r++ ) { \
|
||||
for (int _i = 0; _i < B.N ; _i++ ) {
|
||||
|
||||
#define END_BENCHMARK(B) \
|
||||
} \
|
||||
} \
|
||||
bench_stop(&B);
|
||||
|
||||
#define BENCHMARK_SUMMARY(B) bench_print_summary(&B);
|
||||
|
||||
#define BENCHMARK_RECORD_CSV(B,filename) \
|
||||
FILE *fp = fopen(filename, "a+"); \
|
||||
fprintf(fp, "%ld,%.2f\n", unixtime(), (B.N * B.R) / (B.end - B.start)); \
|
||||
fclose(fp);
|
||||
|
||||
#endif /* !BENCH_H */
|
||||
|
|
|
@ -13,6 +13,15 @@
|
|||
#include "str_array.h"
|
||||
#include "zmalloc.h"
|
||||
|
||||
START_TEST (test_pattern_to_opcode)
|
||||
{
|
||||
ck_assert( r3_pattern_to_opcode("\\w+", strlen("\\w+")) == OP_EXPECT_MORE_WORDS );
|
||||
ck_assert( r3_pattern_to_opcode("\\d+", strlen("\\d+")) == OP_EXPECT_MORE_DIGITS );
|
||||
ck_assert( r3_pattern_to_opcode("[^/]+",strlen("[^/]+")) == OP_EXPECT_NOSLASH );
|
||||
ck_assert( r3_pattern_to_opcode("[^-]+",strlen("[^-]+")) == OP_EXPECT_NODASH );
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_slug_compile)
|
||||
{
|
||||
char * path = "/user/{id}";
|
||||
|
@ -41,24 +50,24 @@ START_TEST (test_contains_slug)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_find_slug_pattern)
|
||||
START_TEST (test_slug_find_pattern)
|
||||
{
|
||||
int len;
|
||||
char * namerex = find_slug_pattern("{name:\\s+}", &len);
|
||||
char * namerex = slug_find_pattern("{name:\\s+}", &len);
|
||||
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST (test_find_slug_placeholder)
|
||||
START_TEST (test_slug_find_placeholder)
|
||||
{
|
||||
int slug_len = 0;
|
||||
char * slug;
|
||||
slug = find_slug_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
|
||||
slug = slug_find_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
|
||||
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
|
||||
|
||||
|
||||
slug = find_slug_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
|
||||
slug = slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
|
||||
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
|
||||
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
|
||||
}
|
||||
|
@ -86,10 +95,10 @@ START_TEST (test_slug_count)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_find_slug_placeholder_with_broken_slug)
|
||||
START_TEST (test_slug_find_placeholder_with_broken_slug)
|
||||
{
|
||||
int slug_len = 0;
|
||||
char * slug = find_slug_placeholder("/user/{name:\\s+/to/{id", &slug_len);
|
||||
char * slug = slug_find_placeholder("/user/{name:\\s+/to/{id", &slug_len);
|
||||
ck_assert(! slug);
|
||||
}
|
||||
END_TEST
|
||||
|
@ -101,11 +110,12 @@ Suite* r3_suite (void) {
|
|||
tcase_set_timeout(tcase, 30);
|
||||
tcase_add_test(tcase, test_contains_slug);
|
||||
tcase_add_test(tcase, test_inside_slug);
|
||||
tcase_add_test(tcase, test_find_slug_pattern);
|
||||
tcase_add_test(tcase, test_find_slug_placeholder);
|
||||
tcase_add_test(tcase, test_find_slug_placeholder_with_broken_slug);
|
||||
tcase_add_test(tcase, test_slug_find_pattern);
|
||||
tcase_add_test(tcase, test_slug_find_placeholder);
|
||||
tcase_add_test(tcase, test_slug_find_placeholder_with_broken_slug);
|
||||
tcase_add_test(tcase, test_slug_count);
|
||||
tcase_add_test(tcase, test_slug_compile);
|
||||
tcase_add_test(tcase, test_pattern_to_opcode);
|
||||
|
||||
suite_add_tcase(suite, tcase);
|
||||
return suite;
|
||||
|
|
|
@ -32,7 +32,7 @@ START_TEST (test_r3_node_find_edge)
|
|||
|
||||
node * child = r3_tree_create(3);
|
||||
|
||||
fail_if( r3_node_add_child(n, zstrdup("/add") , child) == FALSE );
|
||||
fail_if( r3_node_connect(n, zstrdup("/add") , child) == FALSE );
|
||||
|
||||
fail_if( r3_node_find_edge(n, "/add") == NULL );
|
||||
fail_if( r3_node_find_edge(n, "/bar") != NULL );
|
||||
|
@ -42,22 +42,25 @@ START_TEST (test_r3_node_find_edge)
|
|||
END_TEST
|
||||
|
||||
|
||||
START_TEST (test_compile)
|
||||
{
|
||||
str_array *t;
|
||||
static node * create_simple_str_tree() {
|
||||
node * n;
|
||||
n = r3_tree_create(10);
|
||||
|
||||
|
||||
node *m;
|
||||
edge *e ;
|
||||
|
||||
r3_tree_insert_path(n, "/zoo", NULL);
|
||||
r3_tree_insert_path(n, "/foo", NULL);
|
||||
r3_tree_insert_path(n, "/bar", NULL);
|
||||
r3_tree_compile(n);
|
||||
fail_if( n->combined_pattern );
|
||||
fail_if( NULL == r3_node_find_edge_str(n, "/", strlen("/") ) );
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
START_TEST (test_compile)
|
||||
{
|
||||
str_array *t;
|
||||
node * n = create_simple_str_tree();
|
||||
|
||||
node *m;
|
||||
edge *e ;
|
||||
|
||||
#ifdef DEBUG
|
||||
r3_tree_dump(n, 0);
|
||||
|
@ -165,7 +168,6 @@ START_TEST (test_pcre_patterns_insert_3)
|
|||
matched = r3_tree_match(n, "/post/11", NULL);
|
||||
ck_assert(!matched);
|
||||
|
||||
|
||||
matched = r3_tree_match(n, "/post/11/", NULL);
|
||||
ck_assert(!matched);
|
||||
|
||||
|
|
Loading…
Reference in a new issue