Compare commits
154 commits
edge-array
...
2.0
Author | SHA1 | Date | |
---|---|---|---|
ade1527bef | |||
|
c1aab00c40 | ||
|
9887545ab0 | ||
|
c105117b40 | ||
|
9168f7e4d4 | ||
|
58d8b0c028 | ||
|
91405adda5 | ||
|
b6639e557f | ||
|
c8123430a9 | ||
|
9b69f38527 | ||
|
25cc816025 | ||
|
edbeb0631d | ||
|
04d52a6dd1 | ||
|
cfed420cd3 | ||
|
76e2770304 | ||
|
90450def8b | ||
|
2f3e0b01ff | ||
|
bf11f8e2e6 | ||
|
f0dd25bd53 | ||
|
e533bae646 | ||
|
b44f052897 | ||
|
06c4fc41bf | ||
|
35c5d13df8 | ||
|
4f3c1cd994 | ||
|
5114d894e5 | ||
|
79a3bc7c50 | ||
|
9c8feff07f | ||
|
b13dc8aa6e | ||
|
eca8d9992e | ||
|
c9743f3904 | ||
|
383717a8c7 | ||
|
673bb2f6d9 | ||
|
4babe735e8 | ||
|
0072b618b6 | ||
|
00ec8b7f2b | ||
|
d2fcf2f2d4 | ||
|
da0c89b6db | ||
|
3228fb8cb5 | ||
|
ff1ef2c148 | ||
|
ac7af9697c | ||
|
36198aefba | ||
|
e20e48a5ce | ||
|
79fd587615 | ||
|
1b9e007dfc | ||
|
81f77ffe5a | ||
|
0d70b8f5de | ||
|
577cfa0ccb | ||
|
3dac164cec | ||
|
f8a3741211 | ||
|
845c47907f | ||
|
2ad6b4c4f0 | ||
|
3364df80ee | ||
|
db91289ab6 | ||
|
d516237aab | ||
|
41685d402d | ||
|
27d4d3191e | ||
|
fd34c7244a | ||
|
2b332bffba | ||
|
91cfc9d282 | ||
|
fdc698f924 | ||
|
0485554d44 | ||
|
4b066dd0fc | ||
|
43666a1183 | ||
|
3f410ef5d4 | ||
|
8e18a995d8 | ||
|
410f66bc1a | ||
|
848b8efdca | ||
|
2a08bc62d5 | ||
|
917fa6e385 | ||
|
4ab222a308 | ||
|
9761bdeec3 | ||
|
69e31ce07a | ||
|
22a6b99b34 | ||
|
8abc03ea56 | ||
|
b3dbf75da5 | ||
|
afd2c486c6 | ||
|
e701bfd596 | ||
|
d1c06cd3e9 | ||
|
2be2a08750 | ||
|
e9afe4b6cf | ||
|
3b9bb5745a | ||
|
179ee52801 | ||
|
081ccb2bde | ||
|
cf92c9dc96 | ||
|
6565274ce8 | ||
|
1fceec760f | ||
|
2f96c59929 | ||
|
a2396fe15b | ||
|
2b37680087 | ||
|
59d182b1c1 | ||
|
1eeff1598a | ||
|
f8131b53d6 | ||
|
55de164023 | ||
|
8d0b90f6e1 | ||
|
5cab368af2 | ||
|
021c54308a | ||
|
0d78599a57 | ||
|
234e64f584 | ||
|
7e4c74d625 | ||
|
267ab34c36 | ||
|
cefefb239a | ||
|
341a29387b | ||
|
9411039fce | ||
|
ffc9e8571b | ||
|
75438ef3d3 | ||
|
0ba956159c | ||
|
5a644ee046 | ||
|
ef910789c0 | ||
|
67fa8929f7 | ||
|
839001afec | ||
|
40e0e1c2a0 | ||
|
b7c0132fa9 | ||
|
400768394d | ||
|
c609003c95 | ||
|
44ee48724f | ||
|
82611c93b5 | ||
|
daee40756c | ||
|
03031e02aa | ||
|
c3ef959539 | ||
|
29a2a934d0 | ||
|
ca5ad7497e | ||
|
49ffb454f7 | ||
|
ef55fb9cdb | ||
|
1f1ab15cdd | ||
|
b0971e1553 | ||
|
c128cdef13 | ||
|
3808cb37aa | ||
|
a2f5205bc5 | ||
|
973a2cb85c | ||
|
6275e8724c | ||
|
e5ef80a200 | ||
|
5e6252d8a3 | ||
|
63577cfecc | ||
|
88dc323f7f | ||
|
38651578f9 | ||
|
122d85d9e1 | ||
|
520dba47a5 | ||
|
dbc18a86c4 | ||
|
2484b7328c | ||
|
af8acd0286 | ||
|
35b8bb1cf2 | ||
|
84a7d83812 | ||
|
0407c48884 | ||
|
b52af2acbd | ||
|
150f7953a2 | ||
|
acb2ff1767 | ||
|
cd430968ef | ||
|
4ce9068963 | ||
|
d4850d3564 | ||
|
28726b27af | ||
|
89e4517772 | ||
|
f795785dce | ||
|
2f3bcb7116 | ||
|
b70c239b2c |
70 changed files with 2506 additions and 1599 deletions
70
.github/workflows/ci.yml
vendored
Normal file
70
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
name: ci
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
autotools:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -qq check lcov
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --enable-check --enable-debug --enable-gcov
|
||||||
|
make V=1
|
||||||
|
- name: Install
|
||||||
|
run: sudo make install
|
||||||
|
- name: Run tests
|
||||||
|
run: make check
|
||||||
|
- name: Collect coverage
|
||||||
|
run: lcov --capture -d '.' --exclude '/usr*' -o coverage.info
|
||||||
|
- name: Upload coverage
|
||||||
|
if: github.repository == 'c9s/r3'
|
||||||
|
uses: coverallsapp/github-action@1.1.3
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
path-to-lcov: coverage.info
|
||||||
|
|
||||||
|
cmake:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -qq check ninja-build
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build and test
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake -GNinja ..
|
||||||
|
ninja -v
|
||||||
|
ctest --verbose
|
||||||
|
|
||||||
|
sanitizers:
|
||||||
|
name: ${{ matrix.sanitizer }}-sanitizer [${{ matrix.compiler }}]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
compiler: [gcc, clang]
|
||||||
|
sanitizer: [thread, undefined, leak, address]
|
||||||
|
steps:
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -qq check
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
CC: ${{ matrix.compiler }}
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
CFLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-sanitize-recover=all -fno-omit-frame-pointer" cmake ..
|
||||||
|
VERBOSE=1 make all
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest --verbose
|
21
.github/workflows/coverity.yml
vendored
Normal file
21
.github/workflows/coverity.yml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: coverity
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [2.0]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
if: github.repository == 'c9s/r3'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --enable-check
|
||||||
|
- uses: vapier/coverity-scan-action@v1
|
||||||
|
with:
|
||||||
|
project: r3
|
||||||
|
email: yoanlin93+github@gmail.com
|
||||||
|
token: ${{ secrets.COVERITY_TOKEN }}
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -51,3 +51,8 @@ autoscan.log
|
||||||
r3.pc
|
r3.pc
|
||||||
stamp-h1
|
stamp-h1
|
||||||
tests/bench_str.csv
|
tests/bench_str.csv
|
||||||
|
tests/check_host
|
||||||
|
|
||||||
|
config.h.in
|
||||||
|
examples/simple
|
||||||
|
examples/simple_cpp
|
||||||
|
|
5
.travis-ci/after_success.sh
Executable file
5
.travis-ci/after_success.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ x$COVERALLS == xyes ]; then
|
||||||
|
coveralls --exclude php --exclude 3rdparty
|
||||||
|
fi
|
24
.travis-ci/install.sh
Executable file
24
.travis-ci/install.sh
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -qq \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
build-essential \
|
||||||
|
check \
|
||||||
|
clang \
|
||||||
|
cmake \
|
||||||
|
graphviz-dev \
|
||||||
|
libjemalloc-dev \
|
||||||
|
libpcre2-dev \
|
||||||
|
libtool \
|
||||||
|
ninja-build \
|
||||||
|
pkg-config
|
||||||
|
|
||||||
|
if [ x$COVERALLS == xyes ]; then
|
||||||
|
pip install cpp-coveralls
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x$VALGRIND == xyes ]; then
|
||||||
|
apt-get install valgrind
|
||||||
|
fi
|
18
.travis-ci/script-autotools.sh
Executable file
18
.travis-ci/script-autotools.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -ev
|
||||||
|
|
||||||
|
./autogen.sh
|
||||||
|
./configure --enable-check $CONFIGURE_OPTION
|
||||||
|
make V=1
|
||||||
|
make install
|
||||||
|
if [ x$VALGRIND == xyes ]; then
|
||||||
|
make check
|
||||||
|
else
|
||||||
|
make check V=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# XXX: tracing memory leak, disabled for some mystery reason for automake...
|
||||||
|
#if [ x$VALGRIND == xyes && x$DEBUG == xyes ]; then
|
||||||
|
# valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full
|
||||||
|
#fi
|
8
.travis-ci/script-cmake.sh
Executable file
8
.travis-ci/script-cmake.sh
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -ev
|
||||||
|
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake -GNinja ..
|
||||||
|
ninja -v
|
||||||
|
ctest
|
119
.travis.yml
119
.travis.yml
|
@ -1,7 +1,8 @@
|
||||||
language: c
|
language: c
|
||||||
|
sudo: required
|
||||||
|
|
||||||
compiler:
|
services:
|
||||||
- gcc
|
- docker
|
||||||
|
|
||||||
git:
|
git:
|
||||||
depth: 1
|
depth: 1
|
||||||
|
@ -9,34 +10,102 @@ git:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc' COVERALLS=yes VALGRIND=no DEBUG=yes
|
env:
|
||||||
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=no
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: CONFIGURE_OPTION='--enable-debug --enable-gcov' COVERALLS=yes VALGRIND=yes DEBUG=yes LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/
|
env:
|
||||||
# -D_BSD_SOURCE=1 is for asprintf
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/local/clang-3.4/bin/llvm-symbolizer CFLAGS='-fsanitize=address -g -O1 -D_BSD_SOURCE=1' CXX=clang++ CXXFLAGS='-fsanitize=address -g -O1 -D_BSD_SOURCE=1'
|
env:
|
||||||
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=clang
|
||||||
|
- CXX=clang++
|
||||||
|
- compiler: gcc
|
||||||
|
env:
|
||||||
|
- TYPE=cmake
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
|
#power Jobs Added
|
||||||
|
- compiler: gcc
|
||||||
|
arch: pc64le
|
||||||
|
env:
|
||||||
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=no
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
|
- compiler: gcc
|
||||||
|
arch: ppc64le
|
||||||
|
env:
|
||||||
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
|
- compiler: clang
|
||||||
|
arch: ppc64le
|
||||||
|
env:
|
||||||
|
- TYPE=autotools
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=clang
|
||||||
|
- CXX=clang++
|
||||||
|
- compiler: gcc
|
||||||
|
arch: ppc64le
|
||||||
|
env:
|
||||||
|
- TYPE=cmake
|
||||||
|
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
||||||
|
- COVERALLS=yes
|
||||||
|
- VALGRIND=yes
|
||||||
|
- DEBUG=yes
|
||||||
|
- CC=gcc
|
||||||
|
- CXX=g++
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- docker run -d
|
||||||
|
--name build
|
||||||
|
-v $(pwd):/travis
|
||||||
|
-e "CONFIGURE_OPTION=$CONFIGURE_OPTION"
|
||||||
|
-e "COVERALLS=$COVERALLS"
|
||||||
|
-e "VALGRIND=$VALGRIND"
|
||||||
|
-e "DEBUG=$DEBUG"
|
||||||
|
-e "CC=$CC"
|
||||||
|
-e "CXX=$CXX"
|
||||||
|
ubuntu:16.04
|
||||||
|
tail -f /dev/null
|
||||||
|
- docker ps
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- sudo apt-get update -qq
|
- docker exec -t build bash -c "cd /travis && .travis-ci/install.sh"
|
||||||
- sudo apt-get install -qq automake pkg-config build-essential libtool automake autoconf m4 gnulib
|
|
||||||
- sudo apt-get install -qq check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1
|
|
||||||
- sudo apt-get install -qq graphviz-dev graphviz
|
|
||||||
- if [ "x$COVERALLS" == xyes ]; then sudo pip install cpp-coveralls; fi
|
|
||||||
- if [ "x$VALGRIND" == xyes ]; then sudo apt-get install valgrind; fi
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- sudo ldconfig
|
|
||||||
script:
|
script:
|
||||||
- ./autogen.sh
|
- docker exec -t build bash -c "cd /travis && .travis-ci/script-$TYPE.sh"
|
||||||
- ./configure --enable-check $CONFIGURE_OPTION
|
|
||||||
- make V=1
|
|
||||||
- sudo make install
|
|
||||||
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
|
|
||||||
# XXX: tracing memory leak, disabled for some mystery reason for automake...
|
|
||||||
# - if [ "x$VALGRIND" == xyes && "x$DEBUG" == xyes ]; then valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- if [ x$COVERALLS == xyes ]; then coveralls --exclude php --exclude 3rdparty; fi
|
- docker exec -t build bash -c "cd /travis && .travis-ci/after_success.sh"
|
||||||
|
|
||||||
cache:
|
|
||||||
apt: true
|
|
||||||
|
|
6
3rdparty/CMakeLists.txt
vendored
6
3rdparty/CMakeLists.txt
vendored
|
@ -1,6 +0,0 @@
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}")
|
|
||||||
set(lib3rdparty_SRCS zmalloc.c)
|
|
||||||
add_library(lib3rdparty STATIC ${lib3rdparty_SRCS})
|
|
||||||
# add_library(r3 SHARED ${libr3_SRCS})
|
|
||||||
# target_link_libraries(r3 cblas)
|
|
||||||
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
|
|
14
3rdparty/Makefile.am
vendored
14
3rdparty/Makefile.am
vendored
|
@ -1,14 +0,0 @@
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
|
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libr3ext.la
|
|
||||||
libr3ext_la_SOURCES = zmalloc.c
|
|
||||||
libr3ext_la_LIBADD=$(DEPS_LIBS)
|
|
||||||
# noinst_LIBRARIES = libr3ext.la
|
|
||||||
libr3ext_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/3rdparty -Wall -std=c99
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
|
||||||
zmalloc.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
|
|
368
3rdparty/zmalloc.c
vendored
368
3rdparty/zmalloc.c
vendored
|
@ -1,368 +0,0 @@
|
||||||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of Redis nor the names of its contributors may be used
|
|
||||||
* to endorse or promote products derived from this software without
|
|
||||||
* specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* This function provide us access to the original libc free(). This is useful
|
|
||||||
* for instance to free results obtained by backtrace_symbols(). We need
|
|
||||||
* to define this function before including zmalloc.h that may shadow the
|
|
||||||
* free implementation if we use jemalloc or another non standard allocator. */
|
|
||||||
void zlibc_free(void *ptr) {
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "config.h"
|
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_MALLOC_SIZE
|
|
||||||
#define PREFIX_SIZE (0)
|
|
||||||
#else
|
|
||||||
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
|
|
||||||
#define PREFIX_SIZE (sizeof(long long))
|
|
||||||
#else
|
|
||||||
#define PREFIX_SIZE (sizeof(size_t))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Explicitly override malloc/free etc when using tcmalloc. */
|
|
||||||
#if defined(USE_TCMALLOC)
|
|
||||||
#define malloc(size) tc_malloc(size)
|
|
||||||
#define calloc(count,size) tc_calloc(count,size)
|
|
||||||
#define realloc(ptr,size) tc_realloc(ptr,size)
|
|
||||||
#define free(ptr) tc_free(ptr)
|
|
||||||
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
|
|
||||||
#include <jemalloc/jemalloc.h>
|
|
||||||
#define malloc(size) je_malloc(size)
|
|
||||||
#define calloc(count,size) je_calloc(count,size)
|
|
||||||
#define realloc(ptr,size) je_realloc(ptr,size)
|
|
||||||
#define free(ptr) je_free(ptr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ATOMIC
|
|
||||||
#define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
|
|
||||||
#define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
|
|
||||||
#else
|
|
||||||
#define update_zmalloc_stat_add(__n) do { \
|
|
||||||
pthread_mutex_lock(&used_memory_mutex); \
|
|
||||||
used_memory += (__n); \
|
|
||||||
pthread_mutex_unlock(&used_memory_mutex); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define update_zmalloc_stat_sub(__n) do { \
|
|
||||||
pthread_mutex_lock(&used_memory_mutex); \
|
|
||||||
used_memory -= (__n); \
|
|
||||||
pthread_mutex_unlock(&used_memory_mutex); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define update_zmalloc_stat_alloc(__n) do { \
|
|
||||||
size_t _n = (__n); \
|
|
||||||
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
|
||||||
if (zmalloc_thread_safe) { \
|
|
||||||
update_zmalloc_stat_add(_n); \
|
|
||||||
} else { \
|
|
||||||
used_memory += _n; \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define update_zmalloc_stat_free(__n) do { \
|
|
||||||
size_t _n = (__n); \
|
|
||||||
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
|
|
||||||
if (zmalloc_thread_safe) { \
|
|
||||||
update_zmalloc_stat_sub(_n); \
|
|
||||||
} else { \
|
|
||||||
used_memory -= _n; \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
static size_t used_memory = 0;
|
|
||||||
static int zmalloc_thread_safe = 0;
|
|
||||||
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
static void zmalloc_default_oom(size_t size) {
|
|
||||||
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
|
|
||||||
size);
|
|
||||||
fflush(stderr);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
|
|
||||||
|
|
||||||
void *zmalloc(size_t size) {
|
|
||||||
void *ptr = malloc(size+PREFIX_SIZE);
|
|
||||||
|
|
||||||
if (!ptr) zmalloc_oom_handler(size);
|
|
||||||
#ifdef HAVE_MALLOC_SIZE
|
|
||||||
update_zmalloc_stat_alloc(zmalloc_size(ptr));
|
|
||||||
return ptr;
|
|
||||||
#else
|
|
||||||
*((size_t*)ptr) = size;
|
|
||||||
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
|
|
||||||
return (char*)ptr+PREFIX_SIZE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void *zcalloc(size_t size) {
|
|
||||||
void *ptr = calloc(1, size+PREFIX_SIZE);
|
|
||||||
|
|
||||||
if (!ptr) zmalloc_oom_handler(size);
|
|
||||||
#ifdef HAVE_MALLOC_SIZE
|
|
||||||
update_zmalloc_stat_alloc(zmalloc_size(ptr));
|
|
||||||
return ptr;
|
|
||||||
#else
|
|
||||||
*((size_t*)ptr) = size;
|
|
||||||
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
|
|
||||||
return (char*)ptr+PREFIX_SIZE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void *zrealloc(void *ptr, size_t size) {
|
|
||||||
#ifndef HAVE_MALLOC_SIZE
|
|
||||||
void *realptr;
|
|
||||||
#endif
|
|
||||||
size_t oldsize;
|
|
||||||
void *newptr;
|
|
||||||
|
|
||||||
if (ptr == NULL) return zmalloc(size);
|
|
||||||
#ifdef HAVE_MALLOC_SIZE
|
|
||||||
oldsize = zmalloc_size(ptr);
|
|
||||||
newptr = realloc(ptr,size);
|
|
||||||
if (!newptr) zmalloc_oom_handler(size);
|
|
||||||
|
|
||||||
update_zmalloc_stat_free(oldsize);
|
|
||||||
update_zmalloc_stat_alloc(zmalloc_size(newptr));
|
|
||||||
return newptr;
|
|
||||||
#else
|
|
||||||
realptr = (char*)ptr-PREFIX_SIZE;
|
|
||||||
oldsize = *((size_t*)realptr);
|
|
||||||
newptr = realloc(realptr,size+PREFIX_SIZE);
|
|
||||||
if (!newptr) zmalloc_oom_handler(size);
|
|
||||||
|
|
||||||
*((size_t*)newptr) = size;
|
|
||||||
update_zmalloc_stat_free(oldsize);
|
|
||||||
update_zmalloc_stat_alloc(size);
|
|
||||||
return (char*)newptr+PREFIX_SIZE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Provide zmalloc_size() for systems where this function is not provided by
|
|
||||||
* malloc itself, given that in that case we store a header with this
|
|
||||||
* information as the first bytes of every allocation. */
|
|
||||||
#ifndef HAVE_MALLOC_SIZE
|
|
||||||
size_t zmalloc_size(void *ptr) {
|
|
||||||
void *realptr = (char*)ptr-PREFIX_SIZE;
|
|
||||||
size_t size = *((size_t*)realptr);
|
|
||||||
/* Assume at least that all the allocations are padded at sizeof(long) by
|
|
||||||
* the underlying allocator. */
|
|
||||||
if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
|
|
||||||
return size+PREFIX_SIZE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void zfree(void *ptr) {
|
|
||||||
#ifndef HAVE_MALLOC_SIZE
|
|
||||||
void *realptr;
|
|
||||||
size_t oldsize;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ptr == NULL) return;
|
|
||||||
#ifdef HAVE_MALLOC_SIZE
|
|
||||||
update_zmalloc_stat_free(zmalloc_size(ptr));
|
|
||||||
free(ptr);
|
|
||||||
#else
|
|
||||||
realptr = (char*)ptr-PREFIX_SIZE;
|
|
||||||
oldsize = *((size_t*)realptr);
|
|
||||||
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
|
|
||||||
free(realptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
char *zstrdup(const char *s) {
|
|
||||||
size_t l = strlen(s)+1;
|
|
||||||
char *p = zmalloc(l);
|
|
||||||
|
|
||||||
memcpy(p,s,l);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * zstrndup (const char *s, size_t n)
|
|
||||||
{
|
|
||||||
char *result;
|
|
||||||
size_t len = strlen (s);
|
|
||||||
|
|
||||||
if (n < len)
|
|
||||||
len = n;
|
|
||||||
|
|
||||||
result = (char *) zmalloc (len + 1);
|
|
||||||
if (!result)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
result[len] = '\0';
|
|
||||||
return (char *) memcpy (result, s, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t zmalloc_used_memory(void) {
|
|
||||||
size_t um;
|
|
||||||
|
|
||||||
if (zmalloc_thread_safe) {
|
|
||||||
#ifdef HAVE_ATOMIC
|
|
||||||
um = __sync_add_and_fetch(&used_memory, 0);
|
|
||||||
#else
|
|
||||||
pthread_mutex_lock(&used_memory_mutex);
|
|
||||||
um = used_memory;
|
|
||||||
pthread_mutex_unlock(&used_memory_mutex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
um = used_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
return um;
|
|
||||||
}
|
|
||||||
|
|
||||||
void zmalloc_enable_thread_safeness(void) {
|
|
||||||
zmalloc_thread_safe = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
|
|
||||||
zmalloc_oom_handler = oom_handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the RSS information in an OS-specific way.
|
|
||||||
*
|
|
||||||
* WARNING: the function zmalloc_get_rss() is not designed to be fast
|
|
||||||
* and may not be called in the busy loops where Redis tries to release
|
|
||||||
* memory expiring or swapping out objects.
|
|
||||||
*
|
|
||||||
* For this kind of "fast RSS reporting" usages use instead the
|
|
||||||
* function RedisEstimateRSS() that is a much faster (and less precise)
|
|
||||||
* version of the function. */
|
|
||||||
|
|
||||||
#if defined(HAVE_PROC_STAT)
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
size_t zmalloc_get_rss(void) {
|
|
||||||
int page = sysconf(_SC_PAGESIZE);
|
|
||||||
size_t rss;
|
|
||||||
char buf[4096];
|
|
||||||
char filename[256];
|
|
||||||
int fd, count;
|
|
||||||
char *p, *x;
|
|
||||||
|
|
||||||
snprintf(filename,256,"/proc/%d/stat",getpid());
|
|
||||||
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
|
|
||||||
if (read(fd,buf,4096) <= 0) {
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
p = buf;
|
|
||||||
count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
|
|
||||||
while(p && count--) {
|
|
||||||
p = strchr(p,' ');
|
|
||||||
if (p) p++;
|
|
||||||
}
|
|
||||||
if (!p) return 0;
|
|
||||||
x = strchr(p,' ');
|
|
||||||
if (!x) return 0;
|
|
||||||
*x = '\0';
|
|
||||||
|
|
||||||
rss = strtoll(p,NULL,10);
|
|
||||||
rss *= page;
|
|
||||||
return rss;
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_TASKINFO)
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#include <mach/task.h>
|
|
||||||
#include <mach/mach_init.h>
|
|
||||||
|
|
||||||
size_t zmalloc_get_rss(void) {
|
|
||||||
task_t task = MACH_PORT_NULL;
|
|
||||||
struct task_basic_info t_info;
|
|
||||||
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
|
||||||
|
|
||||||
if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
|
|
||||||
|
|
||||||
return t_info.resident_size;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
size_t zmalloc_get_rss(void) {
|
|
||||||
/* If we can't get the RSS in an OS-specific way for this system just
|
|
||||||
* return the memory usage we estimated in zmalloc()..
|
|
||||||
*
|
|
||||||
* Fragmentation will appear to be always 1 (no fragmentation)
|
|
||||||
* of course... */
|
|
||||||
return zmalloc_used_memory();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fragmentation = RSS / allocated-bytes */
|
|
||||||
float zmalloc_get_fragmentation_ratio(size_t rss) {
|
|
||||||
return (float)rss/zmalloc_used_memory();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(HAVE_PROC_SMAPS)
|
|
||||||
size_t zmalloc_get_private_dirty(void) {
|
|
||||||
char line[1024];
|
|
||||||
size_t pd = 0;
|
|
||||||
FILE *fp = fopen("/proc/self/smaps","r");
|
|
||||||
|
|
||||||
if (!fp) return 0;
|
|
||||||
while(fgets(line,sizeof(line),fp) != NULL) {
|
|
||||||
if (strncmp(line,"Private_Dirty:",14) == 0) {
|
|
||||||
char *p = strchr(line,'k');
|
|
||||||
if (p) {
|
|
||||||
*p = '\0';
|
|
||||||
pd += strtol(line+14,NULL,10) * 1024;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return pd;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
size_t zmalloc_get_private_dirty(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
86
3rdparty/zmalloc.h
vendored
86
3rdparty/zmalloc.h
vendored
|
@ -1,86 +0,0 @@
|
||||||
#ifndef ZMALLOC_H
|
|
||||||
#define ZMALLOC_H
|
|
||||||
|
|
||||||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of Redis nor the names of its contributors may be used
|
|
||||||
* to endorse or promote products derived from this software without
|
|
||||||
* specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Double expansion needed for stringification of macro values. */
|
|
||||||
#define __xstr(s) __str(s)
|
|
||||||
#define __str(s) #s
|
|
||||||
|
|
||||||
#if defined(USE_TCMALLOC)
|
|
||||||
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
|
|
||||||
#include <google/tcmalloc.h>
|
|
||||||
#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
|
|
||||||
#define HAVE_MALLOC_SIZE 1
|
|
||||||
#define zmalloc_size(p) tc_malloc_size(p)
|
|
||||||
#else
|
|
||||||
#error "Newer version of tcmalloc required"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
|
|
||||||
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
|
|
||||||
#include <jemalloc/jemalloc.h>
|
|
||||||
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
|
|
||||||
#define HAVE_MALLOC_SIZE 1
|
|
||||||
#define zmalloc_size(p) je_malloc_usable_size(p)
|
|
||||||
#else
|
|
||||||
#error "Newer version of jemalloc required"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#include <malloc/malloc.h>
|
|
||||||
#define HAVE_MALLOC_SIZE 1
|
|
||||||
#define zmalloc_size(p) malloc_size(p)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ZMALLOC_LIB
|
|
||||||
#define ZMALLOC_LIB "libc"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void *zmalloc(size_t size);
|
|
||||||
void *zcalloc(size_t size);
|
|
||||||
void *zrealloc(void *ptr, size_t size);
|
|
||||||
void zfree(void *ptr);
|
|
||||||
char *zstrdup(const char *s);
|
|
||||||
char *zstrndup(const char *s, size_t n);
|
|
||||||
size_t zmalloc_used_memory(void);
|
|
||||||
void zmalloc_enable_thread_safeness(void);
|
|
||||||
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
|
|
||||||
float zmalloc_get_fragmentation_ratio(size_t rss);
|
|
||||||
size_t zmalloc_get_rss(void);
|
|
||||||
size_t zmalloc_get_private_dirty(void);
|
|
||||||
void zlibc_free(void *ptr);
|
|
||||||
|
|
||||||
#ifndef HAVE_MALLOC_SIZE
|
|
||||||
size_t zmalloc_size(void *ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ZMALLOC_H
|
|
|
@ -3,6 +3,11 @@
|
||||||
by Yo-An Lin <yoanlin93@gmail.com>
|
by Yo-An Lin <yoanlin93@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
|
### 2.0 - Wed Nov 11 11:08:22 2015
|
||||||
|
|
||||||
|
- Renamed node/edge struct to R3Node and R3Edge
|
||||||
|
|
||||||
|
|
||||||
### 1.3.3 - Sat Jun 28 00:53:48 2014
|
### 1.3.3 - Sat Jun 28 00:53:48 2014
|
||||||
|
|
||||||
- Fix graphviz generator.
|
- Fix graphviz generator.
|
||||||
|
|
|
@ -1,34 +1,49 @@
|
||||||
# cmake file examples
|
cmake_minimum_required(VERSION 3.0)
|
||||||
# https://code.google.com/p/opencv-feature-tracker/source/browse/CMakeLists.txt?r=f804b03e704147e65183c19a50f57abedb22f45c
|
project(r3 VERSION 2.0.0)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
# TODO:
|
find_package(Check)
|
||||||
# cmake clean... orz
|
find_package(PCRE2 REQUIRED)
|
||||||
# http://stackoverflow.com/questions/9680420/looking-for-a-cmake-clean-command-to-clear-up-cmake-output
|
|
||||||
|
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
check_symbol_exists(strdup string.h HAVE_STRDUP)
|
||||||
|
check_symbol_exists(strndup string.h HAVE_STRNDUP)
|
||||||
|
check_include_file(stdbool.h HAVE_STDBOOL_H)
|
||||||
|
configure_file(config.h.cmake config.h)
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 2.8)
|
|
||||||
project(r3)
|
|
||||||
|
|
||||||
SET(CMAKE_MODULE_PATH
|
|
||||||
${PROJECT_SOURCE_DIR}/cmake
|
|
||||||
${CMAKE_MODULE_PATH}
|
|
||||||
)
|
|
||||||
|
|
||||||
include_directories(. ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty /opt/local/include)
|
|
||||||
# include_directories(. ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR})
|
|
||||||
|
|
||||||
link_directories(${LINK_DIRECTORIES} /opt/local/lib)
|
|
||||||
find_package(PCRE REQUIRED)
|
|
||||||
# find_package(Judy REQUIRED)
|
|
||||||
|
|
||||||
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} r3)
|
|
||||||
set(LIBS ${LIBS} ${PCRE_LIBRARIES} r3)
|
|
||||||
|
|
||||||
# set (CMAKE_CXX_FLAGS "-std=c++0x -arch x86_64 -stdlib=libc++ -g3 -Wall -O0")
|
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
add_subdirectory(3rdparty)
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
include/memory.h
|
||||||
|
include/r3.h
|
||||||
|
include/r3_list.h
|
||||||
|
include/r3_slug.h
|
||||||
|
include/r3_gvc.h
|
||||||
|
include/r3_json.h
|
||||||
|
include/str_array.h
|
||||||
|
include/r3.hpp
|
||||||
|
DESTINATION include/r3)
|
||||||
|
|
||||||
|
# Configure substitutions for r3.pc. The variables set here must match the
|
||||||
|
# @<values>@ in r3.pc.in.
|
||||||
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||||
|
set(exec_prefix ${prefix})
|
||||||
|
set(includedir ${prefix}/include)
|
||||||
|
set(libdir ${prefix}/lib)
|
||||||
|
set(PACKAGE_VERSION ${PROJECT_VERSION})
|
||||||
|
configure_file(r3.pc.in r3.pc @ONLY)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${PROJECT_BINARY_DIR}/r3.pc
|
||||||
|
DESTINATION lib/pkgconfig)
|
||||||
|
|
||||||
|
if(CHECK_FOUND)
|
||||||
|
enable_testing()
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
# add_test(test_tree ${CMAKE_CURRENT_BINARY_DIR}/check_tree)
|
else()
|
||||||
|
message(STATUS "Skipping unit tests, Check library not found!")
|
||||||
|
endif()
|
||||||
|
|
16
Makefile.am
16
Makefile.am
|
@ -1,11 +1,15 @@
|
||||||
SUBDIRS=3rdparty src . tests examples
|
SUBDIRS=src . examples
|
||||||
|
|
||||||
|
if ENABLE_CHECK
|
||||||
|
SUBDIRS += tests
|
||||||
|
endif
|
||||||
|
|
||||||
lib_LTLIBRARIES = libr3.la
|
lib_LTLIBRARIES = libr3.la
|
||||||
libr3_la_SOURCES =
|
libr3_la_SOURCES =
|
||||||
libr3_la_LIBADD = 3rdparty/libr3ext.la src/libr3core.la
|
libr3_la_LIBADD = src/libr3core.la
|
||||||
libr3_la_LDFLAGS =
|
libr3_la_LDFLAGS =
|
||||||
|
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
|
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
|
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +17,8 @@ ACLOCAL_AMFLAGS=-I m4
|
||||||
|
|
||||||
if ENABLE_DEBUG
|
if ENABLE_DEBUG
|
||||||
AM_CFLAGS += -ggdb -fprofile-arcs -ftest-coverage
|
AM_CFLAGS += -ggdb -fprofile-arcs -ftest-coverage
|
||||||
|
else
|
||||||
|
AM_CFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_JEMALLOC
|
if USE_JEMALLOC
|
||||||
|
@ -21,10 +27,10 @@ endif
|
||||||
|
|
||||||
r3_includedir = $(includedir)/r3
|
r3_includedir = $(includedir)/r3
|
||||||
r3_include_HEADERS = \
|
r3_include_HEADERS = \
|
||||||
|
include/memory.h \
|
||||||
include/r3.h \
|
include/r3.h \
|
||||||
include/r3_define.h \
|
|
||||||
include/r3_list.h \
|
include/r3_list.h \
|
||||||
include/r3_str.h \
|
include/r3_slug.h \
|
||||||
include/r3_gvc.h \
|
include/r3_gvc.h \
|
||||||
include/r3_json.h \
|
include/r3_json.h \
|
||||||
include/str_array.h \
|
include/str_array.h \
|
||||||
|
|
66
README.md
66
README.md
|
@ -1,12 +1,12 @@
|
||||||
R3
|
R3
|
||||||
================
|
================
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=master)](https://travis-ci.org/c9s/r3)
|
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=2.0)](https://travis-ci.org/c9s/r3)
|
||||||
|
|
||||||
[![Coverage Status](https://coveralls.io/repos/c9s/r3/badge.svg)](https://coveralls.io/r/c9s/r3)
|
[![Coverage Status](https://coveralls.io/repos/c9s/r3/badge.svg)](https://coveralls.io/r/c9s/r3)
|
||||||
|
|
||||||
R3 is an URL router library with high performance, thus, it's implemented in C.
|
R3 is an URL router library with high performance, thus, it's implemented in C.
|
||||||
It compiles your route paths into a prefix trie.
|
It compiles your R3Route paths into a prefix trie.
|
||||||
|
|
||||||
By using the prefix tree constructed in the start-up time, you can dispatch
|
By using the prefix tree constructed in the start-up time, you can dispatch
|
||||||
the path to the controller with high efficiency.
|
the path to the controller with high efficiency.
|
||||||
|
@ -25,7 +25,7 @@ Requirement
|
||||||
|
|
||||||
### Runtime Requirement
|
### Runtime Requirement
|
||||||
|
|
||||||
* pcre
|
* pcre2
|
||||||
* (optional) graphviz version 2.38.0 (20140413.2041)
|
* (optional) graphviz version 2.38.0 (20140413.2041)
|
||||||
* (optional) libjson-c-dev
|
* (optional) libjson-c-dev
|
||||||
|
|
||||||
|
@ -43,11 +43,11 @@ API
|
||||||
#include <r3/r3.h>
|
#include <r3/r3.h>
|
||||||
|
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
||||||
node *n = r3_tree_create(10);
|
R3Node *n = r3_tree_create(10);
|
||||||
|
|
||||||
int route_data = 3;
|
int route_data = 3;
|
||||||
|
|
||||||
// insert the route path into the router tree
|
// insert the R3Route path into the router tree
|
||||||
r3_tree_insert_path(n, "/bar", &route_data); // ignore the length of path
|
r3_tree_insert_path(n, "/bar", &route_data); // ignore the length of path
|
||||||
|
|
||||||
r3_tree_insert_pathl(n, "/zoo", strlen("/zoo"), &route_data );
|
r3_tree_insert_pathl(n, "/zoo", strlen("/zoo"), &route_data );
|
||||||
|
@ -61,7 +61,7 @@ r3_tree_insert_pathl(n, "/user/{id:\\d+}", strlen("/user/{id:\\d+}"), &route_dat
|
||||||
// if you want to catch error, you may call the extended path function for insertion
|
// if you want to catch error, you may call the extended path function for insertion
|
||||||
int data = 10;
|
int data = 10;
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
node *ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, &data, &errstr);
|
R3Node *ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, &data, &errstr);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
// failed insertion
|
// failed insertion
|
||||||
printf("error: %s\n", errstr);
|
printf("error: %s\n", errstr);
|
||||||
|
@ -83,7 +83,7 @@ if (err != 0) {
|
||||||
r3_tree_dump(n, 0);
|
r3_tree_dump(n, 0);
|
||||||
|
|
||||||
// match a route
|
// match a route
|
||||||
node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
|
R3Node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
|
||||||
if (matched_node) {
|
if (matched_node) {
|
||||||
int ret = *( (int*) matched_node->data );
|
int ret = *( (int*) matched_node->data );
|
||||||
}
|
}
|
||||||
|
@ -114,10 +114,10 @@ entry->request_method = METHOD_POST;
|
||||||
entry->request_method = METHOD_GET | METHOD_POST;
|
entry->request_method = METHOD_GET | METHOD_POST;
|
||||||
```
|
```
|
||||||
|
|
||||||
When using `match_entry`, you may match the route with `r3_tree_match_entry` function:
|
When using `match_entry`, you may match the R3Route with `r3_tree_match_entry` function:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
node *matched_node = r3_tree_match_entry(n, entry);
|
R3Node * matched_node = r3_tree_match_entry(n, entry);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ node *matched_node = r3_tree_match_entry(n, entry);
|
||||||
|
|
||||||
**Release Memory**
|
**Release Memory**
|
||||||
|
|
||||||
To release the memory, you may call `r3_tree_free(node *tree)` to release the whole tree structure,
|
To release the memory, you may call `r3_tree_free(R3Node *tree)` to release the whole tree structure,
|
||||||
`node*`, `edge*`, `route*` objects that were inserted into the tree will be freed.
|
`node*`, `edge*`, `route*` objects that were inserted into the tree will be freed.
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ n = r3_tree_create(10);
|
||||||
|
|
||||||
int route_data = 3;
|
int route_data = 3;
|
||||||
|
|
||||||
// insert the route path into the router tree
|
// insert the R3Route path into the router tree
|
||||||
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/post", sizeof("/blog/post") - 1, &route_data );
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/post", sizeof("/blog/post") - 1, &route_data );
|
||||||
|
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
|
@ -160,7 +160,7 @@ match_entry * entry = match_entry_create("/blog/post");
|
||||||
entry->request_method = METHOD_GET;
|
entry->request_method = METHOD_GET;
|
||||||
|
|
||||||
|
|
||||||
route *matched_route = r3_tree_match_route(n, entry);
|
R3Route *matched_R3Route = r3_tree_match_route(n, entry);
|
||||||
matched_route->data; // get the data from matched route
|
matched_route->data; // get the data from matched route
|
||||||
|
|
||||||
// free the objects at the end
|
// free the objects at the end
|
||||||
|
@ -179,7 +179,7 @@ To specify the pattern of a slug, you may write a colon to separate the slug nam
|
||||||
|
|
||||||
"/user/{userId:\\d+}"
|
"/user/{userId:\\d+}"
|
||||||
|
|
||||||
The above route will use `\d+` as its pattern.
|
The above R3Route will use `\d+` as its pattern.
|
||||||
|
|
||||||
|
|
||||||
Optimization
|
Optimization
|
||||||
|
@ -187,13 +187,13 @@ Optimization
|
||||||
Simple regular expressions are optimized through a regexp pattern to opcode
|
Simple regular expressions are optimized through a regexp pattern to opcode
|
||||||
translator, which translates simple patterns into small & fast scanners.
|
translator, which translates simple patterns into small & fast scanners.
|
||||||
|
|
||||||
By using this method, r3 reduces the matching overhead of pcre library.
|
By using this method, r3 reduces the matching overhead of pcre2 library.
|
||||||
|
|
||||||
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+` or `[^-]+`
|
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+`, `[^-]+` or `.*`.
|
||||||
|
|
||||||
Slugs without specified regular expression will be compiled into the `[^/]+` pattern. therefore, it's optimized too.
|
Slugs without specified regular expression will be compiled into the `[^/]+` pattern. therefore, it's optimized too.
|
||||||
|
|
||||||
Complex regular expressions will still use libpcre to match URL (partially).
|
Complex regular expressions will still use libpcre2 to match URL (partially).
|
||||||
|
|
||||||
|
|
||||||
Performance
|
Performance
|
||||||
|
@ -206,7 +206,7 @@ And here is the result of the router journey:
|
||||||
|
|
||||||
omg 9932.9 (±4.8%) i/s - 49873 in 5.033452s
|
omg 9932.9 (±4.8%) i/s - 49873 in 5.033452s
|
||||||
|
|
||||||
r3 uses the same route path data for benchmarking, and here is the benchmark:
|
r3 uses the same R3Route path data for benchmarking, and here is the benchmark:
|
||||||
|
|
||||||
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
|
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
|
||||||
11460057.83 i/sec
|
11460057.83 i/sec
|
||||||
|
@ -214,7 +214,7 @@ r3 uses the same route path data for benchmarking, and here is the benchmark:
|
||||||
|
|
||||||
### The Route Paths Of Benchmark
|
### The Route Paths Of Benchmark
|
||||||
|
|
||||||
The route path generator is from <https://github.com/stevegraham/rails/pull/1>:
|
The R3Route path generator is from <https://github.com/stevegraham/rails/pull/1>:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
@ -242,7 +242,7 @@ Function prefix mapping
|
||||||
Rendering Routes With Graphviz
|
Rendering Routes With Graphviz
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
The `r3_tree_render_file` API let you render the whole route trie into a image.
|
The `r3_tree_render_file` API let you render the whole R3Route trie into a image.
|
||||||
|
|
||||||
To use graphviz, you need to enable graphviz while you run `configure`:
|
To use graphviz, you need to enable graphviz while you run `configure`:
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ Here is the sample code of generating graph output:
|
||||||
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
node * n = r3_tree_create(1);
|
R3Node * n = r3_tree_create(1);
|
||||||
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
|
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
|
||||||
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
|
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
|
||||||
|
@ -300,13 +300,13 @@ digraph g {
|
||||||
### Graphviz Related Functions
|
### Graphviz Related Functions
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int r3_tree_render_file(const node * tree, const char * format, const char * filename);
|
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
|
||||||
|
|
||||||
int r3_tree_render(const node * tree, const char *layout, const char * format, FILE *fp);
|
int r3_tree_render(const R3Node * tree, const char *layout, const char * format, FILE *fp);
|
||||||
|
|
||||||
int r3_tree_render_dot(const node * tree, const char *layout, FILE *fp);
|
int r3_tree_render_dot(const R3Node * tree, const char *layout, FILE *fp);
|
||||||
|
|
||||||
int r3_tree_render_file(const node * tree, const char * format, const char * filename);
|
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ $ret = r3_dispatch($rs, '/blog/post/3' );
|
||||||
list($complete, $route, $variables) = $ret;
|
list($complete, $route, $variables) = $ret;
|
||||||
|
|
||||||
// matched conditions aren't done yet
|
// matched conditions aren't done yet
|
||||||
list($error, $message) = r3_validate($route); // validate route conditions
|
list($error, $message) = r3_validate($route); // validate R3Route conditions
|
||||||
if ( $error ) {
|
if ( $error ) {
|
||||||
echo $message; // "Method not allowed", "...";
|
echo $message; // "Method not allowed", "...";
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ if ( $error ) {
|
||||||
Install
|
Install
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
sudo apt-get install check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
|
sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
|
||||||
sudo apt-get install graphviz-dev graphviz # if you want graphviz
|
sudo apt-get install graphviz-dev graphviz # if you want graphviz
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
./configure && make
|
./configure && make
|
||||||
|
@ -364,7 +364,7 @@ Install
|
||||||
|
|
||||||
And we support debian-based distro now!
|
And we support debian-based distro now!
|
||||||
|
|
||||||
sudo apt-get install build-essential autoconf automake libpcre3-dev pkg-config debhelper libtool check
|
sudo apt-get install build-essential autoconf automake libpcre2-dev pkg-config debhelper libtool check
|
||||||
mv dist-debian debian
|
mv dist-debian debian
|
||||||
dpkg-buildpackage -b -us -uc
|
dpkg-buildpackage -b -us -uc
|
||||||
sudo gdebi ../libr3*.deb
|
sudo gdebi ../libr3*.deb
|
||||||
|
@ -396,9 +396,17 @@ Binding For Other Languages
|
||||||
* Python pyr3 by @thedrow <https://github.com/thedrow/pyr3>
|
* Python pyr3 by @thedrow <https://github.com/thedrow/pyr3>
|
||||||
* Haskell r3 by @MnO2 <https://github.com/MnO2/r3>
|
* Haskell r3 by @MnO2 <https://github.com/MnO2/r3>
|
||||||
* Vala r3-vala by @Ronmi <https://github.com/Ronmi/r3-vala>
|
* Vala r3-vala by @Ronmi <https://github.com/Ronmi/r3-vala>
|
||||||
* Node.js node-r3 by @othree <https://github.com/othree/node-r3>
|
|
||||||
* Node.js node-libr3 by @caasi <https://github.com/caasi/node-r3>
|
Node.js
|
||||||
|
|
||||||
|
* node-r3 by @othree <https://github.com/othree/node-r3>
|
||||||
|
* node-libr3 by @caasi <https://github.com/caasi/node-r3>
|
||||||
|
|
||||||
|
Ruby
|
||||||
|
|
||||||
* Ruby rr3 by @tonytonyjan <https://github.com/tonytonyjan/rr3>
|
* Ruby rr3 by @tonytonyjan <https://github.com/tonytonyjan/rr3>
|
||||||
|
* mruby r3 <https://github.com/rail44/mruby-r3>
|
||||||
|
* mruby rake r3 <https://github.com/rail44/mruby-rack-r3>
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
|
|
11
bench.html
11
bench.html
|
@ -150,12 +150,17 @@
|
||||||
|
|
||||||
var lines = data.split(/\n/);
|
var lines = data.split(/\n/);
|
||||||
|
|
||||||
// keep window size to 30 records
|
// keep window size to 60 records
|
||||||
lines.splice(-30);
|
lines = lines.splice(-60);
|
||||||
lines = lines.splice(lines.length - 30);
|
|
||||||
|
|
||||||
$(lines).each(function(i,line) {
|
$(lines).each(function(i,line) {
|
||||||
|
if (line == "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var columns = line.split(/,/);
|
var columns = line.split(/,/);
|
||||||
|
if (columns.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var a;
|
var a;
|
||||||
a = parseInt(columns[1]);
|
a = parseInt(columns[1]);
|
||||||
options.series[0].data.push(a || 0);
|
options.series[0].data.push(a || 0);
|
||||||
|
|
|
@ -629,4 +629,18 @@
|
||||||
1447158285,11638128.71,5241775.30,71089.90,2321077.83
|
1447158285,11638128.71,5241775.30,71089.90,2321077.83
|
||||||
1447158396,13539837.29,5874704.47,47662.55,2533571.93
|
1447158396,13539837.29,5874704.47,47662.55,2533571.93
|
||||||
1447158415,14054879.53,5952300.47,41527.76,2571669.83
|
1447158415,14054879.53,5952300.47,41527.76,2571669.83
|
||||||
1447158461,14000558.11,5739623.36,53092.46,2529610.40
|
1447210457,13616841.50,5604087.24,83886.08,2458628.97
|
||||||
|
1447210807,14529897.99,5833087.33,77672.30,1845729.06
|
||||||
|
1447210834,14016924.69,5806227.80,66576.25,1715107.19
|
||||||
|
1447211104,14738120.40,5873312.56,58254.22,2092537.05
|
||||||
|
1447211128,14875503.82,5649431.95,27776.85,2033045.40
|
||||||
|
1447211244,15335902.86,6019829.26,77672.30,1842297.15
|
||||||
|
1447211259,14365504.46,5812325.12,91180.52,1965977.09
|
||||||
|
1447211278,15175749.51,5931324.37,99864.38,1905029.23
|
||||||
|
1447211529,15442994.79,5909448.56,91180.52,1953744.42
|
||||||
|
1447211564,15175229.72,6100062.87,58254.22,1918667.68
|
||||||
|
1447211712,15957717.02,6145969.23,77672.30,1960098.15
|
||||||
|
1447211732,15692151.82,5725138.47,62601.55,1711560.29
|
||||||
|
1447211755,15758474.73,6033801.22,82241.25,1995758.04
|
||||||
|
1447766311,15118132.03,6006294.55,31068.92,1946048.29
|
||||||
|
1447829172,15903322.09,5728120.55,58254.22,1988443.21
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 447.
|
|
@ -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)
|
|
37
cmake/Modules/FindPCRE2.cmake
Normal file
37
cmake/Modules/FindPCRE2.cmake
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# 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 pcre2
|
||||||
|
# Find the native PCRE2 headers and libraries.
|
||||||
|
#
|
||||||
|
# PCRE2_INCLUDE_DIRS - where to find pcre2.h, etc.
|
||||||
|
# PCRE2_LIBRARIES - List of libraries when using pcre2.
|
||||||
|
# PCRE2_FOUND - True if pcre2 found.
|
||||||
|
|
||||||
|
# Look for the header file.
|
||||||
|
FIND_PATH(PCRE2_INCLUDE_DIR NAMES pcre2.h)
|
||||||
|
|
||||||
|
# Look for the library.
|
||||||
|
FIND_LIBRARY(PCRE2_LIBRARY NAMES pcre2-8)
|
||||||
|
|
||||||
|
# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 DEFAULT_MSG PCRE2_LIBRARY PCRE2_INCLUDE_DIR)
|
||||||
|
|
||||||
|
# Copy the results to the output variables.
|
||||||
|
IF(PCRE2_FOUND)
|
||||||
|
SET(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
|
||||||
|
SET(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
|
||||||
|
ELSE(PCRE2_FOUND)
|
||||||
|
SET(PCRE2_LIBRARIES)
|
||||||
|
SET(PCRE2_INCLUDE_DIRS)
|
||||||
|
ENDIF(PCRE2_FOUND)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)
|
3
config.h.cmake
Normal file
3
config.h.cmake
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
|
||||||
|
#cmakedefine HAVE_STRNDUP @HAVE_STRNDUP@
|
||||||
|
#cmakedefine HAVE_STDBOOL_H @HAVE_STDBOOL_H@
|
14
configure.ac
14
configure.ac
|
@ -1,4 +1,4 @@
|
||||||
AC_INIT([r3], 1.3.3)
|
AC_INIT([r3], 2.0.0)
|
||||||
AC_PREREQ([2.64])
|
AC_PREREQ([2.64])
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
|
@ -10,6 +10,7 @@ AC_PROG_CC
|
||||||
AC_PROG_CC_STDC
|
AC_PROG_CC_STDC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
AC_HEADER_STDBOOL
|
||||||
|
|
||||||
# older debian
|
# older debian
|
||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
|
@ -22,8 +23,6 @@ AC_C_INLINE
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
|
|
||||||
# Checks for library functions.
|
# Checks for library functions.
|
||||||
AC_FUNC_MALLOC
|
|
||||||
AC_FUNC_REALLOC
|
|
||||||
AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr])
|
AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr])
|
||||||
PKG_PROG_PKG_CONFIG
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ AM_CONDITIONAL(USE_JEMALLOC, test "x$have_jemalloc" = "xyes")
|
||||||
# AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc")
|
# AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc")
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(DEPS, [libpcre])
|
PKG_CHECK_MODULES(DEPS, [libpcre2-8])
|
||||||
AC_SUBST(DEPS_CFLAGS)
|
AC_SUBST(DEPS_CFLAGS)
|
||||||
AC_SUBST(DEPS_LIBS)
|
AC_SUBST(DEPS_LIBS)
|
||||||
|
|
||||||
|
@ -117,20 +116,21 @@ AC_ARG_ENABLE(check,
|
||||||
AS_HELP_STRING([--enable-check],
|
AS_HELP_STRING([--enable-check],
|
||||||
[enable unit testing]),
|
[enable unit testing]),
|
||||||
, enable_check=unset)
|
, enable_check=unset)
|
||||||
|
|
||||||
if test "x$enable_check" != "xunset" ; then
|
if test "x$enable_check" != "xunset" ; then
|
||||||
PKG_CHECK_MODULES(CHECK,[check >= 0.9.4],:,[
|
PKG_CHECK_MODULES(CHECK,[check >= 0.9.4],:,[
|
||||||
ifdef([AM_PATH_CHECK],
|
ifdef([AM_PATH_CHECK],
|
||||||
[AM_PATH_CHECK(,[have_check="yes"])],
|
[AM_PATH_CHECK(,[have_check="yes"])],
|
||||||
AC_MSG_WARN([Check not found; cannot run unit tests!])
|
AC_MSG_WARN([Check not found; cannot run unit tests!])
|
||||||
[have_check="no"])]
|
[have_check="no"]
|
||||||
|
)]
|
||||||
])
|
])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
|
AM_CONDITIONAL(ENABLE_CHECK, test "x$enable_check" = "xyes")
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
r3.pc
|
r3.pc
|
||||||
Makefile
|
Makefile
|
||||||
3rdparty/Makefile
|
|
||||||
src/Makefile
|
src/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
|
|
|
@ -2,7 +2,7 @@ Source: libr3
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Ronmi Ren <ronmi.ren@gmail.com>
|
Maintainer: Ronmi Ren <ronmi.ren@gmail.com>
|
||||||
Build-Depends: debhelper (>= 8.0.0), automake, autotools-dev, autoconf,
|
Build-Depends: debhelper (>= 8.0.0), automake, autotools-dev, autoconf,
|
||||||
libtool, libpcre3-dev, pkg-config, check
|
libtool, libpcre2-dev, pkg-config, check
|
||||||
Standards-Version: 3.9.4
|
Standards-Version: 3.9.4
|
||||||
Section: libs
|
Section: libs
|
||||||
Homepage: https://github.com/c9s/r3
|
Homepage: https://github.com/c9s/r3
|
||||||
|
@ -13,7 +13,7 @@ Architecture: any
|
||||||
Depends: libr3 (= ${binary:Version})
|
Depends: libr3 (= ${binary:Version})
|
||||||
Description: Development files for libr3
|
Description: Development files for libr3
|
||||||
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
||||||
performance, thus, it's implemented in C. It compiles your route paths into
|
performance, thus, it's implemented in C. It compiles your R3Route paths into
|
||||||
a prefix trie.
|
a prefix trie.
|
||||||
.
|
.
|
||||||
This package contains header files for libr3.
|
This package contains header files for libr3.
|
||||||
|
@ -24,5 +24,5 @@ Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Description: High performance URL routing library written in C.
|
Description: High performance URL routing library written in C.
|
||||||
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
||||||
performance, thus, it's implemented in C. It compiles your route paths into
|
performance, thus, it's implemented in C. It compiles your R3Route paths into
|
||||||
a prefix trie.
|
a prefix trie.
|
||||||
|
|
95
examples/routing.c
Normal file
95
examples/routing.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* check_slug.c
|
||||||
|
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "../include/r3.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void test1(void) {
|
||||||
|
R3Node *n = r3_tree_create(10);
|
||||||
|
|
||||||
|
int route_data1 = 3;
|
||||||
|
int route_data2 = 44;
|
||||||
|
int route_data3 = 555;
|
||||||
|
|
||||||
|
// insert the R3Route path into the router tree
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog", sizeof("/blog") - 1, &route_data1 );
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{idl:\\d+}/asf/{id}", strlen("/blog/{idl:\\d+}/asf/{id}"), &route_data2 );
|
||||||
|
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe", sizeof("/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe") - 1, &route_data3 );
|
||||||
|
|
||||||
|
char *errstr = NULL;
|
||||||
|
int err = r3_tree_compile(n, &errstr);
|
||||||
|
if (err != 0) {
|
||||||
|
// fail
|
||||||
|
printf("error: %s\n", errstr);
|
||||||
|
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
||||||
|
}
|
||||||
|
// r3_tree_dump(n,0);
|
||||||
|
|
||||||
|
|
||||||
|
// in your http server handler
|
||||||
|
|
||||||
|
// create the match entry for capturing dynamic variables.
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
int i;
|
||||||
|
for (int k = 0; k < 3000000; k++) {
|
||||||
|
// printf("round N%d\n",k);
|
||||||
|
entry = match_entry_create("/blog/432/asf/678");
|
||||||
|
entry->request_method = METHOD_GET;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
// if (matched_route) {
|
||||||
|
// printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
|
||||||
|
// if (entry->vars.tokens.size == entry->vars.slugs.size) {
|
||||||
|
// for (i = 0; i < entry->vars.tokens.size; i++) {
|
||||||
|
// // entry->vars.slugs.entries[i];
|
||||||
|
// // entry->vars.tokens.entries[i];
|
||||||
|
// printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
|
||||||
|
// entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
|
||||||
|
// printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
|
||||||
|
// entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // printf("Slugs and tokens sizes are not equal\n");
|
||||||
|
// // for (i = 0; i < entry->vars.slugs.size; i++) {
|
||||||
|
// // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
|
||||||
|
// // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
|
||||||
|
// // }
|
||||||
|
// // for (i = 0; i < entry->vars.tokens.size; i++) {
|
||||||
|
// // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
|
||||||
|
// // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// free the objects at the end
|
||||||
|
match_entry_free(entry);
|
||||||
|
}
|
||||||
|
// entry = match_entry_create("/blog/aaa/asd/123/qwe");
|
||||||
|
// if (entry != NULL) {
|
||||||
|
// entry->request_method = METHOD_GET;
|
||||||
|
// matched_route = r3_tree_match_route(n, entry);
|
||||||
|
// if (matched_route != NULL) {
|
||||||
|
// // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
|
||||||
|
// for (int i = 0; i < entry->vars->len; i++) {
|
||||||
|
// // entry->vars->slugs[i];
|
||||||
|
// // entry->vars->tokens[i];
|
||||||
|
// printf("Slug name is: %s\n",entry->vars->slugs[i]);
|
||||||
|
// printf("Slug value is: %s\n",entry->vars->tokens[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // free the objects at the end
|
||||||
|
// match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
test1();
|
||||||
|
}
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(3);
|
R3Node * n = r3_tree_create(3);
|
||||||
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
|
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
|
||||||
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
|
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
|
||||||
|
@ -44,15 +44,16 @@ int main()
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
node *m;
|
R3Node *m;
|
||||||
|
|
||||||
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
||||||
|
|
||||||
match_entry * e = match_entry_createl("/garply/baz/grault", strlen("/garply/baz/grault") );
|
match_entry * e = match_entry_createl("/garply/baz/grault", strlen("/garply/baz/grault") );
|
||||||
m = r3_tree_match_entry(n , e);
|
m = r3_tree_match_entry(n , e);
|
||||||
if (m) {
|
if (m) {
|
||||||
printf("Matched! %s\n", e->path);
|
printf("Matched! %s\n", e->path.base);
|
||||||
}
|
}
|
||||||
match_entry_free(e);
|
match_entry_free(e);
|
||||||
|
r3_tree_free(n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ void example_1() {
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
||||||
r3::Tree tree(10);
|
r3::Tree tree(10);
|
||||||
|
|
||||||
// insert the route path into the router tree
|
// insert the R3Route path into the router tree
|
||||||
int route_data_1 = 1;
|
int route_data_1 = 1;
|
||||||
tree.insert_path("/bar", &route_data_1); // ignore the length of path
|
tree.insert_path("/bar", &route_data_1); // ignore the length of path
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ void example_2() {
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
||||||
r3::Tree tree(10);
|
r3::Tree tree(10);
|
||||||
|
|
||||||
// insert the route path into the router tree
|
// insert the R3Route path into the router tree
|
||||||
int route_data = 1;
|
int route_data = 1;
|
||||||
tree.insert_routel(METHOD_GET | METHOD_POST, "/blog/post",
|
tree.insert_routel(METHOD_GET | METHOD_POST, "/blog/post",
|
||||||
sizeof("/blog/post") - 1, &route_data);
|
sizeof("/blog/post") - 1, &route_data);
|
||||||
|
|
|
@ -10,7 +10,7 @@ puts <<END
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
START_TEST (test_routes)
|
START_TEST (test_routes)
|
||||||
|
|
141
include/memory.h
Normal file
141
include/memory.h
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef r3__memory_h
|
||||||
|
#define r3__memory_h
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define R3_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__)
|
||||||
|
#else
|
||||||
|
#define R3_GNUC_VERSION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 201112L
|
||||||
|
#define R3_NORETURN _Noreturn
|
||||||
|
#elif defined(__clang__) || defined(__GNUC__) && R3_GNUC_VERSION >= 0x20500
|
||||||
|
// noreturn was not defined before gcc 2.5
|
||||||
|
#define R3_NORETURN __attribute__((noreturn))
|
||||||
|
#else
|
||||||
|
#define R3_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__) && R3_GNUC_VERSION >= 0x40900
|
||||||
|
// returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2)
|
||||||
|
#define R3_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||||
|
#else
|
||||||
|
#define R3_RETURNS_NONNULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer structure compatible with iovec
|
||||||
|
*/
|
||||||
|
typedef struct st_r3_iovec_t {
|
||||||
|
const char *base;
|
||||||
|
unsigned int len;
|
||||||
|
} r3_iovec_t;
|
||||||
|
|
||||||
|
#define R3_VECTOR(type) \
|
||||||
|
struct { \
|
||||||
|
type *entries; \
|
||||||
|
unsigned int size; \
|
||||||
|
unsigned int capacity; \
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef R3_VECTOR(void) r3_vector_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints an error message and aborts
|
||||||
|
*/
|
||||||
|
R3_NORETURN void r3_fatal(const char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor for r3_iovec_t
|
||||||
|
*/
|
||||||
|
static r3_iovec_t r3_iovec_init(const void *base, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrapper of malloc; allocates given size of memory or dies if impossible
|
||||||
|
*/
|
||||||
|
R3_RETURNS_NONNULL static void *r3_mem_alloc(unsigned int sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrapper of realloc; reallocs the given chunk or dies if impossible
|
||||||
|
*/
|
||||||
|
static void *r3_mem_realloc(void *oldp, unsigned int sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
|
||||||
|
* @param vector the vector
|
||||||
|
* @param element_size size of the elements stored in the vector
|
||||||
|
* @param new_capacity the capacity of the buffer after the function returns
|
||||||
|
*/
|
||||||
|
#define r3_vector_reserve(vector, new_capacity) \
|
||||||
|
r3_vector__reserve((r3_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (new_capacity))
|
||||||
|
static void r3_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
|
||||||
|
void r3_vector__expand(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
|
||||||
|
|
||||||
|
/* inline defs */
|
||||||
|
|
||||||
|
inline r3_iovec_t r3_iovec_init(const void *base, unsigned int len)
|
||||||
|
{
|
||||||
|
/* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */
|
||||||
|
r3_iovec_t buf;
|
||||||
|
buf.base = (char *)base;
|
||||||
|
buf.len = len;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *r3_mem_alloc(unsigned int sz)
|
||||||
|
{
|
||||||
|
void *p = malloc(sz);
|
||||||
|
if (p == NULL)
|
||||||
|
r3_fatal("no memory");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *r3_mem_realloc(void *oldp, unsigned int sz)
|
||||||
|
{
|
||||||
|
void *newp = realloc(oldp, sz);
|
||||||
|
if (newp == NULL) {
|
||||||
|
r3_fatal("no memory");
|
||||||
|
return oldp;
|
||||||
|
}
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void r3_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
|
||||||
|
{
|
||||||
|
if (vector->capacity < new_capacity) {
|
||||||
|
r3_vector__expand(vector, element_size, new_capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
189
include/r3.h
189
include/r3.h
|
@ -10,11 +10,24 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pcre.h>
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ <= 201710L
|
||||||
|
#ifdef HAVE_STDBOOL_H
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
#include "r3_define.h"
|
#elif !defined(bool) && !defined(__cplusplus)
|
||||||
|
typedef unsigned char bool;
|
||||||
|
# define bool bool /* For redefinition guards */
|
||||||
|
# define false 0
|
||||||
|
# define true 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -23,124 +36,99 @@ extern "C" {
|
||||||
struct _edge;
|
struct _edge;
|
||||||
struct _node;
|
struct _node;
|
||||||
struct _route;
|
struct _route;
|
||||||
typedef struct _edge edge;
|
typedef struct _edge R3Edge;
|
||||||
typedef struct _node node;
|
typedef struct _node R3Node;
|
||||||
typedef struct _route route;
|
typedef struct _R3Route R3Route;
|
||||||
|
|
||||||
struct _node {
|
struct _node {
|
||||||
edge * edges;
|
R3_VECTOR(R3Edge) edges;
|
||||||
// edge ** edge_table;
|
R3_VECTOR(R3Route) routes;
|
||||||
char * combined_pattern;
|
char * combined_pattern;
|
||||||
pcre * pcre_pattern;
|
pcre2_code * pcre_pattern;
|
||||||
|
pcre2_match_data * match_data;
|
||||||
// #ifdef PCRE_STUDY_JIT_COMPILE
|
|
||||||
pcre_extra * pcre_extra;
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// edges are mostly less than 255
|
// edges are mostly less than 255
|
||||||
unsigned int edge_len;
|
|
||||||
unsigned int compare_type; // compare_type: pcre, opcode, string
|
unsigned int compare_type; // compare_type: pcre, opcode, string
|
||||||
unsigned char endpoint; // endpoint, should be zero for non-endpoint nodes
|
unsigned int endpoint; // endpoint, should be zero for non-endpoint nodes
|
||||||
unsigned char ov_cnt; // capture vector array size for pcre
|
|
||||||
|
|
||||||
// almost less than 255
|
// the pointer of R3Route data
|
||||||
unsigned char edge_cap;
|
|
||||||
unsigned char route_len;
|
|
||||||
unsigned char route_cap;
|
|
||||||
// <-- here comes a char[1] struct padding for alignment since we have 4 char above.
|
|
||||||
|
|
||||||
|
|
||||||
/** compile-time variables here.... **/
|
|
||||||
|
|
||||||
/* the combined regexp pattern string from pattern_tokens */
|
|
||||||
|
|
||||||
route ** routes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the pointer of route data
|
|
||||||
*/
|
|
||||||
void * data;
|
void * data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define r3_node_edge_pattern(node,i) node->edges[i]->pattern
|
#define r3_node_edge_pattern(node,i) node->edges.entries[i].pattern.base
|
||||||
#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len
|
#define r3_node_edge_pattern_len(node,i) node->edges.entries[i].pattern.len
|
||||||
|
|
||||||
struct _edge {
|
struct _edge {
|
||||||
char * pattern; // 8 bytes
|
r3_iovec_t pattern; // 8 bytes
|
||||||
node * child; // 8 bytes
|
R3Node * child; // 8 bytes
|
||||||
unsigned int pattern_len; // 1 byte
|
unsigned int opcode; // 4byte
|
||||||
unsigned int opcode;
|
unsigned int has_slug; // 4byte
|
||||||
// unsigned char opcode:4; // 4 bit
|
|
||||||
unsigned char has_slug:1; // 1 bit
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _route {
|
struct _R3Route {
|
||||||
char * path;
|
r3_iovec_t path;
|
||||||
int path_len;
|
R3_VECTOR(r3_iovec_t) slugs;
|
||||||
|
|
||||||
int request_method; // can be (GET || POST)
|
int request_method; // can be (GET || POST)
|
||||||
|
r3_iovec_t host; // required host name
|
||||||
char * host; // required host name
|
|
||||||
int host_len;
|
|
||||||
|
|
||||||
void * data;
|
void * data;
|
||||||
|
|
||||||
char * remote_addr_pattern;
|
r3_iovec_t remote_addr_pattern;
|
||||||
int remote_addr_pattern_len;
|
|
||||||
|
unsigned int remote_addr_v4;
|
||||||
|
int remote_addr_v4_bits;
|
||||||
|
|
||||||
|
unsigned int remote_addr_v6[4];
|
||||||
|
int remote_addr_v6_bits[4];
|
||||||
|
|
||||||
|
int http_scheme; // can be (SCHEME_HTTP or SCHEME_HTTPS)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct _R3Entry match_entry;
|
||||||
str_array * vars;
|
struct _R3Entry {
|
||||||
const char * path; // current path to dispatch
|
str_array vars;
|
||||||
int path_len; // the length of the current path
|
r3_iovec_t path; // current path to dispatch
|
||||||
int request_method; // current request method
|
int request_method; // current request method
|
||||||
|
|
||||||
void * data; // route ptr
|
void * data; // R3Route ptr
|
||||||
|
|
||||||
char * host; // the request host
|
r3_iovec_t host; // the request host
|
||||||
int host_len;
|
r3_iovec_t remote_addr;
|
||||||
|
|
||||||
char * remote_addr;
|
int http_scheme;
|
||||||
int remote_addr_len;
|
};
|
||||||
} match_entry;
|
|
||||||
|
|
||||||
|
|
||||||
|
R3Node * r3_tree_create(int cap);
|
||||||
|
|
||||||
|
// R3Node * r3_node_create();
|
||||||
|
|
||||||
|
void r3_tree_free(R3Node * tree);
|
||||||
|
|
||||||
|
R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int strdup, R3Node *child);
|
||||||
|
|
||||||
|
|
||||||
node * r3_tree_create(int cap);
|
|
||||||
|
|
||||||
node * r3_node_create();
|
|
||||||
|
|
||||||
void r3_tree_free(node * tree);
|
|
||||||
|
|
||||||
edge * r3_node_connectl(node * n, const char * pat, int len, int strdup, node *child);
|
|
||||||
|
|
||||||
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
|
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
|
||||||
|
|
||||||
edge * r3_node_find_edge(const node * n, const char * pat, int pat_len);
|
R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len);
|
||||||
|
|
||||||
edge * r3_node_append_edge(node *n, edge *child);
|
R3Edge * r3_node_append_edge(R3Node *n);
|
||||||
|
|
||||||
|
R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr);
|
||||||
|
|
||||||
edge * r3_node_find_common_prefix(node *n, const char *path, int path_len, int *prefix_len, char **errstr);
|
R3Node * r3_tree_insert_pathl(R3Node *tree, const char *path, int path_len, void * data);
|
||||||
|
|
||||||
node * r3_tree_insert_pathl(node *tree, const char *path, int path_len, void * data);
|
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, 0, 0, data, NULL)
|
||||||
|
|
||||||
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, NULL , data, NULL)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
route * r3_tree_insert_routel(node *tree, int method, const char *path, int path_len, void *data);
|
R3Route * r3_tree_insert_routel(R3Node * tree, int method, const char *path, int path_len, void *data);
|
||||||
|
|
||||||
route * r3_tree_insert_routel_ex(node *tree, int method, const char *path, int path_len, void *data, char **errstr);
|
R3Route * r3_tree_insert_routel_ex(R3Node * tree, int method, const char *path, int path_len, void *data, char **errstr);
|
||||||
|
|
||||||
#define r3_tree_insert_routel(n, method, path, path_len, data) r3_tree_insert_routel_ex(n, method, path, path_len, data, NULL)
|
#define r3_tree_insert_routel(n, method, path, path_len, data) r3_tree_insert_routel_ex(n, method, path, path_len, data, NULL)
|
||||||
|
|
||||||
#define r3_tree_insert_path(n,p,d) r3_tree_insert_pathl_ex(n,p,strlen(p), NULL, d, NULL)
|
#define r3_tree_insert_path(n,p,d) r3_tree_insert_pathl_ex(n,p,strlen(p), 0, 0, d, NULL)
|
||||||
|
|
||||||
#define r3_tree_insert_route(n,method,path,data) r3_tree_insert_routel(n, method, path, strlen(path), data)
|
#define r3_tree_insert_route(n,method,path,data) r3_tree_insert_routel(n, method, path, strlen(path), data)
|
||||||
|
|
||||||
|
@ -148,51 +136,51 @@ route * r3_tree_insert_routel_ex(node *tree, int method, const char *path, int p
|
||||||
/**
|
/**
|
||||||
* The private API to insert a path
|
* The private API to insert a path
|
||||||
*/
|
*/
|
||||||
node * r3_tree_insert_pathl_ex(node *tree, const char *path, int path_len, route * route, void * data, char ** errstr);
|
R3Node * r3_tree_insert_pathl_ex(R3Node *tree, const char *path, unsigned int path_len, int method, unsigned int router, void * data, char **errstr);
|
||||||
|
|
||||||
void r3_tree_dump(const node * n, int level);
|
void r3_tree_dump(const R3Node * n, int level);
|
||||||
|
|
||||||
|
|
||||||
edge * r3_node_find_edge_str(const node * n, const char * str, int str_len);
|
R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len);
|
||||||
|
|
||||||
|
|
||||||
int r3_tree_compile(node *n, char** errstr);
|
int r3_tree_compile(R3Node *n, char** errstr);
|
||||||
|
|
||||||
int r3_tree_compile_patterns(node * n, char** errstr);
|
int r3_tree_compile_patterns(R3Node * n, char** errstr);
|
||||||
|
|
||||||
node * r3_tree_matchl(const node * n, const char * path, int path_len, match_entry * entry);
|
R3Node * r3_tree_matchl(const R3Node * n, const char * path, unsigned int path_len, match_entry * entry);
|
||||||
|
|
||||||
#define r3_tree_match(n,p,e) r3_tree_matchl(n,p, strlen(p), e)
|
#define r3_tree_match(n,p,e) r3_tree_matchl(n,p, strlen(p), e)
|
||||||
|
|
||||||
// node * r3_tree_match_entry(node * n, match_entry * entry);
|
// R3Node * r3_tree_match_entry(R3Node * n, match_entry * entry);
|
||||||
#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry)
|
#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path.base, entry->path.len, entry)
|
||||||
|
|
||||||
bool r3_node_has_slug_edges(const node *n);
|
bool r3_node_has_slug_edges(const R3Node *n);
|
||||||
|
|
||||||
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child);
|
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child);
|
||||||
|
|
||||||
void r3_edge_initl(edge *e, const char * pattern, int pattern_len, node * child);
|
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child);
|
||||||
|
|
||||||
node * r3_edge_branch(edge *e, int dl);
|
R3Node * r3_edge_branch(R3Edge *e, int dl);
|
||||||
|
|
||||||
void r3_edge_free(edge * edge);
|
void r3_edge_free(R3Edge * edge);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
route * r3_route_create(const char * path);
|
R3Route * r3_route_create(const char * path);
|
||||||
|
|
||||||
route * r3_route_createl(const char * path, int path_len);
|
// R3Route * r3_route_createl(const char * path, int path_len);
|
||||||
|
|
||||||
|
|
||||||
void r3_node_append_route(node * n, route * route);
|
R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data);
|
||||||
|
|
||||||
void r3_route_free(route * route);
|
void r3_route_free(R3Route * route);
|
||||||
|
|
||||||
int r3_route_cmp(const route *r1, const match_entry *r2);
|
int r3_route_cmp(const R3Route *r1, const match_entry *r2);
|
||||||
|
|
||||||
route * r3_tree_match_route(const node *n, match_entry * entry);
|
R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry);
|
||||||
|
|
||||||
#define r3_route_create(p) r3_route_createl(p, strlen(p))
|
#define r3_route_create(p) r3_route_createl(p, strlen(p))
|
||||||
|
|
||||||
|
@ -205,13 +193,16 @@ route * r3_tree_match_route(const node *n, match_entry * entry);
|
||||||
#define METHOD_HEAD 2<<5
|
#define METHOD_HEAD 2<<5
|
||||||
#define METHOD_OPTIONS 2<<6
|
#define METHOD_OPTIONS 2<<6
|
||||||
|
|
||||||
|
#define SCHEME_HTTP 2
|
||||||
|
#define SCHEME_HTTPS 2<<1
|
||||||
|
|
||||||
|
|
||||||
int r3_pattern_to_opcode(const char * pattern, int pattern_len);
|
int r3_pattern_to_opcode(const char * pattern, unsigned int len);
|
||||||
|
|
||||||
enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE };
|
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 };
|
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH,
|
||||||
|
OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA, OP_GREEDY_ANY};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#define R3_HPP
|
#define R3_HPP
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <r3.h>
|
#include "r3.h"
|
||||||
|
|
||||||
namespace r3 {
|
namespace r3 {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -37,8 +37,8 @@ namespace r3 {
|
||||||
private:
|
private:
|
||||||
T* p_;
|
T* p_;
|
||||||
};
|
};
|
||||||
typedef Base<node> Node;
|
typedef Base<R3Node> Node;
|
||||||
typedef Base<route> Route;
|
typedef Base<R3Route> Route;
|
||||||
|
|
||||||
class MatchEntry : public Base<match_entry> {
|
class MatchEntry : public Base<match_entry> {
|
||||||
public:
|
public:
|
||||||
|
@ -69,7 +69,7 @@ namespace r3 {
|
||||||
MatchEntry& operator =(const MatchEntry&);
|
MatchEntry& operator =(const MatchEntry&);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Tree : public Base<node> {
|
class Tree : public Base<R3Node> {
|
||||||
public:
|
public:
|
||||||
explicit Tree(int cap)
|
explicit Tree(int cap)
|
||||||
: Base(r3_tree_create(cap)) {
|
: Base(r3_tree_create(cap)) {
|
||||||
|
@ -90,13 +90,13 @@ namespace r3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node insert_path(const char* path, void* data, char** errstr = NULL) {
|
Node insert_path(const char* path, void* data, char** errstr = NULL) {
|
||||||
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), NULL,
|
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), 0, 0,
|
||||||
data, errstr);
|
data, errstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node insert_pathl(const char* path, int path_len, void* data,
|
Node insert_pathl(const char* path, int path_len, void* data,
|
||||||
char** errstr = NULL) {
|
char** errstr = NULL) {
|
||||||
return r3_tree_insert_pathl_ex(get(), path, path_len, NULL, data,
|
return r3_tree_insert_pathl_ex(get(), path, path_len, 0, 0, data,
|
||||||
errstr);
|
errstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* r3_define.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEFINE_H
|
|
||||||
#define DEFINE_H
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#if !defined(bool) && !defined(__cplusplus)
|
|
||||||
typedef unsigned char bool;
|
|
||||||
#endif
|
|
||||||
#ifndef FALSE
|
|
||||||
# define FALSE 0
|
|
||||||
#endif
|
|
||||||
#ifndef TRUE
|
|
||||||
# define TRUE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// #define DEBUG 1
|
|
||||||
#ifdef DEBUG
|
|
||||||
|
|
||||||
#define info(fmt, ...) \
|
|
||||||
do { fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
|
|
||||||
|
|
||||||
#define debug(fmt, ...) \
|
|
||||||
do { fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
|
|
||||||
__LINE__, __func__, __VA_ARGS__); } while (0)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define info(...);
|
|
||||||
#define debug(...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !DEFINE_H */
|
|
|
@ -11,13 +11,13 @@
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
|
|
||||||
json_object * r3_edge_to_json_object(const edge * e);
|
json_object * r3_edge_to_json_object(const R3Edge * e);
|
||||||
json_object * r3_node_to_json_object(const node * n);
|
json_object * r3_node_to_json_object(const R3Node * n);
|
||||||
json_object * r3_route_to_json_object(const route * r);
|
json_object * r3_route_to_json_object(const R3Route * r);
|
||||||
|
|
||||||
const char * r3_node_to_json_string_ext(const node * n, int options);
|
const char * r3_node_to_json_string_ext(const R3Node * n, int options);
|
||||||
const char * r3_node_to_json_pretty_string(const node * n);
|
const char * r3_node_to_json_pretty_string(const R3Node * n);
|
||||||
const char * r3_node_to_json_string(const node * n);
|
const char * r3_node_to_json_string(const R3Node * n);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
30
include/r3_slug.h
Normal file
30
include/r3_slug.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* r3_str.h
|
||||||
|
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#ifndef R3_SLUG_H
|
||||||
|
#define R3_SLUG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char * r3_slug_compile(const char * str, unsigned int len);
|
||||||
|
|
||||||
|
const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len);
|
||||||
|
|
||||||
|
const char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len);
|
||||||
|
|
||||||
|
const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len);
|
||||||
|
|
||||||
|
int r3_slug_count(const char * needle, int len, char **errstr);
|
||||||
|
|
||||||
|
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !R3_SLUG_H */
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* r3_str.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#ifndef STR_H
|
|
||||||
#define STR_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char * r3_slug_compile(const char * str, int len);
|
|
||||||
|
|
||||||
char * r3_slug_find_pattern(const char *s1, int *len);
|
|
||||||
|
|
||||||
char * r3_slug_find_name(const char *s1, int *len);
|
|
||||||
|
|
||||||
char * r3_slug_find_placeholder(const char *s1, int *len);
|
|
||||||
|
|
||||||
int r3_slug_count(const char * needle, int len, char **errstr);
|
|
||||||
|
|
||||||
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr);
|
|
||||||
|
|
||||||
void str_repeat(char *s, const char *c, int len);
|
|
||||||
|
|
||||||
void print_indent(int level);
|
|
||||||
|
|
||||||
|
|
||||||
#if _GNU_SOURCE || POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700 || __DARWIN_C_LEVEL >= 200809L
|
|
||||||
#ifndef HAVE_STRNDUP
|
|
||||||
#define HAVE_STRNDUP
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _SVID_SOURCE || _BSD_SOURCE \
|
|
||||||
|| _XOPEN_SOURCE >= 500 \
|
|
||||||
|| _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED \
|
|
||||||
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L \
|
|
||||||
|| __DARWIN_C_LEVEL >= 200809L
|
|
||||||
#ifndef HAVE_STRDUP
|
|
||||||
#define HAVE_STRDUP
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_STRDUP
|
|
||||||
char *strdup(const char *s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
|
||||||
char *strndup(const char *s, int n);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !STR_H */
|
|
||||||
|
|
|
@ -8,28 +8,34 @@
|
||||||
#ifndef STR_ARRAY_H
|
#ifndef STR_ARRAY_H
|
||||||
#define STR_ARRAY_H
|
#define STR_ARRAY_H
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ <= 201710L
|
||||||
|
#ifdef HAVE_STDBOOL_H
|
||||||
|
# include <stdbool.h>
|
||||||
|
#elif !defined(bool) && !defined(__cplusplus)
|
||||||
|
typedef unsigned char bool;
|
||||||
|
# define bool bool /* For redefinition guards */
|
||||||
|
# define false 0
|
||||||
|
# define true 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _str_array {
|
typedef struct _str_array {
|
||||||
char **tokens;
|
R3_VECTOR(r3_iovec_t) slugs;
|
||||||
int len;
|
R3_VECTOR(r3_iovec_t) tokens;
|
||||||
int cap;
|
|
||||||
} str_array;
|
} str_array;
|
||||||
|
|
||||||
str_array * str_array_create(int cap);
|
bool str_array_append(str_array * l, const char * token, unsigned int len);
|
||||||
|
|
||||||
bool str_array_is_full(const str_array * l);
|
|
||||||
|
|
||||||
bool str_array_resize(str_array *l, int new_cap);
|
|
||||||
|
|
||||||
bool str_array_append(str_array * list, char * token);
|
|
||||||
|
|
||||||
void str_array_free(str_array *l);
|
void str_array_free(str_array *l);
|
||||||
|
|
||||||
|
void str_array_dump_slugs(const str_array *l);
|
||||||
|
|
||||||
void str_array_dump(const str_array *l);
|
void str_array_dump(const str_array *l);
|
||||||
|
|
||||||
str_array * split_route_pattern(char *pattern, int pattern_len);
|
#define str_array_fetch(t,i) t->tokens.entries[i]
|
||||||
|
#define str_array_len(t) t->tokens.size
|
||||||
#define str_array_fetch(t,i) t->tokens[i]
|
#define str_array_cap(t) t->tokens.capacity
|
||||||
#define str_array_len(t) t->len
|
|
||||||
#define str_array_cap(t) t->cap
|
|
||||||
|
|
||||||
#endif /* !STR_ARRAY_H */
|
#endif /* !STR_ARRAY_H */
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "r3",
|
"name": "r3",
|
||||||
"version": "1.3.3",
|
"version": "2.0.0",
|
||||||
"repo": "brendanashworth/r3",
|
"repo": "brendanashworth/r3",
|
||||||
"description": "high-performance path dispatching library",
|
"description": "high-performance path dispatching library",
|
||||||
"keywords": ["path", "dispatch", "performance", "r3", "c9s"],
|
"keywords": ["path", "dispatch", "performance", "r3", "c9s"],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"src": ["3rdparty/zmalloc.c", "3rdparty/zmalloc.h", "include/r3.h", "include/r3.hpp", "include/r3_define.h", "include/r3_gvc.h", "include/r3_json.h", "include/r3_list.h", "include/r3_str.h", "include/str_array.h", "src/edge.c", "src/gvc.c", "src/json.c", "src/list.c", "src/match_entry.c", "src/node.c", "src/slug.c", "src/slug.h", "src/str.c", "src/token.c"]
|
"src": ["include/memory.h", "include/r3.h", "include/r3.hpp", "include/r3_gvc.h", "include/r3_json.h", "include/r3_list.h", "include/r3_slug.h", "include/str_array.h", "src/edge.c", "src/gvc.c", "src/json.c", "src/list.c", "src/match_entry.c", "src/node.c", "src/slug.c", "src/slug.h", "src/str.c", "src/token.c"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,8 +407,8 @@ PHP_FUNCTION(r3_match)
|
||||||
}
|
}
|
||||||
|
|
||||||
zval *z_route;
|
zval *z_route;
|
||||||
z_route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
|
z_R3Route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
|
||||||
if ( z_route != NULL ) {
|
if ( z_R3Route != NULL ) {
|
||||||
*return_value = *z_route;
|
*return_value = *z_route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
return;
|
return;
|
||||||
|
@ -438,7 +438,7 @@ PHP_FUNCTION(r3_persistent_dispatch)
|
||||||
char *ns, *filename, *path;
|
char *ns, *filename, *path;
|
||||||
int ns_len, filename_len, path_len;
|
int ns_len, filename_len, path_len;
|
||||||
zval *mux = NULL;
|
zval *mux = NULL;
|
||||||
zval *route = NULL;
|
zval *R3Route = NULL;
|
||||||
zval *z_path = NULL;
|
zval *z_path = NULL;
|
||||||
|
|
||||||
/* parse parameters */
|
/* parse parameters */
|
||||||
|
@ -463,15 +463,15 @@ PHP_FUNCTION(r3_persistent_dispatch)
|
||||||
ZVAL_STRINGL(z_path, path ,path_len, 1); // no copy
|
ZVAL_STRINGL(z_path, path ,path_len, 1); // no copy
|
||||||
|
|
||||||
// XXX: pass return_value to the method call, so we don't need to copy
|
// XXX: pass return_value to the method call, so we don't need to copy
|
||||||
route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
|
R3Route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
|
||||||
zval_ptr_dtor(&z_path);
|
zval_ptr_dtor(&z_path);
|
||||||
|
|
||||||
if ( route ) {
|
if ( R3Route ) {
|
||||||
*return_value = *route;
|
*return_value = *route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// route not found
|
// R3Route not found
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +649,7 @@ inline zval * php_r3_match(zval *z_routes, char *path, int path_len TSRMLS_DC) {
|
||||||
|
|
||||||
// tell garbage collector to collect it, we need to use pcre_subpats later.
|
// tell garbage collector to collect it, we need to use pcre_subpats later.
|
||||||
|
|
||||||
// check conditions only when route option is provided
|
// check conditions only when R3Route option is provided
|
||||||
if ( zend_hash_index_find( Z_ARRVAL_PP(z_route_pp), 3, (void**) &z_route_options_pp) == SUCCESS ) {
|
if ( zend_hash_index_find( Z_ARRVAL_PP(z_route_pp), 3, (void**) &z_route_options_pp) == SUCCESS ) {
|
||||||
if ( zend_hash_num_elements(Z_ARRVAL_PP(z_route_options_pp)) ) {
|
if ( zend_hash_num_elements(Z_ARRVAL_PP(z_route_options_pp)) ) {
|
||||||
if ( 0 == validate_request_method( z_route_options_pp, current_request_method TSRMLS_CC) ) {
|
if ( 0 == validate_request_method( z_route_options_pp, current_request_method TSRMLS_CC) ) {
|
||||||
|
|
|
@ -81,7 +81,7 @@ zend_class_entry ** get_pattern_compiler_ce(TSRMLS_D) {
|
||||||
return ce_pattern_compiler;
|
return ce_pattern_compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns compiled route zval
|
// Returns compiled R3Route zval
|
||||||
zval * compile_route_pattern(zval *z_pattern, zval *z_options, zend_class_entry **ce_pattern_compiler TSRMLS_DC)
|
zval * compile_route_pattern(zval *z_pattern, zval *z_options, zend_class_entry **ce_pattern_compiler TSRMLS_DC)
|
||||||
{
|
{
|
||||||
// zend_class_entry **ce_pattern_compiler;
|
// zend_class_entry **ce_pattern_compiler;
|
||||||
|
@ -92,10 +92,10 @@ zval * compile_route_pattern(zval *z_pattern, zval *z_options, zend_class_entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zval *z_compiled_route = NULL; // will be an array
|
zval *z_compiled_R3Route = NULL; // will be an array
|
||||||
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &z_compiled_route, 2, z_pattern, z_options TSRMLS_CC );
|
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &z_compiled_route, 2, z_pattern, z_options TSRMLS_CC );
|
||||||
|
|
||||||
if ( z_compiled_route == NULL ) {
|
if ( z_compiled_R3Route == NULL ) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if ( Z_TYPE_P(z_compiled_route) == IS_NULL ) {
|
} else if ( Z_TYPE_P(z_compiled_route) == IS_NULL ) {
|
||||||
zval_ptr_dtor(&z_compiled_route);
|
zval_ptr_dtor(&z_compiled_route);
|
||||||
|
@ -467,7 +467,7 @@ PHP_METHOD(Mux, mount) {
|
||||||
// zval for new route
|
// zval for new route
|
||||||
zval *z_new_routes;
|
zval *z_new_routes;
|
||||||
|
|
||||||
// zval for route item
|
// zval for R3Route item
|
||||||
zval **z_is_pcre; // route[0]
|
zval **z_is_pcre; // route[0]
|
||||||
zval **z_route_pattern;
|
zval **z_route_pattern;
|
||||||
zval **z_route_callback;
|
zval **z_route_callback;
|
||||||
|
@ -514,10 +514,10 @@ PHP_METHOD(Mux, mount) {
|
||||||
|
|
||||||
// $routeArgs = PatternCompiler::compile($newPattern,
|
// $routeArgs = PatternCompiler::compile($newPattern,
|
||||||
// array_merge_recursive($route[3], $options) );
|
// array_merge_recursive($route[3], $options) );
|
||||||
zval *z_compiled_route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
|
zval *z_compiled_R3Route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
|
||||||
|
|
||||||
|
|
||||||
if ( z_compiled_route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
|
if ( z_compiled_R3Route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
|
||||||
php_error( E_ERROR, "Cannot compile pattern: %s", new_pattern);
|
php_error( E_ERROR, "Cannot compile pattern: %s", new_pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ PHP_METHOD(Mux, mount) {
|
||||||
Z_ADDREF_P(z_compiled_route);
|
Z_ADDREF_P(z_compiled_route);
|
||||||
Z_ADDREF_P(z_new_routes);
|
Z_ADDREF_P(z_new_routes);
|
||||||
|
|
||||||
// create new route and append to mux->routes
|
// create new R3Route and append to mux->routes
|
||||||
add_index_bool(z_new_routes, 0 , 1); // pcre flag == false
|
add_index_bool(z_new_routes, 0 , 1); // pcre flag == false
|
||||||
add_index_zval(z_new_routes, 1, *z_compiled_route_pattern);
|
add_index_zval(z_new_routes, 1, *z_compiled_route_pattern);
|
||||||
add_index_zval(z_new_routes, 2 , *z_route_callback);
|
add_index_zval(z_new_routes, 2 , *z_route_callback);
|
||||||
|
@ -558,7 +558,7 @@ PHP_METHOD(Mux, mount) {
|
||||||
|
|
||||||
int new_pattern_len = pattern_len + Z_STRLEN_PP(z_route_pattern);
|
int new_pattern_len = pattern_len + Z_STRLEN_PP(z_route_pattern);
|
||||||
|
|
||||||
// Merge the mount options with the route options
|
// Merge the mount options with the R3Route options
|
||||||
zval *z_new_route_options;
|
zval *z_new_route_options;
|
||||||
MAKE_STD_ZVAL(z_new_route_options);
|
MAKE_STD_ZVAL(z_new_route_options);
|
||||||
array_init(z_new_route_options);
|
array_init(z_new_route_options);
|
||||||
|
@ -681,11 +681,11 @@ PHP_METHOD(Mux, getRoute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
zval *z_routes_by_id = NULL;
|
zval *z_routes_by_id = NULL;
|
||||||
zval **z_route = NULL;
|
zval **z_R3Route = NULL;
|
||||||
z_routes_by_id = zend_read_property( ce_r3_mux , this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
|
z_routes_by_id = zend_read_property( ce_r3_mux , this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
|
||||||
|
|
||||||
// php_var_dump(&z_routes_by_id, 1 TSRMLS_CC);
|
// php_var_dump(&z_routes_by_id, 1 TSRMLS_CC);
|
||||||
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_route ) == SUCCESS ) {
|
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_R3Route ) == SUCCESS ) {
|
||||||
*return_value = **z_route;
|
*return_value = **z_route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
return;
|
return;
|
||||||
|
@ -788,7 +788,7 @@ PHP_METHOD(Mux, compile) {
|
||||||
zend_call_method( NULL, NULL, NULL, "usort", strlen("usort"), &rv, 2,
|
zend_call_method( NULL, NULL, NULL, "usort", strlen("usort"), &rv, 2,
|
||||||
z_routes, z_sort_callback TSRMLS_CC );
|
z_routes, z_sort_callback TSRMLS_CC );
|
||||||
zval_ptr_dtor(&z_sort_callback); // recycle sort callback zval
|
zval_ptr_dtor(&z_sort_callback); // recycle sort callback zval
|
||||||
// php_error(E_ERROR,"route sort failed.");
|
// php_error(E_ERROR,"R3Route sort failed.");
|
||||||
// zend_update_property(ce_r3_mux, getThis(), "routes", sizeof("routes")-1, z_routes TSRMLS_CC);
|
// zend_update_property(ce_r3_mux, getThis(), "routes", sizeof("routes")-1, z_routes TSRMLS_CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ PHP_METHOD(Mux, dispatch) {
|
||||||
int path_len;
|
int path_len;
|
||||||
zval *z_path;
|
zval *z_path;
|
||||||
|
|
||||||
zval *z_return_route = NULL;
|
zval *z_return_R3Route = NULL;
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) {
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) {
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
|
@ -856,7 +856,7 @@ PHP_METHOD(Mux, dispatch) {
|
||||||
zend_hash_quick_find( &ce_r3_mux->function_table, "match", sizeof("match"), zend_inline_hash_func(ZEND_STRS("match")), (void **) &fe);
|
zend_hash_quick_find( &ce_r3_mux->function_table, "match", sizeof("match"), zend_inline_hash_func(ZEND_STRS("match")), (void **) &fe);
|
||||||
zend_call_method( &this_ptr, ce_r3_mux, &fe, "match", strlen("match"), &z_return_route, 1, z_path, NULL TSRMLS_CC );
|
zend_call_method( &this_ptr, ce_r3_mux, &fe, "match", strlen("match"), &z_return_route, 1, z_path, NULL TSRMLS_CC );
|
||||||
|
|
||||||
if ( ! z_return_route || Z_TYPE_P(z_return_route) == IS_NULL ) {
|
if ( ! z_return_R3Route || Z_TYPE_P(z_return_route) == IS_NULL ) {
|
||||||
zval_ptr_dtor(&z_path);
|
zval_ptr_dtor(&z_path);
|
||||||
RETURN_NULL();
|
RETURN_NULL();
|
||||||
}
|
}
|
||||||
|
@ -908,11 +908,11 @@ PHP_METHOD(Mux, dispatch) {
|
||||||
zval *z_substr;
|
zval *z_substr;
|
||||||
|
|
||||||
if ( zend_hash_quick_find( Z_ARRVAL_PP(z_options) , "vars", sizeof("vars"), zend_inline_hash_func(ZEND_STRS("vars")), (void**) &z_route_vars ) == FAILURE ) {
|
if ( zend_hash_quick_find( Z_ARRVAL_PP(z_options) , "vars", sizeof("vars"), zend_inline_hash_func(ZEND_STRS("vars")), (void**) &z_route_vars ) == FAILURE ) {
|
||||||
php_error(E_ERROR, "require route vars");
|
php_error(E_ERROR, "require R3Route vars");
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
if ( zend_hash_index_find( Z_ARRVAL_PP(z_options) , 0 , (void**) &z_route_vars_0 ) == FAILURE ) {
|
if ( zend_hash_index_find( Z_ARRVAL_PP(z_options) , 0 , (void**) &z_route_vars_0 ) == FAILURE ) {
|
||||||
php_error(E_ERROR, "require route vars[0]");
|
php_error(E_ERROR, "require R3Route vars[0]");
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +955,7 @@ PHP_METHOD(Mux, dispatch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( z_return_route ) {
|
if ( z_return_R3Route ) {
|
||||||
*return_value = *z_return_route;
|
*return_value = *z_return_route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
}
|
}
|
||||||
|
@ -972,7 +972,7 @@ PHP_METHOD(Mux, match) {
|
||||||
}
|
}
|
||||||
|
|
||||||
zval **z_route_pp = NULL;
|
zval **z_route_pp = NULL;
|
||||||
zval *z_route = NULL;
|
zval *z_R3Route = NULL;
|
||||||
if ( zend_hash_find( Z_ARRVAL_P( zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes") - 1, 1 TSRMLS_CC) ), path, path_len, (void**)&z_route_pp) == SUCCESS ) {
|
if ( zend_hash_find( Z_ARRVAL_P( zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes") - 1, 1 TSRMLS_CC) ), path, path_len, (void**)&z_route_pp) == SUCCESS ) {
|
||||||
if ( Z_TYPE_PP(z_route_pp) != IS_NULL ) {
|
if ( Z_TYPE_PP(z_route_pp) != IS_NULL ) {
|
||||||
*return_value = **z_route_pp;
|
*return_value = **z_route_pp;
|
||||||
|
@ -981,8 +981,8 @@ PHP_METHOD(Mux, match) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z_route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
|
z_R3Route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
|
||||||
if ( z_route != NULL ) {
|
if ( z_R3Route != NULL ) {
|
||||||
*return_value = *z_route;
|
*return_value = *z_route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
Z_ADDREF_P(z_route);
|
Z_ADDREF_P(z_route);
|
||||||
|
@ -1058,7 +1058,7 @@ PHP_METHOD(Mux, appendPCRERoute) {
|
||||||
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &rv, 1, z_pattern, NULL TSRMLS_CC );
|
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &rv, 1, z_pattern, NULL TSRMLS_CC );
|
||||||
|
|
||||||
if ( rv == NULL || Z_TYPE_P(rv) == IS_NULL ) {
|
if ( rv == NULL || Z_TYPE_P(rv) == IS_NULL ) {
|
||||||
zend_throw_exception(ce_r3_exception, "Can not compile route pattern", 0 TSRMLS_CC);
|
zend_throw_exception(ce_r3_exception, "Can not compile R3Route pattern", 0 TSRMLS_CC);
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
add_next_index_zval(z_routes, rv);
|
add_next_index_zval(z_routes, rv);
|
||||||
|
@ -1115,9 +1115,9 @@ inline void mux_add_route(INTERNAL_FUNCTION_PARAMETERS)
|
||||||
MAKE_STD_ZVAL(z_pattern);
|
MAKE_STD_ZVAL(z_pattern);
|
||||||
ZVAL_STRINGL(z_pattern, pattern, pattern_len, 1);
|
ZVAL_STRINGL(z_pattern, pattern, pattern_len, 1);
|
||||||
|
|
||||||
zval *z_compiled_route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
|
zval *z_compiled_R3Route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
|
||||||
if ( z_compiled_route == NULL ) {
|
if ( z_compiled_R3Route == NULL ) {
|
||||||
zend_throw_exception(ce_r3_exception, "Unable to compile route pattern.", 0 TSRMLS_CC);
|
zend_throw_exception(ce_r3_exception, "Unable to compile R3Route pattern.", 0 TSRMLS_CC);
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
zval_ptr_dtor(&z_pattern);
|
zval_ptr_dtor(&z_pattern);
|
||||||
|
@ -1160,7 +1160,7 @@ inline void mux_add_route(INTERNAL_FUNCTION_PARAMETERS)
|
||||||
add_index_zval( z_new_route, 3 , z_options);
|
add_index_zval( z_new_route, 3 , z_options);
|
||||||
add_next_index_zval(z_routes, z_new_route);
|
add_next_index_zval(z_routes, z_new_route);
|
||||||
|
|
||||||
// if there is no option specified in z_options, we can add the route to our static route hash
|
// if there is no option specified in z_options, we can add the R3Route to our static R3Route hash
|
||||||
if ( zend_hash_num_elements(Z_ARRVAL_P(z_options)) ) {
|
if ( zend_hash_num_elements(Z_ARRVAL_P(z_options)) ) {
|
||||||
zval * z_static_routes = zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes")-1, 1 TSRMLS_CC);
|
zval * z_static_routes = zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes")-1, 1 TSRMLS_CC);
|
||||||
if ( z_static_routes ) {
|
if ( z_static_routes ) {
|
||||||
|
@ -1173,7 +1173,7 @@ inline void mux_add_route(INTERNAL_FUNCTION_PARAMETERS)
|
||||||
zval * z_routes_by_id = zend_read_property(ce_r3_mux, this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
|
zval * z_routes_by_id = zend_read_property(ce_r3_mux, this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
zval *id_route = NULL;
|
zval *id_R3Route = NULL;
|
||||||
ALLOC_ZVAL(id_route);
|
ALLOC_ZVAL(id_route);
|
||||||
ZVAL_COPY_VALUE(id_route, z_new_route);
|
ZVAL_COPY_VALUE(id_route, z_new_route);
|
||||||
zval_copy_ctor(id_route);
|
zval_copy_ctor(id_route);
|
||||||
|
|
2
r3.pc.in
2
r3.pc.in
|
@ -6,6 +6,6 @@ libdir=@libdir@
|
||||||
Name: r3
|
Name: r3
|
||||||
Description: High-performance URL router library
|
Description: High-performance URL router library
|
||||||
Version: @PACKAGE_VERSION@
|
Version: @PACKAGE_VERSION@
|
||||||
Requires: libpcre
|
Requires: libpcre2-8
|
||||||
Libs: -L${libdir} -lr3
|
Libs: -L${libdir} -lr3
|
||||||
CFlags: -I${includedir}
|
CFlags: -I${includedir}
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/3rdparty ${PROJECT_SOURCE_DIR}")
|
add_library(r3 STATIC
|
||||||
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
|
edge.c
|
||||||
find_package(PCRE REQUIRED)
|
match_entry.c
|
||||||
set(libr3_SRCS node.c edge.c list.c slug.c str.c token.c match_entry.c)
|
memory.c
|
||||||
set(LIBS ${LIBS} ${PCRE_LIBRARIES} r3)
|
node.c
|
||||||
|
slug.c
|
||||||
|
str.c
|
||||||
|
token.c)
|
||||||
|
|
||||||
add_library(r3 STATIC ${libr3_SRCS})
|
target_compile_definitions(r3
|
||||||
target_link_libraries(r3 lib3rdparty pcre)
|
PRIVATE
|
||||||
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
|
_GNU_SOURCE)
|
||||||
|
|
||||||
|
target_include_directories(r3
|
||||||
|
PUBLIC
|
||||||
|
${PCRE2_INCLUDE_DIR}
|
||||||
|
${PROJECT_BINARY_DIR}
|
||||||
|
${PROJECT_SOURCE_DIR}/3rdparty
|
||||||
|
${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
target_link_libraries(r3
|
||||||
|
PUBLIC
|
||||||
|
${PCRE2_LIBRARIES})
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS r3
|
||||||
|
DESTINATION lib)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
|
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS)
|
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS)
|
||||||
MAYBE_COVERAGE=--coverage
|
MAYBE_COVERAGE=--coverage
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libr3core.la
|
noinst_LTLIBRARIES = libr3core.la
|
||||||
# lib_LIBRARIES = libr3.a
|
# lib_LIBRARIES = libr3.a
|
||||||
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c
|
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c memory.c
|
||||||
|
|
||||||
if ENABLE_JSON
|
if ENABLE_JSON
|
||||||
libr3core_la_SOURCES += json.c
|
libr3core_la_SOURCES += json.c
|
||||||
|
@ -23,7 +23,7 @@ MOSTLYCLEANFILES = *.gcov *.gcda *.gcno
|
||||||
|
|
||||||
# libr3_la_LIBADD=$(DEPS_LIBS) $(LIBOBJS) $(ALLOCA)
|
# libr3_la_LIBADD=$(DEPS_LIBS) $(LIBOBJS) $(ALLOCA)
|
||||||
# libr3core_la_LIBADD=$(DEPS_LIBS)
|
# libr3core_la_LIBADD=$(DEPS_LIBS)
|
||||||
# libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
|
# libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
||||||
|
|
||||||
if ENABLE_GRAPHVIZ
|
if ENABLE_GRAPHVIZ
|
||||||
libr3core_la_SOURCES += gvc.c
|
libr3core_la_SOURCES += gvc.c
|
||||||
|
|
101
src/edge.c
101
src/edge.c
|
@ -13,101 +13,76 @@
|
||||||
// Jemalloc memory management
|
// Jemalloc memory management
|
||||||
// #include <jemalloc/jemalloc.h>
|
// #include <jemalloc/jemalloc.h>
|
||||||
|
|
||||||
// PCRE
|
|
||||||
#include <pcre.h>
|
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "slug.h"
|
#include "slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
|
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void r3_edge_initl(edge *e, const char * pattern, int pattern_len, node * child)
|
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child)
|
||||||
{
|
{
|
||||||
e->pattern = (char*) pattern;
|
e->pattern.base = (char*) pattern;
|
||||||
e->pattern_len = pattern_len;
|
e->pattern.len = (unsigned int)pattern_len;
|
||||||
e->opcode = 0;
|
// e->opcode = 0;
|
||||||
e->child = child;
|
e->child = child;
|
||||||
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
e->has_slug = r3_path_contains_slug_char(e->pattern.base, e->pattern.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child)
|
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child)
|
||||||
{
|
// {
|
||||||
edge * e = (edge*) zmalloc( sizeof(edge) );
|
// R3Edge * e = (R3Edge*) malloc( sizeof(R3Edge) );
|
||||||
CHECK_PTR(e);
|
// CHECK_PTR(e);
|
||||||
e->pattern = (char*) pattern;
|
// e->pattern = (char*) pattern;
|
||||||
e->pattern_len = pattern_len;
|
// e->pattern_len = pattern_len;
|
||||||
e->opcode = 0;
|
// e->opcode = 0;
|
||||||
e->child = child;
|
// e->child = child;
|
||||||
e->has_slug = r3_path_contains_slug_char(e->pattern);
|
// e->has_slug = r3_path_contains_slug_char(e->pattern);
|
||||||
return e;
|
// return e;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* r3_edge_branch splits the edge and append the rest part as the child of the
|
||||||
|
* first level child
|
||||||
|
*
|
||||||
* branch the edge pattern at "dl" offset,
|
* branch the edge pattern at "dl" offset,
|
||||||
* insert a dummy child between the edges.
|
* and insert a dummy child between the edges.
|
||||||
*
|
*
|
||||||
*
|
* A -> [EDGE: abcdefg] -> B -> [EDGE:branch1], [EDGE:branch2]
|
||||||
* A -> [prefix..suffix] -> B
|
* A -> [EDGE: abcd] -> B1 -> [efg] -> B2 (new child with copied data from B)
|
||||||
* A -> [prefix] -> B -> [suffix] -> New Child (Copy Data, Edges from B)
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
node * r3_edge_branch(edge *e, int dl) {
|
R3Node * r3_edge_branch(R3Edge *e, int dl) {
|
||||||
node *new_child;
|
R3Node * new_child;
|
||||||
edge *e1;
|
R3Edge * new_edge;
|
||||||
char * s1 = e->pattern + dl;
|
|
||||||
int s1_len = 0;
|
// the rest string
|
||||||
|
const char * s1 = e->pattern.base + dl;
|
||||||
|
int s1_len = e->pattern.len - dl;
|
||||||
|
|
||||||
// the suffix edge of the leaf
|
// the suffix edge of the leaf
|
||||||
new_child = r3_tree_create(3);
|
new_child = r3_tree_create(3);
|
||||||
s1_len = e->pattern_len - dl;
|
|
||||||
e1 = r3_edge_createl(zstrndup(s1, s1_len), s1_len, new_child);
|
|
||||||
|
|
||||||
// Migrate the child edges to the new edge we just created.
|
new_edge = r3_node_append_edge(new_child);
|
||||||
for (int i = 0 ; i < e->child->edge_len ; i++) {
|
r3_edge_initl(new_edge, s1, s1_len, e->child);
|
||||||
r3_node_append_edge(new_child, &e->child->edges[i]);
|
e->child = new_child;
|
||||||
// e->child->edges[i] = NULL;
|
|
||||||
}
|
|
||||||
e->child->edge_len = 0;
|
|
||||||
|
|
||||||
|
|
||||||
// Migrate the child routes
|
|
||||||
for ( int i = 0 ; i < e->child->route_len ; i++ ) {
|
|
||||||
r3_node_append_route(new_child, e->child->routes[i]);
|
|
||||||
e->child->routes[i] = NULL;
|
|
||||||
}
|
|
||||||
e->child->route_len = 0;
|
|
||||||
|
|
||||||
// Migrate the endpoint
|
|
||||||
new_child->endpoint = e->child->endpoint;
|
|
||||||
e->child->endpoint = 0; // reset endpoint
|
|
||||||
|
|
||||||
// Migrate the data
|
|
||||||
new_child->data = e->child->data; // copy data pointer
|
|
||||||
e->child->data = NULL;
|
|
||||||
|
|
||||||
r3_node_append_edge(e->child, e1);
|
|
||||||
|
|
||||||
// truncate the original edge pattern
|
// truncate the original edge pattern
|
||||||
char *oldpattern = e->pattern;
|
e->pattern.len = dl;
|
||||||
e->pattern = zstrndup(e->pattern, dl);
|
|
||||||
e->pattern_len = dl;
|
|
||||||
zfree(oldpattern);
|
|
||||||
|
|
||||||
return new_child;
|
return new_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_edge_free(edge * e) {
|
void r3_edge_free(R3Edge * e) {
|
||||||
zfree(e->pattern);
|
if (e) {
|
||||||
if ( e->child ) {
|
if ( e->child ) {
|
||||||
r3_tree_free(e->child);
|
r3_tree_free(e->child);
|
||||||
}
|
}
|
||||||
// free itself
|
// free itself
|
||||||
zfree(e);
|
// free(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/gvc.c
11
src/gvc.c
|
@ -10,14 +10,13 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_gvc.h"
|
#include "r3_gvc.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) {
|
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) {
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
for ( int i = 0 ; i < n->edges.size ; i++ ) {
|
||||||
edge * e = n->edges[i];
|
edge * e = n->edges.entries + i;
|
||||||
(*node_cnt)++;
|
(*node_cnt)++;
|
||||||
|
|
||||||
Agnode_t *agn_child = NULL;
|
Agnode_t *agn_child = NULL;
|
||||||
|
@ -25,9 +24,11 @@ void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node
|
||||||
|
|
||||||
char *nodename = NULL;
|
char *nodename = NULL;
|
||||||
if ( e && e->child && e->child->combined_pattern ) {
|
if ( e && e->child && e->child->combined_pattern ) {
|
||||||
asprintf(&nodename,"%s", e->child->combined_pattern);
|
int r = asprintf(&nodename,"%s", e->child->combined_pattern);
|
||||||
|
if (r) {};
|
||||||
} else {
|
} else {
|
||||||
asprintf(&nodename,"#%d", *node_cnt);
|
int r = asprintf(&nodename,"#%d", *node_cnt);
|
||||||
|
if (r) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
agn_child = agnode(g, nodename, 1);
|
agn_child = agnode(g, nodename, 1);
|
||||||
|
|
24
src/json.c
24
src/json.c
|
@ -9,29 +9,29 @@
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_json.h"
|
#include "r3_json.h"
|
||||||
|
|
||||||
json_object * r3_route_to_json_object(const route * r) {
|
json_object * r3_route_to_json_object(const R3Route * r) {
|
||||||
json_object *obj;
|
json_object *obj;
|
||||||
|
|
||||||
obj = json_object_new_object();
|
obj = json_object_new_object();
|
||||||
json_object_object_add(obj, "path", json_object_new_string(r->path));
|
json_object_object_add(obj, "path", json_object_new_string(r->path.base));
|
||||||
json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method));
|
json_object_object_add(obj, "allowed_methods", json_object_new_int(r->request_method));
|
||||||
|
|
||||||
|
|
||||||
if (r->host) {
|
if (r->host) {
|
||||||
json_object_object_add(obj, "host", json_object_new_string(r->host));
|
json_object_object_add(obj, "host", json_object_new_string(r->host.base));
|
||||||
}
|
}
|
||||||
if (r->remote_addr_pattern) {
|
if (r->remote_addr_pattern) {
|
||||||
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern));
|
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern.base));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
json_object * r3_edge_to_json_object(const edge * e) {
|
json_object * r3_edge_to_json_object(const R3Edge * e) {
|
||||||
json_object *obj;
|
json_object *obj;
|
||||||
|
|
||||||
obj = json_object_new_object();
|
obj = json_object_new_object();
|
||||||
json_object_object_add(obj, "pattern", json_object_new_string(e->pattern));
|
json_object_object_add(obj, "pattern", json_object_new_string(e->pattern.base));
|
||||||
json_object_object_add(obj, "opcode", json_object_new_int(e->opcode));
|
json_object_object_add(obj, "opcode", json_object_new_int(e->opcode));
|
||||||
json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug));
|
json_object_object_add(obj, "slug", json_object_new_boolean(e->has_slug));
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ json_object * r3_edge_to_json_object(const edge * e) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object * r3_node_to_json_object(const node * n) {
|
json_object * r3_node_to_json_object(const R3Node * n) {
|
||||||
json_object *obj;
|
json_object *obj;
|
||||||
|
|
||||||
obj = json_object_new_object();
|
obj = json_object_new_object();
|
||||||
|
@ -60,7 +60,7 @@ json_object * r3_node_to_json_object(const node * n) {
|
||||||
json_object *edges_array = json_object_new_array();
|
json_object *edges_array = json_object_new_array();
|
||||||
json_object_object_add(obj, "edges", edges_array);
|
json_object_object_add(obj, "edges", edges_array);
|
||||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
for (i = 0 ; i < n->edge_len ; i++ ) {
|
||||||
json_object *edge_json_obj = r3_edge_to_json_object(n->edges[i]);
|
json_object *edge_json_obj = r3_edge_to_json_object(n->edges.entries + i);
|
||||||
json_object_array_add(edges_array, edge_json_obj);
|
json_object_array_add(edges_array, edge_json_obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ json_object * r3_node_to_json_object(const node * n) {
|
||||||
json_object *routes_array = json_object_new_array();
|
json_object *routes_array = json_object_new_array();
|
||||||
json_object_object_add(obj, "routes", routes_array);
|
json_object_object_add(obj, "routes", routes_array);
|
||||||
for (i = 0; i < n->route_len; i++ ) {
|
for (i = 0; i < n->route_len; i++ ) {
|
||||||
json_object *route_json_obj = r3_route_to_json_object(n->routes[i]);
|
json_object *route_json_obj = r3_route_to_json_object(n->routes.entries + i);
|
||||||
json_object_array_add(routes_array, route_json_obj);
|
json_object_array_add(routes_array, route_json_obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,17 +79,17 @@ json_object * r3_node_to_json_object(const node * n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char * r3_node_to_json_string_ext(const node * n, int options) {
|
const char * r3_node_to_json_string_ext(const R3Node * n, int options) {
|
||||||
json_object *obj = r3_node_to_json_object(n);
|
json_object *obj = r3_node_to_json_object(n);
|
||||||
return json_object_to_json_string_ext(obj, options);
|
return json_object_to_json_string_ext(obj, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * r3_node_to_json_pretty_string(const node * n) {
|
const char * r3_node_to_json_pretty_string(const R3Node * n) {
|
||||||
json_object *obj = r3_node_to_json_object(n);
|
json_object *obj = r3_node_to_json_object(n);
|
||||||
return json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
|
return json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * r3_node_to_json_string(const node * n) {
|
const char * r3_node_to_json_string(const R3Node * n) {
|
||||||
json_object *obj = r3_node_to_json_object(n);
|
json_object *obj = r3_node_to_json_object(n);
|
||||||
return json_object_to_json_string(obj);
|
return json_object_to_json_string(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,13 @@
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "r3_list.h"
|
#include "r3_list.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
/* Naive linked list implementation */
|
/* Naive linked list implementation */
|
||||||
|
|
||||||
list *
|
list *
|
||||||
list_create()
|
list_create()
|
||||||
{
|
{
|
||||||
list *l = (list *) zmalloc(sizeof(list));
|
list *l = (list *) malloc(sizeof(list));
|
||||||
l->count = 0;
|
l->count = 0;
|
||||||
l->head = NULL;
|
l->head = NULL;
|
||||||
l->tail = NULL;
|
l->tail = NULL;
|
||||||
|
@ -38,7 +37,7 @@ list_free(l)
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&(l->mutex));
|
pthread_mutex_unlock(&(l->mutex));
|
||||||
pthread_mutex_destroy(&(l->mutex));
|
pthread_mutex_destroy(&(l->mutex));
|
||||||
zfree(l);
|
free(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ list_item * list_add_element(list * l, void * ptr)
|
||||||
|
|
||||||
pthread_mutex_lock(&(l->mutex));
|
pthread_mutex_lock(&(l->mutex));
|
||||||
|
|
||||||
li = (list_item *) zmalloc(sizeof(list_item));
|
li = (list_item *) malloc(sizeof(list_item));
|
||||||
li->value = ptr;
|
li->value = ptr;
|
||||||
li->next = NULL;
|
li->next = NULL;
|
||||||
li->prev = l->tail;
|
li->prev = l->tail;
|
||||||
|
@ -89,7 +88,7 @@ list_remove_element(l, ptr)
|
||||||
li->next->prev = li->prev;
|
li->next->prev = li->prev;
|
||||||
}
|
}
|
||||||
l->count--;
|
l->count--;
|
||||||
zfree(li);
|
free(li);
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,31 +4,25 @@
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
#include "config.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pcre.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
match_entry * match_entry_createl(const char * path, int path_len) {
|
match_entry * match_entry_createl(const char * path, int path_len) {
|
||||||
match_entry * entry = zmalloc(sizeof(match_entry));
|
match_entry * entry = r3_mem_alloc( sizeof(match_entry) );
|
||||||
if(!entry)
|
memset(entry, 0, sizeof(*entry));
|
||||||
return NULL;
|
r3_vector_reserve(&entry->vars.tokens, 3);
|
||||||
entry->vars = str_array_create(3);
|
entry->path.base = path;
|
||||||
entry->path = path;
|
entry->path.len = path_len;
|
||||||
entry->path_len = path_len;
|
|
||||||
entry->data = NULL;
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void match_entry_free(match_entry * entry) {
|
void match_entry_free(match_entry * entry) {
|
||||||
assert(entry);
|
assert(entry);
|
||||||
if (entry->vars) {
|
free(entry->vars.tokens.entries);
|
||||||
str_array_free(entry->vars);
|
free(entry);
|
||||||
}
|
|
||||||
zfree(entry);
|
|
||||||
}
|
}
|
||||||
|
|
45
src/memory.c
Normal file
45
src/memory.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 DeNA Co., Ltd.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
void r3_fatal(const char *msg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fatal:%s\n", msg);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_vector__expand(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
|
||||||
|
{
|
||||||
|
void *new_entries;
|
||||||
|
assert(vector->capacity < new_capacity);
|
||||||
|
if (!vector->capacity)
|
||||||
|
vector->capacity = 4;
|
||||||
|
while (vector->capacity < new_capacity)
|
||||||
|
vector->capacity *= 2;
|
||||||
|
new_entries = r3_mem_realloc(vector->entries, element_size * vector->capacity);
|
||||||
|
vector->entries = new_entries;
|
||||||
|
}
|
775
src/node.c
775
src/node.c
File diff suppressed because it is too large
Load diff
19
src/r3_debug.h
Normal file
19
src/r3_debug.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef R3_DEBUG_H
|
||||||
|
#define R3_DEBUG_H
|
||||||
|
|
||||||
|
// #define DEBUG 1
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
#define info(fmt, ...) \
|
||||||
|
do { fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
|
||||||
|
|
||||||
|
#define debug(fmt, ...) \
|
||||||
|
do { fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
|
||||||
|
__LINE__, __func__, __VA_ARGS__); } while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define info(...);
|
||||||
|
#define debug(...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !DEBUG_H */
|
19
src/slug.c
19
src/slug.c
|
@ -9,14 +9,14 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "slug.h"
|
#include "slug.h"
|
||||||
#include "zmalloc.h"
|
#include "r3_debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
r3_slug_t * r3_slug_new(const char * path, int path_len) {
|
r3_slug_t * r3_slug_new(const char * path, int path_len) {
|
||||||
r3_slug_t * s = zmalloc(sizeof(r3_slug_t));
|
r3_slug_t * s = malloc(sizeof(r3_slug_t));
|
||||||
if (!s)
|
if (!s)
|
||||||
return NULL;
|
return NULL;
|
||||||
s->path = (char*) path;
|
s->path = (char*) path;
|
||||||
|
@ -32,7 +32,7 @@ r3_slug_t * r3_slug_new(const char * path, int path_len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_slug_free(r3_slug_t * s) {
|
void r3_slug_free(r3_slug_t * s) {
|
||||||
zfree(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ int r3_slug_check(r3_slug_t *s) {
|
||||||
|
|
||||||
char * r3_slug_to_str(const r3_slug_t *s) {
|
char * r3_slug_to_str(const r3_slug_t *s) {
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path);
|
int r = asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path);
|
||||||
|
if (r) {};
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
|
||||||
}
|
}
|
||||||
|
|
||||||
// there is no slug
|
// there is no slug
|
||||||
if (!r3_path_contains_slug_char(offset)) {
|
if (!r3_path_contains_slug_char(offset, needle_len - (offset-needle))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +140,8 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
|
||||||
if (state != 0) {
|
if (state != 0) {
|
||||||
if (errstr) {
|
if (errstr) {
|
||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state);
|
int r = asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state);
|
||||||
|
if (r) {};
|
||||||
*errstr = err;
|
*errstr = err;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -177,7 +179,8 @@ int r3_slug_count(const char * needle, int len, char **errstr) {
|
||||||
if (state != 0) {
|
if (state != 0) {
|
||||||
if (errstr) {
|
if (errstr) {
|
||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state);
|
int r = asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state);
|
||||||
|
if (r) {};
|
||||||
*errstr = err;
|
*errstr = err;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
11
src/slug.h
11
src/slug.h
|
@ -4,8 +4,8 @@
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
#ifndef R3_SLUG_H
|
#ifndef SLUG_H
|
||||||
#define R3_SLUG_H
|
#define SLUG_H
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/**
|
/**
|
||||||
|
@ -49,8 +49,11 @@ char * r3_slug_to_str(const r3_slug_t *s);
|
||||||
|
|
||||||
void r3_slug_free(r3_slug_t * s);
|
void r3_slug_free(r3_slug_t * s);
|
||||||
|
|
||||||
static inline int r3_path_contains_slug_char(const char * str) {
|
static inline int r3_path_contains_slug_char(const char *str, unsigned int len) {
|
||||||
return strchr(str, '{') != NULL ? 1 : 0;
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
if (str[i] == '{') return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !SLUG_H */
|
#endif /* !SLUG_H */
|
||||||
|
|
120
src/str.c
120
src/str.c
|
@ -10,11 +10,18 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
|
#include "str.h"
|
||||||
#include "slug.h"
|
#include "slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
int r3_pattern_to_opcode(const char * pattern, int len) {
|
static const char * strnchr(const char* str, unsigned int len, int ch) {
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
if (str[i] == ch) return str + i;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r3_pattern_to_opcode(const char * pattern, unsigned int len) {
|
||||||
if ( strncmp(pattern, "\\w+",len) == 0 ) {
|
if ( strncmp(pattern, "\\w+",len) == 0 ) {
|
||||||
return OP_EXPECT_MORE_WORDS;
|
return OP_EXPECT_MORE_WORDS;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +43,9 @@ int r3_pattern_to_opcode(const char * pattern, int len) {
|
||||||
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
|
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
|
||||||
return OP_EXPECT_NODASH;
|
return OP_EXPECT_NODASH;
|
||||||
}
|
}
|
||||||
|
if ( strncmp(pattern, ".*", len) == 0 ) {
|
||||||
|
return OP_GREEDY_ANY;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,21 +81,23 @@ char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **
|
||||||
if (found_s1 || found_s2) {
|
if (found_s1 || found_s2) {
|
||||||
// wrong slug pattern
|
// wrong slug pattern
|
||||||
if(errstr) {
|
if(errstr) {
|
||||||
asprintf(errstr, "Incomplete slug pattern");
|
int r = asprintf(errstr, "Incomplete slug pattern");
|
||||||
|
if (r) {};
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * r3_slug_find_placeholder(const char *s1, int *len) {
|
const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len) {
|
||||||
char *c;
|
const char *c;
|
||||||
char *s2;
|
const char *s2;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
if ( NULL != (c = strchr(s1, '{')) ) {
|
if ((c = strnchr(s1, str_len, '{'))) {
|
||||||
// find closing '}'
|
// find closing '}'
|
||||||
s2 = c;
|
s2 = c;
|
||||||
while(*s2) {
|
unsigned int j = str_len - (c - s1);
|
||||||
|
for (unsigned int i = 0; i < j; i++) {
|
||||||
if (*s2 == '{' )
|
if (*s2 == '{' )
|
||||||
cnt++;
|
cnt++;
|
||||||
else if (*s2 == '}' )
|
else if (*s2 == '}' )
|
||||||
|
@ -110,15 +122,16 @@ char * r3_slug_find_placeholder(const char *s1, int *len) {
|
||||||
/**
|
/**
|
||||||
* given a slug string, duplicate the pattern string of the slug
|
* given a slug string, duplicate the pattern string of the slug
|
||||||
*/
|
*/
|
||||||
char * r3_slug_find_pattern(const char *s1, int *len) {
|
const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len) {
|
||||||
char *c;
|
const char *c;
|
||||||
char *s2;
|
const char *s2;
|
||||||
int cnt = 1;
|
unsigned int cnt = 1;
|
||||||
if ( NULL != (c = strchr(s1, ':')) ) {
|
if ( (c = strnchr(s1, str_len, ':')) ) {
|
||||||
c++;
|
c++;
|
||||||
// find closing '}'
|
// find closing '}'
|
||||||
s2 = c;
|
s2 = c;
|
||||||
while(s2) {
|
unsigned int j = str_len - (c - s1);
|
||||||
|
for (unsigned int i = 0; i < j; i++) {
|
||||||
if (*s2 == '{' )
|
if (*s2 == '{' )
|
||||||
cnt++;
|
cnt++;
|
||||||
else if (*s2 == '}' )
|
else if (*s2 == '}' )
|
||||||
|
@ -131,6 +144,9 @@ char * r3_slug_find_pattern(const char *s1, int *len) {
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (cnt!=0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
*len = s2 - c;
|
*len = s2 - c;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -139,54 +155,46 @@ char * r3_slug_find_pattern(const char *s1, int *len) {
|
||||||
/**
|
/**
|
||||||
* given a slug string, duplicate the parameter name string of the slug
|
* given a slug string, duplicate the parameter name string of the slug
|
||||||
*/
|
*/
|
||||||
char * r3_slug_find_name(const char *s1, int *len) {
|
const char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len) {
|
||||||
char *c;
|
const char * c;
|
||||||
char *s2;
|
const char * s2;
|
||||||
int cnt = 0;
|
unsigned int plholder;
|
||||||
c = s1;
|
if ((c = r3_slug_find_placeholder(s1, str_len, &plholder))) {
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if(*c == '{') cnt++;
|
|
||||||
if(*c == '}') cnt--;
|
|
||||||
if(*c == ':') break;
|
|
||||||
if(*c == '\0') return NULL;
|
|
||||||
if(cnt == 0) break;
|
|
||||||
c++;
|
c++;
|
||||||
|
if (( s2 = strnchr(c, plholder, ':') )) {
|
||||||
|
*len = s2 - c;
|
||||||
|
return c;
|
||||||
|
} else {
|
||||||
|
*len = plholder - 2;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// find starting '{'
|
return NULL;
|
||||||
s2 = c;
|
|
||||||
while(1) {
|
|
||||||
if ( *s2 == '{' )
|
|
||||||
break;
|
|
||||||
s2--;
|
|
||||||
}
|
}
|
||||||
s2++;
|
|
||||||
*len = c - s2;
|
|
||||||
return s2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param char * sep separator
|
* @param char * sep separator
|
||||||
*/
|
*/
|
||||||
char * r3_slug_compile(const char * str, int len)
|
char * r3_slug_compile(const char * str, unsigned int len)
|
||||||
{
|
{
|
||||||
char *s1 = NULL, *o = NULL;
|
const char *s1 = NULL;
|
||||||
char *pat = NULL;
|
char *o = NULL;
|
||||||
|
const char *pat = NULL;
|
||||||
char sep = '/';
|
char sep = '/';
|
||||||
|
|
||||||
|
|
||||||
// append prefix
|
// append prefix
|
||||||
int s1_len;
|
unsigned int s1_len;
|
||||||
s1 = r3_slug_find_placeholder(str, &s1_len);
|
s1 = r3_slug_find_placeholder(str, len, &s1_len);
|
||||||
|
|
||||||
if ( s1 == NULL ) {
|
if ( !s1 ) {
|
||||||
return zstrdup(str);
|
return strndup(str,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
char * out = NULL;
|
char * out = NULL;
|
||||||
if ((out = zcalloc(sizeof(char) * 200)) == NULL) {
|
if (!(out = calloc(1, sizeof(char) * 200))) {
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +206,8 @@ char * r3_slug_compile(const char * str, int len)
|
||||||
o += (s1 - str);
|
o += (s1 - str);
|
||||||
|
|
||||||
|
|
||||||
int pat_len;
|
unsigned int pat_len;
|
||||||
pat = r3_slug_find_pattern(s1, &pat_len);
|
pat = r3_slug_find_pattern(s1, s1_len, &pat_len);
|
||||||
|
|
||||||
if (pat) {
|
if (pat) {
|
||||||
*o = '(';
|
*o = '(';
|
||||||
|
@ -213,7 +221,7 @@ char * r3_slug_compile(const char * str, int len)
|
||||||
o+= strlen("([^*]+)");
|
o+= strlen("([^*]+)");
|
||||||
}
|
}
|
||||||
s1 += s1_len;
|
s1 += s1_len;
|
||||||
strncat(o, s1, strlen(s1));
|
strncat(o, s1, len - (s1 - str)); // string after slug
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,13 +230,7 @@ char * ltrim_slash(char* str)
|
||||||
{
|
{
|
||||||
char * p = str;
|
char * p = str;
|
||||||
while (*p == '/') p++;
|
while (*p == '/') p++;
|
||||||
return zstrdup(p);
|
return strdup(p);
|
||||||
}
|
|
||||||
|
|
||||||
void str_repeat(char *s, const char *c, int len) {
|
|
||||||
while(len--) {
|
|
||||||
s[len - 1] = *c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_indent(int level) {
|
void print_indent(int level) {
|
||||||
|
@ -241,13 +243,13 @@ void print_indent(int level) {
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_STRDUP
|
#ifndef HAVE_STRDUP
|
||||||
char *zstrdup(const char *s) {
|
char *strdup(const char *s) {
|
||||||
char *out;
|
char *out;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while( s[count] )
|
while( s[count] )
|
||||||
++count;
|
++count;
|
||||||
++count;
|
++count;
|
||||||
out = zmalloc(sizeof(char) * count);
|
out = malloc(sizeof(char) * count);
|
||||||
out[--count] = 0;
|
out[--count] = 0;
|
||||||
while( --count >= 0 )
|
while( --count >= 0 )
|
||||||
out[count] = s[count];
|
out[count] = s[count];
|
||||||
|
@ -258,13 +260,13 @@ char *zstrdup(const char *s) {
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *zstrndup(const char *s, int n) {
|
char *strndup(const char *s, int n) {
|
||||||
char *out;
|
char *out;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while( count < n && s[count] )
|
while( count < n && s[count] )
|
||||||
++count;
|
++count;
|
||||||
++count;
|
++count;
|
||||||
out = zmalloc(sizeof(char) * count);
|
out = malloc(sizeof(char) * count);
|
||||||
out[--count] = 0;
|
out[--count] = 0;
|
||||||
while( --count >= 0 )
|
while( --count >= 0 )
|
||||||
out[count] = s[count];
|
out[count] = s[count];
|
||||||
|
|
14
src/str.h
Normal file
14
src/str.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef R3_STR_INTERN_H
|
||||||
|
#define R3_STR_INTERN_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void print_indent(int level);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
63
src/token.c
63
src/token.c
|
@ -4,62 +4,51 @@
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
#include "config.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "zmalloc.h"
|
#include "memory.h"
|
||||||
|
|
||||||
str_array * str_array_create(int cap) {
|
|
||||||
str_array * list = (str_array*) zmalloc( sizeof(str_array) );
|
|
||||||
if (!list)
|
|
||||||
return NULL;
|
|
||||||
list->len = 0;
|
|
||||||
list->cap = cap;
|
|
||||||
list->tokens = (char**) zmalloc( sizeof(char*) * cap);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void str_array_free(str_array *l) {
|
void str_array_free(str_array *l) {
|
||||||
assert(l);
|
assert(l);
|
||||||
for ( int i = 0; i < l->len ; i++ ) {
|
free(l->tokens.entries);
|
||||||
if (l->tokens[ i ]) {
|
|
||||||
zfree(l->tokens[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zfree(l->tokens);
|
|
||||||
zfree(l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool str_array_is_full(const str_array * l) {
|
bool str_array_append(str_array * l, const char * token, unsigned int len) {
|
||||||
return l->len >= l->cap;
|
r3_vector_reserve(&l->tokens, l->tokens.size + 1);
|
||||||
|
r3_iovec_t *temp = l->tokens.entries + l->tokens.size++;
|
||||||
|
memset(temp, 0, sizeof(*temp));
|
||||||
|
temp->base = token;
|
||||||
|
temp->len = len;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool str_array_resize(str_array * l, int new_cap) {
|
void str_array_dump_slugs(const str_array *l) {
|
||||||
l->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap);
|
if (l->tokens.size) {
|
||||||
l->cap = new_cap;
|
printf("[");
|
||||||
return l->tokens != NULL;
|
for ( int i = 0; i < l->tokens.size ; i++ ) {
|
||||||
}
|
printf("\"%*.*s\"", l->slugs.entries[i].len,l->slugs.entries[i].len,l->slugs.entries[i].base );
|
||||||
|
if ( i + 1 != l->tokens.size ) {
|
||||||
bool str_array_append(str_array * l, char * token) {
|
printf(", ");
|
||||||
if ( str_array_is_full(l) ) {
|
|
||||||
bool ret = str_array_resize(l, l->cap + 20);
|
|
||||||
if (ret == FALSE ) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l->tokens[ l->len++ ] = token;
|
printf("]\n");
|
||||||
return TRUE;
|
} else {
|
||||||
|
printf("[]\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void str_array_dump(const str_array *l) {
|
void str_array_dump(const str_array *l) {
|
||||||
printf("[");
|
printf("[");
|
||||||
for ( int i = 0; i < l->len ; i++ ) {
|
for ( int i = 0; i < l->tokens.size ; i++ ) {
|
||||||
printf("\"%s\"", l->tokens[i] );
|
printf("\"%*.*s\"", l->tokens.entries[i].len,l->tokens.entries[i].len,l->tokens.entries[i].base );
|
||||||
if ( i + 1 != l->len ) {
|
// printf("\"%s\"", l->tokens.entries[i] );
|
||||||
|
if ( i + 1 != l->tokens.size ) {
|
||||||
printf(", ");
|
printf(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
function(add_r3_test NAME)
|
||||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
add_executable(${NAME} ${ARGN})
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}")
|
|
||||||
find_package(Check REQUIRED)
|
|
||||||
find_package(PCRE REQUIRED)
|
|
||||||
# find_package(Judy REQUIRED)
|
|
||||||
|
|
||||||
if (NOT CHECK_FOUND)
|
target_include_directories(${NAME}
|
||||||
message(STATUS "Skipping unit tests, Check library not found!")
|
PRIVATE
|
||||||
else (NOT CHECK_FOUND)
|
${CHECK_INCLUDE_DIRS}
|
||||||
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3)
|
${PROJECT_BINARY_DIR}
|
||||||
|
${PROJECT_SOURCE_DIR}/src)
|
||||||
|
|
||||||
include_directories(${CHECK_INCLUDE_DIRS})
|
target_link_libraries(${NAME}
|
||||||
# include_directories("${PROJECT_SOURCE_DIR}/include/r2")
|
${CHECK_LDFLAGS}
|
||||||
add_executable(check_tree check_tree.c)
|
r3)
|
||||||
target_link_libraries(check_tree ${TEST_LIBS})
|
|
||||||
|
|
||||||
add_custom_command(
|
add_test(NAME ${NAME} COMMAND ${NAME})
|
||||||
TARGET check_tree POST_BUILD
|
endfunction()
|
||||||
COMMENT "Running unit tests"
|
|
||||||
COMMAND check_tree
|
|
||||||
)
|
|
||||||
endif (NOT CHECK_FOUND)
|
|
||||||
|
|
||||||
|
add_r3_test(check_tree check_tree.c)
|
||||||
|
add_r3_test(check_slug check_slug.c)
|
||||||
|
add_r3_test(check_routes check_routes.c)
|
||||||
|
add_r3_test(check_str_array check_str_array.c)
|
||||||
|
add_r3_test(check_host check_host.c)
|
||||||
|
add_r3_test(check_http_scheme check_http_scheme.c)
|
||||||
|
add_r3_test(check_remote_addr check_remote_addr.c)
|
||||||
|
add_r3_test(check_routes2 check_routes2.c)
|
||||||
|
|
||||||
|
add_executable(bench bench.c)
|
||||||
|
target_link_libraries(bench r3)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TESTS =
|
TESTS =
|
||||||
|
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -I$(top_builddir)/3rdparty -Wall -std=c99 -ggdb -Wall
|
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -Wall -std=c99 -ggdb `pkg-config --cflags --libs check`
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
|
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
|
||||||
|
|
||||||
if USE_JEMALLOC
|
if USE_JEMALLOC
|
||||||
|
@ -27,6 +27,18 @@ check_routes_SOURCES = check_routes.c
|
||||||
TESTS += check_str_array
|
TESTS += check_str_array
|
||||||
check_str_array_SOURCES = check_str_array.c
|
check_str_array_SOURCES = check_str_array.c
|
||||||
|
|
||||||
|
TESTS += check_host
|
||||||
|
check_host_SOURCES = check_host.c
|
||||||
|
|
||||||
|
TESTS += check_remote_addr
|
||||||
|
check_remote_addr_SOURCES = check_remote_addr.c
|
||||||
|
|
||||||
|
TESTS += check_http_scheme
|
||||||
|
check_http_scheme_SOURCES = check_http_scheme.c
|
||||||
|
|
||||||
|
TESTS += check_routes2
|
||||||
|
check_routes2_SOURCES = check_routes2.c
|
||||||
|
|
||||||
|
|
||||||
if ENABLE_JSON
|
if ENABLE_JSON
|
||||||
TESTS += check_json
|
TESTS += check_json
|
||||||
|
@ -49,4 +61,3 @@ bench_SOURCES = bench.c
|
||||||
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir)/include
|
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir)/include
|
||||||
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include
|
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include
|
||||||
CLEANFILES = check_tree.log
|
CLEANFILES = check_tree.log
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,14 @@
|
||||||
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
|
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
|
||||||
|
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long unixtime() {
|
unsigned long unixtime() {
|
||||||
struct timeval tp;
|
struct timeval tp;
|
||||||
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
|
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
||||||
return tp.tv_sec;
|
return tp.tv_sec;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -30,7 +29,7 @@ double microtime() {
|
||||||
struct timeval tp;
|
struct timeval tp;
|
||||||
long sec = 0L;
|
long sec = 0L;
|
||||||
double msec = 0.0;
|
double msec = 0.0;
|
||||||
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
|
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
||||||
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
|
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
|
||||||
sec = tp.tv_sec;
|
sec = tp.tv_sec;
|
||||||
if (msec >= 1.0)
|
if (msec >= 1.0)
|
||||||
|
@ -96,7 +95,7 @@ void bench_append_csv(char *filename, int countOfB, ...) {
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(1);
|
R3Node * n = r3_tree_create(1);
|
||||||
|
|
||||||
int route_data = 999;
|
int route_data = 999;
|
||||||
|
|
||||||
|
@ -441,7 +440,7 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
||||||
r3_tree_compile(n, NULL);
|
r3_tree_compile(n, NULL);
|
||||||
END_MEASURE(tree_compile)
|
END_MEASURE(tree_compile)
|
||||||
|
|
||||||
node *m;
|
R3Node * m;
|
||||||
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
||||||
assert(m != NULL);
|
assert(m != NULL);
|
||||||
assert( *((int*) m->data) == 999 );
|
assert( *((int*) m->data) == 999 );
|
||||||
|
@ -461,9 +460,10 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
||||||
BENCHMARK_SUMMARY(str_match_entry);
|
BENCHMARK_SUMMARY(str_match_entry);
|
||||||
|
|
||||||
|
|
||||||
node * tree2 = r3_tree_create(1);
|
R3Node * tree2 = r3_tree_create(1);
|
||||||
r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL);
|
r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL);
|
||||||
r3_tree_compile(tree2, NULL);
|
r3_tree_compile(tree2, NULL);
|
||||||
|
// r3_tree_dump(tree2,0);
|
||||||
|
|
||||||
BENCHMARK(pcre_dispatch)
|
BENCHMARK(pcre_dispatch)
|
||||||
r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL);
|
r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_gvc.h"
|
#include "r3_gvc.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
|
|
||||||
START_TEST (test_gvc_render_dot)
|
START_TEST (test_gvc_render_dot)
|
||||||
|
|
92
tests/check_host.c
Normal file
92
tests/check_host.c
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "r3.h"
|
||||||
|
#include "r3_slug.h"
|
||||||
|
|
||||||
|
START_TEST (test_hosts)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
R3Route * route = NULL;
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo";
|
||||||
|
char * host0 = "foo.com";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
route->host.base = host0;
|
||||||
|
route->host.len = strlen(host0);
|
||||||
|
|
||||||
|
char * uri1 = "/bar";
|
||||||
|
char * host1 = "*.bar.com";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
route->host.base = host1;
|
||||||
|
route->host.len = strlen(host1);
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->host.base = host0;
|
||||||
|
entry->host.len = strlen(host0);
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->host.base = "www.bar.com";
|
||||||
|
entry->host.len = strlen("www.bar.com");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->host.base = "bar.com";
|
||||||
|
entry->host.len = strlen("bar.com");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->host.base = ".bar.com";
|
||||||
|
entry->host.len = strlen(".bar.com");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->host.base = "a.bar.com";
|
||||||
|
entry->host.len = strlen("a.bar.com");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite* r3_suite (void) {
|
||||||
|
Suite *suite = suite_create("r3 host tests");
|
||||||
|
TCase *tcase = tcase_create("testcase");
|
||||||
|
tcase_add_test(tcase, test_hosts);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
int number_failed;
|
||||||
|
Suite *suite = r3_suite();
|
||||||
|
SRunner *runner = srunner_create(suite);
|
||||||
|
srunner_run_all(runner, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(runner);
|
||||||
|
srunner_free(runner);
|
||||||
|
return number_failed;
|
||||||
|
}
|
105
tests/check_http_scheme.c
Normal file
105
tests/check_http_scheme.c
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "r3.h"
|
||||||
|
#include "r3_slug.h"
|
||||||
|
|
||||||
|
START_TEST (test_http_scheme)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
R3Route * route = NULL;
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
|
||||||
|
char * uri1 = "/bar";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
route->http_scheme = SCHEME_HTTPS;
|
||||||
|
|
||||||
|
char * uri2 = "/boo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
|
||||||
|
route->http_scheme = SCHEME_HTTP | SCHEME_HTTPS;
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->http_scheme = SCHEME_HTTP;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->http_scheme = SCHEME_HTTP;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->http_scheme = SCHEME_HTTPS;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->http_scheme = SCHEME_HTTP;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri2);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->http_scheme = SCHEME_HTTPS;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri2);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite* r3_suite (void) {
|
||||||
|
Suite *suite = suite_create("r3 remote_addr tests");
|
||||||
|
TCase *tcase = tcase_create("testcase");
|
||||||
|
tcase_add_test(tcase, test_http_scheme);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
int number_failed;
|
||||||
|
Suite *suite = r3_suite();
|
||||||
|
SRunner *runner = srunner_create(suite);
|
||||||
|
srunner_run_all(runner, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(runner);
|
||||||
|
srunner_free(runner);
|
||||||
|
return number_failed;
|
||||||
|
}
|
|
@ -10,13 +10,13 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "r3_json.h"
|
#include "r3_json.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
START_TEST (test_json_encode)
|
START_TEST (test_json_encode)
|
||||||
{
|
{
|
||||||
node * n;
|
R3Node * n;
|
||||||
n = r3_tree_create(10);
|
n = r3_tree_create(10);
|
||||||
|
|
||||||
ck_assert(n);
|
ck_assert(n);
|
||||||
|
|
216
tests/check_remote_addr.c
Normal file
216
tests/check_remote_addr.c
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "r3.h"
|
||||||
|
#include "r3_slug.h"
|
||||||
|
|
||||||
|
START_TEST (test_remote_addrs)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
R3Route * route = NULL;
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
route->remote_addr_v4 = 0;
|
||||||
|
route->remote_addr_v4_bits = 0;
|
||||||
|
|
||||||
|
char * uri1 = "/bar";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
route->remote_addr_v4 = inet_network("127.0.0.1");
|
||||||
|
route->remote_addr_v4_bits = 32;
|
||||||
|
|
||||||
|
char * uri2 = "/boo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
|
||||||
|
route->remote_addr_v4 = inet_network("127.0.0.1");
|
||||||
|
route->remote_addr_v4_bits = 24;
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->remote_addr.base = "127.0.0.1";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->remote_addr.base = "127.0.0.1";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->remote_addr.base = "127.0.0.2";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->remote_addr.base = "127.0.0.1";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri2);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->remote_addr.base = "127.0.0.2";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri2);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->remote_addr.base = "127.0.1.2";
|
||||||
|
entry->remote_addr.len = sizeof("127.0.1.2") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/boo");
|
||||||
|
entry->remote_addr.base = "127.0.1.333"; // invalid ip address
|
||||||
|
entry->remote_addr.len = sizeof("127.0.1.333") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
void parse_ipv6(const char *ipv6, int nmask, R3Route * route)
|
||||||
|
{
|
||||||
|
struct in6_addr addr6;
|
||||||
|
int ret = inet_pton(AF_INET6, ipv6, (void *)&addr6);
|
||||||
|
ck_assert(ret == 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
route->remote_addr_v6[i] = ntohl(addr6.__in6_u.__u6_addr32[i]);
|
||||||
|
|
||||||
|
if (nmask >= 32) {
|
||||||
|
route->remote_addr_v6_bits[i] = 32;
|
||||||
|
} else if (nmask > 0) {
|
||||||
|
route->remote_addr_v6_bits[i] = nmask;
|
||||||
|
} else {
|
||||||
|
route->remote_addr_v6_bits[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nmask -= 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_remote_addrs_ipv6)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
R3Route * route = NULL;
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
parse_ipv6("fe80:fe80::1", 128, route); // "fe80:fe80::1"
|
||||||
|
|
||||||
|
char * uri1 = "/bar";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
parse_ipv6("fe80:fe80::", 32, route); // "fe80:fe80::/32"
|
||||||
|
|
||||||
|
char * uri2 = "/goo";
|
||||||
|
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
|
||||||
|
parse_ipv6("::1", 128, route); // "::1"
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->remote_addr.base = "fe80:fe80::1";
|
||||||
|
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->remote_addr.base = "fe80:fe80::2";
|
||||||
|
entry->remote_addr.len = sizeof("fe80:fe80::2") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
entry->remote_addr.base = "fe88:fe80::1";
|
||||||
|
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->remote_addr.base = "fe80:fe80::1";
|
||||||
|
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/bar");
|
||||||
|
entry->remote_addr.base = "fe88:fe80::1";
|
||||||
|
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/goo");
|
||||||
|
entry->remote_addr.base = "::1";
|
||||||
|
entry->remote_addr.len = sizeof("::1") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri2);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/goo");
|
||||||
|
entry->remote_addr.base = "::2";
|
||||||
|
entry->remote_addr.len = sizeof("::2") - 1;
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route == NULL);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
Suite* r3_suite (void) {
|
||||||
|
Suite *suite = suite_create("r3 remote_addr tests");
|
||||||
|
TCase *tcase = tcase_create("testcase");
|
||||||
|
tcase_add_test(tcase, test_remote_addrs);
|
||||||
|
tcase_add_test(tcase, test_remote_addrs_ipv6);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
int number_failed;
|
||||||
|
Suite *suite = r3_suite();
|
||||||
|
SRunner *runner = srunner_create(suite);
|
||||||
|
srunner_run_all(runner, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(runner);
|
||||||
|
srunner_free(runner);
|
||||||
|
return number_failed;
|
||||||
|
}
|
|
@ -7,13 +7,12 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
START_TEST (test_routes)
|
START_TEST (test_routes)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
node * m = NULL;
|
R3Node * m = NULL;
|
||||||
|
|
||||||
char *data0 = "/foo/bar/baz";
|
char *data0 = "/foo/bar/baz";
|
||||||
r3_tree_insert_path(n, "/foo/bar/baz", (void*) data0);
|
r3_tree_insert_path(n, "/foo/bar/baz", (void*) data0);
|
||||||
|
|
117
tests/check_routes2.c
Normal file
117
tests/check_routes2.c
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "r3.h"
|
||||||
|
#include "r3_slug.h"
|
||||||
|
|
||||||
|
START_TEST (greedy_pattern)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo{:.*}";
|
||||||
|
r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo/bar");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo/");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo/bar/foo/mmasdfasdfasd/f/asdf/as/df");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (common_pattern)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
match_entry * entry;
|
||||||
|
R3Route *r, *matched_route;
|
||||||
|
|
||||||
|
char * uri0 = "/foo/{slug}";
|
||||||
|
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
ck_assert(r != NULL);
|
||||||
|
char * uri1 = "/foo/{slug}/bar";
|
||||||
|
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
ck_assert(r != NULL);
|
||||||
|
|
||||||
|
char * err = NULL;
|
||||||
|
r3_tree_compile(n, &err);
|
||||||
|
ck_assert(err == NULL);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo/bar");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri0);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
entry = match_entry_create("/foo/bar/bar");
|
||||||
|
matched_route = r3_tree_match_route(n, entry);
|
||||||
|
ck_assert(matched_route != NULL);
|
||||||
|
ck_assert(matched_route->data == &uri1);
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (incomplete_pattern)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
R3Route * r;
|
||||||
|
|
||||||
|
char * uri0 = "{slug";
|
||||||
|
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
|
||||||
|
ck_assert(r == NULL);
|
||||||
|
char * uri1 = "/foo/{slug";
|
||||||
|
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
|
||||||
|
ck_assert(r == NULL);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite* r3_suite (void) {
|
||||||
|
Suite *suite = suite_create("r3 routes2 tests");
|
||||||
|
TCase *tcase = tcase_create("testcase");
|
||||||
|
tcase_add_test(tcase, greedy_pattern);
|
||||||
|
tcase_add_test(tcase, common_pattern);
|
||||||
|
tcase_add_test(tcase, incomplete_pattern);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
int number_failed;
|
||||||
|
Suite *suite = r3_suite();
|
||||||
|
SRunner *runner = srunner_create(suite);
|
||||||
|
srunner_run_all(runner, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(runner);
|
||||||
|
srunner_free(runner);
|
||||||
|
return number_failed;
|
||||||
|
}
|
|
@ -9,9 +9,9 @@
|
||||||
#include <check.h>
|
#include <check.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
#include "slug.h"
|
#include "slug.h"
|
||||||
|
#include "r3_debug.h"
|
||||||
|
|
||||||
START_TEST (test_pattern_to_opcode)
|
START_TEST (test_pattern_to_opcode)
|
||||||
{
|
{
|
||||||
|
@ -27,69 +27,75 @@ START_TEST (test_r3_slug_compile)
|
||||||
char * path = "/user/{id}";
|
char * path = "/user/{id}";
|
||||||
char * c = NULL;
|
char * c = NULL;
|
||||||
ck_assert_str_eq( c = r3_slug_compile(path, strlen(path) ) , "^/user/([^/]+)" );
|
ck_assert_str_eq( c = r3_slug_compile(path, strlen(path) ) , "^/user/([^/]+)" );
|
||||||
zfree(c);
|
free(c);
|
||||||
|
|
||||||
char * path2 = "/what/{id}-foo";
|
char * path2 = "/what/{id}-foo";
|
||||||
ck_assert_str_eq( c = r3_slug_compile(path2, strlen(path2) ) , "^/what/([^/]+)-foo" );
|
ck_assert_str_eq( c = r3_slug_compile(path2, strlen(path2) ) , "^/what/([^/]+)-foo" );
|
||||||
zfree(c);
|
free(c);
|
||||||
|
|
||||||
char * path3 = "-{id}";
|
char * path3 = "-{id}";
|
||||||
ck_assert_str_eq( c = r3_slug_compile(path3, strlen(path3)), "^-([^/]+)" );
|
ck_assert_str_eq( c = r3_slug_compile(path3, strlen(path3)), "^-([^/]+)" );
|
||||||
zfree(c);
|
free(c);
|
||||||
|
|
||||||
char * path4 = "-{idx:\\d{3}}";
|
char * path4 = "-{idx:\\d{3}}";
|
||||||
ck_assert_str_eq( c = r3_slug_compile(path4, strlen(path4)), "^-(\\d{3})" );
|
ck_assert_str_eq( c = r3_slug_compile(path4, strlen(path4)), "^-(\\d{3})" );
|
||||||
zfree(c);
|
free(c);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_contains_slug)
|
START_TEST (test_contains_slug)
|
||||||
{
|
{
|
||||||
ck_assert( r3_path_contains_slug_char("/user/{id}/{name}") );
|
char *test_str = "/user/{id}/{name}";
|
||||||
|
ck_assert( r3_path_contains_slug_char(test_str, strlen(test_str)) );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_pattern)
|
START_TEST (test_r3_slug_find_pattern)
|
||||||
{
|
{
|
||||||
int len;
|
unsigned int len;
|
||||||
char * namerex = r3_slug_find_pattern("{name:\\s+}", &len);
|
char *test_str = "{name:\\s+}";
|
||||||
|
const char * namerex = r3_slug_find_pattern(test_str, strlen(test_str), &len);
|
||||||
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
|
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_name)
|
START_TEST (test_r3_slug_find_name)
|
||||||
{
|
{
|
||||||
int len;
|
unsigned int len;
|
||||||
char * namerex = r3_slug_find_name("{name:\\s+}", &len);
|
char *test_str = "{name:\\s+}";
|
||||||
|
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
|
||||||
ck_assert( strncmp(namerex, "name", len) == 0 );
|
ck_assert( strncmp(namerex, "name", len) == 0 );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_name_without_pattern)
|
START_TEST (test_r3_slug_find_name_without_pattern)
|
||||||
{
|
{
|
||||||
int len;
|
unsigned int len;
|
||||||
char * namerex = r3_slug_find_name("{name}", &len);
|
char *test_str = "{name}";
|
||||||
|
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
|
||||||
ck_assert( strncmp(namerex, "name", len) == 0 );
|
ck_assert( strncmp(namerex, "name", len) == 0 );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_name_with_multiple_slug)
|
START_TEST (test_r3_slug_find_name_with_multiple_slug)
|
||||||
{
|
{
|
||||||
int len;
|
unsigned int len;
|
||||||
char * namerex = r3_slug_find_name("{name}/{name2}", &len);
|
char *test_str = "{name}/{name2}";
|
||||||
|
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
|
||||||
ck_assert( strncmp(namerex, "name", len) == 0 );
|
ck_assert( strncmp(namerex, "name", len) == 0 );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_placeholder)
|
START_TEST (test_r3_slug_find_placeholder)
|
||||||
{
|
{
|
||||||
int slug_len = 0;
|
unsigned int slug_len = 0;
|
||||||
char * slug;
|
const char * slug;
|
||||||
slug = r3_slug_find_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
|
char *test_str = "/user/{name:\\s+}/to/{id}";
|
||||||
|
slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len);
|
||||||
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
|
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
|
||||||
|
|
||||||
|
test_str = "/user/{idx:\\d{3}}/to/{idy:\\d{3}}";
|
||||||
slug = r3_slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
|
slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len);
|
||||||
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
|
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
|
||||||
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
|
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
|
||||||
}
|
}
|
||||||
|
@ -99,7 +105,7 @@ START_TEST (test_r3_inside_slug)
|
||||||
{
|
{
|
||||||
char * pattern = "/user/{name:\\s+}/to/{id}";
|
char * pattern = "/user/{name:\\s+}/to/{id}";
|
||||||
char * offset = strchr(pattern, '{') + 2;
|
char * offset = strchr(pattern, '{') + 2;
|
||||||
ck_assert( (int)r3_inside_slug(pattern, strlen(pattern), offset, NULL) );
|
ck_assert( r3_inside_slug(pattern, strlen(pattern), offset, NULL) != NULL );
|
||||||
ck_assert( *(r3_inside_slug(pattern, strlen(pattern), offset, NULL)) == '{' );
|
ck_assert( *(r3_inside_slug(pattern, strlen(pattern), offset, NULL)) == '{' );
|
||||||
ck_assert( ! r3_inside_slug(pattern, strlen(pattern), pattern, NULL) );
|
ck_assert( ! r3_inside_slug(pattern, strlen(pattern), pattern, NULL) );
|
||||||
}
|
}
|
||||||
|
@ -112,7 +118,7 @@ START_TEST (test_incomplete_slug)
|
||||||
char * pattern = "/user/{name:\\d{3}}/to/{id";
|
char * pattern = "/user/{name:\\d{3}}/to/{id";
|
||||||
cnt = r3_slug_count(pattern, strlen(pattern), &errstr);
|
cnt = r3_slug_count(pattern, strlen(pattern), &errstr);
|
||||||
ck_assert_int_eq(cnt, -1);
|
ck_assert_int_eq(cnt, -1);
|
||||||
ck_assert(errstr);
|
ck_assert(errstr != NULL);
|
||||||
printf("%s\n",errstr);
|
printf("%s\n",errstr);
|
||||||
free(errstr);
|
free(errstr);
|
||||||
}
|
}
|
||||||
|
@ -184,8 +190,9 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_r3_slug_find_placeholder_with_broken_slug)
|
START_TEST (test_r3_slug_find_placeholder_with_broken_slug)
|
||||||
{
|
{
|
||||||
int slug_len = 0;
|
unsigned int slug_len = 0;
|
||||||
char * slug = r3_slug_find_placeholder("/user/{name:\\s+/to/{id", &slug_len);
|
char *sl_test = "/user/{name:\\s+/to/{id";
|
||||||
|
const char * slug = r3_slug_find_placeholder(sl_test, strlen(sl_test), &slug_len);
|
||||||
ck_assert(slug == 0);
|
ck_assert(slug == 0);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
|
@ -8,29 +8,59 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <check.h>
|
#include <check.h>
|
||||||
#include "r3.h"
|
#include "str_array.h"
|
||||||
#include "r3_str.h"
|
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
START_TEST (test_str_array)
|
START_TEST (test_str_array)
|
||||||
{
|
{
|
||||||
str_array * l = str_array_create(3);
|
str_array *vars = r3_mem_alloc(sizeof(str_array));
|
||||||
ck_assert(l);
|
memset(vars, 0, sizeof(*vars));
|
||||||
|
|
||||||
ck_assert(str_array_append(l, zstrdup("abc")));
|
char *test_str = "abc";
|
||||||
ck_assert( l->len == 1 );
|
ck_assert( str_array_append(vars, test_str, strlen(test_str)));
|
||||||
|
ck_assert( vars->tokens.size == 1 );
|
||||||
|
|
||||||
ck_assert(str_array_append(l, zstrdup("foo") ));
|
char *test_str1 = "foo";
|
||||||
ck_assert( l->len == 2 );
|
ck_assert( str_array_append(vars, test_str1, strlen(test_str1)));
|
||||||
|
ck_assert( vars->tokens.size == 2 );
|
||||||
|
|
||||||
ck_assert( str_array_append(l, zstrdup("bar") ) );
|
char *test_str2 = "bar";
|
||||||
ck_assert( l->len == 3 );
|
ck_assert( str_array_append(vars, test_str2, strlen(test_str2)));
|
||||||
|
ck_assert( vars->tokens.size == 3 );
|
||||||
|
|
||||||
ck_assert( str_array_append(l, zstrdup("zoo") ) );
|
char *test_str3 = "zoo";
|
||||||
ck_assert( l->len == 4 );
|
ck_assert( str_array_append(vars, test_str3, strlen(test_str3)));
|
||||||
|
ck_assert( vars->tokens.size == 4 );
|
||||||
|
|
||||||
ck_assert( str_array_resize(l, l->cap * 2) );
|
str_array_free(vars);
|
||||||
str_array_free(l);
|
free(vars);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_access_macros)
|
||||||
|
{
|
||||||
|
str_array *vars = r3_mem_alloc(sizeof(str_array));
|
||||||
|
memset(vars, 0, sizeof(*vars));
|
||||||
|
ck_assert( str_array_len(vars) == 0);
|
||||||
|
ck_assert( str_array_cap(vars) == 0);
|
||||||
|
|
||||||
|
r3_vector_reserve(&vars->tokens, 4);
|
||||||
|
ck_assert( str_array_len(vars) == 0);
|
||||||
|
ck_assert( str_array_cap(vars) == 4);
|
||||||
|
|
||||||
|
char *token1 = "first";
|
||||||
|
char *token2 = "second";
|
||||||
|
ck_assert( str_array_append(vars, token1, strlen(token1)));
|
||||||
|
ck_assert( str_array_append(vars, token2, strlen(token2)));
|
||||||
|
ck_assert( str_array_len(vars) == 2);
|
||||||
|
ck_assert( str_array_cap(vars) == 4);
|
||||||
|
|
||||||
|
ck_assert( strncmp(str_array_fetch(vars,0).base, "first", 5) == 0);
|
||||||
|
ck_assert( str_array_fetch(vars,0).len == 5);
|
||||||
|
ck_assert( strncmp(str_array_fetch(vars,1).base, "second", 6) == 0);
|
||||||
|
ck_assert( str_array_fetch(vars,1).len == 6);
|
||||||
|
|
||||||
|
str_array_free(vars);
|
||||||
|
free(vars);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
@ -38,6 +68,7 @@ Suite* r3_suite (void) {
|
||||||
Suite *suite = suite_create("str_array test");
|
Suite *suite = suite_create("str_array test");
|
||||||
TCase *tcase = tcase_create("testcase");
|
TCase *tcase = tcase_create("testcase");
|
||||||
tcase_add_test(tcase, test_str_array);
|
tcase_add_test(tcase, test_str_array);
|
||||||
|
tcase_add_test(tcase, test_access_macros);
|
||||||
suite_add_tcase(suite, tcase);
|
suite_add_tcase(suite, tcase);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,32 +4,37 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_str.h"
|
#include "r3_slug.h"
|
||||||
#include "zmalloc.h"
|
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
|
#include "../src/r3_debug.h"
|
||||||
|
|
||||||
#define SAFE_FREE(ptr) if(ptr) free(ptr);
|
#define SAFE_FREE(ptr) if(ptr) free(ptr);
|
||||||
|
|
||||||
|
#define STR(str) str, sizeof(str)-1
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix)
|
START_TEST (test_find_common_prefix)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
char *test_str = "/foo/{slug}";
|
||||||
edge * e = r3_edge_createl(zstrdup("/foo/{slug}"), sizeof("/foo/{slug}")-1, NULL);
|
R3Node * n = r3_tree_create(10);
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
int prefix_len = 0;
|
int prefix_len = 0;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr);
|
char *test_pref1 = "/foo";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 4);
|
ck_assert_int_eq(prefix_len, 4);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/", sizeof("/foo/")-1, &prefix_len, &errstr);
|
char *test_pref2 = "/foo/";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 5);
|
ck_assert_int_eq(prefix_len, 5);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
@ -37,35 +42,40 @@ START_TEST (test_find_common_prefix)
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
prefix_len = 0;
|
prefix_len = 0;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/{slog}", sizeof("/foo/{slog}")-1, &prefix_len, &errstr);
|
char *test_pref3 = "/foo/{slog}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 5);
|
ck_assert_int_eq(prefix_len, 5);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/{bar}", sizeof("/foo/{bar}")-1, &prefix_len, &errstr);
|
char *test_pref4 = "/foo/{bar}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 5);
|
ck_assert_int_eq(prefix_len, 5);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/bar", sizeof("/foo/bar")-1, &prefix_len, &errstr);
|
char *test_pref5 = "/foo/bar";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref5, strlen(test_pref5), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 5);
|
ck_assert_int_eq(prefix_len, 5);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/bar/", sizeof("/bar/")-1, &prefix_len, &errstr);
|
char *test_pref6 = "/bar/";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref6, strlen(test_pref6), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 1);
|
ck_assert_int_eq(prefix_len, 1);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "{bar}", sizeof("{bar}")-1, &prefix_len, &errstr);
|
char *test_pref7 = "{bar}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref7, strlen(test_pref7), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge == NULL);
|
ck_assert(ret_edge == NULL);
|
||||||
ck_assert_int_eq(prefix_len, 0);
|
ck_assert_int_eq(prefix_len, 0);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
@ -81,30 +91,34 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix_after)
|
START_TEST (test_find_common_prefix_after)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
char *test_str = "{slug}/foo";
|
||||||
edge * e = r3_edge_createl(zstrdup("{slug}/foo"), sizeof("{slug}/foo")-1, NULL);
|
R3Node * n = r3_tree_create(10);
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
int prefix_len = 0;
|
int prefix_len = 0;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr);
|
char *test_pref1 = "/foo";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge == NULL);
|
ck_assert(ret_edge == NULL);
|
||||||
ck_assert_int_eq(prefix_len, 0);
|
ck_assert_int_eq(prefix_len, 0);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "{slug}/bar", sizeof("{slug}/bar")-1, &prefix_len, &errstr);
|
char *test_pref2 = "{slug}/bar";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 7);
|
ck_assert_int_eq(prefix_len, 7);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "{slug}/foo", sizeof("{slug}/foo")-1, &prefix_len, &errstr);
|
char *test_pref3 = "{slug}/foo";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge != NULL);
|
ck_assert(ret_edge != NULL);
|
||||||
ck_assert_int_eq(prefix_len, 10);
|
ck_assert_int_eq(prefix_len, 10);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
@ -118,16 +132,18 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix_double_middle)
|
START_TEST (test_find_common_prefix_double_middle)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
char *test_str = "{slug}/foo/{name}";
|
||||||
edge * e = r3_edge_createl(zstrdup("{slug}/foo/{name}"), sizeof("{slug}/foo/{name}")-1, NULL);
|
R3Node * n = r3_tree_create(10);
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
char *errstr;
|
char *errstr;
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "{slug}/foo/{number}", sizeof("{slug}/foo/{number}")-1, &prefix_len, &errstr);
|
char *test_pref1 = "{slug}/foo/{number}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge);
|
ck_assert(ret_edge);
|
||||||
ck_assert_int_eq(prefix_len, 11);
|
ck_assert_int_eq(prefix_len, 11);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
@ -140,22 +156,25 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix_middle)
|
START_TEST (test_find_common_prefix_middle)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
edge * e = r3_edge_createl(zstrdup("/foo/{slug}/hate"), sizeof("/foo/{slug}/hate")-1, NULL);
|
char *test_str = "/foo/{slug}/hate";
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/{slug}/bar", sizeof("/foo/{slug}/bar")-1, &prefix_len, &errstr);
|
char *test_str1 = "/foo/{slug}/bar";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_str1, strlen(test_str1), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge);
|
ck_assert(ret_edge);
|
||||||
ck_assert_int_eq(prefix_len, 12);
|
ck_assert_int_eq(prefix_len, 12);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
errstr = NULL;
|
errstr = NULL;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/fo/{slug}/bar", sizeof("/fo/{slug}/bar")-1, &prefix_len, &errstr);
|
char *test_str2 = "/fo/{slug}/bar";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_str2, strlen(test_str2), &prefix_len, &errstr);
|
||||||
ck_assert(ret_edge);
|
ck_assert(ret_edge);
|
||||||
ck_assert_int_eq(prefix_len, 3);
|
ck_assert_int_eq(prefix_len, 3);
|
||||||
SAFE_FREE(errstr);
|
SAFE_FREE(errstr);
|
||||||
|
@ -166,12 +185,13 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix_same_pattern)
|
START_TEST (test_find_common_prefix_same_pattern)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
edge * e = r3_edge_createl(zstrdup("/foo/{slug:xxx}/hate"), sizeof("/foo/{slug:xxx}/hate")-1, NULL);
|
char *test_str = "/foo/{slug:xxx}/hate";
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
|
|
||||||
prefix_len = 0;
|
prefix_len = 0;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "/foo/{slug:yyy}/hate", sizeof("/foo/{slug:yyy}/hate")-1, &prefix_len, NULL);
|
ret_edge = r3_node_find_common_prefix(n, "/foo/{slug:yyy}/hate", sizeof("/foo/{slug:yyy}/hate")-1, &prefix_len, NULL);
|
||||||
|
@ -190,12 +210,13 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_common_prefix_same_pattern2)
|
START_TEST (test_find_common_prefix_same_pattern2)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
edge * e = r3_edge_createl(zstrdup("{slug:xxx}/hate"), sizeof("{slug:xxx}/hate")-1, NULL);
|
char *test_str = "{slug:xxx}/hate";
|
||||||
r3_node_append_edge(n,e);
|
R3Edge * e = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e, test_str, strlen(test_str), NULL);
|
||||||
|
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
edge *ret_edge = NULL;
|
R3Edge *ret_edge = NULL;
|
||||||
|
|
||||||
prefix_len = 0;
|
prefix_len = 0;
|
||||||
ret_edge = r3_node_find_common_prefix(n, "{slug:yyy}/hate", sizeof("{slug:yyy}/hate")-1, &prefix_len, NULL);
|
ret_edge = r3_node_find_common_prefix(n, "{slug:yyy}/hate", sizeof("{slug:yyy}/hate")-1, &prefix_len, NULL);
|
||||||
|
@ -206,7 +227,59 @@ START_TEST (test_find_common_prefix_same_pattern2)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_find_common_prefix_multi_edge)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
|
char *test_str1 = "{id}/foo";
|
||||||
|
R3Edge * e1 = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e1, test_str1, strlen(test_str1), NULL);
|
||||||
|
|
||||||
|
char *test_str2 = "{id2}/bar";
|
||||||
|
R3Edge * e2 = r3_node_append_edge(n);
|
||||||
|
r3_edge_initl(e2, test_str2, strlen(test_str2), NULL);
|
||||||
|
|
||||||
|
R3Edge *ret_edge = NULL;
|
||||||
|
int prefix_len = 0;
|
||||||
|
char *errstr = NULL;
|
||||||
|
|
||||||
|
char *test_pref1 = "{id}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
|
||||||
|
ck_assert(ret_edge != NULL);
|
||||||
|
ck_assert_int_eq(prefix_len, 4);
|
||||||
|
ck_assert(ret_edge == e1);
|
||||||
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
prefix_len = 0;
|
||||||
|
errstr = NULL;
|
||||||
|
char *test_pref2 = "{id}/foo";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
|
||||||
|
ck_assert(ret_edge != NULL);
|
||||||
|
ck_assert_int_eq(prefix_len, 8);
|
||||||
|
ck_assert(ret_edge == e1);
|
||||||
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
prefix_len = 0;
|
||||||
|
errstr = NULL;
|
||||||
|
char *test_pref3 = "{id2}";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
|
||||||
|
ck_assert(ret_edge != NULL);
|
||||||
|
ck_assert_int_eq(prefix_len, 5);
|
||||||
|
ck_assert(ret_edge == e2);
|
||||||
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
prefix_len = 0;
|
||||||
|
errstr = NULL;
|
||||||
|
char *test_pref4 = "{id2}/bar";
|
||||||
|
ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr);
|
||||||
|
ck_assert(ret_edge != NULL);
|
||||||
|
ck_assert_int_eq(prefix_len, 9);
|
||||||
|
ck_assert(ret_edge == e2);
|
||||||
|
SAFE_FREE(errstr);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,15 +297,15 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_node_construct_and_free)
|
START_TEST (test_node_construct_and_free)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
node * another_tree = r3_tree_create(3);
|
R3Node * another_tree = r3_tree_create(3);
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
r3_tree_free(another_tree);
|
r3_tree_free(another_tree);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
static node * create_simple_str_tree() {
|
static R3Node * create_simple_str_tree() {
|
||||||
node * n;
|
R3Node * n;
|
||||||
n = r3_tree_create(10);
|
n = r3_tree_create(10);
|
||||||
r3_tree_insert_path(n, "/zoo", NULL);
|
r3_tree_insert_path(n, "/zoo", NULL);
|
||||||
r3_tree_insert_path(n, "/foo", NULL);
|
r3_tree_insert_path(n, "/foo", NULL);
|
||||||
|
@ -245,8 +318,8 @@ static node * create_simple_str_tree() {
|
||||||
|
|
||||||
START_TEST (test_compile)
|
START_TEST (test_compile)
|
||||||
{
|
{
|
||||||
node *n;
|
R3Node *n;
|
||||||
node *m;
|
R3Node *m;
|
||||||
|
|
||||||
n = create_simple_str_tree();
|
n = create_simple_str_tree();
|
||||||
|
|
||||||
|
@ -258,41 +331,49 @@ START_TEST (test_compile)
|
||||||
r3_tree_insert_path(n, "/{id}", NULL);
|
r3_tree_insert_path(n, "/{id}", NULL);
|
||||||
r3_tree_compile(n, NULL);
|
r3_tree_compile(n, NULL);
|
||||||
r3_tree_compile(n, NULL); // test double compile
|
r3_tree_compile(n, NULL); // test double compile
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
match_entry * entry;
|
match_entry * entry;
|
||||||
|
|
||||||
entry = match_entry_createl( "foo" , strlen("/foo") );
|
entry = match_entry_createl( "foo" , strlen("/foo") );
|
||||||
m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry);
|
m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
entry = match_entry_createl( "/zoo" , strlen("/zoo") );
|
entry = match_entry_createl( "/zoo" , strlen("/zoo") );
|
||||||
m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry);
|
m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
entry = match_entry_createl( "/bar" , strlen("/bar") );
|
entry = match_entry_createl( "/bar" , strlen("/bar") );
|
||||||
m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry);
|
m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
entry = match_entry_createl( "/xxx" , strlen("/xxx") );
|
entry = match_entry_createl( "/xxx" , strlen("/xxx") );
|
||||||
m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry);
|
m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") );
|
entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") );
|
||||||
m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry);
|
m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
entry = match_entry_createl( "/some_id" , strlen("/some_id") );
|
entry = match_entry_createl( "/some_id" , strlen("/some_id") );
|
||||||
m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry);
|
m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry);
|
||||||
ck_assert( m );
|
ck_assert( m );
|
||||||
|
match_entry_free(entry);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
START_TEST (test_incomplete_slug_path)
|
START_TEST (test_incomplete_slug_path)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
node * ret_node;
|
R3Node * ret_node;
|
||||||
|
|
||||||
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
|
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
|
||||||
ret_node = r3_tree_insert_path(n, "/post/{handle", NULL);
|
ret_node = r3_tree_insert_path(n, "/post/{handle", NULL);
|
||||||
|
@ -319,7 +400,7 @@ START_TEST (test_incomplete_slug_path)
|
||||||
ck_assert(ret_node);
|
ck_assert(ret_node);
|
||||||
|
|
||||||
// OK to insert, but should return error when compiling patterns
|
// OK to insert, but should return error when compiling patterns
|
||||||
node * ret_node2 = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy:aaa}", NULL);
|
R3Node * ret_node2 = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy:aaa}", NULL);
|
||||||
ck_assert(ret_node2);
|
ck_assert(ret_node2);
|
||||||
ck_assert(ret_node2 != ret_node); // make sure it's another node
|
ck_assert(ret_node2 != ret_node); // make sure it's another node
|
||||||
|
|
||||||
|
@ -328,7 +409,7 @@ START_TEST (test_incomplete_slug_path)
|
||||||
r3_tree_compile(n, &errstr);
|
r3_tree_compile(n, &errstr);
|
||||||
ck_assert(errstr == NULL); // no error
|
ck_assert(errstr == NULL); // no error
|
||||||
|
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
|
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
|
@ -337,7 +418,7 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_pcre_patterns_insert)
|
START_TEST (test_pcre_patterns_insert)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
|
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
|
||||||
r3_tree_insert_path(n, "/post/{handle:\\d+}-{id:\\d+}", NULL);
|
r3_tree_insert_path(n, "/post/{handle:\\d+}-{id:\\d+}", NULL);
|
||||||
|
@ -352,7 +433,7 @@ START_TEST (test_pcre_patterns_insert)
|
||||||
|
|
||||||
// r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
|
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
|
|
||||||
|
|
||||||
matched = r3_tree_match(n, "/post/foo", NULL);
|
matched = r3_tree_match(n, "/post/foo", NULL);
|
||||||
|
@ -389,7 +470,7 @@ END_TEST
|
||||||
*/
|
*/
|
||||||
START_TEST (test_root_match)
|
START_TEST (test_root_match)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
int a = 10;
|
int a = 10;
|
||||||
int b = 20;
|
int b = 20;
|
||||||
|
@ -401,8 +482,8 @@ START_TEST (test_root_match)
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
r3_tree_compile(n, &errstr);
|
r3_tree_compile(n, &errstr);
|
||||||
|
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
matched = r3_tree_match(n, "/", NULL);
|
matched = r3_tree_match(n, "/", NULL);
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(matched->data == &a);
|
ck_assert(matched->data == &a);
|
||||||
|
@ -417,6 +498,8 @@ START_TEST (test_root_match)
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(matched->data == &c);
|
ck_assert(matched->data == &c);
|
||||||
ck_assert(matched->endpoint > 0);
|
ck_assert(matched->endpoint > 0);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
@ -428,7 +511,7 @@ END_TEST
|
||||||
*/
|
*/
|
||||||
START_TEST (test_pcre_patterns_insert_2)
|
START_TEST (test_pcre_patterns_insert_2)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy:\\d{2}}", NULL);
|
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy:\\d{2}}", NULL);
|
||||||
r3_tree_insert_path(n, "/zoo", NULL);
|
r3_tree_insert_path(n, "/zoo", NULL);
|
||||||
r3_tree_insert_path(n, "/foo", NULL);
|
r3_tree_insert_path(n, "/foo", NULL);
|
||||||
|
@ -437,11 +520,13 @@ START_TEST (test_pcre_patterns_insert_2)
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
r3_tree_compile(n, &errstr);
|
r3_tree_compile(n, &errstr);
|
||||||
|
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
matched = r3_tree_match(n, "/post/11/22", NULL);
|
matched = r3_tree_match(n, "/post/11/22", NULL);
|
||||||
ck_assert((int)matched);
|
ck_assert(matched);
|
||||||
ck_assert(matched->endpoint > 0);
|
ck_assert(matched->endpoint > 0);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
@ -450,14 +535,14 @@ END_TEST
|
||||||
*/
|
*/
|
||||||
START_TEST (test_pcre_patterns_insert_3)
|
START_TEST (test_pcre_patterns_insert_3)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
printf("Inserting /post/{idx:\\d{2}}/{idy}\n");
|
printf("Inserting /post/{idx:\\d{2}}/{idy}\n");
|
||||||
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy}", NULL);
|
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy}", NULL);
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
|
|
||||||
printf("Inserting /zoo\n");
|
printf("Inserting /zoo\n");
|
||||||
r3_tree_insert_path(n, "/zoo", NULL);
|
r3_tree_insert_path(n, "/zoo", NULL);
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
|
|
||||||
r3_tree_insert_path(n, "/foo", NULL);
|
r3_tree_insert_path(n, "/foo", NULL);
|
||||||
r3_tree_insert_path(n, "/bar", NULL);
|
r3_tree_insert_path(n, "/bar", NULL);
|
||||||
|
@ -465,12 +550,12 @@ START_TEST (test_pcre_patterns_insert_3)
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
r3_tree_compile(n, &errstr);
|
r3_tree_compile(n, &errstr);
|
||||||
|
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
|
|
||||||
|
|
||||||
matched = r3_tree_match(n, "/post/11/22", NULL);
|
matched = r3_tree_match(n, "/post/11/22", NULL);
|
||||||
ck_assert((int)matched);
|
ck_assert(matched);
|
||||||
|
|
||||||
matched = r3_tree_match(n, "/post/11", NULL);
|
matched = r3_tree_match(n, "/post/11", NULL);
|
||||||
ck_assert(!matched);
|
ck_assert(!matched);
|
||||||
|
@ -482,6 +567,8 @@ START_TEST (test_pcre_patterns_insert_3)
|
||||||
matched = r3_tree_match(n, "/post/113", NULL);
|
matched = r3_tree_match(n, "/post/113", NULL);
|
||||||
ck_assert(!matched);
|
ck_assert(!matched);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
@ -489,12 +576,12 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_insert_pathl_fail)
|
START_TEST (test_insert_pathl_fail)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
node * ret;
|
R3Node * ret;
|
||||||
|
|
||||||
char *errstr = NULL;
|
char *errstr = NULL;
|
||||||
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, NULL, &errstr);
|
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, &errstr);
|
||||||
ck_assert(ret == NULL);
|
ck_assert(ret == NULL);
|
||||||
ck_assert(errstr != NULL);
|
ck_assert(errstr != NULL);
|
||||||
printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1
|
printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1
|
||||||
|
@ -508,14 +595,31 @@ START_TEST (test_insert_pathl_fail)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (test_insert_pathl_fail2)
|
||||||
|
{
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
char *errstr = NULL;
|
||||||
|
R3Node * ret;
|
||||||
|
|
||||||
|
ret = r3_tree_insert_pathl_ex(n, "/foo", strlen("/foo"), 0, 0, 0, NULL);
|
||||||
|
ck_assert(ret);
|
||||||
|
|
||||||
|
/* Insert an incomplete pattern without requesting an error string */
|
||||||
|
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, NULL);
|
||||||
|
ck_assert(ret == NULL);
|
||||||
|
|
||||||
|
r3_tree_compile(n, &errstr);
|
||||||
|
ck_assert(errstr == NULL);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_insert_pathl)
|
START_TEST (test_insert_pathl)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
node * ret;
|
R3Node * ret;
|
||||||
|
|
||||||
ret = r3_tree_insert_path(n, "/foo/bar", NULL);
|
ret = r3_tree_insert_path(n, "/foo/bar", NULL);
|
||||||
ck_assert(ret);
|
ck_assert(ret);
|
||||||
|
@ -551,8 +655,7 @@ START_TEST (test_insert_pathl)
|
||||||
char * errstr = NULL;
|
char * errstr = NULL;
|
||||||
r3_tree_compile(n, &errstr);
|
r3_tree_compile(n, &errstr);
|
||||||
ck_assert(errstr == NULL);
|
ck_assert(errstr == NULL);
|
||||||
|
// r3_tree_dump(n, 0);
|
||||||
r3_tree_dump(n, 0);
|
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -561,9 +664,9 @@ END_TEST
|
||||||
|
|
||||||
START_TEST (test_compile_fail)
|
START_TEST (test_compile_fail)
|
||||||
{
|
{
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
node * ret;
|
R3Node * ret;
|
||||||
|
|
||||||
ret = r3_tree_insert_path(n, "/foo/{idx}/{idy:)}", NULL);
|
ret = r3_tree_insert_path(n, "/foo/{idx}/{idy:)}", NULL);
|
||||||
ck_assert(ret);
|
ck_assert(ret);
|
||||||
|
@ -577,7 +680,7 @@ START_TEST (test_compile_fail)
|
||||||
fprintf(stderr, "Compile failed: %s\n", errstr);
|
fprintf(stderr, "Compile failed: %s\n", errstr);
|
||||||
free(errstr);
|
free(errstr);
|
||||||
|
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -606,7 +709,9 @@ END_TEST
|
||||||
|
|
||||||
START_TEST(test_route_cmp)
|
START_TEST(test_route_cmp)
|
||||||
{
|
{
|
||||||
route *r1 = r3_route_create("/blog/post");
|
R3Node * n = r3_tree_create(10);
|
||||||
|
char *test_str = "/blog/post";
|
||||||
|
R3Route *r1 = r3_node_append_route(n,test_str, strlen(test_str),0,0);
|
||||||
match_entry * m = match_entry_create("/blog/post");
|
match_entry * m = match_entry_create("/blog/post");
|
||||||
|
|
||||||
fail_if( r3_route_cmp(r1, m) == -1, "should match");
|
fail_if( r3_route_cmp(r1, m) == -1, "should match");
|
||||||
|
@ -623,8 +728,8 @@ START_TEST(test_route_cmp)
|
||||||
m->request_method = METHOD_POST | METHOD_GET;
|
m->request_method = METHOD_POST | METHOD_GET;
|
||||||
fail_if( r3_route_cmp(r1, m) == -1, "should match");
|
fail_if( r3_route_cmp(r1, m) == -1, "should match");
|
||||||
|
|
||||||
r3_route_free(r1);
|
|
||||||
match_entry_free(m);
|
match_entry_free(m);
|
||||||
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
@ -633,16 +738,17 @@ START_TEST(test_pcre_pattern_simple)
|
||||||
{
|
{
|
||||||
match_entry * entry;
|
match_entry * entry;
|
||||||
entry = match_entry_createl( "/user/123" , strlen("/user/123") );
|
entry = match_entry_createl( "/user/123" , strlen("/user/123") );
|
||||||
node * n = r3_tree_create(10);
|
R3Node * n = r3_tree_create(10);
|
||||||
r3_tree_insert_path(n, "/user/{id:\\d+}", NULL);
|
r3_tree_insert_path(n, "/user/{id:\\d+}", NULL);
|
||||||
r3_tree_insert_path(n, "/user", NULL);
|
r3_tree_insert_path(n, "/user", NULL);
|
||||||
r3_tree_compile(n, NULL);
|
r3_tree_compile(n, NULL);
|
||||||
// r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
|
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(entry->vars->len > 0);
|
ck_assert(entry->vars.tokens.size > 0);
|
||||||
ck_assert_str_eq(entry->vars->tokens[0],"123");
|
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
|
||||||
|
match_entry_free(entry);
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -651,8 +757,9 @@ END_TEST
|
||||||
START_TEST(test_pcre_pattern_more)
|
START_TEST(test_pcre_pattern_more)
|
||||||
{
|
{
|
||||||
match_entry * entry;
|
match_entry * entry;
|
||||||
entry = match_entry_createl( "/user/123" , strlen("/user/123") );
|
entry = match_entry_create( "/user/123" );
|
||||||
node * n = r3_tree_create(10);
|
entry->request_method = 0;
|
||||||
|
R3Node * n = r3_tree_create(10);
|
||||||
|
|
||||||
int var0 = 5;
|
int var0 = 5;
|
||||||
int var1 = 100;
|
int var1 = 100;
|
||||||
|
@ -669,35 +776,56 @@ START_TEST(test_pcre_pattern_more)
|
||||||
r3_tree_insert_path(n, "/user3/{id:\\d{3}}", &var3);
|
r3_tree_insert_path(n, "/user3/{id:\\d{3}}", &var3);
|
||||||
r3_tree_insert_path(n, "/user", &var0);
|
r3_tree_insert_path(n, "/user", &var0);
|
||||||
r3_tree_compile(n, NULL);
|
r3_tree_compile(n, NULL);
|
||||||
r3_tree_dump(n, 0);
|
// r3_tree_dump(n, 0);
|
||||||
node *matched;
|
R3Node *matched;
|
||||||
|
|
||||||
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
|
matched = r3_tree_match(n, "/user/123", entry);
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(entry->vars->len > 0);
|
ck_assert(entry->vars.tokens.size > 0);
|
||||||
ck_assert_str_eq(entry->vars->tokens[0],"123");
|
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
|
||||||
|
|
||||||
info("matched %p\n", matched->data);
|
|
||||||
info("matched %p\n", matched->data);
|
info("matched %p\n", matched->data);
|
||||||
ck_assert_int_eq( *((int*) matched->data), var1);
|
ck_assert_int_eq( *((int*) matched->data), var1);
|
||||||
|
|
||||||
matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry);
|
matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry);
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(entry->vars->len > 0);
|
ck_assert(entry->vars.tokens.size > 0);
|
||||||
ck_assert_str_eq(entry->vars->tokens[0],"123");
|
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
|
||||||
|
info("matched %p\n", matched->data);
|
||||||
ck_assert_int_eq( *((int*)matched->data), var2);
|
ck_assert_int_eq( *((int*)matched->data), var2);
|
||||||
|
|
||||||
matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry);
|
matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry);
|
||||||
ck_assert(matched);
|
ck_assert(matched);
|
||||||
ck_assert(entry->vars->len > 0);
|
ck_assert(entry->vars.tokens.size > 0);
|
||||||
ck_assert_str_eq(entry->vars->tokens[0],"123");
|
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
|
||||||
|
info("matched %p\n", matched->data);
|
||||||
ck_assert_int_eq( *((int*)matched->data), var3);
|
ck_assert_int_eq( *((int*)matched->data), var3);
|
||||||
|
|
||||||
|
match_entry_free(entry);
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST(test_insert_pathl_before_root)
|
||||||
|
{
|
||||||
|
char *errstr = NULL;
|
||||||
|
int var1 = 22;
|
||||||
|
int var2 = 33;
|
||||||
|
int var3 = 44;
|
||||||
|
R3Node * n = r3_tree_create(3);
|
||||||
|
r3_tree_insert_pathl_ex(n, STR("/blog/post"), 0, 0, &var1, NULL);
|
||||||
|
r3_tree_insert_pathl_ex(n, STR("/blog"), 0, 0, &var2, NULL);
|
||||||
|
r3_tree_insert_pathl_ex(n, STR("/"), 0, 0, &var3, NULL);
|
||||||
|
|
||||||
|
errstr = NULL;
|
||||||
|
r3_tree_compile(n, &errstr);
|
||||||
|
|
||||||
|
r3_tree_dump(n, 0);
|
||||||
|
|
||||||
|
r3_tree_free(n);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
START_TEST(test_insert_route)
|
START_TEST(test_insert_route)
|
||||||
|
@ -706,12 +834,12 @@ START_TEST(test_insert_route)
|
||||||
int var2 = 33;
|
int var2 = 33;
|
||||||
|
|
||||||
|
|
||||||
node * n = r3_tree_create(2);
|
R3Node * n = r3_tree_create(2);
|
||||||
r3_tree_insert_route(n, METHOD_GET, "/blog/post", &var1);
|
r3_tree_insert_route(n, METHOD_GET, "/blog/post", &var1);
|
||||||
r3_tree_insert_route(n, METHOD_POST, "/blog/post", &var2);
|
r3_tree_insert_route(n, METHOD_POST, "/blog/post", &var2);
|
||||||
|
|
||||||
match_entry * entry;
|
match_entry * entry;
|
||||||
route *r;
|
R3Route *r;
|
||||||
|
|
||||||
entry = match_entry_create("/blog/post");
|
entry = match_entry_create("/blog/post");
|
||||||
entry->request_method = METHOD_GET;
|
entry->request_method = METHOD_GET;
|
||||||
|
@ -736,25 +864,34 @@ START_TEST(test_insert_route)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
Suite* r3_suite (void) {
|
Suite* r3_suite (void) {
|
||||||
Suite *suite = suite_create("r3 core tests");
|
Suite *suite = suite_create("r3 core tests");
|
||||||
|
TCase *tcase = tcase_create("common_prefix_testcase");
|
||||||
TCase *tcase = tcase_create("testcase");
|
|
||||||
|
|
||||||
tcase_add_test(tcase, test_find_common_prefix);
|
tcase_add_test(tcase, test_find_common_prefix);
|
||||||
tcase_add_test(tcase, test_find_common_prefix_after);
|
tcase_add_test(tcase, test_find_common_prefix_after);
|
||||||
tcase_add_test(tcase, test_find_common_prefix_double_middle);
|
tcase_add_test(tcase, test_find_common_prefix_double_middle);
|
||||||
tcase_add_test(tcase, test_find_common_prefix_middle);
|
tcase_add_test(tcase, test_find_common_prefix_middle);
|
||||||
tcase_add_test(tcase, test_find_common_prefix_same_pattern);
|
tcase_add_test(tcase, test_find_common_prefix_same_pattern);
|
||||||
tcase_add_test(tcase, test_find_common_prefix_same_pattern2);
|
tcase_add_test(tcase, test_find_common_prefix_same_pattern2);
|
||||||
|
tcase_add_test(tcase, test_find_common_prefix_multi_edge);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
|
||||||
|
tcase = tcase_create("insert_testcase");
|
||||||
tcase_add_test(tcase, test_insert_pathl);
|
tcase_add_test(tcase, test_insert_pathl);
|
||||||
tcase_add_test(tcase, test_insert_pathl_fail);
|
tcase_add_test(tcase, test_insert_pathl_fail);
|
||||||
|
tcase_add_test(tcase, test_insert_pathl_fail2);
|
||||||
tcase_add_test(tcase, test_node_construct_and_free);
|
tcase_add_test(tcase, test_node_construct_and_free);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
|
||||||
|
tcase = tcase_create("compile_testcase");
|
||||||
tcase_add_test(tcase, test_compile);
|
tcase_add_test(tcase, test_compile);
|
||||||
tcase_add_test(tcase, test_compile_fail);
|
tcase_add_test(tcase, test_compile_fail);
|
||||||
tcase_add_test(tcase, test_route_cmp);
|
tcase_add_test(tcase, test_route_cmp);
|
||||||
tcase_add_test(tcase, test_insert_route);
|
tcase_add_test(tcase, test_insert_route);
|
||||||
|
tcase_add_test(tcase, test_insert_pathl_before_root);
|
||||||
|
suite_add_tcase(suite, tcase);
|
||||||
|
|
||||||
|
tcase = tcase_create("pcre_pattern_testcase");
|
||||||
tcase_add_test(tcase, test_pcre_pattern_simple);
|
tcase_add_test(tcase, test_pcre_pattern_simple);
|
||||||
tcase_add_test(tcase, test_pcre_pattern_more);
|
tcase_add_test(tcase, test_pcre_pattern_more);
|
||||||
tcase_add_test(tcase, test_pcre_patterns_insert);
|
tcase_add_test(tcase, test_pcre_patterns_insert);
|
||||||
|
|
Loading…
Reference in a new issue