Compare commits
No commits in common. "2.0" and "autotool" have entirely different histories.
110 changed files with 24778 additions and 18268 deletions
70
.github/workflows/ci.yml
vendored
70
.github/workflows/ci.yml
vendored
|
@ -1,70 +0,0 @@
|
||||||
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
21
.github/workflows/coverity.yml
vendored
|
@ -1,21 +0,0 @@
|
||||||
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 }}
|
|
46
.gitignore
vendored
46
.gitignore
vendored
|
@ -17,42 +17,12 @@ tags
|
||||||
*.la
|
*.la
|
||||||
*.dylib
|
*.dylib
|
||||||
*.o
|
*.o
|
||||||
|
/aclocal.m4
|
||||||
Makefile
|
/autom4te.cache
|
||||||
|
/compile
|
||||||
|
/configure
|
||||||
|
/depcomp
|
||||||
|
/install-sh
|
||||||
|
/missing
|
||||||
|
/stamp-h1
|
||||||
Makefile.in
|
Makefile.in
|
||||||
aclocal.m4
|
|
||||||
autom4te.cache
|
|
||||||
compile
|
|
||||||
config.guess
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
config.sub
|
|
||||||
configure
|
|
||||||
depcomp
|
|
||||||
gumbo.pc
|
|
||||||
gumbo_test
|
|
||||||
gumbo_test.log
|
|
||||||
gumbo_test.trs
|
|
||||||
install-sh
|
|
||||||
libtool
|
|
||||||
ltmain.sh
|
|
||||||
m4/
|
|
||||||
missing
|
|
||||||
test-driver
|
|
||||||
test-suite.log
|
|
||||||
config.h
|
|
||||||
|
|
||||||
tests/*.log
|
|
||||||
tests/*.trs
|
|
||||||
configure.scan
|
|
||||||
autoscan.log
|
|
||||||
.libs
|
|
||||||
.deps
|
|
||||||
r3.pc
|
|
||||||
stamp-h1
|
|
||||||
tests/bench_str.csv
|
|
||||||
tests/check_host
|
|
||||||
|
|
||||||
config.h.in
|
|
||||||
examples/simple
|
|
||||||
examples/simple_cpp
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
if [ x$COVERALLS == xyes ]; then
|
|
||||||
coveralls --exclude php --exclude 3rdparty
|
|
||||||
fi
|
|
|
@ -1,24 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -ev
|
|
||||||
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake -GNinja ..
|
|
||||||
ninja -v
|
|
||||||
ctest
|
|
111
.travis.yml
111
.travis.yml
|
@ -1,111 +0,0 @@
|
||||||
language: c
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
git:
|
|
||||||
depth: 1
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- compiler: gcc
|
|
||||||
env:
|
|
||||||
- TYPE=autotools
|
|
||||||
- CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc'
|
|
||||||
- COVERALLS=yes
|
|
||||||
- VALGRIND=no
|
|
||||||
- DEBUG=yes
|
|
||||||
- CC=gcc
|
|
||||||
- CXX=g++
|
|
||||||
- compiler: gcc
|
|
||||||
env:
|
|
||||||
- TYPE=autotools
|
|
||||||
- CONFIGURE_OPTION='--enable-debug --enable-gcov'
|
|
||||||
- COVERALLS=yes
|
|
||||||
- VALGRIND=yes
|
|
||||||
- DEBUG=yes
|
|
||||||
- CC=gcc
|
|
||||||
- CXX=g++
|
|
||||||
- compiler: clang
|
|
||||||
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:
|
|
||||||
- docker exec -t build bash -c "cd /travis && .travis-ci/install.sh"
|
|
||||||
|
|
||||||
script:
|
|
||||||
- docker exec -t build bash -c "cd /travis && .travis-ci/script-$TYPE.sh"
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- docker exec -t build bash -c "cd /travis && .travis-ci/after_success.sh"
|
|
72
CHANGES.md
72
CHANGES.md
|
@ -1,72 +0,0 @@
|
||||||
# CHANGELOG
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
- Fix graphviz generator.
|
|
||||||
|
|
||||||
|
|
||||||
### 1.3.2 - Sat Jun 28 00:54:22 2014
|
|
||||||
|
|
||||||
- `HAVE_STRNDUP` and `HAVE_STRDUP` definition fix
|
|
||||||
|
|
||||||
### 1.3.0 - Tue Jun 3 18:47:14 2014
|
|
||||||
|
|
||||||
- Added Incorrect slug syntax warnings
|
|
||||||
- Added error message support for pcre/pcre-jit compile
|
|
||||||
- Added JSON encode support for the tree structure
|
|
||||||
- Improved Graphivz Related Functions
|
|
||||||
- More failing test cases
|
|
||||||
|
|
||||||
### 1.2.1 - Tue May 27 21:16:13 2014
|
|
||||||
|
|
||||||
- Bug fixes.
|
|
||||||
- Function declaration improvement.
|
|
||||||
- pkg-config flags update (r3.pc)
|
|
||||||
|
|
||||||
### 1.2 - Fri May 23 23:30:11 2014
|
|
||||||
|
|
||||||
- Added simple pattern optimization.
|
|
||||||
- Clean up.
|
|
||||||
- Bug fixes.
|
|
||||||
|
|
||||||
### 0.9999 - Mon May 19 10:03:41 2014
|
|
||||||
|
|
||||||
API changes:
|
|
||||||
|
|
||||||
1. Removed the `route` argument from `r3_tree_insert_pathl_ex`:
|
|
||||||
|
|
||||||
node * r3_tree_insert_pathl_ex(node *tree, char *path, int path_len, void * data);
|
|
||||||
|
|
||||||
This reduce the interface complexity, e.g.,
|
|
||||||
|
|
||||||
r3_tree_insert_path(n, "/user2/{id:\\d+}", &var2);
|
|
||||||
|
|
||||||
2. The original `r3_tree_insert_pathl_ex` has been moved to `r3_tree_insert_pathl_ex` as a private API.
|
|
||||||
|
|
||||||
3. Moved `r3_tree_matchl` to `r3_tree_matchl` since it require the length of the path string.
|
|
||||||
|
|
||||||
m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry);
|
|
||||||
|
|
||||||
4. Added `r3_tree_match` for users to match a path without the length of the path string.
|
|
||||||
|
|
||||||
m = r3_tree_match( n , "/foo", entry);
|
|
||||||
|
|
||||||
5. Added `r3_tree_match_entry` for users want to match a `match_entry`, which is just a macro to simplify the use:
|
|
||||||
|
|
||||||
|
|
||||||
#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry)
|
|
||||||
|
|
||||||
|
|
||||||
6. Please note that A path that is inserted by `r3_tree_insert_route` can only be matched by `r3_tree_match_route`.
|
|
||||||
|
|
||||||
7. Added `r3_` prefix to `route` related methods.
|
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
project(r3 VERSION 2.0.0)
|
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
|
||||||
|
|
||||||
find_package(Check)
|
|
||||||
find_package(PCRE2 REQUIRED)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
else()
|
|
||||||
message(STATUS "Skipping unit tests, Check library not found!")
|
|
||||||
endif()
|
|
687
COPYING
687
COPYING
|
@ -1,21 +1,674 @@
|
||||||
The MIT License (MIT)
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (c) 2014 yoanlin93@gmail.com
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Preamble
|
||||||
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
|
The GNU General Public License is a free, copyleft license for
|
||||||
all copies or substantial portions of the Software.
|
software and other kinds of works.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The licenses for most software and other practical works are designed
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
share and change all versions of a program--to make sure it remains free
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
GNU General Public License for most of our software; it applies also to
|
||||||
THE SOFTWARE.
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
|
|
21
LICENSE
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 yoanlin93@gmail.com
|
|
||||||
|
|
||||||
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.
|
|
52
Makefile.am
52
Makefile.am
|
@ -1,51 +1 @@
|
||||||
SUBDIRS=src . examples
|
SUBDIRS=src tests
|
||||||
|
|
||||||
if ENABLE_CHECK
|
|
||||||
SUBDIRS += tests
|
|
||||||
endif
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libr3.la
|
|
||||||
libr3_la_SOURCES =
|
|
||||||
libr3_la_LIBADD = src/libr3core.la
|
|
||||||
libr3_la_LDFLAGS =
|
|
||||||
|
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
|
|
||||||
|
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS=-I m4
|
|
||||||
|
|
||||||
if ENABLE_DEBUG
|
|
||||||
AM_CFLAGS += -ggdb -fprofile-arcs -ftest-coverage
|
|
||||||
else
|
|
||||||
AM_CFLAGS += -O2
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_JEMALLOC
|
|
||||||
AM_LDFLAGS += -ljemalloc
|
|
||||||
endif
|
|
||||||
|
|
||||||
r3_includedir = $(includedir)/r3
|
|
||||||
r3_include_HEADERS = \
|
|
||||||
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 \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
|
||||||
pkgconfig_DATA = r3.pc
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
autogen.sh \
|
|
||||||
bench.html \
|
|
||||||
demo.c \
|
|
||||||
gen_routes.rb \
|
|
||||||
HACKING.md \
|
|
||||||
LICENSE \
|
|
||||||
README.md \
|
|
||||||
$(NULL)
|
|
||||||
|
|
362
README.md
362
README.md
|
@ -1,33 +1,20 @@
|
||||||
R3
|
R3
|
||||||
================
|
================
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=2.0)](https://travis-ci.org/c9s/r3)
|
R3 is an URI router library with high performance, thus, it's implemented in C.
|
||||||
|
It compiles your route paths into a prefix trie.
|
||||||
[![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.
|
|
||||||
It compiles your R3Route paths into a prefix trie.
|
|
||||||
|
|
||||||
By using the prefix tree constructed in the start-up time, you can dispatch
|
|
||||||
the path to the controller with high efficiency.
|
|
||||||
|
|
||||||
|
By using the constructed prefix trie in the start-up time, you can dispatch
|
||||||
|
routes with efficiency.
|
||||||
|
|
||||||
|
|
||||||
Requirement
|
Requirement
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
### Build Requirement
|
* cmake
|
||||||
|
|
||||||
* autoconf
|
|
||||||
* automake
|
|
||||||
* check
|
* check
|
||||||
* pkg-config
|
* pcre
|
||||||
|
* jemalloc
|
||||||
### Runtime Requirement
|
|
||||||
|
|
||||||
* pcre2
|
|
||||||
* (optional) graphviz version 2.38.0 (20140413.2041)
|
|
||||||
* (optional) libjson-c-dev
|
|
||||||
|
|
||||||
Pattern Syntax
|
Pattern Syntax
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -36,167 +23,37 @@ Pattern Syntax
|
||||||
/blog/post/{id:\d+} use `\d+` regular expression instead of default.
|
/blog/post/{id:\d+} use `\d+` regular expression instead of default.
|
||||||
|
|
||||||
|
|
||||||
API
|
C API
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
```c
|
|
||||||
#include <r3/r3.h>
|
|
||||||
|
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
|
||||||
R3Node *n = r3_tree_create(10);
|
|
||||||
|
|
||||||
int route_data = 3;
|
|
||||||
|
|
||||||
// insert the R3Route path into the router tree
|
|
||||||
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, "/foo/bar", strlen("/foo/bar"), &route_data );
|
|
||||||
|
|
||||||
r3_tree_insert_pathl(n ,"/post/{id}", strlen("/post/{id}") , &route_data );
|
|
||||||
|
|
||||||
r3_tree_insert_pathl(n, "/user/{id:\\d+}", strlen("/user/{id:\\d+}"), &route_data );
|
|
||||||
|
|
||||||
|
|
||||||
// if you want to catch error, you may call the extended path function for insertion
|
|
||||||
int data = 10;
|
|
||||||
char *errstr = NULL;
|
|
||||||
R3Node *ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, &data, &errstr);
|
|
||||||
if (ret == NULL) {
|
|
||||||
// failed insertion
|
|
||||||
printf("error: %s\n", errstr);
|
|
||||||
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// let's compile the tree!
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// dump the compiled tree
|
|
||||||
r3_tree_dump(n, 0);
|
|
||||||
|
|
||||||
// match a route
|
|
||||||
R3Node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
|
|
||||||
if (matched_node) {
|
|
||||||
int ret = *( (int*) matched_node->data );
|
|
||||||
}
|
|
||||||
|
|
||||||
// release the tree
|
|
||||||
r3_tree_free(n);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
**Capture Dynamic Variables**
|
|
||||||
|
|
||||||
If you want to capture the variables from regular expression, you will need to
|
|
||||||
create a `match_entry` object and pass the object to `r3_tree_matchl` function,
|
|
||||||
the catched variables will be pushed into the match entry structure:
|
|
||||||
|
|
||||||
```c
|
|
||||||
match_entry * entry = match_entry_create("/foo/bar");
|
|
||||||
|
|
||||||
// free the match entry
|
|
||||||
match_entry_free(entry);
|
|
||||||
```
|
|
||||||
|
|
||||||
And you can even specify the request method restriction:
|
|
||||||
|
|
||||||
```c
|
|
||||||
entry->request_method = METHOD_GET;
|
|
||||||
entry->request_method = METHOD_POST;
|
|
||||||
entry->request_method = METHOD_GET | METHOD_POST;
|
|
||||||
```
|
|
||||||
|
|
||||||
When using `match_entry`, you may match the R3Route with `r3_tree_match_entry` function:
|
|
||||||
|
|
||||||
```c
|
|
||||||
R3Node * matched_node = r3_tree_match_entry(n, entry);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Release Memory**
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Routing with conditions
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// 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)
|
||||||
n = r3_tree_create(10);
|
n = r3_tree_create(10);
|
||||||
|
|
||||||
int route_data = 3;
|
int route_data = 3;
|
||||||
|
|
||||||
// insert the R3Route path into the router tree
|
// insert the route 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_pathn(n , "/zoo" , strlen("/zoo") , &route_data );
|
||||||
|
r3_tree_insert_pathn(n , "/foo/bar" , strlen("/foo/bar") , &route_data );
|
||||||
|
r3_tree_insert_pathn(n , "/bar" , strlen("/bar") , &route_data );
|
||||||
|
r3_tree_insert_pathn(n , "/post/{id}" , strlen("/post/{id}") , &route_data );
|
||||||
|
|
||||||
char *errstr = NULL;
|
// let's compile the tree!
|
||||||
int err = r3_tree_compile(n, &errstr);
|
r3_tree_compile(n);
|
||||||
if (err != 0) {
|
|
||||||
// fail
|
|
||||||
printf("error: %s\n", errstr);
|
|
||||||
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// in your http server handler
|
// dump the compiled tree
|
||||||
|
r3_tree_dump(n, 0);
|
||||||
|
|
||||||
// create the match entry for capturing dynamic variables.
|
// match a route
|
||||||
match_entry * entry = match_entry_create("/blog/post");
|
node *matched_node = r3_tree_match(n, "/foo/bar", strlen("/foo/bar") );
|
||||||
entry->request_method = METHOD_GET;
|
matched_node->endpoint; // make sure there is a route end at here.
|
||||||
|
int ret = *( (*int) matched_node->route_ptr );
|
||||||
|
|
||||||
R3Route *matched_R3Route = r3_tree_match_route(n, entry);
|
|
||||||
matched_route->data; // get the data from matched route
|
|
||||||
|
|
||||||
// free the objects at the end
|
|
||||||
match_entry_free(entry);
|
|
||||||
r3_tree_free(n);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Slug
|
|
||||||
-----------------------
|
|
||||||
A slug is a placeholder, which captures the string from the URL as a variable.
|
|
||||||
Slugs will be compiled into regular expression patterns.
|
|
||||||
|
|
||||||
Slugs without patterns (like `/user/{userId}`) will be compiled into the `[^/]+` pattern.
|
|
||||||
|
|
||||||
To specify the pattern of a slug, you may write a colon to separate the slug name and the pattern:
|
|
||||||
|
|
||||||
"/user/{userId:\\d+}"
|
|
||||||
|
|
||||||
The above R3Route will use `\d+` as its pattern.
|
|
||||||
|
|
||||||
|
|
||||||
Optimization
|
Benchmark
|
||||||
-----------------------
|
|
||||||
Simple regular expressions are optimized through a regexp pattern to opcode
|
|
||||||
translator, which translates simple patterns into small & fast scanners.
|
|
||||||
|
|
||||||
By using this method, r3 reduces the matching overhead of pcre2 library.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Complex regular expressions will still use libpcre2 to match URL (partially).
|
|
||||||
|
|
||||||
|
|
||||||
Performance
|
|
||||||
-----------------------
|
-----------------------
|
||||||
The routing benchmark from stevegraham/rails' PR <https://github.com/stevegraham/rails/pull/1>:
|
The routing benchmark from stevegraham/rails' PR <https://github.com/stevegraham/rails/pull/1>:
|
||||||
|
|
||||||
|
@ -206,15 +63,17 @@ 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 R3Route path data for benchmarking, and here is the benchmark:
|
r3 uses the same route path data for benchmarking, and here is the benchmark:
|
||||||
|
|
||||||
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
|
5000000 iterations finished in 0.905591 seconds
|
||||||
11460057.83 i/sec
|
5521256.22 i/sec
|
||||||
|
|
||||||
|
The matching speed of r3 is 527+ times faster than rails' trie router.
|
||||||
|
|
||||||
|
|
||||||
### The Route Paths Of Benchmark
|
### The benchmarking route paths
|
||||||
|
|
||||||
The R3Route path generator is from <https://github.com/stevegraham/rails/pull/1>:
|
The route path generator is from <https://github.com/stevegraham/rails/pull/1>:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
@ -225,114 +84,9 @@ paths.each do |path|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
Function prefix mapping
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
|Function Prefix |Description |
|
|
||||||
|------------------|------------------------------------------------------------------------------------|
|
|
||||||
|`r3_tree_*` |Tree related operations, which require a node to operate a whole tree |
|
|
||||||
|`r3_node_*` |Single node related operations, which do not go through its own children or parent. |
|
|
||||||
|`r3_edge_*` |Edge related operations |
|
|
||||||
|`r3_route_*` |Route related operations, which are needed only when the tree is defined by routes |
|
|
||||||
|`match_entry_*` |Match entry related operations, a `match_entry` is just like the request parameters |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Rendering Routes With Graphviz
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
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`:
|
|
||||||
|
|
||||||
|
|
||||||
./configure --enable-graphviz
|
|
||||||
|
|
||||||
|
|
||||||
Here is the sample code of generating graph output:
|
|
||||||
|
|
||||||
|
|
||||||
```c
|
|
||||||
R3Node * n = r3_tree_create(1);
|
|
||||||
|
|
||||||
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/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/user/{id}", NULL);
|
|
||||||
r3_tree_insert_path(n, "/post/{title:\\w+}", NULL);
|
|
||||||
|
|
||||||
char *errstr = NULL;
|
|
||||||
int err;
|
|
||||||
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_render_file(n, "png", "check_gvc.png");
|
|
||||||
r3_tree_free(n);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
![Imgur](http://imgur.com/HrUoEbI.png)
|
|
||||||
|
|
||||||
Or you can even export it with dot format:
|
|
||||||
|
|
||||||
```dot
|
|
||||||
digraph g {
|
|
||||||
graph [bb="0,0,205.1,471"];
|
|
||||||
node [label="\N"];
|
|
||||||
"{root}" [height=0.5,
|
|
||||||
pos="35.097,453",
|
|
||||||
width=0.97491];
|
|
||||||
"#1" [height=0.5,
|
|
||||||
pos="35.097,366",
|
|
||||||
width=0.75];
|
|
||||||
....
|
|
||||||
```
|
|
||||||
|
|
||||||
### Graphviz Related Functions
|
|
||||||
|
|
||||||
```c
|
|
||||||
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
|
|
||||||
|
|
||||||
int r3_tree_render(const R3Node * tree, const char *layout, const char * format, FILE *fp);
|
|
||||||
|
|
||||||
int r3_tree_render_dot(const R3Node * tree, const char *layout, FILE *fp);
|
|
||||||
|
|
||||||
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
JSON Output
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
You can render the whole tree structure into json format output.
|
|
||||||
|
|
||||||
Please run `configure` with the `--enable-json` option.
|
|
||||||
|
|
||||||
Here is the sample code to generate JSON string:
|
|
||||||
|
|
||||||
```c
|
|
||||||
json_object * obj = r3_node_to_json_object(n);
|
|
||||||
|
|
||||||
const char *json = r3_node_to_json_pretty_string(n);
|
|
||||||
printf("Pretty JSON: %s\n",json);
|
|
||||||
|
|
||||||
const char *json = r3_node_to_json_string(n);
|
|
||||||
printf("JSON: %s\n",json);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Use case in PHP
|
Use case in PHP
|
||||||
-----------------------
|
-----------------------
|
||||||
**not implemented yet**
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Here is the paths data structure
|
// Here is the paths data structure
|
||||||
|
@ -347,7 +101,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 R3Route conditions
|
list($error, $message) = r3_validate($route); // validate route conditions
|
||||||
if ( $error ) {
|
if ( $error ) {
|
||||||
echo $message; // "Method not allowed", "...";
|
echo $message; // "Method not allowed", "...";
|
||||||
}
|
}
|
||||||
|
@ -356,59 +110,7 @@ if ( $error ) {
|
||||||
Install
|
Install
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
|
cmake CMakeLists.txt -Wno-dev
|
||||||
sudo apt-get install graphviz-dev graphviz # if you want graphviz
|
make
|
||||||
./autogen.sh
|
|
||||||
./configure && make
|
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
And we support debian-based distro now!
|
|
||||||
|
|
||||||
sudo apt-get install build-essential autoconf automake libpcre2-dev pkg-config debhelper libtool check
|
|
||||||
mv dist-debian debian
|
|
||||||
dpkg-buildpackage -b -us -uc
|
|
||||||
sudo gdebi ../libr3*.deb
|
|
||||||
|
|
||||||
|
|
||||||
#### Run Unit Tests
|
|
||||||
|
|
||||||
./configure --enable-check
|
|
||||||
make check
|
|
||||||
|
|
||||||
#### Enable Graphviz
|
|
||||||
|
|
||||||
./configure --enable-graphviz
|
|
||||||
|
|
||||||
#### With jemalloc
|
|
||||||
|
|
||||||
./configure --with-malloc=jemalloc
|
|
||||||
|
|
||||||
ubuntu PPA
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The PPA for libr3 can be found in <https://launchpad.net/~r3-team/+archive/libr3-daily>.
|
|
||||||
|
|
||||||
Binding For Other Languages
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
* Perl Router::R3 by @CindyLinz <https://metacpan.org/pod/Router::R3>
|
|
||||||
* Python pyr3 by @lucemia <https://github.com/lucemia/pyr3>
|
|
||||||
* Python pyr3 by @thedrow <https://github.com/thedrow/pyr3>
|
|
||||||
* Haskell r3 by @MnO2 <https://github.com/MnO2/r3>
|
|
||||||
* Vala r3-vala by @Ronmi <https://github.com/Ronmi/r3-vala>
|
|
||||||
|
|
||||||
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>
|
|
||||||
* mruby r3 <https://github.com/rail44/mruby-r3>
|
|
||||||
* mruby rake r3 <https://github.com/rail44/mruby-rack-r3>
|
|
||||||
|
|
||||||
|
|
||||||
License
|
|
||||||
--------------------
|
|
||||||
This software is released under MIT License.
|
|
||||||
|
|
10084
aclocal.m4
vendored
Normal file
10084
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@ for l in glibtoolize libtoolize15 libtoolize14 libtoolize ; do
|
||||||
echo "Did not find $l"
|
echo "Did not find $l"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "x$libtoolize" = "x" ]; then
|
if [ "x$libtoolize" == "x" ]; then
|
||||||
echo "Can't find libtoolize on your system"
|
echo "Can't find libtoolize on your system"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -30,7 +30,7 @@ $libtoolize -c -f
|
||||||
autoconf -f -W all,no-obsolete
|
autoconf -f -W all,no-obsolete
|
||||||
autoheader -f -W all
|
autoheader -f -W all
|
||||||
# automake -a -c -f -W all
|
# automake -a -c -f -W all
|
||||||
automake --add-missing --foreign --copy -c -W all
|
automake --add-missing --foreign -c -W all
|
||||||
|
|
||||||
rm -rf autom4te.cache
|
rm -rf autom4te.cache
|
||||||
exit 0
|
exit 0
|
||||||
|
|
110
bench.html
110
bench.html
|
@ -9,9 +9,7 @@
|
||||||
<script src="http://code.highcharts.com/modules/exporting.js"></script>
|
<script src="http://code.highcharts.com/modules/exporting.js"></script>
|
||||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
|
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
|
||||||
<script>
|
<script>
|
||||||
$.get('bench_str.csv', function(data) {
|
$.get('tests/bench_str.csv', function(data) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
chart: {
|
chart: {
|
||||||
|
@ -62,13 +60,11 @@
|
||||||
}],
|
}],
|
||||||
|
|
||||||
legend: {
|
legend: {
|
||||||
align: 'right',
|
align: 'left',
|
||||||
verticalAlign: 'top',
|
verticalAlign: 'top',
|
||||||
y: 50,
|
y: 20,
|
||||||
floating: false,
|
floating: true,
|
||||||
layout: 'vertical',
|
borderWidth: 0
|
||||||
background: '#fff',
|
|
||||||
borderWidth: 1,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
@ -77,7 +73,6 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
plotOptions: {
|
plotOptions: {
|
||||||
/*
|
|
||||||
area: {
|
area: {
|
||||||
fillColor: {
|
fillColor: {
|
||||||
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1},
|
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1},
|
||||||
|
@ -97,82 +92,28 @@
|
||||||
},
|
},
|
||||||
threshold: null
|
threshold: null
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
|
|
||||||
series: [
|
series: [{
|
||||||
{
|
type: 'area',
|
||||||
type: 'area',
|
name: 'Speed',
|
||||||
name: 'string matching',
|
pointInterval: 1000,
|
||||||
pointInterval: 1000,
|
lineWidth: 2,
|
||||||
lineWidth: 1,
|
marker: {
|
||||||
marker: {
|
radius: 3
|
||||||
radius: 3
|
|
||||||
},
|
|
||||||
pointStart: Date.UTC(2014, 5, 16),
|
|
||||||
data: []
|
|
||||||
},
|
},
|
||||||
{
|
pointStart: Date.UTC(2014, 5, 16),
|
||||||
type: 'area',
|
data: []
|
||||||
name: 'simple pattern matching',
|
}]
|
||||||
pointInterval: 1000,
|
|
||||||
lineWidth: 1,
|
|
||||||
marker: {
|
|
||||||
radius: 3
|
|
||||||
},
|
|
||||||
pointStart: Date.UTC(2014, 5, 16),
|
|
||||||
data: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'area',
|
|
||||||
name: 'tree_compile',
|
|
||||||
pointInterval: 1000,
|
|
||||||
lineWidth: 1,
|
|
||||||
marker: {
|
|
||||||
radius: 3
|
|
||||||
},
|
|
||||||
pointStart: Date.UTC(2014, 5, 16),
|
|
||||||
data: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'area',
|
|
||||||
name: 'match_entry with str',
|
|
||||||
pointInterval: 1000,
|
|
||||||
lineWidth: 1,
|
|
||||||
marker: {
|
|
||||||
radius: 3
|
|
||||||
},
|
|
||||||
pointStart: Date.UTC(2014, 5, 16),
|
|
||||||
data: []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var lines = data.split(/\n/);
|
var lines = data.split(/\n/);
|
||||||
|
|
||||||
// keep window size to 60 records
|
|
||||||
lines = lines.splice(-60);
|
|
||||||
|
|
||||||
$(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) {
|
var i = parseInt(columns[1]);
|
||||||
return;
|
if(i) {
|
||||||
|
options.series[0].data.push(i);
|
||||||
}
|
}
|
||||||
var a;
|
|
||||||
a = parseInt(columns[1]);
|
|
||||||
options.series[0].data.push(a || 0);
|
|
||||||
|
|
||||||
a = parseInt(columns[2]);
|
|
||||||
options.series[1].data.push(a || 0);
|
|
||||||
|
|
||||||
a = parseInt(columns[3]);
|
|
||||||
options.series[2].data.push(a || 0);
|
|
||||||
|
|
||||||
a = parseInt(columns[4]);
|
|
||||||
options.series[3].data.push(a || 0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#chart').highcharts(options);
|
$('#chart').highcharts(options);
|
||||||
|
@ -184,7 +125,7 @@
|
||||||
|
|
||||||
<h1>R3: Router Benchmark</h1>
|
<h1>R3: Router Benchmark</h1>
|
||||||
|
|
||||||
<div id="chart" style="width: 100%; height: 450px; margin: 0 auto"></div>
|
<div id="chart" style="width: 800px; height: 400px; margin: 0 auto"></div>
|
||||||
|
|
||||||
<h2>Data Set</h2>
|
<h2>Data Set</h2>
|
||||||
|
|
||||||
|
@ -529,16 +470,5 @@
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
<script>
|
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
|
||||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
|
||||||
|
|
||||||
ga('create', 'UA-2196512-14', 'c9s.github.io');
|
|
||||||
ga('send', 'pageview');
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
646
bench_str.csv
646
bench_str.csv
|
@ -1,646 +0,0 @@
|
||||||
1400242718,5649455.80
|
|
||||||
1400242784,5775186.12
|
|
||||||
1400242814,5653481.02
|
|
||||||
1400242868,5857187.70
|
|
||||||
1400242938,5732228.92
|
|
||||||
1400243193,5959689.05
|
|
||||||
1400243423,5717292.34
|
|
||||||
1400243528,5669803.44
|
|
||||||
1400243702,5880318.26
|
|
||||||
1400243875,5789509.57
|
|
||||||
1400243912,5889038.56
|
|
||||||
1400243951,5922317.92
|
|
||||||
1400243971,6069795.56
|
|
||||||
1400243982,5904973.70
|
|
||||||
1400243985,5888983.99
|
|
||||||
1400244196,5174852.68
|
|
||||||
1400244284,5821697.95
|
|
||||||
1400244307,6012282.29
|
|
||||||
1400244516,5929306.97
|
|
||||||
1400244550,5858897.69
|
|
||||||
1400244556,5998727.11
|
|
||||||
1400244574,5846792.25
|
|
||||||
1400244592,5930319.69
|
|
||||||
1400244599,5910137.48
|
|
||||||
1400244639,5936452.01
|
|
||||||
1400244648,5978607.43
|
|
||||||
1400244653,5956364.63
|
|
||||||
1400244657,5911318.61
|
|
||||||
1400244829,6362496.45
|
|
||||||
1400244887,6330902.59
|
|
||||||
1400244895,6390983.42
|
|
||||||
1400244908,6380415.58
|
|
||||||
1400244914,6346830.19
|
|
||||||
1400244932,6610181.08
|
|
||||||
1400245102,6404550.11
|
|
||||||
1400245168,6085174.66
|
|
||||||
1400245176,6400679.76
|
|
||||||
1400245216,6416409.15
|
|
||||||
1400245227,6485899.37
|
|
||||||
1400245230,5862573.02
|
|
||||||
1400245233,6526163.60
|
|
||||||
1400245281,6205337.09
|
|
||||||
1400245289,6217947.43
|
|
||||||
1400245311,6423151.81
|
|
||||||
1400251162,5826610.20
|
|
||||||
1400251172,6039034.62
|
|
||||||
1400251256,6219533.32
|
|
||||||
1400251264,6015717.76
|
|
||||||
1400278620,5733465.40
|
|
||||||
1400279249,6306920.57
|
|
||||||
1400282602,11775983.90
|
|
||||||
1400282802,11627473.22
|
|
||||||
1400282839,10222898.61
|
|
||||||
1400282930,11960583.69
|
|
||||||
1400283101,11659005.75
|
|
||||||
1400283479,11578012.31
|
|
||||||
1400283485,10742869.09
|
|
||||||
1400283755,11545078.70
|
|
||||||
1400284307,11493777.72
|
|
||||||
1400370342,11414560.92
|
|
||||||
1400370407,10759059.85
|
|
||||||
1400370448,10686226.48
|
|
||||||
1400370672,10532221.14
|
|
||||||
1400370683,10874340.04
|
|
||||||
1400370920,11307031.13
|
|
||||||
1400371092,11106355.37
|
|
||||||
1400371132,11313608.81
|
|
||||||
1400371165,10266146.59
|
|
||||||
1400371326,10644609.51
|
|
||||||
1400371371,10958943.43
|
|
||||||
1400371431,10145302.26
|
|
||||||
1400371504,11383090.96
|
|
||||||
1400371511,10023676.85
|
|
||||||
1400371561,10912042.58
|
|
||||||
1400371589,11439666.09
|
|
||||||
1400371602,11012616.42
|
|
||||||
1400371709,11058171.50
|
|
||||||
1400371751,11091926.38
|
|
||||||
1400371943,11103873.79
|
|
||||||
1400372774,10613683.19
|
|
||||||
1400372795,11841766.62
|
|
||||||
1400372820,12690699.18
|
|
||||||
1400372836,11596848.23
|
|
||||||
1400372848,11541418.97
|
|
||||||
1400372904,12034679.40
|
|
||||||
1400372910,12755936.07
|
|
||||||
1400373185,13716181.30
|
|
||||||
1400374415,13164892.40
|
|
||||||
1400382244,12226293.04
|
|
||||||
1400382299,11775631.24
|
|
||||||
1400382382,12331702.88
|
|
||||||
1400382578,13521992.76
|
|
||||||
1400382591,12607054.51
|
|
||||||
1400382780,12319337.31
|
|
||||||
1400382819,12453653.04
|
|
||||||
1400385205,13620526.43
|
|
||||||
1400385278,12130720.00
|
|
||||||
1400385318,13755788.28
|
|
||||||
1400385481,12663400.57
|
|
||||||
1400385502,12667686.69
|
|
||||||
1400385515,13077823.94
|
|
||||||
1400385528,13333901.32
|
|
||||||
1400385535,11961732.08
|
|
||||||
1400385563,12910309.71
|
|
||||||
1400385616,12105227.61
|
|
||||||
1400385713,13601851.15
|
|
||||||
1400385728,13344674.03
|
|
||||||
1400385734,13685060.22
|
|
||||||
1400385774,13223631.32
|
|
||||||
1400385951,11001406.94
|
|
||||||
1400386286,10682057.04
|
|
||||||
1400386296,11152665.22
|
|
||||||
1400386480,10908179.24
|
|
||||||
1400386496,11514008.98
|
|
||||||
1400386505,11172976.25
|
|
||||||
1400386731,11184613.82
|
|
||||||
1400387044,10760384.75
|
|
||||||
1400387138,10813584.63
|
|
||||||
1400387154,10825571.07
|
|
||||||
1400387176,9958256.23
|
|
||||||
1400387232,11035725.37
|
|
||||||
1400387264,11006703.61
|
|
||||||
1400387291,11123431.08
|
|
||||||
1400387303,10762934.26
|
|
||||||
1400387318,10842286.92
|
|
||||||
1400387384,10651069.93
|
|
||||||
1400387532,11055554.04
|
|
||||||
1400387761,10803251.35
|
|
||||||
1400387926,10854580.56
|
|
||||||
1400388003,11099634.54
|
|
||||||
1400388313,11132551.99
|
|
||||||
1400388338,11139229.93
|
|
||||||
1400388369,10898128.85
|
|
||||||
1400388529,10815527.23
|
|
||||||
1400388539,10930897.10
|
|
||||||
1400388591,10720695.10
|
|
||||||
1400388676,10571166.21
|
|
||||||
1400388683,10882166.49
|
|
||||||
1400388712,11008826.02
|
|
||||||
1400388799,10728815.96
|
|
||||||
1400388848,10409083.22
|
|
||||||
1400388867,10470546.30
|
|
||||||
1400388931,10554179.23
|
|
||||||
1400388944,10969249.80
|
|
||||||
1400388966,10116208.17
|
|
||||||
1400389070,11138537.72
|
|
||||||
1400389087,10874695.29
|
|
||||||
1400389125,10358558.63
|
|
||||||
1400389184,10999293.17
|
|
||||||
1400389215,10781509.38
|
|
||||||
1400389227,10347289.13
|
|
||||||
1400389233,10851573.79
|
|
||||||
1400389241,10631550.45
|
|
||||||
1400389267,10864289.97
|
|
||||||
1400389287,11080291.51
|
|
||||||
1400389343,11017300.69
|
|
||||||
1400389511,11126324.77
|
|
||||||
1400393822,10834745.34
|
|
||||||
1400393905,10709222.20
|
|
||||||
1400394012,10213843.65
|
|
||||||
1400394020,10789186.08
|
|
||||||
1400394033,10376120.72
|
|
||||||
1400394043,10870636.70
|
|
||||||
1400394050,10627263.79
|
|
||||||
1400394080,10766286.36
|
|
||||||
1400394087,10864430.68
|
|
||||||
1400394095,11008891.52
|
|
||||||
1400394100,10578167.34
|
|
||||||
1400394266,10622702.57
|
|
||||||
1400394385,10413209.43
|
|
||||||
1400394571,8615372.65
|
|
||||||
1400394590,10964999.94
|
|
||||||
1400394658,11173658.86
|
|
||||||
1400395575,10502560.60
|
|
||||||
1400396023,10925991.89
|
|
||||||
1400396031,10299722.97
|
|
||||||
1400396055,10781849.35
|
|
||||||
1400396123,10746610.69
|
|
||||||
1400396341,10811271.16
|
|
||||||
1400396368,10631572.01
|
|
||||||
1400396396,10442039.18
|
|
||||||
1400396467,10833155.84
|
|
||||||
1400396500,10639776.08
|
|
||||||
1400396541,9454881.65
|
|
||||||
1400396547,10795847.32
|
|
||||||
1400396725,10488850.71
|
|
||||||
1400396745,10442025.32
|
|
||||||
1400396765,10689592.72
|
|
||||||
1400406039,11164926.18
|
|
||||||
1400406130,10852846.69
|
|
||||||
1400406200,9606388.04
|
|
||||||
1400406388,10630125.97
|
|
||||||
1400406712,10901099.14
|
|
||||||
1400406757,10977776.63
|
|
||||||
1400406780,10923630.07
|
|
||||||
1400406834,10665256.26
|
|
||||||
1400406846,10841057.59
|
|
||||||
1400406860,10987088.01
|
|
||||||
1400406868,10991821.64
|
|
||||||
1400406881,11040200.72
|
|
||||||
1400406887,11491514.59
|
|
||||||
1400406950,10874497.93
|
|
||||||
1400407239,11002642.12
|
|
||||||
1400407250,10744268.90
|
|
||||||
1400407276,11144966.17
|
|
||||||
1400407292,10470853.00
|
|
||||||
1400407305,10632588.97
|
|
||||||
1400407323,11275701.84
|
|
||||||
1400407364,10827173.25
|
|
||||||
1400407380,11232917.51
|
|
||||||
1400407384,10892217.62
|
|
||||||
1400407454,10793665.50
|
|
||||||
1400407490,11078867.15
|
|
||||||
1400407498,10995093.02
|
|
||||||
1400407520,10914505.42
|
|
||||||
1400407544,10139300.12
|
|
||||||
1400407549,11140837.53
|
|
||||||
1400407572,11242381.65
|
|
||||||
1400407586,10545015.96
|
|
||||||
1400407832,11318167.86
|
|
||||||
1400407846,11412502.78
|
|
||||||
1400407864,10788301.74
|
|
||||||
1400408080,10813960.08
|
|
||||||
1400408117,11053281.53
|
|
||||||
1400408148,10925976.71
|
|
||||||
1400408157,10866706.90
|
|
||||||
1400408486,10438246.84
|
|
||||||
1400408495,10637030.99
|
|
||||||
1400408503,10998237.54
|
|
||||||
1400408743,10746673.10
|
|
||||||
1400408973,10696597.06
|
|
||||||
1400409590,10747379.89
|
|
||||||
1400409621,10925100.16
|
|
||||||
1400409674,10243836.44
|
|
||||||
1400409691,10938038.79
|
|
||||||
1400409739,10663533.54
|
|
||||||
1400409845,11063203.93
|
|
||||||
1400409863,11118679.72
|
|
||||||
1400410121,10935751.60
|
|
||||||
1400410132,10839286.96
|
|
||||||
1400410167,10427826.47
|
|
||||||
1400410180,10851581.27
|
|
||||||
1400410252,11133237.55
|
|
||||||
1400410283,10618062.83
|
|
||||||
1400410318,10166831.58
|
|
||||||
1400410399,11007341.02
|
|
||||||
1400410441,10929677.98
|
|
||||||
1400410704,10685427.91
|
|
||||||
1400411026,11125022.32
|
|
||||||
1400411267,10710017.05
|
|
||||||
1400411298,10809190.81
|
|
||||||
1400411322,10574819.37
|
|
||||||
1400411340,10536563.80
|
|
||||||
1400411381,10703727.13
|
|
||||||
1400411406,10814145.96
|
|
||||||
1400411717,10680938.12
|
|
||||||
1400411829,11149498.96
|
|
||||||
1400411833,11062632.01
|
|
||||||
1400411856,9571612.03
|
|
||||||
1400411876,11221957.84
|
|
||||||
1400411895,10599710.42
|
|
||||||
1400411903,10817749.52
|
|
||||||
1400412670,10728801.32
|
|
||||||
1400412684,10962187.64
|
|
||||||
1400412708,11267224.66
|
|
||||||
1400412723,10857559.01
|
|
||||||
1400412770,8906644.57
|
|
||||||
1400412827,10953246.38
|
|
||||||
1400412838,10923438.51
|
|
||||||
1400412848,11015834.62
|
|
||||||
1400412895,11344942.77
|
|
||||||
1400412944,10841369.57
|
|
||||||
1400412949,11040353.77
|
|
||||||
1400412961,11156072.62
|
|
||||||
1400412966,10831108.08
|
|
||||||
1400412981,10884440.74
|
|
||||||
1400413003,10862551.12
|
|
||||||
1400413012,10582158.17
|
|
||||||
1400413058,10546292.20
|
|
||||||
1400413092,10922604.09
|
|
||||||
1400413230,11067709.38
|
|
||||||
1400413269,10410991.73
|
|
||||||
1400413317,10980282.65
|
|
||||||
1400413354,10964929.24
|
|
||||||
1400413388,10650346.91
|
|
||||||
1400413435,11113745.92
|
|
||||||
1400413458,11146293.04
|
|
||||||
1400413550,10472731.92
|
|
||||||
1400413559,11177595.40
|
|
||||||
1400413586,10852453.55
|
|
||||||
1400413660,10108857.97
|
|
||||||
1400413696,10929343.81
|
|
||||||
1400413713,10824792.50
|
|
||||||
1400413729,10115599.85
|
|
||||||
1400413766,10973125.90
|
|
||||||
1400413779,9519723.81
|
|
||||||
1400413806,10690956.88
|
|
||||||
1400413819,11268613.09
|
|
||||||
1400414037,11204556.58
|
|
||||||
1400414053,10782873.08
|
|
||||||
1400414061,10921441.80
|
|
||||||
1400414081,11191230.95
|
|
||||||
1400414123,10777241.27
|
|
||||||
1400414133,11087850.62
|
|
||||||
1400414141,10921616.22
|
|
||||||
1400414173,11040258.84
|
|
||||||
1400414317,11319968.07
|
|
||||||
1400414342,10822736.73
|
|
||||||
1400414355,11015188.51
|
|
||||||
1400414389,8485410.70
|
|
||||||
1400414457,11241764.95
|
|
||||||
1400414479,11088645.99
|
|
||||||
1400414501,10750962.96
|
|
||||||
1400414556,11007510.49
|
|
||||||
1400414587,10903071.42
|
|
||||||
1400415353,10705889.14
|
|
||||||
1400415397,11505319.20
|
|
||||||
1400465549,13249817.73
|
|
||||||
1400465650,13467612.96
|
|
||||||
1400465723,13269768.49
|
|
||||||
1400465767,13374884.38
|
|
||||||
1400465776,13440016.82
|
|
||||||
1400465836,13386592.12
|
|
||||||
1400465865,13137081.39
|
|
||||||
1400465878,13376710.05
|
|
||||||
1400465928,13251983.44
|
|
||||||
1400466198,13359933.76
|
|
||||||
1400466833,13166545.46
|
|
||||||
1400466875,13515485.94
|
|
||||||
1400467139,13047096.38
|
|
||||||
1400467481,13594764.91
|
|
||||||
1400468648,13474532.60
|
|
||||||
1400570358,16277787.44
|
|
||||||
1400570442,16505301.07
|
|
||||||
1400570494,16651367.19
|
|
||||||
1400570540,16509970.21
|
|
||||||
1400571025,16271291.64
|
|
||||||
1400571045,16347991.85
|
|
||||||
1400571109,16051262.35
|
|
||||||
1400571116,16000716.18
|
|
||||||
1400571171,15655022.26
|
|
||||||
1400571314,15695138.73
|
|
||||||
1400571328,15779592.30
|
|
||||||
1400571446,16173358.85
|
|
||||||
1400571511,15816846.60
|
|
||||||
1400571580,15165532.41
|
|
||||||
1400571819,15473025.62
|
|
||||||
1400571872,14901576.43
|
|
||||||
1400571879,14751988.30
|
|
||||||
1400571889,15028402.84
|
|
||||||
1400571925,13450622.41
|
|
||||||
1400571993,13276463.85
|
|
||||||
1400572069,13113355.08
|
|
||||||
1400572160,13281786.31
|
|
||||||
1400573791,13580509.03
|
|
||||||
1400573832,10555723.33
|
|
||||||
1400573839,10582884.42
|
|
||||||
1400573847,10478482.69
|
|
||||||
1400573855,15087645.17
|
|
||||||
1400573891,15207920.79
|
|
||||||
1400592138,13289883.29
|
|
||||||
1400592160,13689866.38
|
|
||||||
1400592167,13887614.50
|
|
||||||
1400592181,12902438.30
|
|
||||||
1400592212,12711239.59
|
|
||||||
1400592282,13868279.63
|
|
||||||
1400592287,14008688.28
|
|
||||||
1400592314,13915819.27
|
|
||||||
1400592447,13857005.45
|
|
||||||
1400592453,13737673.35
|
|
||||||
1400592520,13746939.61
|
|
||||||
1400592698,13522088.67
|
|
||||||
1400592756,14069856.66
|
|
||||||
1400592898,13964804.85
|
|
||||||
1400592906,12335090.17
|
|
||||||
1400592931,14145688.00
|
|
||||||
1400592964,13071020.50
|
|
||||||
1400593034,13921007.60
|
|
||||||
1400593050,12790569.45
|
|
||||||
1400593062,13672159.26
|
|
||||||
1400593069,13522175.86
|
|
||||||
1400593171,13911803.66
|
|
||||||
1400593186,13788854.92
|
|
||||||
1400593197,13978543.79
|
|
||||||
1400593210,13568445.16
|
|
||||||
1400593219,13704926.07
|
|
||||||
1400599508,13991454.07
|
|
||||||
1400599553,13826120.84
|
|
||||||
1400599756,12099437.82
|
|
||||||
1400599972,13982492.37
|
|
||||||
1400600045,13977543.80
|
|
||||||
1400600057,13901438.41
|
|
||||||
1400600326,14049707.03
|
|
||||||
1400600677,13384789.38
|
|
||||||
1400600754,13649118.34
|
|
||||||
1400601224,13742996.84
|
|
||||||
1400603778,13736212.66
|
|
||||||
1400603800,13715365.00
|
|
||||||
1400603827,12742770.05
|
|
||||||
1400604427,13725403.62
|
|
||||||
1400604504,13787120.46
|
|
||||||
1400604527,13505264.87
|
|
||||||
1400604546,13522321.17
|
|
||||||
1400605108,13746963.64
|
|
||||||
1400605113,13899221.05
|
|
||||||
1400605117,13066929.36
|
|
||||||
1400605122,13818325.58
|
|
||||||
1400605132,13624101.24
|
|
||||||
1400605227,12992570.34
|
|
||||||
1400605241,13631407.12
|
|
||||||
1400605247,13773296.72
|
|
||||||
1400605254,13601113.09
|
|
||||||
1400605334,13477173.69
|
|
||||||
1400605341,13528406.95
|
|
||||||
1400605371,13822120.38
|
|
||||||
1400605378,13627925.89
|
|
||||||
1400605452,13704460.37
|
|
||||||
1400605482,13612516.46
|
|
||||||
1400605625,12647482.46
|
|
||||||
1400605676,13671799.76
|
|
||||||
1400605706,13269956.01
|
|
||||||
1400605735,13684822.09
|
|
||||||
1400605834,13635682.11
|
|
||||||
1400606038,13788132.68
|
|
||||||
1400606140,13834040.49
|
|
||||||
1400606400,13665833.66
|
|
||||||
1400606404,13519944.18
|
|
||||||
1400606406,13923000.83
|
|
||||||
1400606409,13742645.62
|
|
||||||
1400606411,13878225.03
|
|
||||||
1400606451,13922301.44
|
|
||||||
1400606491,14030387.83
|
|
||||||
1400606523,13157029.51
|
|
||||||
1400606567,13999364.95
|
|
||||||
1400607671,13906437.74
|
|
||||||
1400607682,13828950.20
|
|
||||||
1400607689,13932349.19
|
|
||||||
1400607695,13583203.56
|
|
||||||
1400607698,13630627.45
|
|
||||||
1400607700,13972490.11
|
|
||||||
1400659046,19754150.71
|
|
||||||
1400668268,13174604.57
|
|
||||||
1400668574,13632260.72
|
|
||||||
1400681414,10832905.89
|
|
||||||
1400685490,13185955.87
|
|
||||||
1400762875,10472029.42
|
|
||||||
1400764426,10066458.45,1590373.41
|
|
||||||
1400765068,10657617.64,2131810.12
|
|
||||||
1400766518,10259200.94,1878279.25,96697.86
|
|
||||||
1400766623,11057429.08,2113683.19,95835.70
|
|
||||||
1400815975,11316714.26,2165050.14,55188.21
|
|
||||||
1400815990,10826986.93,1780938.43,55188.21
|
|
||||||
1400816005,10584527.76,1707721.44,55924.05
|
|
||||||
1400816427,9376611.56,2006568.41,53092.46
|
|
||||||
1400816438,9096902.53,2108994.21,59074.70
|
|
||||||
1400816448,9260790.48,2131479.91,55188.21
|
|
||||||
1400816458,9303957.38,2110797.39,55924.05
|
|
||||||
1400816525,9330370.85,1985782.06,59074.70
|
|
||||||
1400816594,9389101.94,1989498.64,34663.67
|
|
||||||
1400816645,9201251.49,2105517.01,43240.25
|
|
||||||
1400816815,9228390.29,2097606.06,23301.69
|
|
||||||
1400817268,9242018.45,2109706.16,38479.85
|
|
||||||
1400817280,9320308.27,1891100.64,47662.55
|
|
||||||
1400817392,6448229.88,1994875.02,34663.67
|
|
||||||
1400817671,8654311.52,2094510.75,47662.55
|
|
||||||
1400817706,9362050.27,1981074.38,62601.55
|
|
||||||
1400818067,9247601.69,1944615.34,35848.75
|
|
||||||
1400818654,10797650.12,2550647.32,52428.80
|
|
||||||
1400818717,10964008.21,2607023.59,59074.70
|
|
||||||
1400818725,11160125.46,2574373.69,47127.01
|
|
||||||
1400818732,10829199.02,2557782.44,67650.06
|
|
||||||
1400818739,10859734.88,2538368.71,41527.76
|
|
||||||
1400820693,12547680.62,2375764.20,55924.05
|
|
||||||
1400820703,12815067.19,2375474.47,34379.54
|
|
||||||
1400820719,11693810.54,2231143.55,47662.55
|
|
||||||
1400820728,12612875.15,2357108.19,49932.19
|
|
||||||
1400820868,12158497.75,2598723.80,62601.55
|
|
||||||
1400820877,12254639.62,2583601.86,77672.30
|
|
||||||
1400820886,12274457.34,2393445.83,55188.21
|
|
||||||
1400820922,12218386.22,2604565.56,77672.30
|
|
||||||
1400820933,12443155.46,2361317.46,45590.26
|
|
||||||
1400829105,12110496.08,4797414.85,38479.85
|
|
||||||
1400829117,12258758.55,4129968.45,59074.70
|
|
||||||
1400829143,12339827.27,4775224.01,55924.05
|
|
||||||
1400831278,11421287.15,4742488.93,39945.75
|
|
||||||
1400832805,11676305.28,4832961.50,58254.22
|
|
||||||
1400832811,11785948.52,4137657.27,45590.26
|
|
||||||
1400832831,11918383.46,4859275.06,47662.55
|
|
||||||
1400832837,11650937.22,4734982.85,61680.94
|
|
||||||
1400832892,11728021.34,4274247.24,45590.26
|
|
||||||
1400832912,11580034.68,4752494.99,62601.55
|
|
||||||
1400833017,11890578.32,4501803.27,29330.80
|
|
||||||
1400833024,11715363.55,4726544.41,59074.70
|
|
||||||
1400833045,11813359.08,4828190.72,53092.46
|
|
||||||
1400833051,11082009.03,4721512.49,62601.55
|
|
||||||
1400837501,11958680.82,4777890.52,45590.26
|
|
||||||
1400837621,11423775.75,4679207.46,59074.70,2459430.07
|
|
||||||
1400837636,11534281.98,4192617.73,66576.25,2968590.57
|
|
||||||
1400837657,11693260.66,4815393.82,77672.30,2856236.96
|
|
||||||
1400837667,11834338.05,4822006.81,47662.55,3015821.63
|
|
||||||
1400837677,11999462.15,4854783.73,49932.19,3008349.32
|
|
||||||
1400837696,11814938.63,4740948.30,55188.21,3007002.06
|
|
||||||
1400837706,11535595.30,4712420.14,62601.55,2865728.03
|
|
||||||
1400837716,11928552.18,4833449.01,35848.75,2990344.18
|
|
||||||
1400837725,11873673.72,4275934.73,45590.26,3024045.98
|
|
||||||
1400837735,11805064.50,4855078.95,47662.55,3016256.98
|
|
||||||
1400837744,12041094.07,4815428.09,61680.94,2991090.14
|
|
||||||
1400837754,11766504.83,4848425.07,47662.55,2986385.66
|
|
||||||
1400837764,11979089.24,4257134.48,47662.55,3015693.70
|
|
||||||
1400837774,11190990.08,4331119.44,45590.26,2587281.10
|
|
||||||
1400837785,10306507.50,3909290.89,47662.55,2827471.10
|
|
||||||
1400837797,10323334.38,4221122.48,55924.05,2294463.55
|
|
||||||
1400922358,11238818.94,4585324.58,59074.70,2649691.23
|
|
||||||
1400922668,10605016.95,4435942.19,52428.80,2805666.62
|
|
||||||
1400922931,10906416.86,4595485.60,55924.05,2744562.44
|
|
||||||
1400922941,11009432.85,4532428.61,47662.55,2763157.51
|
|
||||||
1400922951,11053192.20,4323815.83,45590.26,2783158.56
|
|
||||||
1400922974,10151535.91,3794968.57,47662.55,2474383.18
|
|
||||||
1400922986,10218555.01,3887695.21,53092.46,2200366.58
|
|
||||||
1400922997,10051469.51,4460938.45,59074.70,2490310.13
|
|
||||||
1400923283,11180779.62,4365911.08,71089.90,2629220.52
|
|
||||||
1400923294,11193863.27,4516227.63,82241.25,2545079.35
|
|
||||||
1400923304,11423045.65,4137604.47,47662.55,2655584.06
|
|
||||||
1400923315,10840939.91,4663256.98,55924.05,2611667.47
|
|
||||||
1400923325,11091416.01,4103660.70,59074.70,2817256.97
|
|
||||||
1400923335,11435046.07,4356917.52,45100.04,2883103.51
|
|
||||||
1400928121,11717285.79,4816672.70,58254.22,2897866.52
|
|
||||||
1400928131,11343621.37,4759351.32,45100.04,2849262.65
|
|
||||||
1400928141,11268332.55,4717279.18,55188.21,2871378.81
|
|
||||||
1400928151,11308055.40,4652350.21,47662.55,2866742.89
|
|
||||||
1400928225,10802915.60,4687267.34,58254.22,2632936.94
|
|
||||||
1400928235,10661874.62,4739682.52,62601.55,2740810.88
|
|
||||||
1400928262,11033784.15,4714416.68,55188.21,2737984.12
|
|
||||||
1400928272,10649279.69,4567955.12,47662.55,2716598.01
|
|
||||||
1400928319,10230059.66,4527332.79,49932.19,2345303.39
|
|
||||||
1400928329,11085172.21,4647514.08,62601.55,2735715.15
|
|
||||||
1400929424,11030888.11,4442984.66,55924.05,2892178.39
|
|
||||||
1400929434,11544517.30,4792322.97,77672.30,2718374.75
|
|
||||||
1400929444,11729287.31,4167112.20,47662.55,2880342.59
|
|
||||||
1401713584,11611550.10,3615349.83,59074.70,2395398.52
|
|
||||||
1401713613,11497337.95,3867069.72,76260.07,2513425.94
|
|
||||||
1401713624,11012180.78,4218063.79,62601.55,2274326.51
|
|
||||||
1401713638,10375230.94,3665431.16,59074.70,1995737.34
|
|
||||||
1401713649,11430757.90,3840336.12,62601.55,2385432.38
|
|
||||||
1401713661,8970219.06,4509359.41,62601.55,2278745.62
|
|
||||||
1401713673,11040727.70,3743492.87,55188.21,2408080.74
|
|
||||||
1401785936,11348169.84,4097861.38,77672.30,2199971.87
|
|
||||||
1401785947,11312609.98,3904129.33,77672.30,2560323.79
|
|
||||||
1401785958,10537229.10,4396861.86,58254.22,2424404.69
|
|
||||||
1401785969,11206290.89,4517530.60,45100.04,2551294.60
|
|
||||||
1401785980,11248534.36,4396504.83,45100.04,2262115.57
|
|
||||||
1401785991,11198475.79,4330140.21,47662.55,2628625.68
|
|
||||||
1401786002,11160024.50,4168595.71,59074.70,2536134.48
|
|
||||||
1401786013,10430212.17,4125745.93,45590.26,2506666.43
|
|
||||||
1401786024,10213079.29,4298993.08,45100.04,2533248.03
|
|
||||||
1401786035,10579681.12,4386844.66,37117.73,2541278.85
|
|
||||||
1401882943,11243814.21,3713601.99,71089.90,2059566.22
|
|
||||||
1401882981,11134212.84,4231286.57,53092.46,2180900.77
|
|
||||||
1401882993,10950888.02,4182279.39,53092.46,2164511.15
|
|
||||||
1401883005,11123999.47,3725357.71,76260.07,2211605.54
|
|
||||||
1401883017,10773686.78,3988825.00,45590.26,2256792.94
|
|
||||||
1401883041,10991057.38,4192016.84,55924.05,2164285.17
|
|
||||||
1401883053,11253995.23,4111639.22,45100.04,2096238.88
|
|
||||||
1401883388,11153576.69,4347093.92,76260.07,2205268.76
|
|
||||||
1401883411,11501180.01,4506130.97,58254.22,2243712.66
|
|
||||||
1401883422,11156015.26,4540579.82,47662.55,2279418.81
|
|
||||||
1401883445,11195098.22,4455873.90,38479.85,2267750.98
|
|
||||||
1401883468,11467197.28,4422749.94,72315.59,2289153.70
|
|
||||||
1401883480,11087024.10,4312175.00,55188.21,2296830.48
|
|
||||||
1401925287,11654811.40,4536210.26,72315.59,2379382.00
|
|
||||||
1401925299,11573243.70,3894464.26,59074.70,2276455.83
|
|
||||||
1401925310,11944273.21,4666625.62,62601.55,2304322.33
|
|
||||||
1401925322,11775622.43,3945455.94,43690.67,2149656.21
|
|
||||||
1401925333,11539429.12,4630751.73,43240.25,2270121.49
|
|
||||||
1401925344,11312437.08,4589657.39,62601.55,2329731.93
|
|
||||||
1401926595,11633680.46,4701904.00,55924.05,2410241.02
|
|
||||||
1401926639,11630837.25,3933338.77,55924.05,2346259.71
|
|
||||||
1401926649,11822018.52,4686898.26,76260.07,2419184.30
|
|
||||||
1401926661,11800543.07,4196806.70,71089.90,2295282.55
|
|
||||||
1401926673,10529846.71,3931058.57,49932.19,2165044.18
|
|
||||||
1401926686,10117457.56,3362173.28,55924.05,1994411.93
|
|
||||||
1401926711,11029110.99,4353057.39,49932.19,2239772.42
|
|
||||||
1401926725,10862072.89,2750694.08,32263.88,2104475.43
|
|
||||||
1402402553,11294194.69,4189904.32,49932.19,2123185.29
|
|
||||||
1402402565,11164650.78,4006360.04,55924.05,2049352.49
|
|
||||||
1402402578,9943455.54,3781047.14,45590.26,2166878.84
|
|
||||||
1447151242,13847614.65,5481111.96,66576.25,2528296.71
|
|
||||||
1447151252,13478094.70,5762300.49,99864.38,2467814.73
|
|
||||||
1447151261,13318275.24,5669995.06,91180.52,2528263.08
|
|
||||||
1447151271,13328641.49,5792107.41,62601.55,2534213.23
|
|
||||||
1447151281,13603554.01,5690401.12,52428.80,2533696.10
|
|
||||||
1447151291,13893573.36,5447950.39,66576.25,2532335.35
|
|
||||||
1447151303,13091255.94,3616732.34,62601.55,2227987.21
|
|
||||||
1447151314,11690373.06,4497110.65,91180.52,2136426.50
|
|
||||||
1447151325,13580596.98,4134246.08,91180.52,2373758.39
|
|
||||||
1447151335,13974417.41,5615391.00,59074.70,2507497.84
|
|
||||||
1447152253,13474619.18,4825849.40,49932.19,2424468.13
|
|
||||||
1447152263,12626952.28,5517283.96,49932.19,2459678.52
|
|
||||||
1447152273,13712806.08,5401932.71,91180.52,2531766.93
|
|
||||||
1447152286,13674890.28,5105976.43,91180.52,1637699.37
|
|
||||||
1447152296,12598276.86,5621295.29,91180.52,2265631.05
|
|
||||||
1447152307,13427458.88,5257266.07,24966.10,2309148.88
|
|
||||||
1447152317,13658739.92,5880717.85,62601.55,2403685.89
|
|
||||||
1447152327,13697028.28,5704775.21,91180.52,2397147.59
|
|
||||||
1447152337,13854967.00,5598234.96,43690.67,2516441.18
|
|
||||||
1447152348,13446160.91,4623962.27,91180.52,2349433.72
|
|
||||||
1447154320,13805978.08,5843317.38,66576.25,2529583.04
|
|
||||||
1447154330,13794992.46,5866609.62,89240.51,2479643.35
|
|
||||||
1447154340,12999574.36,5870781.62,83886.08,2565547.20
|
|
||||||
1447154349,13813759.40,5896996.47,59074.70,2577608.73
|
|
||||||
1447154359,13646711.36,5716116.84,47662.55,2574703.24
|
|
||||||
1447154368,13664364.46,5873110.25,41527.76,2502096.76
|
|
||||||
1447154378,13345158.07,5929994.94,66576.25,2526050.75
|
|
||||||
1447154388,13619724.42,5891895.35,66576.25,2542931.44
|
|
||||||
1447154397,13274559.00,5736176.87,66576.25,2538733.05
|
|
||||||
1447154407,13445232.76,5381001.80,89240.51,2576233.33
|
|
||||||
1447155008,13277391.26,5722360.39,71089.90,2475000.02
|
|
||||||
1447155019,13581101.21,5484972.04,45100.04,2192286.64
|
|
||||||
1447155029,13116025.99,5830570.40,52428.80,2522486.73
|
|
||||||
1447155066,13645222.60,5724509.20,62601.55,2514659.99
|
|
||||||
1447155349,11915902.67,5912124.62,58254.22,2421361.02
|
|
||||||
1447155679,13951049.58,5897239.13,26379.27,2527577.97
|
|
||||||
1447155699,13781189.15,5851252.25,62601.55,2539751.33
|
|
||||||
1447156053,13415522.24,5930072.07,82241.25,2533834.67
|
|
||||||
1447156073,13492327.24,5848589.68,52428.80,2567896.99
|
|
||||||
1447156411,13229275.90,5858750.37,66576.25,2523350.73
|
|
||||||
1447156432,13556025.90,5873947.56,62601.55,2487130.01
|
|
||||||
1447156745,13744909.39,5913103.69,66576.25,2551782.92
|
|
||||||
1447158285,11638128.71,5241775.30,71089.90,2321077.83
|
|
||||||
1447158396,13539837.29,5874704.47,47662.55,2533571.93
|
|
||||||
1447158415,14054879.53,5952300.47,41527.76,2571669.83
|
|
||||||
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 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)
|
|
37
cmake_modules/FindPCRE.cmake
Normal file
37
cmake_modules/FindPCRE.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 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)
|
63
config.h
Normal file
63
config.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* config.h. Generated from config.h.in by configure. */
|
||||||
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
|
#define HAVE_DLFCN_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#define HAVE_INTTYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#define HAVE_STRINGS_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#define HAVE_STRING_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#define HAVE_SYS_TYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||||
|
*/
|
||||||
|
#define LT_OBJDIR ".libs/"
|
||||||
|
|
||||||
|
/* Name of package */
|
||||||
|
#define PACKAGE "r3"
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#define PACKAGE_BUGREPORT ""
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#define PACKAGE_NAME "r3"
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#define PACKAGE_STRING "r3 1.0"
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#define PACKAGE_TARNAME "r3"
|
||||||
|
|
||||||
|
/* Define to the home page for this package. */
|
||||||
|
#define PACKAGE_URL ""
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#define PACKAGE_VERSION "1.0"
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Version number of package */
|
||||||
|
#define VERSION "1.0"
|
|
@ -1,3 +0,0 @@
|
||||||
#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
|
|
||||||
#cmakedefine HAVE_STRNDUP @HAVE_STRNDUP@
|
|
||||||
#cmakedefine HAVE_STDBOOL_H @HAVE_STDBOOL_H@
|
|
62
config.h.in
Normal file
62
config.h.in
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
|
#undef HAVE_DLFCN_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#undef HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#undef HAVE_STRING_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||||
|
*/
|
||||||
|
#undef LT_OBJDIR
|
||||||
|
|
||||||
|
/* Name of package */
|
||||||
|
#undef PACKAGE
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#undef PACKAGE_BUGREPORT
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#undef PACKAGE_NAME
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#undef PACKAGE_STRING
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#undef PACKAGE_TARNAME
|
||||||
|
|
||||||
|
/* Define to the home page for this package. */
|
||||||
|
#undef PACKAGE_URL
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#undef PACKAGE_VERSION
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Version number of package */
|
||||||
|
#undef VERSION
|
2052
config.status
Executable file
2052
config.status
Executable file
File diff suppressed because it is too large
Load diff
137
configure.ac
137
configure.ac
|
@ -1,138 +1,19 @@
|
||||||
AC_INIT([r3], 2.0.0)
|
AC_INIT([r3], 1.0)
|
||||||
AC_PREREQ([2.64])
|
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AM_SILENT_RULES([yes])
|
AM_INIT_AUTOMAKE
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
|
||||||
LT_INIT
|
LT_INIT
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CC_STDC
|
|
||||||
AC_PROG_CXX
|
|
||||||
AC_PROG_INSTALL
|
|
||||||
AC_HEADER_STDBOOL
|
|
||||||
|
|
||||||
# older debian
|
# AM_PATH_CHECK()
|
||||||
AC_PROG_LIBTOOL
|
AM_PATH_CHECK(,[have_check="yes"],
|
||||||
AM_PROG_CC_C_O
|
AC_MSG_WARN([Check not found; cannot run unit tests!])
|
||||||
|
[have_check="no"])
|
||||||
|
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
|
||||||
|
|
||||||
AC_CHECK_HEADERS([stdlib.h string.h sys/time.h])
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
|
||||||
AC_C_INLINE
|
|
||||||
AC_TYPE_SIZE_T
|
|
||||||
|
|
||||||
# Checks for library functions.
|
|
||||||
AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr])
|
|
||||||
PKG_PROG_PKG_CONFIG
|
PKG_PROG_PKG_CONFIG
|
||||||
|
PKG_CHECK_MODULES(DEPS, [libpcre check])
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([gcov],
|
|
||||||
[AS_HELP_STRING([--enable-gcov],
|
|
||||||
[use Gcov to test the test suite])],
|
|
||||||
[],
|
|
||||||
[enable_gcov=no])
|
|
||||||
AM_CONDITIONAL([COND_GCOV],[test '!' "$enable_gcov" = no])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_WITH([malloc],
|
|
||||||
AS_HELP_STRING([--without-malloc], [Use the default malloc]))
|
|
||||||
|
|
||||||
AS_IF([test "x$with_malloc" == "xjemalloc"],
|
|
||||||
[AC_CHECK_HEADERS([jemalloc/jemalloc.h], [
|
|
||||||
found_jemalloc=yes; break
|
|
||||||
])])
|
|
||||||
|
|
||||||
if test "x$found_jemalloc" == "xyes" ; then
|
|
||||||
|
|
||||||
AC_MSG_CHECKING([Checking jemalloc version])
|
|
||||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <jemalloc/jemalloc.h>]],
|
|
||||||
[[
|
|
||||||
#ifdef JEMALLOC_VERSION_MAJOR > 2
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
]])],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
AC_DEFINE_UNQUOTED([USE_JEMALLOC], 1, [Define to 1 if you have the PATH_MAX macro.])
|
|
||||||
have_jemalloc=yes
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
AC_DEFINE_UNQUOTED([USE_JEMALLOC], 0, [Define to 1 if you have the PATH_MAX macro.])
|
|
||||||
have_jemalloc=no
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(USE_JEMALLOC, test "x$have_jemalloc" = "xyes")
|
|
||||||
|
|
||||||
# AM_CONDITIONAL(USE_JEMALLOC, test "x$found_jemalloc" = "xyes")
|
|
||||||
# AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc")
|
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(DEPS, [libpcre2-8])
|
|
||||||
AC_SUBST(DEPS_CFLAGS)
|
AC_SUBST(DEPS_CFLAGS)
|
||||||
AC_SUBST(DEPS_LIBS)
|
AC_SUBST(DEPS_LIBS)
|
||||||
|
AC_CONFIG_FILES(Makefile src/Makefile tests/Makefile)
|
||||||
|
|
||||||
AC_ARG_ENABLE(debug,AS_HELP_STRING([--enable-debug],[enable debug]))
|
|
||||||
if test "x$enable_debug" = "xyes"; then
|
|
||||||
AC_DEFINE(DEBUG, 1, "debug")
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(ENABLE_DEBUG, test "x$enable_debug" = "xyes")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(graphviz, AS_HELP_STRING([--enable-graphviz],[enable graphviz support]))
|
|
||||||
if test "x$enable_graphviz" = "xyes" ; then
|
|
||||||
PKG_CHECK_MODULES(GVC_DEPS, [libgvc])
|
|
||||||
AC_SUBST(GVC_DEPS_CFLAGS)
|
|
||||||
AC_SUBST(GVC_DEPS_LIBS)
|
|
||||||
AC_DEFINE(ENABLE_GRAPHVIZ, 1, "whether graphviz is enable")
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(ENABLE_GRAPHVIZ, test "x$enable_graphviz" = "xyes")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(json, AS_HELP_STRING([--enable-json],[enable json encoder]))
|
|
||||||
if test "x$enable_json" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES(JSONC, [json-c])
|
|
||||||
AC_SUBST(JSONC_CFLAGS)
|
|
||||||
AC_SUBST(JSONC_LIBS)
|
|
||||||
AC_DEFINE(ENABLE_JSON, 1, [enable json])
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(ENABLE_JSON, test "x$enable_json" = "xyes")
|
|
||||||
|
|
||||||
|
|
||||||
# This does not work because configure does not look into /opt/local/include...
|
|
||||||
# AC_CHECK_HEADERS([check.h],[ enable_check=yes ],[ enable_check=unset ])
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(check,
|
|
||||||
AS_HELP_STRING([--enable-check],
|
|
||||||
[enable unit testing]),
|
|
||||||
, enable_check=unset)
|
|
||||||
|
|
||||||
if test "x$enable_check" != "xunset" ; then
|
|
||||||
PKG_CHECK_MODULES(CHECK,[check >= 0.9.4],:,[
|
|
||||||
ifdef([AM_PATH_CHECK],
|
|
||||||
[AM_PATH_CHECK(,[have_check="yes"])],
|
|
||||||
AC_MSG_WARN([Check not found; cannot run unit tests!])
|
|
||||||
[have_check="no"]
|
|
||||||
)]
|
|
||||||
])
|
|
||||||
fi
|
|
||||||
AM_CONDITIONAL(ENABLE_CHECK, test "x$enable_check" = "xyes")
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
|
||||||
r3.pc
|
|
||||||
Makefile
|
|
||||||
src/Makefile
|
|
||||||
tests/Makefile
|
|
||||||
examples/Makefile
|
|
||||||
])
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
7
demo.c
Normal file
7
demo.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
libr3 (1.3.1-1) unstable; urgency=low
|
|
||||||
|
|
||||||
* Initial release using libr3 1.3.1.
|
|
||||||
|
|
||||||
-- Ronmi Ren <ronmi.ren@gmail.com> Thu, 12 Jun 2014 10:54:16 +0800
|
|
|
@ -1 +0,0 @@
|
||||||
9
|
|
|
@ -1,28 +0,0 @@
|
||||||
Source: libr3
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: Ronmi Ren <ronmi.ren@gmail.com>
|
|
||||||
Build-Depends: debhelper (>= 8.0.0), automake, autotools-dev, autoconf,
|
|
||||||
libtool, libpcre2-dev, pkg-config, check
|
|
||||||
Standards-Version: 3.9.4
|
|
||||||
Section: libs
|
|
||||||
Homepage: https://github.com/c9s/r3
|
|
||||||
|
|
||||||
Package: libr3-dev
|
|
||||||
Section: libdevel
|
|
||||||
Architecture: any
|
|
||||||
Depends: libr3 (= ${binary:Version})
|
|
||||||
Description: Development files for libr3
|
|
||||||
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
|
||||||
performance, thus, it's implemented in C. It compiles your R3Route paths into
|
|
||||||
a prefix trie.
|
|
||||||
.
|
|
||||||
This package contains header files for libr3.
|
|
||||||
|
|
||||||
Package: libr3
|
|
||||||
Section: libs
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: High performance URL routing library written in C.
|
|
||||||
libr3 (https://github.com/c9s/r3) is an URL router library with high
|
|
||||||
performance, thus, it's implemented in C. It compiles your R3Route paths into
|
|
||||||
a prefix trie.
|
|
|
@ -1,30 +0,0 @@
|
||||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: libr3
|
|
||||||
Source: https://github.com/c9s/r3
|
|
||||||
|
|
||||||
Files: *
|
|
||||||
Copyright: 2014 yoanlin93@gmail.com
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
Files: debian/*
|
|
||||||
Copyright: 2014 Ronmi Ren <ronmi.ren@gmail.com>
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
License: MIT
|
|
||||||
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.
|
|
|
@ -1 +0,0 @@
|
||||||
README.md
|
|
|
@ -1,2 +0,0 @@
|
||||||
usr/lib
|
|
||||||
usr/include
|
|
|
@ -1,4 +0,0 @@
|
||||||
usr/include/*
|
|
||||||
usr/lib/lib*.a
|
|
||||||
usr/lib/lib*.so
|
|
||||||
usr/lib/pkgconfig/*
|
|
|
@ -1 +0,0 @@
|
||||||
usr/lib
|
|
|
@ -1 +0,0 @@
|
||||||
usr/lib/lib*.so.*
|
|
|
@ -1,12 +0,0 @@
|
||||||
#!/usr/bin/make -f
|
|
||||||
# -*- makefile -*-
|
|
||||||
|
|
||||||
# Uncomment this to turn on verbose mode.
|
|
||||||
#export DH_VERBOSE=1
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@ --with autotools-dev
|
|
||||||
|
|
||||||
override_dh_auto_configure:
|
|
||||||
./autogen.sh
|
|
||||||
./configure --enable-check --prefix=/usr
|
|
|
@ -1 +0,0 @@
|
||||||
3.0 (quilt)
|
|
|
@ -1,7 +0,0 @@
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir)/include -Wall -std=c99
|
|
||||||
AM_CXXFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir)/include -Wall
|
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(top_builddir)/libr3.la
|
|
||||||
|
|
||||||
noinst_PROGRAMS = simple simple_cpp
|
|
||||||
simple_SOURCES = simple.c
|
|
||||||
simple_cpp_SOURCES = simple_cpp.cpp
|
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* bench.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "r3.h"
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
R3Node * n = r3_tree_create(3);
|
|
||||||
|
|
||||||
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/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/foo", NULL);
|
|
||||||
|
|
||||||
char *errstr = NULL;
|
|
||||||
int err = r3_tree_compile(n, &errstr);
|
|
||||||
if(err) {
|
|
||||||
printf("%s\n",errstr);
|
|
||||||
free(errstr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
R3Node *m;
|
|
||||||
|
|
||||||
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
|
||||||
|
|
||||||
match_entry * e = match_entry_createl("/garply/baz/grault", strlen("/garply/baz/grault") );
|
|
||||||
m = r3_tree_match_entry(n , e);
|
|
||||||
if (m) {
|
|
||||||
printf("Matched! %s\n", e->path.base);
|
|
||||||
}
|
|
||||||
match_entry_free(e);
|
|
||||||
r3_tree_free(n);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
|
||||||
#include <r3.hpp>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void example_1() {
|
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
|
||||||
r3::Tree tree(10);
|
|
||||||
|
|
||||||
// insert the R3Route path into the router tree
|
|
||||||
int route_data_1 = 1;
|
|
||||||
tree.insert_path("/bar", &route_data_1); // ignore the length of path
|
|
||||||
|
|
||||||
int route_data_2 = 2;
|
|
||||||
tree.insert_pathl("/zoo", strlen("/zoo"), &route_data_2);
|
|
||||||
int route_data_3 = 3;
|
|
||||||
tree.insert_pathl("/foo/bar", strlen("/foo/bar"), &route_data_3);
|
|
||||||
|
|
||||||
int route_data_4 = 4;
|
|
||||||
tree.insert_pathl("/post/{id}", strlen("/post/{id}") , &route_data_4);
|
|
||||||
|
|
||||||
int route_data_5 = 5;
|
|
||||||
tree.insert_pathl("/user/{id:\\d+}", strlen("/user/{id:\\d+}"),
|
|
||||||
&route_data_5);
|
|
||||||
|
|
||||||
// if you want to catch error, you may call the extended path function for insertion
|
|
||||||
int data = 10;
|
|
||||||
char* errstr;
|
|
||||||
r3::Node ret = tree.insert_pathl("/foo/{name:\\d{5}",
|
|
||||||
strlen("/foo/{name:\\d{5}"), &data, &errstr);
|
|
||||||
if (ret == NULL) {
|
|
||||||
// failed insertion
|
|
||||||
cout << "error: " << errstr << endl;
|
|
||||||
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's compile the tree!
|
|
||||||
int err = tree.compile(&errstr);
|
|
||||||
if (err != 0) {
|
|
||||||
cout << "error: " << errstr << endl;
|
|
||||||
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
|
||||||
}
|
|
||||||
|
|
||||||
// dump the compiled tree
|
|
||||||
tree.dump(0);
|
|
||||||
|
|
||||||
// match a route
|
|
||||||
r3::Node matched_node = tree.matchl("/foo/bar", strlen("/foo/bar"));
|
|
||||||
if (matched_node) {
|
|
||||||
int ret = *static_cast<int*>(matched_node.data());
|
|
||||||
cout << "match path ret: " << ret << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
r3::MatchEntry entry("/foo/bar");
|
|
||||||
matched_node = tree.match_entry(entry);
|
|
||||||
if (matched_node) {
|
|
||||||
int ret = *static_cast<int*>(matched_node.data());
|
|
||||||
cout << "match entry ret: " << ret << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void example_2() {
|
|
||||||
// create a router tree with 10 children capacity (this capacity can grow dynamically)
|
|
||||||
r3::Tree tree(10);
|
|
||||||
|
|
||||||
// insert the R3Route path into the router tree
|
|
||||||
int route_data = 1;
|
|
||||||
tree.insert_routel(METHOD_GET | METHOD_POST, "/blog/post",
|
|
||||||
sizeof("/blog/post") - 1, &route_data);
|
|
||||||
|
|
||||||
char* errstr;
|
|
||||||
int err = tree.compile(&errstr);
|
|
||||||
if (err != 0) {
|
|
||||||
cout << "errstr: " << errstr << endl;
|
|
||||||
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
|
|
||||||
}
|
|
||||||
|
|
||||||
// in your http server handler
|
|
||||||
|
|
||||||
// create the match entry for capturing dynamic variables.
|
|
||||||
r3::MatchEntry entry("/blog/post");
|
|
||||||
entry.set_request_method(METHOD_GET);
|
|
||||||
|
|
||||||
r3::Route matched_route = tree.match_route(entry);
|
|
||||||
if (matched_route) {
|
|
||||||
int ret = *static_cast<int*>(matched_route.data());
|
|
||||||
cout << "match route ret: " << ret << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
example_1();
|
|
||||||
example_2();
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
puts <<END
|
|
||||||
|
|
||||||
/** DO NOT MODIFY THIS FILE, THIS TEST FILE IS AUTO-GENERATED. **/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <check.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "r3.h"
|
|
||||||
#include "r3_slug.h"
|
|
||||||
#include "zmalloc.h"
|
|
||||||
|
|
||||||
START_TEST (test_routes)
|
|
||||||
{
|
|
||||||
node * n = r3_tree_create(10);
|
|
||||||
node * m = NULL;
|
|
||||||
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
||||||
arr = ["foo", "bar", "baz", "qux", "quux", "corge", "grault", "garply"]
|
|
||||||
paths = arr.permutation(3).map { |a| "/#{a.join '/'}" }
|
|
||||||
paths.each_index do |idx|
|
|
||||||
path = paths.fetch(idx)
|
|
||||||
puts " char *data#{idx} = \"#{path}\";"
|
|
||||||
puts " r3_tree_insert_path(n, \"#{path}\", (void*) data#{idx});"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
puts <<END
|
|
||||||
char *err = NULL;
|
|
||||||
r3_tree_compile(n, &err);
|
|
||||||
ck_assert(err == NULL);
|
|
||||||
END
|
|
||||||
|
|
||||||
paths.each_index do |idx|
|
|
||||||
path = paths.fetch(idx)
|
|
||||||
puts " m = r3_tree_match(n, \"#{path}\", NULL);"
|
|
||||||
puts " ck_assert(m != NULL);"
|
|
||||||
puts " ck_assert(m->data == data#{idx});"
|
|
||||||
puts " ck_assert(m->endpoint > 0);"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
puts <<END
|
|
||||||
|
|
||||||
r3_tree_free(n);
|
|
||||||
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Suite* r3_suite (void) {
|
|
||||||
Suite *suite = suite_create("r3 routes tests");
|
|
||||||
TCase *tcase = tcase_create("testcase");
|
|
||||||
tcase_add_test(tcase, test_routes);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
END
|
|
|
@ -2,5 +2,6 @@
|
||||||
arr = ["foo", "bar", "baz", "qux", "quux", "corge", "grault", "garply"]
|
arr = ["foo", "bar", "baz", "qux", "quux", "corge", "grault", "garply"]
|
||||||
paths = arr.permutation(3).map { |a| "/#{a.join '/'}" }
|
paths = arr.permutation(3).map { |a| "/#{a.join '/'}" }
|
||||||
paths.each do |path|
|
paths.each do |path|
|
||||||
puts "r3_tree_insert_path(n, \"#{path}\", NULL, NULL);"
|
# puts "r3_tree_insert_path(n, \"#{path}\", NULL);"
|
||||||
|
puts path
|
||||||
end
|
end
|
||||||
|
|
141
include/memory.h
141
include/memory.h
|
@ -1,141 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
233
include/r3.h
233
include/r3.h
|
@ -1,225 +1,112 @@
|
||||||
/*
|
/*
|
||||||
* r3.h
|
* r3.h
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
#ifndef R3_NODE_H
|
|
||||||
#define R3_NODE_H
|
#ifndef NODE_H
|
||||||
|
#define NODE_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
#include <assert.h>
|
||||||
#include <pcre2.h>
|
#include <pcre.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
|
|
||||||
|
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "r3_slug.h"
|
|
||||||
#include "memory.h"
|
|
||||||
|
|
||||||
|
#define node_edge_pattern(node,i) node->edges[i]->pattern
|
||||||
|
#define node_edge_pattern_len(node,i) node->edges[i]->pattern_len
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct _edge;
|
struct _edge;
|
||||||
struct _node;
|
struct _node;
|
||||||
struct _route;
|
typedef struct _edge edge;
|
||||||
typedef struct _edge R3Edge;
|
typedef struct _node node;
|
||||||
typedef struct _node R3Node;
|
|
||||||
typedef struct _R3Route R3Route;
|
|
||||||
|
|
||||||
struct _node {
|
struct _node {
|
||||||
R3_VECTOR(R3Edge) edges;
|
edge ** edges;
|
||||||
R3_VECTOR(R3Route) routes;
|
int edge_len;
|
||||||
|
int edge_cap;
|
||||||
|
|
||||||
|
|
||||||
|
/** compile-time variables here.... **/
|
||||||
|
|
||||||
|
/* the combined regexp pattern string from pattern_tokens */
|
||||||
char * combined_pattern;
|
char * combined_pattern;
|
||||||
pcre2_code * pcre_pattern;
|
int combined_pattern_len;
|
||||||
pcre2_match_data * match_data;
|
pcre * pcre_pattern;
|
||||||
|
pcre_extra * pcre_extra;
|
||||||
|
int ov_cnt;
|
||||||
|
int * ov;
|
||||||
|
|
||||||
// edges are mostly less than 255
|
/**
|
||||||
unsigned int compare_type; // compare_type: pcre, opcode, string
|
* the pointer of route structure
|
||||||
unsigned int endpoint; // endpoint, should be zero for non-endpoint nodes
|
*/
|
||||||
|
void * route_ptr;
|
||||||
|
|
||||||
// the pointer of R3Route data
|
int endpoint;
|
||||||
void * data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define r3_node_edge_pattern(node,i) node->edges.entries[i].pattern.base
|
|
||||||
#define r3_node_edge_pattern_len(node,i) node->edges.entries[i].pattern.len
|
|
||||||
|
|
||||||
struct _edge {
|
struct _edge {
|
||||||
r3_iovec_t pattern; // 8 bytes
|
char * pattern;
|
||||||
R3Node * child; // 8 bytes
|
int pattern_len;
|
||||||
unsigned int opcode; // 4byte
|
bool has_slug;
|
||||||
unsigned int has_slug; // 4byte
|
node * child;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _R3Route {
|
typedef struct {
|
||||||
r3_iovec_t path;
|
str_array * vars;
|
||||||
R3_VECTOR(r3_iovec_t) slugs;
|
char * path; // dispatched path
|
||||||
int request_method; // can be (GET || POST)
|
int path_len;
|
||||||
r3_iovec_t host; // required host name
|
void * route_ptr; // route ptr
|
||||||
|
} match_entry;
|
||||||
|
|
||||||
void * data;
|
|
||||||
|
|
||||||
r3_iovec_t remote_addr_pattern;
|
node * r3_tree_create(int cap);
|
||||||
|
|
||||||
unsigned int remote_addr_v4;
|
node * r3_node_create();
|
||||||
int remote_addr_v4_bits;
|
|
||||||
|
|
||||||
unsigned int remote_addr_v6[4];
|
void r3_tree_free(node * tree);
|
||||||
int remote_addr_v6_bits[4];
|
|
||||||
|
|
||||||
int http_scheme; // can be (SCHEME_HTTP or SCHEME_HTTPS)
|
void r3_edge_free(edge * edge);
|
||||||
|
|
||||||
};
|
edge * r3_tree_add_child(node * n, char * pat , node *child);
|
||||||
|
|
||||||
typedef struct _R3Entry match_entry;
|
edge * r3_node_find_edge(node * n, char * pat);
|
||||||
struct _R3Entry {
|
|
||||||
str_array vars;
|
|
||||||
r3_iovec_t path; // current path to dispatch
|
|
||||||
int request_method; // current request method
|
|
||||||
|
|
||||||
void * data; // R3Route ptr
|
void r3_tree_append_edge(node *n, edge *child);
|
||||||
|
|
||||||
r3_iovec_t host; // the request host
|
node * r3_tree_insert_path(node *tree, char *route, void * route_ptr);
|
||||||
r3_iovec_t remote_addr;
|
|
||||||
|
|
||||||
int http_scheme;
|
node * r3_tree_insert_pathn(node *tree, char *route, int route_len, void * route_ptr);
|
||||||
};
|
|
||||||
|
|
||||||
|
void r3_tree_dump(node * n, int level);
|
||||||
|
|
||||||
R3Node * r3_tree_create(int cap);
|
edge * r3_node_find_edge_str(node * n, char * str, int str_len);
|
||||||
|
|
||||||
// R3Node * r3_node_create();
|
|
||||||
|
|
||||||
void r3_tree_free(R3Node * tree);
|
void r3_tree_compile(node *n);
|
||||||
|
|
||||||
R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int strdup, R3Node *child);
|
void r3_tree_compile_patterns(node * n);
|
||||||
|
|
||||||
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
|
node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry);
|
||||||
|
|
||||||
R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len);
|
bool r3_node_has_slug_edges(node *n);
|
||||||
|
|
||||||
R3Edge * r3_node_append_edge(R3Node *n);
|
node * r3_tree_lookup(node * tree, char * path, int path_len);
|
||||||
|
|
||||||
R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr);
|
edge * r3_edge_create(char * pattern, int pattern_len, node * child);
|
||||||
|
|
||||||
R3Node * r3_tree_insert_pathl(R3Node *tree, const char *path, int path_len, void * data);
|
void r3_edge_branch(edge *e, int dl);
|
||||||
|
|
||||||
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, 0, 0, data, NULL)
|
void r3_edge_free(edge * edge);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R3Route * r3_tree_insert_routel(R3Node * tree, int method, const char *path, int path_len, void *data);
|
match_entry * match_entry_create(char * path, int path_len);
|
||||||
|
|
||||||
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_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)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The private API to insert a path
|
|
||||||
*/
|
|
||||||
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 R3Node * n, int level);
|
|
||||||
|
|
||||||
|
|
||||||
R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len);
|
|
||||||
|
|
||||||
|
|
||||||
int r3_tree_compile(R3Node *n, char** errstr);
|
|
||||||
|
|
||||||
int r3_tree_compile_patterns(R3Node * n, char** errstr);
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
// R3Node * r3_tree_match_entry(R3Node * n, match_entry * 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 R3Node *n);
|
|
||||||
|
|
||||||
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child);
|
|
||||||
|
|
||||||
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child);
|
|
||||||
|
|
||||||
R3Node * r3_edge_branch(R3Edge *e, int dl);
|
|
||||||
|
|
||||||
void r3_edge_free(R3Edge * edge);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R3Route * r3_route_create(const char * path);
|
|
||||||
|
|
||||||
// R3Route * r3_route_createl(const char * path, int path_len);
|
|
||||||
|
|
||||||
|
|
||||||
R3Route * r3_node_append_route(R3Node *tree, const char * path, int path_len, int method, void *data);
|
|
||||||
|
|
||||||
void r3_route_free(R3Route * route);
|
|
||||||
|
|
||||||
int r3_route_cmp(const R3Route *r1, const match_entry *r2);
|
|
||||||
|
|
||||||
R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry);
|
|
||||||
|
|
||||||
#define r3_route_create(p) r3_route_createl(p, strlen(p))
|
|
||||||
|
|
||||||
|
|
||||||
#define METHOD_GET 2
|
|
||||||
#define METHOD_POST 2<<1
|
|
||||||
#define METHOD_PUT 2<<2
|
|
||||||
#define METHOD_DELETE 2<<3
|
|
||||||
#define METHOD_PATCH 2<<4
|
|
||||||
#define METHOD_HEAD 2<<5
|
|
||||||
#define METHOD_OPTIONS 2<<6
|
|
||||||
|
|
||||||
#define SCHEME_HTTP 2
|
|
||||||
#define SCHEME_HTTPS 2<<1
|
|
||||||
|
|
||||||
|
|
||||||
int r3_pattern_to_opcode(const char * pattern, unsigned int len);
|
|
||||||
|
|
||||||
enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE };
|
|
||||||
|
|
||||||
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH,
|
|
||||||
OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA, OP_GREEDY_ANY};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
match_entry * match_entry_createl(const char * path, int path_len);
|
|
||||||
|
|
||||||
#define match_entry_create(path) match_entry_createl(path,strlen(path))
|
|
||||||
|
|
||||||
void match_entry_free(match_entry * entry);
|
void match_entry_free(match_entry * entry);
|
||||||
|
|
||||||
|
#endif /* !NODE_H */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !R3_NODE_H */
|
|
||||||
|
|
140
include/r3.hpp
140
include/r3.hpp
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* r3.hpp
|
|
||||||
* Copyright (C) 2014 whitglint <whitglint.tw@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#ifndef R3_HPP
|
|
||||||
#define R3_HPP
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include "r3.h"
|
|
||||||
|
|
||||||
namespace r3 {
|
|
||||||
template <typename T>
|
|
||||||
class Base {
|
|
||||||
public:
|
|
||||||
Base(T* p)
|
|
||||||
: p_(p) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void* data() const {
|
|
||||||
return p_->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* get() const {
|
|
||||||
return p_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_null() const {
|
|
||||||
return p_ == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator void*() const {
|
|
||||||
return p_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T* p_;
|
|
||||||
};
|
|
||||||
typedef Base<R3Node> Node;
|
|
||||||
typedef Base<R3Route> Route;
|
|
||||||
|
|
||||||
class MatchEntry : public Base<match_entry> {
|
|
||||||
public:
|
|
||||||
explicit MatchEntry(const char* path)
|
|
||||||
: Base(match_entry_create(path)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
MatchEntry(const char* path, int path_len)
|
|
||||||
: Base(match_entry_createl(path, path_len)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
~MatchEntry() {
|
|
||||||
if (get()) {
|
|
||||||
match_entry_free(get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int request_method() const {
|
|
||||||
return get()->request_method;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_request_method(int request_method) {
|
|
||||||
get()->request_method = request_method;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MatchEntry(const MatchEntry&);
|
|
||||||
MatchEntry& operator =(const MatchEntry&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Tree : public Base<R3Node> {
|
|
||||||
public:
|
|
||||||
explicit Tree(int cap)
|
|
||||||
: Base(r3_tree_create(cap)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
~Tree() {
|
|
||||||
if (get()) {
|
|
||||||
r3_tree_free(get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int compile(char** errstr = NULL) {
|
|
||||||
return r3_tree_compile(get(), errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump(int level) const {
|
|
||||||
r3_tree_dump(get(), level);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node insert_path(const char* path, void* data, char** errstr = NULL) {
|
|
||||||
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), 0, 0,
|
|
||||||
data, errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node insert_pathl(const char* path, int path_len, void* data,
|
|
||||||
char** errstr = NULL) {
|
|
||||||
return r3_tree_insert_pathl_ex(get(), path, path_len, 0, 0, data,
|
|
||||||
errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Route insert_route(int method, const char* path, void* data,
|
|
||||||
char** errstr = NULL) {
|
|
||||||
return r3_tree_insert_routel_ex(get(), method, path,
|
|
||||||
std::strlen(path), data, errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Route insert_routel(int method, const char* path, int path_len,
|
|
||||||
void* data, char** errstr = NULL) {
|
|
||||||
return r3_tree_insert_routel_ex(get(), method, path, path_len, data,
|
|
||||||
errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node match(const char* path, MatchEntry* entry = NULL) const {
|
|
||||||
return r3_tree_match(get(), path,
|
|
||||||
entry != NULL ? entry->get() : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node matchl(const char* path, int path_len, MatchEntry* entry = NULL)
|
|
||||||
const {
|
|
||||||
return r3_tree_matchl(get(), path, path_len,
|
|
||||||
entry != NULL ? entry->get() : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node match_entry(MatchEntry& entry) const {
|
|
||||||
return r3_tree_match_entry(get(), entry.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Route match_route(MatchEntry& entry) const {
|
|
||||||
return r3_tree_match_route(get(), entry.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Tree(const Tree&);
|
|
||||||
Tree& operator =(const Tree&);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // R3_HPP
|
|
36
include/r3_define.h
Normal file
36
include/r3_define.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* r3_define.h
|
||||||
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEFINE_H
|
||||||
|
#define DEFINE_H
|
||||||
|
|
||||||
|
#ifndef bool
|
||||||
|
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 */
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* r3_gvc.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#ifndef R3_GVC_H
|
|
||||||
#define R3_GVC_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <gvc.h>
|
|
||||||
#include "r3.h"
|
|
||||||
|
|
||||||
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt);
|
|
||||||
|
|
||||||
int r3_tree_render(const node * 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_file(const node * tree, const char * format, const char * filename);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !R3_GVC_H */
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* r3_json.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef R3_JSON_H
|
|
||||||
#define R3_JSON_H
|
|
||||||
|
|
||||||
#include <json-c/json.h>
|
|
||||||
#include "r3.h"
|
|
||||||
|
|
||||||
json_object * r3_edge_to_json_object(const R3Edge * e);
|
|
||||||
json_object * r3_node_to_json_object(const R3Node * n);
|
|
||||||
json_object * r3_route_to_json_object(const R3Route * r);
|
|
||||||
|
|
||||||
const char * r3_node_to_json_string_ext(const R3Node * n, int options);
|
|
||||||
const char * r3_node_to_json_pretty_string(const R3Node * n);
|
|
||||||
const char * r3_node_to_json_string(const R3Node * n);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !R3_JSON_H */
|
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* r3_list.h
|
* r3_list.h
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef R3_LIST_H
|
#ifndef LIST_H
|
||||||
#define R3_LIST_H
|
#define LIST_H
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
@ -32,4 +32,4 @@ void list_each_element(list *l, int (*func)(list_item *));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !R3_LIST_H */
|
#endif /* !LIST_H */
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
37
include/r3_str.h
Normal file
37
include/r3_str.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* r3_str.h
|
||||||
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#ifndef STR_H
|
||||||
|
#define STR_H
|
||||||
|
|
||||||
|
#include "r3_define.h"
|
||||||
|
|
||||||
|
int strndiff(char * d1, char * d2, unsigned int n);
|
||||||
|
|
||||||
|
int strdiff(char * d1, char * d2);
|
||||||
|
|
||||||
|
int count_slug(char * p, int len);
|
||||||
|
|
||||||
|
char * compile_slug(char * str, int len);
|
||||||
|
|
||||||
|
bool contains_slug(char * str);
|
||||||
|
|
||||||
|
|
||||||
|
char * ltrim_slash(char* str);
|
||||||
|
|
||||||
|
char** str_split(char* a_str, const char a_delim);
|
||||||
|
|
||||||
|
void str_repeat(char *s, char *c, int len);
|
||||||
|
|
||||||
|
void print_indent(int level);
|
||||||
|
|
||||||
|
char *my_strdup(const char *s);
|
||||||
|
|
||||||
|
char *my_strndup(const char *s, int n);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !STR_H */
|
||||||
|
|
|
@ -1,41 +1,37 @@
|
||||||
/*
|
/*
|
||||||
* str_array.h
|
* str_array.h
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef STR_ARRAY_H
|
#ifndef TOKEN_H
|
||||||
#define STR_ARRAY_H
|
#define TOKEN_H
|
||||||
|
|
||||||
#include "memory.h"
|
#include "r3_define.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 {
|
||||||
R3_VECTOR(r3_iovec_t) slugs;
|
char **tokens;
|
||||||
R3_VECTOR(r3_iovec_t) tokens;
|
int len;
|
||||||
|
int cap;
|
||||||
} str_array;
|
} str_array;
|
||||||
|
|
||||||
bool str_array_append(str_array * l, const char * token, unsigned int len);
|
str_array * str_array_create(int cap);
|
||||||
|
|
||||||
|
bool str_array_is_full(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(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_fetch(t,i) t->tokens[i]
|
||||||
#define str_array_len(t) t->tokens.size
|
#define str_array_len(t) t->len
|
||||||
#define str_array_cap(t) t->tokens.capacity
|
#define str_array_cap(t) t->cap
|
||||||
|
|
||||||
#endif /* !STR_ARRAY_H */
|
#endif /* !TOKEN_H */
|
||||||
|
|
0
m4/.keep
0
m4/.keep
17
main.c
Normal file
17
main.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pcre.h>
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
typedef struct _Node {
|
||||||
|
char ** patterns;
|
||||||
|
} Node;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void compile() {
|
||||||
|
|
||||||
|
}
|
6
main.h
Normal file
6
main.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
void compile();
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"name": "r3",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"repo": "brendanashworth/r3",
|
|
||||||
"description": "high-performance path dispatching library",
|
|
||||||
"keywords": ["path", "dispatch", "performance", "r3", "c9s"],
|
|
||||||
"license": "MIT",
|
|
||||||
"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"]
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _phannot_parser_token {
|
|
||||||
char *token;
|
|
||||||
int opcode;
|
|
||||||
int token_len;
|
|
||||||
int free_flag;
|
|
||||||
} phannot_parser_token;
|
|
||||||
|
|
||||||
typedef struct _phannot_parser_status {
|
|
||||||
zval *ret;
|
|
||||||
phannot_scanner_state *scanner_state;
|
|
||||||
phannot_scanner_token *token;
|
|
||||||
int status;
|
|
||||||
zend_uint syntax_error_len;
|
|
||||||
char *syntax_error;
|
|
||||||
} phannot_parser_status;
|
|
||||||
|
|
||||||
#define PHANNOT_PARSING_OK 1
|
|
||||||
#define PHANNOT_PARSING_FAILED 0
|
|
||||||
|
|
||||||
extern int phannot_parse_annotations(zval *result, zval *view_code, zval *template_path, zval *line TSRMLS_DC);
|
|
||||||
int phannot_internal_parse_annotations(zval **result, zval *view_code, zval *template_path, zval *line, zval **error_msg TSRMLS_DC);
|
|
|
@ -1,441 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
const phannot_token_names phannot_tokens[] =
|
|
||||||
{
|
|
||||||
{ "INTEGER", PHANNOT_T_INTEGER },
|
|
||||||
{ "DOUBLE", PHANNOT_T_DOUBLE },
|
|
||||||
{ "STRING", PHANNOT_T_STRING },
|
|
||||||
{ "IDENTIFIER", PHANNOT_T_IDENTIFIER },
|
|
||||||
{ "@", PHANNOT_T_AT },
|
|
||||||
{ ",", PHANNOT_T_COMMA },
|
|
||||||
{ "=", PHANNOT_T_EQUALS },
|
|
||||||
{ ":", PHANNOT_T_COLON },
|
|
||||||
{ "(", PHANNOT_T_PARENTHESES_OPEN },
|
|
||||||
{ ")", PHANNOT_T_PARENTHESES_CLOSE },
|
|
||||||
{ "{", PHANNOT_T_BRACKET_OPEN },
|
|
||||||
{ "}", PHANNOT_T_BRACKET_CLOSE },
|
|
||||||
{ "[", PHANNOT_T_SBRACKET_OPEN },
|
|
||||||
{ "]", PHANNOT_T_SBRACKET_CLOSE },
|
|
||||||
{ "ARBITRARY TEXT", PHANNOT_T_ARBITRARY_TEXT },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper to alloc memory within the parser
|
|
||||||
*/
|
|
||||||
static void *phannot_wrapper_alloc(size_t bytes){
|
|
||||||
return emalloc(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper to free memory within the parser
|
|
||||||
*/
|
|
||||||
static void phannot_wrapper_free(void *pointer){
|
|
||||||
efree(pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a parser_token to be passed to the parser
|
|
||||||
*/
|
|
||||||
static void phannot_parse_with_token(void* phannot_parser, int opcode, int parsercode, phannot_scanner_token *token, phannot_parser_status *parser_status){
|
|
||||||
|
|
||||||
phannot_parser_token *pToken;
|
|
||||||
|
|
||||||
pToken = emalloc(sizeof(phannot_parser_token));
|
|
||||||
pToken->opcode = opcode;
|
|
||||||
pToken->token = token->value;
|
|
||||||
pToken->token_len = token->len;
|
|
||||||
pToken->free_flag = 1;
|
|
||||||
|
|
||||||
phannot_(phannot_parser, parsercode, pToken, parser_status);
|
|
||||||
|
|
||||||
token->value = NULL;
|
|
||||||
token->len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an error message when it's triggered by the scanner
|
|
||||||
*/
|
|
||||||
static void phannot_scanner_error_msg(phannot_parser_status *parser_status, zval **error_msg TSRMLS_DC){
|
|
||||||
|
|
||||||
int error_length;
|
|
||||||
char *error, *error_part;
|
|
||||||
phannot_scanner_state *state = parser_status->scanner_state;
|
|
||||||
|
|
||||||
ALLOC_INIT_ZVAL(*error_msg);
|
|
||||||
if (state->start) {
|
|
||||||
error_length = 128 + state->start_length + Z_STRLEN_P(state->active_file);
|
|
||||||
error = emalloc(sizeof(char) * error_length);
|
|
||||||
if (state->start_length > 16) {
|
|
||||||
error_part = estrndup(state->start, 16);
|
|
||||||
snprintf(error, 64 + state->start_length, "Scanning error before '%s...' in %s on line %d", error_part, Z_STRVAL_P(state->active_file), state->active_line);
|
|
||||||
efree(error_part);
|
|
||||||
} else {
|
|
||||||
snprintf(error, error_length - 1, "Scanning error before '%s' in %s on line %d", state->start, Z_STRVAL_P(state->active_file), state->active_line);
|
|
||||||
}
|
|
||||||
error[error_length - 1] = '\0';
|
|
||||||
ZVAL_STRING(*error_msg, error, 1);
|
|
||||||
} else {
|
|
||||||
error_length = sizeof(char) * (64 + Z_STRLEN_P(state->active_file));
|
|
||||||
error = emalloc(error_length);
|
|
||||||
snprintf(error, error_length - 1, "Scanning error near to EOF in %s", Z_STRVAL_P(state->active_file));
|
|
||||||
ZVAL_STRING(*error_msg, error, 1);
|
|
||||||
error[error_length - 1] = '\0';
|
|
||||||
}
|
|
||||||
efree(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives the comment tokenizes and parses it
|
|
||||||
*/
|
|
||||||
int phannot_parse_annotations(zval *result, zval *comment, zval *file_path, zval *line TSRMLS_DC){
|
|
||||||
|
|
||||||
zval *error_msg = NULL;
|
|
||||||
|
|
||||||
ZVAL_NULL(result);
|
|
||||||
|
|
||||||
if (Z_TYPE_P(comment) != IS_STRING) {
|
|
||||||
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), ZEND_STRL("Comment must be a string"), 0 TSRMLS_CC);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(phannot_internal_parse_annotations(&result, comment, file_path, line, &error_msg TSRMLS_CC) == FAILURE){
|
|
||||||
if (error_msg != NULL) {
|
|
||||||
// phalcon_throw_exception_string(phalcon_annotations_exception_ce, Z_STRVAL_P(error_msg), Z_STRLEN_P(error_msg), 1 TSRMLS_CC);
|
|
||||||
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), Z_STRVAL_P(error_msg), Z_STRLEN_P(error_msg) , 0 TSRMLS_CC);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// phalcon_throw_exception_string(phalcon_annotations_exception_ce, ZEND_STRL("There was an error parsing annotation"), 1 TSRMLS_CC);
|
|
||||||
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), ZEND_STRL("There was an error parsing annotation") , 0 TSRMLS_CC);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove comment separators from a docblock
|
|
||||||
*/
|
|
||||||
void phannot_remove_comment_separators(zval *return_value, char *comment, int length, int *start_lines) {
|
|
||||||
|
|
||||||
int start_mode = 1, j, i, open_parentheses;
|
|
||||||
smart_str processed_str = {0};
|
|
||||||
char ch;
|
|
||||||
|
|
||||||
(*start_lines) = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
|
|
||||||
ch = comment[i];
|
|
||||||
|
|
||||||
if (start_mode) {
|
|
||||||
if (ch == ' ' || ch == '*' || ch == '/' || ch == '\t' || ch == 11) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
start_mode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '@') {
|
|
||||||
|
|
||||||
smart_str_appendc(&processed_str, ch);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
open_parentheses = 0;
|
|
||||||
for (j = i; j < length; j++) {
|
|
||||||
|
|
||||||
ch = comment[j];
|
|
||||||
|
|
||||||
if (start_mode) {
|
|
||||||
if (ch == ' ' || ch == '*' || ch == '/' || ch == '\t' || ch == 11) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
start_mode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (open_parentheses == 0) {
|
|
||||||
|
|
||||||
if (isalnum(ch) || '_' == ch || '\\' == ch) {
|
|
||||||
smart_str_appendc(&processed_str, ch);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '(') {
|
|
||||||
smart_str_appendc(&processed_str, ch);
|
|
||||||
open_parentheses++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
smart_str_appendc(&processed_str, ch);
|
|
||||||
|
|
||||||
if (ch == '(') {
|
|
||||||
open_parentheses++;
|
|
||||||
} else if (ch == ')') {
|
|
||||||
open_parentheses--;
|
|
||||||
} else if (ch == '\n') {
|
|
||||||
(*start_lines)++;
|
|
||||||
start_mode = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (open_parentheses > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = j;
|
|
||||||
smart_str_appendc(&processed_str, ' ');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '\n') {
|
|
||||||
(*start_lines)++;
|
|
||||||
start_mode = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
smart_str_0(&processed_str);
|
|
||||||
|
|
||||||
if (processed_str.len) {
|
|
||||||
RETURN_STRINGL(processed_str.c, processed_str.len, 0);
|
|
||||||
} else {
|
|
||||||
RETURN_EMPTY_STRING();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a comment returning an intermediate array representation
|
|
||||||
*/
|
|
||||||
int phannot_internal_parse_annotations(zval **result, zval *comment, zval *file_path, zval *line, zval **error_msg TSRMLS_DC) {
|
|
||||||
|
|
||||||
char *error;
|
|
||||||
phannot_scanner_state *state;
|
|
||||||
phannot_scanner_token token;
|
|
||||||
int scanner_status, status = SUCCESS, start_lines, error_length;
|
|
||||||
phannot_parser_status *parser_status = NULL;
|
|
||||||
void* phannot_parser;
|
|
||||||
zval processed_comment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the comment has content
|
|
||||||
*/
|
|
||||||
if (!Z_STRVAL_P(comment)) {
|
|
||||||
ZVAL_BOOL(*result, 0);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Z_STRLEN_P(comment) < 2) {
|
|
||||||
ZVAL_BOOL(*result, 0);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove comment separators
|
|
||||||
*/
|
|
||||||
phannot_remove_comment_separators(&processed_comment, Z_STRVAL_P(comment), Z_STRLEN_P(comment), &start_lines);
|
|
||||||
|
|
||||||
if (Z_STRLEN(processed_comment) < 2) {
|
|
||||||
ZVAL_BOOL(*result, 0);
|
|
||||||
efree(Z_STRVAL(processed_comment));
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the reentrant parser
|
|
||||||
*/
|
|
||||||
phannot_parser = phannot_Alloc(phannot_wrapper_alloc);
|
|
||||||
|
|
||||||
parser_status = emalloc(sizeof(phannot_parser_status));
|
|
||||||
state = emalloc(sizeof(phannot_scanner_state));
|
|
||||||
|
|
||||||
parser_status->status = PHANNOT_PARSING_OK;
|
|
||||||
parser_status->scanner_state = state;
|
|
||||||
parser_status->ret = NULL;
|
|
||||||
parser_status->token = &token;
|
|
||||||
parser_status->syntax_error = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the scanner state
|
|
||||||
*/
|
|
||||||
state->active_token = 0;
|
|
||||||
state->start = Z_STRVAL(processed_comment);
|
|
||||||
state->start_length = 0;
|
|
||||||
state->mode = PHANNOT_MODE_RAW;
|
|
||||||
state->active_file = file_path;
|
|
||||||
|
|
||||||
token.value = NULL;
|
|
||||||
token.len = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Possible start line
|
|
||||||
*/
|
|
||||||
if (Z_TYPE_P(line) == IS_LONG) {
|
|
||||||
state->active_line = Z_LVAL_P(line) - start_lines;
|
|
||||||
} else {
|
|
||||||
state->active_line = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->end = state->start;
|
|
||||||
|
|
||||||
while(0 <= (scanner_status = phannot_get_token(state, &token))) {
|
|
||||||
|
|
||||||
state->active_token = token.opcode;
|
|
||||||
|
|
||||||
state->start_length = (Z_STRVAL(processed_comment) + Z_STRLEN(processed_comment) - state->start);
|
|
||||||
|
|
||||||
switch (token.opcode) {
|
|
||||||
|
|
||||||
case PHANNOT_T_IGNORE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_AT:
|
|
||||||
phannot_(phannot_parser, PHANNOT_AT, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_COMMA:
|
|
||||||
phannot_(phannot_parser, PHANNOT_COMMA, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_EQUALS:
|
|
||||||
phannot_(phannot_parser, PHANNOT_EQUALS, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_COLON:
|
|
||||||
phannot_(phannot_parser, PHANNOT_COLON, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_PARENTHESES_OPEN:
|
|
||||||
phannot_(phannot_parser, PHANNOT_PARENTHESES_OPEN, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_PARENTHESES_CLOSE:
|
|
||||||
phannot_(phannot_parser, PHANNOT_PARENTHESES_CLOSE, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_BRACKET_OPEN:
|
|
||||||
phannot_(phannot_parser, PHANNOT_BRACKET_OPEN, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_BRACKET_CLOSE:
|
|
||||||
phannot_(phannot_parser, PHANNOT_BRACKET_CLOSE, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_SBRACKET_OPEN:
|
|
||||||
phannot_(phannot_parser, PHANNOT_SBRACKET_OPEN, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_SBRACKET_CLOSE:
|
|
||||||
phannot_(phannot_parser, PHANNOT_SBRACKET_CLOSE, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_NULL:
|
|
||||||
phannot_(phannot_parser, PHANNOT_NULL, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_TRUE:
|
|
||||||
phannot_(phannot_parser, PHANNOT_TRUE, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_FALSE:
|
|
||||||
phannot_(phannot_parser, PHANNOT_FALSE, NULL, parser_status);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PHANNOT_T_INTEGER:
|
|
||||||
phannot_parse_with_token(phannot_parser, PHANNOT_T_INTEGER, PHANNOT_INTEGER, &token, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_DOUBLE:
|
|
||||||
phannot_parse_with_token(phannot_parser, PHANNOT_T_DOUBLE, PHANNOT_DOUBLE, &token, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_STRING:
|
|
||||||
phannot_parse_with_token(phannot_parser, PHANNOT_T_STRING, PHANNOT_STRING, &token, parser_status);
|
|
||||||
break;
|
|
||||||
case PHANNOT_T_IDENTIFIER:
|
|
||||||
phannot_parse_with_token(phannot_parser, PHANNOT_T_IDENTIFIER, PHANNOT_IDENTIFIER, &token, parser_status);
|
|
||||||
break;
|
|
||||||
/*case PHANNOT_T_ARBITRARY_TEXT:
|
|
||||||
phannot_parse_with_token(phannot_parser, PHANNOT_T_ARBITRARY_TEXT, PHANNOT_ARBITRARY_TEXT, &token, parser_status);
|
|
||||||
break;*/
|
|
||||||
|
|
||||||
default:
|
|
||||||
parser_status->status = PHANNOT_PARSING_FAILED;
|
|
||||||
if (!*error_msg) {
|
|
||||||
error_length = sizeof(char) * (48 + Z_STRLEN_P(state->active_file));
|
|
||||||
error = emalloc(error_length);
|
|
||||||
snprintf(error, error_length - 1, "Scanner: unknown opcode %d on in %s line %d", token.opcode, Z_STRVAL_P(state->active_file), state->active_line);
|
|
||||||
error[error_length - 1] = '\0';
|
|
||||||
ALLOC_INIT_ZVAL(*error_msg);
|
|
||||||
ZVAL_STRING(*error_msg, error, 1);
|
|
||||||
efree(error);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser_status->status != PHANNOT_PARSING_OK) {
|
|
||||||
status = FAILURE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->end = state->start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != FAILURE) {
|
|
||||||
switch (scanner_status) {
|
|
||||||
case PHANNOT_SCANNER_RETCODE_ERR:
|
|
||||||
case PHANNOT_SCANNER_RETCODE_IMPOSSIBLE:
|
|
||||||
if (!*error_msg) {
|
|
||||||
phannot_scanner_error_msg(parser_status, error_msg TSRMLS_CC);
|
|
||||||
}
|
|
||||||
status = FAILURE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
phannot_(phannot_parser, 0, NULL, parser_status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state->active_token = 0;
|
|
||||||
state->start = NULL;
|
|
||||||
|
|
||||||
if (parser_status->status != PHANNOT_PARSING_OK) {
|
|
||||||
status = FAILURE;
|
|
||||||
if (parser_status->syntax_error) {
|
|
||||||
if (!*error_msg) {
|
|
||||||
ALLOC_INIT_ZVAL(*error_msg);
|
|
||||||
ZVAL_STRING(*error_msg, parser_status->syntax_error, 1);
|
|
||||||
}
|
|
||||||
efree(parser_status->syntax_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
phannot_Free(phannot_parser, phannot_wrapper_free);
|
|
||||||
|
|
||||||
if (status != FAILURE) {
|
|
||||||
if (parser_status->status == PHANNOT_PARSING_OK) {
|
|
||||||
if (parser_status->ret) {
|
|
||||||
ZVAL_ZVAL(*result, parser_status->ret, 0, 0);
|
|
||||||
ZVAL_NULL(parser_status->ret);
|
|
||||||
zval_ptr_dtor(&parser_status->ret);
|
|
||||||
} else {
|
|
||||||
array_init(*result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
efree(Z_STRVAL(processed_comment));
|
|
||||||
|
|
||||||
efree(parser_status);
|
|
||||||
efree(state);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1,687 +0,0 @@
|
||||||
/* Driver template for the LEMON parser generator.
|
|
||||||
** The author disclaims copyright to this source code.
|
|
||||||
*/
|
|
||||||
/* First off, code is include which follows the "include" declaration
|
|
||||||
** in the input file. */
|
|
||||||
#include <stdio.h>
|
|
||||||
%%
|
|
||||||
/* Next is all token values, in a form suitable for use by makeheaders.
|
|
||||||
** This section will be null unless lemon is run with the -m switch.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
** These constants (all generated automatically by the parser generator)
|
|
||||||
** specify the various kinds of tokens (terminals) that the parser
|
|
||||||
** understands.
|
|
||||||
**
|
|
||||||
** Each symbol here is a terminal symbol in the grammar.
|
|
||||||
*/
|
|
||||||
%%
|
|
||||||
/* Make sure the INTERFACE macro is defined.
|
|
||||||
*/
|
|
||||||
#ifndef INTERFACE
|
|
||||||
# define INTERFACE 1
|
|
||||||
#endif
|
|
||||||
/* The next thing included is series of defines which control
|
|
||||||
** various aspects of the generated parser.
|
|
||||||
** YYCODETYPE is the data type used for storing terminal
|
|
||||||
** and nonterminal numbers. "unsigned char" is
|
|
||||||
** used if there are fewer than 250 terminals
|
|
||||||
** and nonterminals. "int" is used otherwise.
|
|
||||||
** YYNOCODE is a number of type YYCODETYPE which corresponds
|
|
||||||
** to no legal terminal or nonterminal number. This
|
|
||||||
** number is used to fill in empty slots of the hash
|
|
||||||
** table.
|
|
||||||
** YYFALLBACK If defined, this indicates that one or more tokens
|
|
||||||
** have fall-back values which should be used if the
|
|
||||||
** original value of the token will not parse.
|
|
||||||
** YYACTIONTYPE is the data type used for storing terminal
|
|
||||||
** and nonterminal numbers. "unsigned char" is
|
|
||||||
** used if there are fewer than 250 rules and
|
|
||||||
** states combined. "int" is used otherwise.
|
|
||||||
** ParseTOKENTYPE is the data type used for minor tokens given
|
|
||||||
** directly to the parser from the tokenizer.
|
|
||||||
** YYMINORTYPE is the data type used for all minor tokens.
|
|
||||||
** This is typically a union of many types, one of
|
|
||||||
** which is ParseTOKENTYPE. The entry in the union
|
|
||||||
** for base tokens is called "yy0".
|
|
||||||
** YYSTACKDEPTH is the maximum depth of the parser's stack.
|
|
||||||
** ParseARG_SDECL A static variable declaration for the %extra_argument
|
|
||||||
** ParseARG_PDECL A parameter declaration for the %extra_argument
|
|
||||||
** ParseARG_STORE Code to store %extra_argument into yypParser
|
|
||||||
** ParseARG_FETCH Code to extract %extra_argument from yypParser
|
|
||||||
** YYNSTATE the combined number of states.
|
|
||||||
** YYNRULE the number of rules in the grammar
|
|
||||||
** YYERRORSYMBOL is the code number of the error symbol. If not
|
|
||||||
** defined, then do no error processing.
|
|
||||||
*/
|
|
||||||
%%
|
|
||||||
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
|
|
||||||
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
|
|
||||||
#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
|
|
||||||
|
|
||||||
/* Next are that tables used to determine what action to take based on the
|
|
||||||
** current state and lookahead token. These tables are used to implement
|
|
||||||
** functions that take a state number and lookahead value and return an
|
|
||||||
** action integer.
|
|
||||||
**
|
|
||||||
** Suppose the action integer is N. Then the action is determined as
|
|
||||||
** follows
|
|
||||||
**
|
|
||||||
** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
|
|
||||||
** token onto the stack and goto state N.
|
|
||||||
**
|
|
||||||
** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
|
|
||||||
**
|
|
||||||
** N == YYNSTATE+YYNRULE A syntax error has occurred.
|
|
||||||
**
|
|
||||||
** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
|
|
||||||
**
|
|
||||||
** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
|
|
||||||
** slots in the yy_action[] table.
|
|
||||||
**
|
|
||||||
** The action table is constructed as a single large table named yy_action[].
|
|
||||||
** Given state S and lookahead X, the action is computed as
|
|
||||||
**
|
|
||||||
** yy_action[ yy_shift_ofst[S] + X ]
|
|
||||||
**
|
|
||||||
** If the index value yy_shift_ofst[S]+X is out of range or if the value
|
|
||||||
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
|
|
||||||
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
|
|
||||||
** and that yy_default[S] should be used instead.
|
|
||||||
**
|
|
||||||
** The formula above is for computing the action when the lookahead is
|
|
||||||
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
|
|
||||||
** a reduce action) then the yy_reduce_ofst[] array is used in place of
|
|
||||||
** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
|
|
||||||
** YY_SHIFT_USE_DFLT.
|
|
||||||
**
|
|
||||||
** The following are the tables generated in this section:
|
|
||||||
**
|
|
||||||
** yy_action[] A single table containing all actions.
|
|
||||||
** yy_lookahead[] A table containing the lookahead for each entry in
|
|
||||||
** yy_action. Used to detect hash collisions.
|
|
||||||
** yy_shift_ofst[] For each state, the offset into yy_action for
|
|
||||||
** shifting terminals.
|
|
||||||
** yy_reduce_ofst[] For each state, the offset into yy_action for
|
|
||||||
** shifting non-terminals after a reduce.
|
|
||||||
** yy_default[] Default action for each state.
|
|
||||||
*/
|
|
||||||
%%
|
|
||||||
#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
|
|
||||||
|
|
||||||
/* The next table maps tokens into fallback tokens. If a construct
|
|
||||||
** like the following:
|
|
||||||
**
|
|
||||||
** %fallback ID X Y Z.
|
|
||||||
**
|
|
||||||
** appears in the grammer, then ID becomes a fallback token for X, Y,
|
|
||||||
** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
|
|
||||||
** but it does not parse, the type of the token is changed to ID and
|
|
||||||
** the parse is retried before an error is thrown.
|
|
||||||
*/
|
|
||||||
#ifdef YYFALLBACK
|
|
||||||
static const YYCODETYPE yyFallback[] = {
|
|
||||||
%%
|
|
||||||
};
|
|
||||||
#endif /* YYFALLBACK */
|
|
||||||
|
|
||||||
/* The following structure represents a single element of the
|
|
||||||
** parser's stack. Information stored includes:
|
|
||||||
**
|
|
||||||
** + The state number for the parser at this level of the stack.
|
|
||||||
**
|
|
||||||
** + The value of the token stored at this level of the stack.
|
|
||||||
** (In other words, the "major" token.)
|
|
||||||
**
|
|
||||||
** + The semantic value stored at this level of the stack. This is
|
|
||||||
** the information used by the action routines in the grammar.
|
|
||||||
** It is sometimes called the "minor" token.
|
|
||||||
*/
|
|
||||||
struct yyStackEntry {
|
|
||||||
int stateno; /* The state-number */
|
|
||||||
int major; /* The major token value. This is the code
|
|
||||||
** number for the token at this stack level */
|
|
||||||
YYMINORTYPE minor; /* The user-supplied minor token value. This
|
|
||||||
** is the value of the token */
|
|
||||||
};
|
|
||||||
typedef struct yyStackEntry yyStackEntry;
|
|
||||||
|
|
||||||
/* The state of the parser is completely contained in an instance of
|
|
||||||
** the following structure */
|
|
||||||
struct yyParser {
|
|
||||||
int yyidx; /* Index of top element in stack */
|
|
||||||
int yyerrcnt; /* Shifts left before out of the error */
|
|
||||||
ParseARG_SDECL /* A place to hold %extra_argument */
|
|
||||||
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
|
|
||||||
};
|
|
||||||
typedef struct yyParser yyParser;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#include <stdio.h>
|
|
||||||
static FILE *yyTraceFILE = 0;
|
|
||||||
static char *yyTracePrompt = 0;
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/*
|
|
||||||
** Turn parser tracing on by giving a stream to which to write the trace
|
|
||||||
** and a prompt to preface each trace message. Tracing is turned off
|
|
||||||
** by making either argument NULL
|
|
||||||
**
|
|
||||||
** Inputs:
|
|
||||||
** <ul>
|
|
||||||
** <li> A FILE* to which trace output should be written.
|
|
||||||
** If NULL, then tracing is turned off.
|
|
||||||
** <li> A prefix string written at the beginning of every
|
|
||||||
** line of trace output. If NULL, then tracing is
|
|
||||||
** turned off.
|
|
||||||
** </ul>
|
|
||||||
**
|
|
||||||
** Outputs:
|
|
||||||
** None.
|
|
||||||
*/
|
|
||||||
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
|
|
||||||
yyTraceFILE = TraceFILE;
|
|
||||||
yyTracePrompt = zTracePrompt;
|
|
||||||
if( yyTraceFILE==0 ) yyTracePrompt = 0;
|
|
||||||
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
|
|
||||||
}
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/* For tracing shifts, the names of all terminals and nonterminals
|
|
||||||
** are required. The following table supplies these names */
|
|
||||||
static const char *yyTokenName[] = {
|
|
||||||
%%
|
|
||||||
};
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/* For tracing reduce actions, the names of all rules are required.
|
|
||||||
*/
|
|
||||||
static const char *yyRuleName[] = {
|
|
||||||
%%
|
|
||||||
};
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This function returns the symbolic name associated with a token
|
|
||||||
** value.
|
|
||||||
*/
|
|
||||||
const char *ParseTokenName(int tokenType){
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
|
|
||||||
return yyTokenName[tokenType];
|
|
||||||
}else{
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return "";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This function allocates a new parser.
|
|
||||||
** The only argument is a pointer to a function which works like
|
|
||||||
** malloc.
|
|
||||||
**
|
|
||||||
** Inputs:
|
|
||||||
** A pointer to the function used to allocate memory.
|
|
||||||
**
|
|
||||||
** Outputs:
|
|
||||||
** A pointer to a parser. This pointer is used in subsequent calls
|
|
||||||
** to Parse and ParseFree.
|
|
||||||
*/
|
|
||||||
void *ParseAlloc(void *(*mallocProc)(size_t)){
|
|
||||||
yyParser *pParser;
|
|
||||||
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
|
|
||||||
if( pParser ){
|
|
||||||
pParser->yyidx = -1;
|
|
||||||
}
|
|
||||||
return pParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The following function deletes the value associated with a
|
|
||||||
** symbol. The symbol can be either a terminal or nonterminal.
|
|
||||||
** "yymajor" is the symbol code, and "yypminor" is a pointer to
|
|
||||||
** the value.
|
|
||||||
*/
|
|
||||||
static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
|
|
||||||
switch( yymajor ){
|
|
||||||
/* Here is inserted the actions which take place when a
|
|
||||||
** terminal or non-terminal is destroyed. This can happen
|
|
||||||
** when the symbol is popped from the stack during a
|
|
||||||
** reduce or during error processing or when a parser is
|
|
||||||
** being destroyed before it is finished parsing.
|
|
||||||
**
|
|
||||||
** Note: during a reduce, the only symbols destroyed are those
|
|
||||||
** which appear on the RHS of the rule, but which are not used
|
|
||||||
** inside the C code.
|
|
||||||
*/
|
|
||||||
%%
|
|
||||||
default: break; /* If no destructor action specified: do nothing */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Pop the parser's stack once.
|
|
||||||
**
|
|
||||||
** If there is a destructor routine associated with the token which
|
|
||||||
** is popped from the stack, then call it.
|
|
||||||
**
|
|
||||||
** Return the major token number for the symbol popped.
|
|
||||||
*/
|
|
||||||
static int yy_pop_parser_stack(yyParser *pParser){
|
|
||||||
YYCODETYPE yymajor;
|
|
||||||
yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
|
|
||||||
|
|
||||||
if( pParser->yyidx<0 ) return 0;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE && pParser->yyidx>=0 ){
|
|
||||||
fprintf(yyTraceFILE,"%sPopping %s\n",
|
|
||||||
yyTracePrompt,
|
|
||||||
yyTokenName[yytos->major]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
yymajor = yytos->major;
|
|
||||||
yy_destructor( yymajor, &yytos->minor);
|
|
||||||
pParser->yyidx--;
|
|
||||||
return yymajor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Deallocate and destroy a parser. Destructors are all called for
|
|
||||||
** all stack elements before shutting the parser down.
|
|
||||||
**
|
|
||||||
** Inputs:
|
|
||||||
** <ul>
|
|
||||||
** <li> A pointer to the parser. This should be a pointer
|
|
||||||
** obtained from ParseAlloc.
|
|
||||||
** <li> A pointer to a function used to reclaim memory obtained
|
|
||||||
** from malloc.
|
|
||||||
** </ul>
|
|
||||||
*/
|
|
||||||
void ParseFree(
|
|
||||||
void *p, /* The parser to be deleted */
|
|
||||||
void (*freeProc)(void*) /* Function used to reclaim memory */
|
|
||||||
){
|
|
||||||
yyParser *pParser = (yyParser*)p;
|
|
||||||
if( pParser==0 ) return;
|
|
||||||
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
|
|
||||||
(*freeProc)((void*)pParser);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find the appropriate action for a parser given the terminal
|
|
||||||
** look-ahead token iLookAhead.
|
|
||||||
**
|
|
||||||
** If the look-ahead token is YYNOCODE, then check to see if the action is
|
|
||||||
** independent of the look-ahead. If it is, return the action, otherwise
|
|
||||||
** return YY_NO_ACTION.
|
|
||||||
*/
|
|
||||||
static int yy_find_shift_action(
|
|
||||||
yyParser *pParser, /* The parser */
|
|
||||||
int iLookAhead /* The look-ahead token */
|
|
||||||
){
|
|
||||||
int i;
|
|
||||||
int stateno = pParser->yystack[pParser->yyidx].stateno;
|
|
||||||
|
|
||||||
/* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
|
|
||||||
i = yy_shift_ofst[stateno];
|
|
||||||
if( i==YY_SHIFT_USE_DFLT ){
|
|
||||||
return yy_default[stateno];
|
|
||||||
}
|
|
||||||
if( iLookAhead==YYNOCODE ){
|
|
||||||
return YY_NO_ACTION;
|
|
||||||
}
|
|
||||||
i += iLookAhead;
|
|
||||||
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
|
|
||||||
#ifdef YYFALLBACK
|
|
||||||
int iFallback; /* Fallback token */
|
|
||||||
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
|
|
||||||
&& (iFallback = yyFallback[iLookAhead])!=0 ){
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
|
|
||||||
yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return yy_find_shift_action(pParser, iFallback);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return yy_default[stateno];
|
|
||||||
}else{
|
|
||||||
return yy_action[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find the appropriate action for a parser given the non-terminal
|
|
||||||
** look-ahead token iLookAhead.
|
|
||||||
**
|
|
||||||
** If the look-ahead token is YYNOCODE, then check to see if the action is
|
|
||||||
** independent of the look-ahead. If it is, return the action, otherwise
|
|
||||||
** return YY_NO_ACTION.
|
|
||||||
*/
|
|
||||||
static int yy_find_reduce_action(
|
|
||||||
yyParser *pParser, /* The parser */
|
|
||||||
int iLookAhead /* The look-ahead token */
|
|
||||||
){
|
|
||||||
int i;
|
|
||||||
int stateno = pParser->yystack[pParser->yyidx].stateno;
|
|
||||||
|
|
||||||
i = yy_reduce_ofst[stateno];
|
|
||||||
if( i==YY_REDUCE_USE_DFLT ){
|
|
||||||
return yy_default[stateno];
|
|
||||||
}
|
|
||||||
if( iLookAhead==YYNOCODE ){
|
|
||||||
return YY_NO_ACTION;
|
|
||||||
}
|
|
||||||
i += iLookAhead;
|
|
||||||
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
|
|
||||||
return yy_default[stateno];
|
|
||||||
}else{
|
|
||||||
return yy_action[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Perform a shift action.
|
|
||||||
*/
|
|
||||||
static void yy_shift(
|
|
||||||
yyParser *yypParser, /* The parser to be shifted */
|
|
||||||
int yyNewState, /* The new state to shift in */
|
|
||||||
int yyMajor, /* The major token to shift in */
|
|
||||||
YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
|
|
||||||
){
|
|
||||||
yyStackEntry *yytos;
|
|
||||||
yypParser->yyidx++;
|
|
||||||
if( yypParser->yyidx>=YYSTACKDEPTH ){
|
|
||||||
ParseARG_FETCH;
|
|
||||||
yypParser->yyidx--;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
|
|
||||||
/* Here code is inserted which will execute if the parser
|
|
||||||
** stack every overflows */
|
|
||||||
%%
|
|
||||||
ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
yytos = &yypParser->yystack[yypParser->yyidx];
|
|
||||||
yytos->stateno = yyNewState;
|
|
||||||
yytos->major = yyMajor;
|
|
||||||
yytos->minor = *yypMinor;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE && yypParser->yyidx>0 ){
|
|
||||||
int i;
|
|
||||||
fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
|
|
||||||
fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
|
|
||||||
for(i=1; i<=yypParser->yyidx; i++)
|
|
||||||
fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
|
|
||||||
fprintf(yyTraceFILE,"\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The following table contains information about every rule that
|
|
||||||
** is used during the reduce.
|
|
||||||
*/
|
|
||||||
static struct {
|
|
||||||
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
|
|
||||||
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
|
|
||||||
} yyRuleInfo[] = {
|
|
||||||
%%
|
|
||||||
};
|
|
||||||
|
|
||||||
static void yy_accept(yyParser*); /* Forward Declaration */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Perform a reduce action and the shift that must immediately
|
|
||||||
** follow the reduce.
|
|
||||||
*/
|
|
||||||
static void yy_reduce(
|
|
||||||
yyParser *yypParser, /* The parser */
|
|
||||||
int yyruleno /* Number of the rule by which to reduce */
|
|
||||||
){
|
|
||||||
int yygoto; /* The next state */
|
|
||||||
int yyact; /* The next action */
|
|
||||||
YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
|
|
||||||
yyStackEntry *yymsp; /* The top of the parser's stack */
|
|
||||||
int yysize; /* Amount to pop the stack */
|
|
||||||
ParseARG_FETCH;
|
|
||||||
yymsp = &yypParser->yystack[yypParser->yyidx];
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE && yyruleno>=0
|
|
||||||
&& yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
|
|
||||||
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
|
|
||||||
yyRuleName[yyruleno]);
|
|
||||||
}
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
switch( yyruleno ){
|
|
||||||
/* Beginning here are the reduction cases. A typical example
|
|
||||||
** follows:
|
|
||||||
** case 0:
|
|
||||||
** #line <lineno> <grammarfile>
|
|
||||||
** { ... } // User supplied code
|
|
||||||
** #line <lineno> <thisfile>
|
|
||||||
** break;
|
|
||||||
*/
|
|
||||||
%%
|
|
||||||
};
|
|
||||||
yygoto = yyRuleInfo[yyruleno].lhs;
|
|
||||||
yysize = yyRuleInfo[yyruleno].nrhs;
|
|
||||||
yypParser->yyidx -= yysize;
|
|
||||||
yyact = yy_find_reduce_action(yypParser,yygoto);
|
|
||||||
if( yyact < YYNSTATE ){
|
|
||||||
yy_shift(yypParser,yyact,yygoto,&yygotominor);
|
|
||||||
}else if( yyact == YYNSTATE + YYNRULE + 1 ){
|
|
||||||
yy_accept(yypParser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The following code executes when the parse fails
|
|
||||||
*/
|
|
||||||
static void yy_parse_failed(
|
|
||||||
yyParser *yypParser /* The parser */
|
|
||||||
){
|
|
||||||
ParseARG_FETCH;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
|
|
||||||
/* Here code is inserted which will be executed whenever the
|
|
||||||
** parser fails */
|
|
||||||
%%
|
|
||||||
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The following code executes when a syntax error first occurs.
|
|
||||||
*/
|
|
||||||
static void yy_syntax_error(
|
|
||||||
yyParser *yypParser, /* The parser */
|
|
||||||
int yymajor, /* The major type of the error token */
|
|
||||||
YYMINORTYPE yyminor /* The minor type of the error token */
|
|
||||||
){
|
|
||||||
ParseARG_FETCH;
|
|
||||||
#define TOKEN (yyminor.yy0)
|
|
||||||
%%
|
|
||||||
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The following is executed when the parser accepts
|
|
||||||
*/
|
|
||||||
static void yy_accept(
|
|
||||||
yyParser *yypParser /* The parser */
|
|
||||||
){
|
|
||||||
ParseARG_FETCH;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
|
|
||||||
/* Here code is inserted which will be executed whenever the
|
|
||||||
** parser accepts */
|
|
||||||
%%
|
|
||||||
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The main parser program.
|
|
||||||
** The first argument is a pointer to a structure obtained from
|
|
||||||
** "ParseAlloc" which describes the current state of the parser.
|
|
||||||
** The second argument is the major token number. The third is
|
|
||||||
** the minor token. The fourth optional argument is whatever the
|
|
||||||
** user wants (and specified in the grammar) and is available for
|
|
||||||
** use by the action routines.
|
|
||||||
**
|
|
||||||
** Inputs:
|
|
||||||
** <ul>
|
|
||||||
** <li> A pointer to the parser (an opaque structure.)
|
|
||||||
** <li> The major token number.
|
|
||||||
** <li> The minor token number.
|
|
||||||
** <li> An option argument of a grammar-specified type.
|
|
||||||
** </ul>
|
|
||||||
**
|
|
||||||
** Outputs:
|
|
||||||
** None.
|
|
||||||
*/
|
|
||||||
void Parse(
|
|
||||||
void *yyp, /* The parser */
|
|
||||||
int yymajor, /* The major token code number */
|
|
||||||
ParseTOKENTYPE yyminor /* The value for the token */
|
|
||||||
ParseARG_PDECL /* Optional %extra_argument parameter */
|
|
||||||
){
|
|
||||||
YYMINORTYPE yyminorunion;
|
|
||||||
int yyact; /* The parser action. */
|
|
||||||
int yyendofinput; /* True if we are at the end of input */
|
|
||||||
int yyerrorhit = 0; /* True if yymajor has invoked an error */
|
|
||||||
yyParser *yypParser; /* The parser */
|
|
||||||
|
|
||||||
/* (re)initialize the parser, if necessary */
|
|
||||||
yypParser = (yyParser*)yyp;
|
|
||||||
if( yypParser->yyidx<0 ){
|
|
||||||
if( yymajor==0 ) return;
|
|
||||||
yypParser->yyidx = 0;
|
|
||||||
yypParser->yyerrcnt = -1;
|
|
||||||
yypParser->yystack[0].stateno = 0;
|
|
||||||
yypParser->yystack[0].major = 0;
|
|
||||||
}
|
|
||||||
yyminorunion.yy0 = yyminor;
|
|
||||||
yyendofinput = (yymajor==0);
|
|
||||||
ParseARG_STORE;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
do{
|
|
||||||
yyact = yy_find_shift_action(yypParser,yymajor);
|
|
||||||
if( yyact<YYNSTATE ){
|
|
||||||
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
|
|
||||||
yypParser->yyerrcnt--;
|
|
||||||
if( yyendofinput && yypParser->yyidx>=0 ){
|
|
||||||
yymajor = 0;
|
|
||||||
}else{
|
|
||||||
yymajor = YYNOCODE;
|
|
||||||
}
|
|
||||||
}else if( yyact < YYNSTATE + YYNRULE ){
|
|
||||||
yy_reduce(yypParser,yyact-YYNSTATE);
|
|
||||||
}else if( yyact == YY_ERROR_ACTION ){
|
|
||||||
int yymx;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef YYERRORSYMBOL
|
|
||||||
/* A syntax error has occurred.
|
|
||||||
** The response to an error depends upon whether or not the
|
|
||||||
** grammar defines an error token "ERROR".
|
|
||||||
**
|
|
||||||
** This is what we do if the grammar does define ERROR:
|
|
||||||
**
|
|
||||||
** * Call the %syntax_error function.
|
|
||||||
**
|
|
||||||
** * Begin popping the stack until we enter a state where
|
|
||||||
** it is legal to shift the error symbol, then shift
|
|
||||||
** the error symbol.
|
|
||||||
**
|
|
||||||
** * Set the error count to three.
|
|
||||||
**
|
|
||||||
** * Begin accepting and shifting new tokens. No new error
|
|
||||||
** processing will occur until three tokens have been
|
|
||||||
** shifted successfully.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
if( yypParser->yyerrcnt<0 ){
|
|
||||||
yy_syntax_error(yypParser,yymajor,yyminorunion);
|
|
||||||
}
|
|
||||||
yymx = yypParser->yystack[yypParser->yyidx].major;
|
|
||||||
if( yymx==YYERRORSYMBOL || yyerrorhit ){
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if( yyTraceFILE ){
|
|
||||||
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
|
|
||||||
yyTracePrompt,yyTokenName[yymajor]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
yy_destructor(yymajor,&yyminorunion);
|
|
||||||
yymajor = YYNOCODE;
|
|
||||||
}else{
|
|
||||||
while(
|
|
||||||
yypParser->yyidx >= 0 &&
|
|
||||||
yymx != YYERRORSYMBOL &&
|
|
||||||
(yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
|
|
||||||
){
|
|
||||||
yy_pop_parser_stack(yypParser);
|
|
||||||
}
|
|
||||||
if( yypParser->yyidx < 0 || yymajor==0 ){
|
|
||||||
yy_destructor(yymajor,&yyminorunion);
|
|
||||||
yy_parse_failed(yypParser);
|
|
||||||
yymajor = YYNOCODE;
|
|
||||||
}else if( yymx!=YYERRORSYMBOL ){
|
|
||||||
YYMINORTYPE u2;
|
|
||||||
u2.YYERRSYMDT = 0;
|
|
||||||
yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yypParser->yyerrcnt = 3;
|
|
||||||
yyerrorhit = 1;
|
|
||||||
#else /* YYERRORSYMBOL is not defined */
|
|
||||||
/* This is what we do if the grammar does not define ERROR:
|
|
||||||
**
|
|
||||||
** * Report an error message, and throw away the input token.
|
|
||||||
**
|
|
||||||
** * If the input token is $, then fail the parse.
|
|
||||||
**
|
|
||||||
** As before, subsequent error messages are suppressed until
|
|
||||||
** three input tokens have been successfully shifted.
|
|
||||||
*/
|
|
||||||
if( yypParser->yyerrcnt<=0 ){
|
|
||||||
yy_syntax_error(yypParser,yymajor,yyminorunion);
|
|
||||||
}
|
|
||||||
yypParser->yyerrcnt = 3;
|
|
||||||
yy_destructor(yymajor,&yyminorunion);
|
|
||||||
if( yyendofinput ){
|
|
||||||
yy_parse_failed(yypParser);
|
|
||||||
}
|
|
||||||
yymajor = YYNOCODE;
|
|
||||||
#endif
|
|
||||||
}else{
|
|
||||||
yy_accept(yypParser);
|
|
||||||
yymajor = YYNOCODE;
|
|
||||||
}
|
|
||||||
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
|
|
||||||
return;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
||||||
#define PHANNOT_COMMA 1
|
|
||||||
#define PHANNOT_AT 2
|
|
||||||
#define PHANNOT_IDENTIFIER 3
|
|
||||||
#define PHANNOT_PARENTHESES_OPEN 4
|
|
||||||
#define PHANNOT_PARENTHESES_CLOSE 5
|
|
||||||
#define PHANNOT_STRING 6
|
|
||||||
#define PHANNOT_EQUALS 7
|
|
||||||
#define PHANNOT_COLON 8
|
|
||||||
#define PHANNOT_INTEGER 9
|
|
||||||
#define PHANNOT_DOUBLE 10
|
|
||||||
#define PHANNOT_NULL 11
|
|
||||||
#define PHANNOT_FALSE 12
|
|
||||||
#define PHANNOT_TRUE 13
|
|
||||||
#define PHANNOT_BRACKET_OPEN 14
|
|
||||||
#define PHANNOT_BRACKET_CLOSE 15
|
|
||||||
#define PHANNOT_SBRACKET_OPEN 16
|
|
||||||
#define PHANNOT_SBRACKET_CLOSE 17
|
|
|
@ -1,335 +0,0 @@
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
%token_prefix PHANNOT_
|
|
||||||
%token_type {phannot_parser_token*}
|
|
||||||
%default_type {zval*}
|
|
||||||
%extra_argument {phannot_parser_status *status}
|
|
||||||
%name phannot_
|
|
||||||
|
|
||||||
%left COMMA .
|
|
||||||
|
|
||||||
%include {
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "php.h"
|
|
||||||
#include "ext/standard/php_smart_str.h"
|
|
||||||
#include "Zend/zend_exceptions.h"
|
|
||||||
|
|
||||||
#include "parser.h"
|
|
||||||
#include "scanner.h"
|
|
||||||
#include "annot.h"
|
|
||||||
|
|
||||||
static zval *phannot_ret_literal_zval(int type, phannot_parser_token *T)
|
|
||||||
{
|
|
||||||
zval *ret;
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(ret);
|
|
||||||
array_init(ret);
|
|
||||||
add_assoc_long(ret, "type", type);
|
|
||||||
if (T) {
|
|
||||||
add_assoc_stringl(ret, "value", T->token, T->token_len, 0);
|
|
||||||
efree(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zval *phannot_ret_array(zval *items)
|
|
||||||
{
|
|
||||||
zval *ret;
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(ret);
|
|
||||||
array_init(ret);
|
|
||||||
add_assoc_long(ret, "type", PHANNOT_T_ARRAY);
|
|
||||||
|
|
||||||
if (items) {
|
|
||||||
add_assoc_zval(ret, "items", items);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zval *phannot_ret_zval_list(zval *list_left, zval *right_list)
|
|
||||||
{
|
|
||||||
|
|
||||||
zval *ret;
|
|
||||||
HashPosition pos;
|
|
||||||
HashTable *list;
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(ret);
|
|
||||||
array_init(ret);
|
|
||||||
|
|
||||||
if (list_left) {
|
|
||||||
|
|
||||||
list = Z_ARRVAL_P(list_left);
|
|
||||||
if (zend_hash_index_exists(list, 0)) {
|
|
||||||
zend_hash_internal_pointer_reset_ex(list, &pos);
|
|
||||||
for (;; zend_hash_move_forward_ex(list, &pos)) {
|
|
||||||
|
|
||||||
zval ** item;
|
|
||||||
|
|
||||||
if (zend_hash_get_current_data_ex(list, (void**) &item, &pos) == FAILURE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Z_ADDREF_PP(item);
|
|
||||||
add_next_index_zval(ret, *item);
|
|
||||||
|
|
||||||
}
|
|
||||||
zval_ptr_dtor(&list_left);
|
|
||||||
} else {
|
|
||||||
add_next_index_zval(ret, list_left);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_next_index_zval(ret, right_list);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zval *phannot_ret_named_item(phannot_parser_token *name, zval *expr)
|
|
||||||
{
|
|
||||||
zval *ret;
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(ret);
|
|
||||||
array_init(ret);
|
|
||||||
add_assoc_zval(ret, "expr", expr);
|
|
||||||
if (name != NULL) {
|
|
||||||
add_assoc_stringl(ret, "name", name->token, name->token_len, 0);
|
|
||||||
efree(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zval *phannot_ret_annotation(phannot_parser_token *name, zval *arguments, phannot_scanner_state *state)
|
|
||||||
{
|
|
||||||
|
|
||||||
zval *ret;
|
|
||||||
|
|
||||||
MAKE_STD_ZVAL(ret);
|
|
||||||
array_init(ret);
|
|
||||||
|
|
||||||
add_assoc_long(ret, "type", PHANNOT_T_ANNOTATION);
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
add_assoc_stringl(ret, "name", name->token, name->token_len, 0);
|
|
||||||
efree(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments) {
|
|
||||||
add_assoc_zval(ret, "arguments", arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
Z_ADDREF_P(state->active_file);
|
|
||||||
add_assoc_zval(ret, "file", state->active_file);
|
|
||||||
add_assoc_long(ret, "line", state->active_line);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
%syntax_error {
|
|
||||||
if (status->scanner_state->start_length) {
|
|
||||||
{
|
|
||||||
|
|
||||||
char *token_name = NULL;
|
|
||||||
const phannot_token_names *tokens = phannot_tokens;
|
|
||||||
int token_found = 0;
|
|
||||||
int active_token = status->scanner_state->active_token;
|
|
||||||
int near_length = status->scanner_state->start_length;
|
|
||||||
|
|
||||||
if (active_token) {
|
|
||||||
do {
|
|
||||||
if (tokens->code == active_token) {
|
|
||||||
token_found = 1;
|
|
||||||
token_name = tokens->name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++tokens;
|
|
||||||
} while (tokens[0].code != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token_name) {
|
|
||||||
token_found = 0;
|
|
||||||
token_name = estrndup("UNKNOWN", strlen("UNKNOWN"));
|
|
||||||
}
|
|
||||||
|
|
||||||
status->syntax_error_len = 128 + strlen(token_name) + Z_STRLEN_P(status->scanner_state->active_file);
|
|
||||||
status->syntax_error = emalloc(sizeof(char) * status->syntax_error_len);
|
|
||||||
|
|
||||||
if (near_length > 0) {
|
|
||||||
if (status->token->value) {
|
|
||||||
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s(%s), near to '%s' in %s on line %d", token_name, status->token->value, status->scanner_state->start, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
|
|
||||||
} else {
|
|
||||||
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s, near to '%s' in %s on line %d", token_name, status->scanner_state->start, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (active_token != PHANNOT_T_IGNORE) {
|
|
||||||
if (status->token->value) {
|
|
||||||
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s(%s), at the end of docblock in %s on line %d", token_name, status->token->value, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
|
|
||||||
} else {
|
|
||||||
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s, at the end of docblock in %s on line %d", token_name, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected EOF, at the end of docblock in %s on line %d", Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
|
|
||||||
}
|
|
||||||
status->syntax_error[status->syntax_error_len-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token_found) {
|
|
||||||
if (token_name) {
|
|
||||||
efree(token_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
status->syntax_error_len = 48 + Z_STRLEN_P(status->scanner_state->active_file);
|
|
||||||
status->syntax_error = emalloc(sizeof(char) * status->syntax_error_len);
|
|
||||||
sprintf(status->syntax_error, "Syntax error, unexpected EOF in %s", Z_STRVAL_P(status->scanner_state->active_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
status->status = PHANNOT_PARSING_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
%token_destructor {
|
|
||||||
if ($$) {
|
|
||||||
if ($$->free_flag) {
|
|
||||||
efree($$->token);
|
|
||||||
}
|
|
||||||
efree($$);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
program ::= annotation_language(Q) . {
|
|
||||||
status->ret = Q;
|
|
||||||
}
|
|
||||||
|
|
||||||
%destructor annotation_language { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
annotation_language(R) ::= annotation_list(L) . {
|
|
||||||
R = L;
|
|
||||||
}
|
|
||||||
|
|
||||||
%destructor annotation_list { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
annotation_list(R) ::= annotation_list(L) annotation(S) . {
|
|
||||||
R = phannot_ret_zval_list(L, S);
|
|
||||||
}
|
|
||||||
|
|
||||||
annotation_list(R) ::= annotation(S) . {
|
|
||||||
R = phannot_ret_zval_list(NULL, S);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%destructor annotation { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
annotation(R) ::= AT IDENTIFIER(I) PARENTHESES_OPEN argument_list(L) PARENTHESES_CLOSE . {
|
|
||||||
R = phannot_ret_annotation(I, L, status->scanner_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
annotation(R) ::= AT IDENTIFIER(I) PARENTHESES_OPEN PARENTHESES_CLOSE . {
|
|
||||||
R = phannot_ret_annotation(I, NULL, status->scanner_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
annotation(R) ::= AT IDENTIFIER(I) . {
|
|
||||||
R = phannot_ret_annotation(I, NULL, status->scanner_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
%destructor argument_list { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
argument_list(R) ::= argument_list(L) COMMA argument_item(I) . {
|
|
||||||
R = phannot_ret_zval_list(L, I);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_list(R) ::= argument_item(I) . {
|
|
||||||
R = phannot_ret_zval_list(NULL, I);
|
|
||||||
}
|
|
||||||
|
|
||||||
%destructor argument_item { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
argument_item(R) ::= expr(E) . {
|
|
||||||
R = phannot_ret_named_item(NULL, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_item(R) ::= STRING(S) EQUALS expr(E) . {
|
|
||||||
R = phannot_ret_named_item(S, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_item(R) ::= STRING(S) COLON expr(E) . {
|
|
||||||
R = phannot_ret_named_item(S, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_item(R) ::= IDENTIFIER(I) EQUALS expr(E) . {
|
|
||||||
R = phannot_ret_named_item(I, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_item(R) ::= IDENTIFIER(I) COLON expr(E) . {
|
|
||||||
R = phannot_ret_named_item(I, E);
|
|
||||||
}
|
|
||||||
|
|
||||||
%destructor expr { zval_ptr_dtor(&$$); }
|
|
||||||
|
|
||||||
expr(R) ::= annotation(S) . {
|
|
||||||
R = S;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= array(A) . {
|
|
||||||
R = A;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= IDENTIFIER(I) . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_IDENTIFIER, I);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= INTEGER(I) . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_INTEGER, I);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= STRING(S) . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_STRING, S);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= DOUBLE(D) . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_DOUBLE, D);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= NULL . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= FALSE . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_FALSE, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
expr(R) ::= TRUE . {
|
|
||||||
R = phannot_ret_literal_zval(PHANNOT_T_TRUE, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
array(R) ::= BRACKET_OPEN argument_list(A) BRACKET_CLOSE . {
|
|
||||||
R = phannot_ret_array(A);
|
|
||||||
}
|
|
||||||
|
|
||||||
array(R) ::= SBRACKET_OPEN argument_list(A) SBRACKET_CLOSE . {
|
|
||||||
R = phannot_ret_array(A);
|
|
||||||
}
|
|
|
@ -1,478 +0,0 @@
|
||||||
State 0:
|
|
||||||
program ::= * annotation_language
|
|
||||||
annotation_language ::= * annotation_list
|
|
||||||
annotation_list ::= * annotation_list annotation
|
|
||||||
annotation_list ::= * annotation
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
program accept
|
|
||||||
annotation_language shift 23
|
|
||||||
annotation_list shift 9
|
|
||||||
annotation shift 24
|
|
||||||
|
|
||||||
State 1:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= AT IDENTIFIER PARENTHESES_OPEN * argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= AT IDENTIFIER PARENTHESES_OPEN * PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_list ::= * argument_list COMMA argument_item
|
|
||||||
argument_list ::= * argument_item
|
|
||||||
argument_item ::= * expr
|
|
||||||
argument_item ::= * STRING EQUALS expr
|
|
||||||
argument_item ::= * STRING COLON expr
|
|
||||||
argument_item ::= * IDENTIFIER EQUALS expr
|
|
||||||
argument_item ::= * IDENTIFIER COLON expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 12
|
|
||||||
PARENTHESES_CLOSE shift 22
|
|
||||||
STRING shift 14
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
argument_list shift 10
|
|
||||||
argument_item shift 17
|
|
||||||
expr shift 28
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 2:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_list ::= * argument_list COMMA argument_item
|
|
||||||
argument_list ::= * argument_item
|
|
||||||
argument_item ::= * expr
|
|
||||||
argument_item ::= * STRING EQUALS expr
|
|
||||||
argument_item ::= * STRING COLON expr
|
|
||||||
argument_item ::= * IDENTIFIER EQUALS expr
|
|
||||||
argument_item ::= * IDENTIFIER COLON expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= BRACKET_OPEN * argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 12
|
|
||||||
STRING shift 14
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
argument_list shift 11
|
|
||||||
argument_item shift 17
|
|
||||||
expr shift 28
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 3:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_list ::= * argument_list COMMA argument_item
|
|
||||||
argument_list ::= * argument_item
|
|
||||||
argument_item ::= * expr
|
|
||||||
argument_item ::= * STRING EQUALS expr
|
|
||||||
argument_item ::= * STRING COLON expr
|
|
||||||
argument_item ::= * IDENTIFIER EQUALS expr
|
|
||||||
argument_item ::= * IDENTIFIER COLON expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
array ::= SBRACKET_OPEN * argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 12
|
|
||||||
STRING shift 14
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
argument_list shift 13
|
|
||||||
argument_item shift 17
|
|
||||||
expr shift 28
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 4:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_list ::= argument_list COMMA * argument_item
|
|
||||||
argument_item ::= * expr
|
|
||||||
argument_item ::= * STRING EQUALS expr
|
|
||||||
argument_item ::= * STRING COLON expr
|
|
||||||
argument_item ::= * IDENTIFIER EQUALS expr
|
|
||||||
argument_item ::= * IDENTIFIER COLON expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 12
|
|
||||||
STRING shift 14
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
argument_item shift 27
|
|
||||||
expr shift 28
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 5:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_item ::= STRING EQUALS * expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 32
|
|
||||||
STRING shift 34
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
expr shift 29
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 6:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_item ::= IDENTIFIER EQUALS * expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 32
|
|
||||||
STRING shift 34
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
expr shift 18
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 7:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_item ::= STRING COLON * expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 32
|
|
||||||
STRING shift 34
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
expr shift 21
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 8:
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
argument_item ::= IDENTIFIER COLON * expr
|
|
||||||
expr ::= * annotation
|
|
||||||
expr ::= * array
|
|
||||||
expr ::= * IDENTIFIER
|
|
||||||
expr ::= * INTEGER
|
|
||||||
expr ::= * STRING
|
|
||||||
expr ::= * DOUBLE
|
|
||||||
expr ::= * NULL
|
|
||||||
expr ::= * FALSE
|
|
||||||
expr ::= * TRUE
|
|
||||||
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
|
|
||||||
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
IDENTIFIER shift 32
|
|
||||||
STRING shift 34
|
|
||||||
INTEGER shift 33
|
|
||||||
DOUBLE shift 35
|
|
||||||
NULL shift 36
|
|
||||||
FALSE shift 37
|
|
||||||
TRUE shift 38
|
|
||||||
BRACKET_OPEN shift 2
|
|
||||||
SBRACKET_OPEN shift 3
|
|
||||||
annotation shift 30
|
|
||||||
expr shift 20
|
|
||||||
array shift 31
|
|
||||||
|
|
||||||
State 9:
|
|
||||||
(1) annotation_language ::= annotation_list *
|
|
||||||
annotation_list ::= annotation_list * annotation
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= * AT IDENTIFIER
|
|
||||||
|
|
||||||
AT shift 16
|
|
||||||
annotation shift 25
|
|
||||||
{default} reduce 1
|
|
||||||
|
|
||||||
State 10:
|
|
||||||
annotation ::= AT IDENTIFIER PARENTHESES_OPEN argument_list * PARENTHESES_CLOSE
|
|
||||||
argument_list ::= argument_list * COMMA argument_item
|
|
||||||
|
|
||||||
COMMA shift 4
|
|
||||||
PARENTHESES_CLOSE shift 26
|
|
||||||
|
|
||||||
State 11:
|
|
||||||
argument_list ::= argument_list * COMMA argument_item
|
|
||||||
array ::= BRACKET_OPEN argument_list * BRACKET_CLOSE
|
|
||||||
|
|
||||||
COMMA shift 4
|
|
||||||
BRACKET_CLOSE shift 39
|
|
||||||
|
|
||||||
State 12:
|
|
||||||
argument_item ::= IDENTIFIER * EQUALS expr
|
|
||||||
argument_item ::= IDENTIFIER * COLON expr
|
|
||||||
(16) expr ::= IDENTIFIER *
|
|
||||||
|
|
||||||
EQUALS shift 6
|
|
||||||
COLON shift 8
|
|
||||||
{default} reduce 16
|
|
||||||
|
|
||||||
State 13:
|
|
||||||
argument_list ::= argument_list * COMMA argument_item
|
|
||||||
array ::= SBRACKET_OPEN argument_list * SBRACKET_CLOSE
|
|
||||||
|
|
||||||
COMMA shift 4
|
|
||||||
SBRACKET_CLOSE shift 19
|
|
||||||
|
|
||||||
State 14:
|
|
||||||
argument_item ::= STRING * EQUALS expr
|
|
||||||
argument_item ::= STRING * COLON expr
|
|
||||||
(18) expr ::= STRING *
|
|
||||||
|
|
||||||
EQUALS shift 5
|
|
||||||
COLON shift 7
|
|
||||||
{default} reduce 18
|
|
||||||
|
|
||||||
State 15:
|
|
||||||
annotation ::= AT IDENTIFIER * PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= AT IDENTIFIER * PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
(6) annotation ::= AT IDENTIFIER *
|
|
||||||
|
|
||||||
PARENTHESES_OPEN shift 1
|
|
||||||
{default} reduce 6
|
|
||||||
|
|
||||||
State 16:
|
|
||||||
annotation ::= AT * IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
|
|
||||||
annotation ::= AT * IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
|
|
||||||
annotation ::= AT * IDENTIFIER
|
|
||||||
|
|
||||||
IDENTIFIER shift 15
|
|
||||||
|
|
||||||
State 17:
|
|
||||||
(8) argument_list ::= argument_item *
|
|
||||||
|
|
||||||
{default} reduce 8
|
|
||||||
|
|
||||||
State 18:
|
|
||||||
(12) argument_item ::= IDENTIFIER EQUALS expr *
|
|
||||||
|
|
||||||
{default} reduce 12
|
|
||||||
|
|
||||||
State 19:
|
|
||||||
(24) array ::= SBRACKET_OPEN argument_list SBRACKET_CLOSE *
|
|
||||||
|
|
||||||
{default} reduce 24
|
|
||||||
|
|
||||||
State 20:
|
|
||||||
(13) argument_item ::= IDENTIFIER COLON expr *
|
|
||||||
|
|
||||||
{default} reduce 13
|
|
||||||
|
|
||||||
State 21:
|
|
||||||
(11) argument_item ::= STRING COLON expr *
|
|
||||||
|
|
||||||
{default} reduce 11
|
|
||||||
|
|
||||||
State 22:
|
|
||||||
(5) annotation ::= AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE *
|
|
||||||
|
|
||||||
{default} reduce 5
|
|
||||||
|
|
||||||
State 23:
|
|
||||||
(0) program ::= annotation_language *
|
|
||||||
|
|
||||||
{default} reduce 0
|
|
||||||
|
|
||||||
State 24:
|
|
||||||
(3) annotation_list ::= annotation *
|
|
||||||
|
|
||||||
{default} reduce 3
|
|
||||||
|
|
||||||
State 25:
|
|
||||||
(2) annotation_list ::= annotation_list annotation *
|
|
||||||
|
|
||||||
{default} reduce 2
|
|
||||||
|
|
||||||
State 26:
|
|
||||||
(4) annotation ::= AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE *
|
|
||||||
|
|
||||||
{default} reduce 4
|
|
||||||
|
|
||||||
State 27:
|
|
||||||
(7) argument_list ::= argument_list COMMA argument_item *
|
|
||||||
|
|
||||||
{default} reduce 7
|
|
||||||
|
|
||||||
State 28:
|
|
||||||
(9) argument_item ::= expr *
|
|
||||||
|
|
||||||
{default} reduce 9
|
|
||||||
|
|
||||||
State 29:
|
|
||||||
(10) argument_item ::= STRING EQUALS expr *
|
|
||||||
|
|
||||||
{default} reduce 10
|
|
||||||
|
|
||||||
State 30:
|
|
||||||
(14) expr ::= annotation *
|
|
||||||
|
|
||||||
{default} reduce 14
|
|
||||||
|
|
||||||
State 31:
|
|
||||||
(15) expr ::= array *
|
|
||||||
|
|
||||||
{default} reduce 15
|
|
||||||
|
|
||||||
State 32:
|
|
||||||
(16) expr ::= IDENTIFIER *
|
|
||||||
|
|
||||||
{default} reduce 16
|
|
||||||
|
|
||||||
State 33:
|
|
||||||
(17) expr ::= INTEGER *
|
|
||||||
|
|
||||||
{default} reduce 17
|
|
||||||
|
|
||||||
State 34:
|
|
||||||
(18) expr ::= STRING *
|
|
||||||
|
|
||||||
{default} reduce 18
|
|
||||||
|
|
||||||
State 35:
|
|
||||||
(19) expr ::= DOUBLE *
|
|
||||||
|
|
||||||
{default} reduce 19
|
|
||||||
|
|
||||||
State 36:
|
|
||||||
(20) expr ::= NULL *
|
|
||||||
|
|
||||||
{default} reduce 20
|
|
||||||
|
|
||||||
State 37:
|
|
||||||
(21) expr ::= FALSE *
|
|
||||||
|
|
||||||
{default} reduce 21
|
|
||||||
|
|
||||||
State 38:
|
|
||||||
(22) expr ::= TRUE *
|
|
||||||
|
|
||||||
{default} reduce 22
|
|
||||||
|
|
||||||
State 39:
|
|
||||||
(23) array ::= BRACKET_OPEN argument_list BRACKET_CLOSE *
|
|
||||||
|
|
||||||
{default} reduce 23
|
|
||||||
|
|
|
@ -1,605 +0,0 @@
|
||||||
/* Generated by re2c 0.13.5 on Sun Feb 16 21:59:06 2014 */
|
|
||||||
#line 1 "scanner.re"
|
|
||||||
|
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "php.h"
|
|
||||||
|
|
||||||
#include "scanner.h"
|
|
||||||
|
|
||||||
#define YYCTYPE unsigned char
|
|
||||||
#define YYCURSOR (s->start)
|
|
||||||
#define YYLIMIT (s->end)
|
|
||||||
#define YYMARKER q
|
|
||||||
|
|
||||||
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token) {
|
|
||||||
|
|
||||||
char next, *q = YYCURSOR, *start = YYCURSOR;
|
|
||||||
int status = PHANNOT_SCANNER_RETCODE_IMPOSSIBLE;
|
|
||||||
|
|
||||||
while (PHANNOT_SCANNER_RETCODE_IMPOSSIBLE == status) {
|
|
||||||
|
|
||||||
if (s->mode == PHANNOT_MODE_RAW) {
|
|
||||||
|
|
||||||
if (*YYCURSOR == '\n') {
|
|
||||||
s->active_line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
next = *(YYCURSOR+1);
|
|
||||||
|
|
||||||
if (*YYCURSOR == '\0' || *YYCURSOR == '@') {
|
|
||||||
if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z')) {
|
|
||||||
s->mode = PHANNOT_MODE_ANNOTATION;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++YYCURSOR;
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
#line 65 "scanner.c"
|
|
||||||
{
|
|
||||||
YYCTYPE yych;
|
|
||||||
unsigned int yyaccept = 0;
|
|
||||||
static const unsigned char yybm[] = {
|
|
||||||
0, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 104, 96, 96, 96, 104, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
104, 96, 32, 96, 96, 96, 96, 64,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
240, 240, 240, 240, 240, 240, 240, 240,
|
|
||||||
240, 240, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 96, 0, 96, 96, 112,
|
|
||||||
96, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 112, 112, 112, 112, 112,
|
|
||||||
112, 112, 112, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
96, 96, 96, 96, 96, 96, 96, 96,
|
|
||||||
};
|
|
||||||
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
switch (yych) {
|
|
||||||
case 0x00: goto yy38;
|
|
||||||
case '\t':
|
|
||||||
case '\r':
|
|
||||||
case ' ': goto yy34;
|
|
||||||
case '\n': goto yy36;
|
|
||||||
case '"': goto yy10;
|
|
||||||
case '\'': goto yy11;
|
|
||||||
case '(': goto yy14;
|
|
||||||
case ')': goto yy16;
|
|
||||||
case ',': goto yy32;
|
|
||||||
case '-': goto yy2;
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9': goto yy4;
|
|
||||||
case ':': goto yy30;
|
|
||||||
case '=': goto yy28;
|
|
||||||
case '@': goto yy26;
|
|
||||||
case 'A':
|
|
||||||
case 'B':
|
|
||||||
case 'C':
|
|
||||||
case 'D':
|
|
||||||
case 'E':
|
|
||||||
case 'G':
|
|
||||||
case 'H':
|
|
||||||
case 'I':
|
|
||||||
case 'J':
|
|
||||||
case 'K':
|
|
||||||
case 'L':
|
|
||||||
case 'M':
|
|
||||||
case 'O':
|
|
||||||
case 'P':
|
|
||||||
case 'Q':
|
|
||||||
case 'R':
|
|
||||||
case 'S':
|
|
||||||
case 'U':
|
|
||||||
case 'V':
|
|
||||||
case 'W':
|
|
||||||
case 'X':
|
|
||||||
case 'Y':
|
|
||||||
case 'Z':
|
|
||||||
case '_':
|
|
||||||
case 'a':
|
|
||||||
case 'b':
|
|
||||||
case 'c':
|
|
||||||
case 'd':
|
|
||||||
case 'e':
|
|
||||||
case 'g':
|
|
||||||
case 'h':
|
|
||||||
case 'i':
|
|
||||||
case 'j':
|
|
||||||
case 'k':
|
|
||||||
case 'l':
|
|
||||||
case 'm':
|
|
||||||
case 'o':
|
|
||||||
case 'p':
|
|
||||||
case 'q':
|
|
||||||
case 'r':
|
|
||||||
case 's':
|
|
||||||
case 'u':
|
|
||||||
case 'v':
|
|
||||||
case 'w':
|
|
||||||
case 'x':
|
|
||||||
case 'y':
|
|
||||||
case 'z': goto yy13;
|
|
||||||
case 'F':
|
|
||||||
case 'f': goto yy8;
|
|
||||||
case 'N':
|
|
||||||
case 'n': goto yy6;
|
|
||||||
case 'T':
|
|
||||||
case 't': goto yy9;
|
|
||||||
case '[': goto yy22;
|
|
||||||
case '\\': goto yy12;
|
|
||||||
case ']': goto yy24;
|
|
||||||
case '{': goto yy18;
|
|
||||||
case '}': goto yy20;
|
|
||||||
default: goto yy40;
|
|
||||||
}
|
|
||||||
yy2:
|
|
||||||
++YYCURSOR;
|
|
||||||
if (yybm[0+(yych = *YYCURSOR)] & 128) {
|
|
||||||
goto yy71;
|
|
||||||
}
|
|
||||||
yy3:
|
|
||||||
#line 182 "scanner.re"
|
|
||||||
{
|
|
||||||
status = PHANNOT_SCANNER_RETCODE_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#line 201 "scanner.c"
|
|
||||||
yy4:
|
|
||||||
yyaccept = 0;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
goto yy72;
|
|
||||||
yy5:
|
|
||||||
#line 66 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_INTEGER;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 215 "scanner.c"
|
|
||||||
yy6:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'U') goto yy66;
|
|
||||||
if (yych == 'u') goto yy66;
|
|
||||||
goto yy44;
|
|
||||||
yy7:
|
|
||||||
#line 108 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_IDENTIFIER;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 231 "scanner.c"
|
|
||||||
yy8:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'A') goto yy61;
|
|
||||||
if (yych == 'a') goto yy61;
|
|
||||||
goto yy44;
|
|
||||||
yy9:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'R') goto yy57;
|
|
||||||
if (yych == 'r') goto yy57;
|
|
||||||
goto yy44;
|
|
||||||
yy10:
|
|
||||||
yyaccept = 2;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych <= 0x00) goto yy3;
|
|
||||||
goto yy55;
|
|
||||||
yy11:
|
|
||||||
yyaccept = 2;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych <= 0x00) goto yy3;
|
|
||||||
goto yy50;
|
|
||||||
yy12:
|
|
||||||
yych = *++YYCURSOR;
|
|
||||||
if (yych <= '^') {
|
|
||||||
if (yych <= '@') goto yy3;
|
|
||||||
if (yych <= 'Z') goto yy43;
|
|
||||||
goto yy3;
|
|
||||||
} else {
|
|
||||||
if (yych == '`') goto yy3;
|
|
||||||
if (yych <= 'z') goto yy43;
|
|
||||||
goto yy3;
|
|
||||||
}
|
|
||||||
yy13:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
goto yy44;
|
|
||||||
yy14:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 116 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_PARENTHESES_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 276 "scanner.c"
|
|
||||||
yy16:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 121 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_PARENTHESES_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 284 "scanner.c"
|
|
||||||
yy18:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 126 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_BRACKET_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 292 "scanner.c"
|
|
||||||
yy20:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 131 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_BRACKET_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 300 "scanner.c"
|
|
||||||
yy22:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 136 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_SBRACKET_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 308 "scanner.c"
|
|
||||||
yy24:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 141 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_SBRACKET_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 316 "scanner.c"
|
|
||||||
yy26:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 146 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_AT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 324 "scanner.c"
|
|
||||||
yy28:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 151 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_EQUALS;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 332 "scanner.c"
|
|
||||||
yy30:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 156 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_COLON;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 340 "scanner.c"
|
|
||||||
yy32:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 161 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_COMMA;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 348 "scanner.c"
|
|
||||||
yy34:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
goto yy42;
|
|
||||||
yy35:
|
|
||||||
#line 166 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 359 "scanner.c"
|
|
||||||
yy36:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 171 "scanner.re"
|
|
||||||
{
|
|
||||||
s->active_line++;
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 368 "scanner.c"
|
|
||||||
yy38:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 177 "scanner.re"
|
|
||||||
{
|
|
||||||
status = PHANNOT_SCANNER_RETCODE_EOF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#line 376 "scanner.c"
|
|
||||||
yy40:
|
|
||||||
yych = *++YYCURSOR;
|
|
||||||
goto yy3;
|
|
||||||
yy41:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
yy42:
|
|
||||||
if (yybm[0+yych] & 8) {
|
|
||||||
goto yy41;
|
|
||||||
}
|
|
||||||
goto yy35;
|
|
||||||
yy43:
|
|
||||||
yyaccept = 1;
|
|
||||||
YYMARKER = ++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
yy44:
|
|
||||||
if (yybm[0+yych] & 16) {
|
|
||||||
goto yy43;
|
|
||||||
}
|
|
||||||
if (yych != '\\') goto yy7;
|
|
||||||
yy45:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
if (yych <= '^') {
|
|
||||||
if (yych <= '@') goto yy46;
|
|
||||||
if (yych <= 'Z') goto yy47;
|
|
||||||
} else {
|
|
||||||
if (yych == '`') goto yy46;
|
|
||||||
if (yych <= 'z') goto yy47;
|
|
||||||
}
|
|
||||||
yy46:
|
|
||||||
YYCURSOR = YYMARKER;
|
|
||||||
if (yyaccept <= 2) {
|
|
||||||
if (yyaccept <= 1) {
|
|
||||||
if (yyaccept <= 0) {
|
|
||||||
goto yy5;
|
|
||||||
} else {
|
|
||||||
goto yy7;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
goto yy3;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yyaccept <= 4) {
|
|
||||||
if (yyaccept <= 3) {
|
|
||||||
goto yy60;
|
|
||||||
} else {
|
|
||||||
goto yy65;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
goto yy69;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy47:
|
|
||||||
yyaccept = 1;
|
|
||||||
YYMARKER = ++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
if (yych <= '[') {
|
|
||||||
if (yych <= '9') {
|
|
||||||
if (yych <= '/') goto yy7;
|
|
||||||
goto yy47;
|
|
||||||
} else {
|
|
||||||
if (yych <= '@') goto yy7;
|
|
||||||
if (yych <= 'Z') goto yy47;
|
|
||||||
goto yy7;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= '_') {
|
|
||||||
if (yych <= '\\') goto yy45;
|
|
||||||
if (yych <= '^') goto yy7;
|
|
||||||
goto yy47;
|
|
||||||
} else {
|
|
||||||
if (yych <= '`') goto yy7;
|
|
||||||
if (yych <= 'z') goto yy47;
|
|
||||||
goto yy7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy49:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
yy50:
|
|
||||||
if (yybm[0+yych] & 32) {
|
|
||||||
goto yy49;
|
|
||||||
}
|
|
||||||
if (yych <= 0x00) goto yy46;
|
|
||||||
if (yych <= '[') goto yy52;
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
if (yych == '\n') goto yy46;
|
|
||||||
goto yy49;
|
|
||||||
yy52:
|
|
||||||
++YYCURSOR;
|
|
||||||
#line 99 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_STRING;
|
|
||||||
token->value = estrndup(q, YYCURSOR - q - 1);
|
|
||||||
token->len = YYCURSOR - q - 1;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 477 "scanner.c"
|
|
||||||
yy54:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
yy55:
|
|
||||||
if (yybm[0+yych] & 64) {
|
|
||||||
goto yy54;
|
|
||||||
}
|
|
||||||
if (yych <= 0x00) goto yy46;
|
|
||||||
if (yych <= '[') goto yy52;
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
if (yych == '\n') goto yy46;
|
|
||||||
goto yy54;
|
|
||||||
yy57:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'U') goto yy58;
|
|
||||||
if (yych != 'u') goto yy44;
|
|
||||||
yy58:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'E') goto yy59;
|
|
||||||
if (yych != 'e') goto yy44;
|
|
||||||
yy59:
|
|
||||||
yyaccept = 3;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yybm[0+yych] & 16) {
|
|
||||||
goto yy43;
|
|
||||||
}
|
|
||||||
if (yych == '\\') goto yy45;
|
|
||||||
yy60:
|
|
||||||
#line 93 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_TRUE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 514 "scanner.c"
|
|
||||||
yy61:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'L') goto yy62;
|
|
||||||
if (yych != 'l') goto yy44;
|
|
||||||
yy62:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'S') goto yy63;
|
|
||||||
if (yych != 's') goto yy44;
|
|
||||||
yy63:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'E') goto yy64;
|
|
||||||
if (yych != 'e') goto yy44;
|
|
||||||
yy64:
|
|
||||||
yyaccept = 4;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yybm[0+yych] & 16) {
|
|
||||||
goto yy43;
|
|
||||||
}
|
|
||||||
if (yych == '\\') goto yy45;
|
|
||||||
yy65:
|
|
||||||
#line 88 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_FALSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 543 "scanner.c"
|
|
||||||
yy66:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'L') goto yy67;
|
|
||||||
if (yych != 'l') goto yy44;
|
|
||||||
yy67:
|
|
||||||
yyaccept = 1;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yych == 'L') goto yy68;
|
|
||||||
if (yych != 'l') goto yy44;
|
|
||||||
yy68:
|
|
||||||
yyaccept = 5;
|
|
||||||
yych = *(YYMARKER = ++YYCURSOR);
|
|
||||||
if (yybm[0+yych] & 16) {
|
|
||||||
goto yy43;
|
|
||||||
}
|
|
||||||
if (yych == '\\') goto yy45;
|
|
||||||
yy69:
|
|
||||||
#line 83 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 567 "scanner.c"
|
|
||||||
yy70:
|
|
||||||
yych = *++YYCURSOR;
|
|
||||||
if (yych <= '/') goto yy46;
|
|
||||||
if (yych <= '9') goto yy73;
|
|
||||||
goto yy46;
|
|
||||||
yy71:
|
|
||||||
yyaccept = 0;
|
|
||||||
YYMARKER = ++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
yy72:
|
|
||||||
if (yybm[0+yych] & 128) {
|
|
||||||
goto yy71;
|
|
||||||
}
|
|
||||||
if (yych == '.') goto yy70;
|
|
||||||
goto yy5;
|
|
||||||
yy73:
|
|
||||||
++YYCURSOR;
|
|
||||||
yych = *YYCURSOR;
|
|
||||||
if (yych <= '/') goto yy75;
|
|
||||||
if (yych <= '9') goto yy73;
|
|
||||||
yy75:
|
|
||||||
#line 75 "scanner.re"
|
|
||||||
{
|
|
||||||
token->opcode = PHANNOT_T_DOUBLE;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#line 597 "scanner.c"
|
|
||||||
}
|
|
||||||
#line 187 "scanner.re"
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define PHANNOT_SCANNER_RETCODE_EOF -1
|
|
||||||
#define PHANNOT_SCANNER_RETCODE_ERR -2
|
|
||||||
#define PHANNOT_SCANNER_RETCODE_IMPOSSIBLE -3
|
|
||||||
|
|
||||||
/** Modes */
|
|
||||||
#define PHANNOT_MODE_RAW 0
|
|
||||||
#define PHANNOT_MODE_ANNOTATION 1
|
|
||||||
|
|
||||||
#define PHANNOT_T_IGNORE 297
|
|
||||||
|
|
||||||
#define PHANNOT_T_DOCBLOCK_ANNOTATION 299
|
|
||||||
#define PHANNOT_T_ANNOTATION 300
|
|
||||||
|
|
||||||
/* Literals & Identifiers */
|
|
||||||
#define PHANNOT_T_INTEGER 301
|
|
||||||
#define PHANNOT_T_DOUBLE 302
|
|
||||||
#define PHANNOT_T_STRING 303
|
|
||||||
#define PHANNOT_T_NULL 304
|
|
||||||
#define PHANNOT_T_FALSE 305
|
|
||||||
#define PHANNOT_T_TRUE 306
|
|
||||||
#define PHANNOT_T_IDENTIFIER 307
|
|
||||||
#define PHANNOT_T_ARRAY 308
|
|
||||||
#define PHANNOT_T_ARBITRARY_TEXT 309
|
|
||||||
|
|
||||||
/* Operators */
|
|
||||||
#define PHANNOT_T_AT '@'
|
|
||||||
#define PHANNOT_T_DOT '.'
|
|
||||||
#define PHANNOT_T_COMMA ','
|
|
||||||
#define PHANNOT_T_EQUALS '='
|
|
||||||
#define PHANNOT_T_COLON ':'
|
|
||||||
#define PHANNOT_T_BRACKET_OPEN '{'
|
|
||||||
#define PHANNOT_T_BRACKET_CLOSE '}'
|
|
||||||
#define PHANNOT_T_SBRACKET_OPEN '['
|
|
||||||
#define PHANNOT_T_SBRACKET_CLOSE ']'
|
|
||||||
#define PHANNOT_T_PARENTHESES_OPEN '('
|
|
||||||
#define PHANNOT_T_PARENTHESES_CLOSE ')'
|
|
||||||
|
|
||||||
/* List of tokens and their names */
|
|
||||||
typedef struct _phannot_token_names {
|
|
||||||
char *name;
|
|
||||||
unsigned int code;
|
|
||||||
} phannot_token_names;
|
|
||||||
|
|
||||||
/* Active token state */
|
|
||||||
typedef struct _phannot_scanner_state {
|
|
||||||
char* start;
|
|
||||||
char* end;
|
|
||||||
int active_token;
|
|
||||||
unsigned int start_length;
|
|
||||||
int mode;
|
|
||||||
unsigned int active_line;
|
|
||||||
zval *active_file;
|
|
||||||
} phannot_scanner_state;
|
|
||||||
|
|
||||||
/* Extra information tokens */
|
|
||||||
typedef struct _phannot_scanner_token {
|
|
||||||
char *value;
|
|
||||||
int opcode;
|
|
||||||
int len;
|
|
||||||
} phannot_scanner_token;
|
|
||||||
|
|
||||||
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token);
|
|
||||||
|
|
||||||
extern const phannot_token_names phannot_tokens[];
|
|
|
@ -1,193 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Phalcon Framework |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| This source file is subject to the New BSD License that is bundled |
|
|
||||||
| with this package in the file docs/LICENSE.txt. |
|
|
||||||
| |
|
|
||||||
| If you did not receive a copy of the license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send an email |
|
|
||||||
| to license@phalconphp.com so we can send you a copy immediately. |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
| Authors: Andres Gutierrez <andres@phalconphp.com> |
|
|
||||||
| Eduar Carvajal <eduar@phalconphp.com> |
|
|
||||||
+------------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "php.h"
|
|
||||||
|
|
||||||
#include "scanner.h"
|
|
||||||
|
|
||||||
#define YYCTYPE unsigned char
|
|
||||||
#define YYCURSOR (s->start)
|
|
||||||
#define YYLIMIT (s->end)
|
|
||||||
#define YYMARKER q
|
|
||||||
|
|
||||||
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token) {
|
|
||||||
|
|
||||||
char next, *q = YYCURSOR, *start = YYCURSOR;
|
|
||||||
int status = PHANNOT_SCANNER_RETCODE_IMPOSSIBLE;
|
|
||||||
|
|
||||||
while (PHANNOT_SCANNER_RETCODE_IMPOSSIBLE == status) {
|
|
||||||
|
|
||||||
if (s->mode == PHANNOT_MODE_RAW) {
|
|
||||||
|
|
||||||
if (*YYCURSOR == '\n') {
|
|
||||||
s->active_line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
next = *(YYCURSOR+1);
|
|
||||||
|
|
||||||
if (*YYCURSOR == '\0' || *YYCURSOR == '@') {
|
|
||||||
if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z')) {
|
|
||||||
s->mode = PHANNOT_MODE_ANNOTATION;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++YYCURSOR;
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/*!re2c
|
|
||||||
re2c:indent:top = 2;
|
|
||||||
re2c:yyfill:enable = 0;
|
|
||||||
|
|
||||||
INTEGER = [\-]?[0-9]+;
|
|
||||||
INTEGER {
|
|
||||||
token->opcode = PHANNOT_T_INTEGER;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DOUBLE = ([\-]?[0-9]+[\.][0-9]+);
|
|
||||||
DOUBLE {
|
|
||||||
token->opcode = PHANNOT_T_DOUBLE;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
'null' {
|
|
||||||
token->opcode = PHANNOT_T_NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
'false' {
|
|
||||||
token->opcode = PHANNOT_T_FALSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
'true' {
|
|
||||||
token->opcode = PHANNOT_T_TRUE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
STRING = (["] ([\\]["]|[\\].|[\001-\377]\[\\"])* ["])|(['] ([\\][']|[\\].|[\001-\377]\[\\'])* [']);
|
|
||||||
STRING {
|
|
||||||
token->opcode = PHANNOT_T_STRING;
|
|
||||||
token->value = estrndup(q, YYCURSOR - q - 1);
|
|
||||||
token->len = YYCURSOR - q - 1;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDENTIFIER = ('\x5C'?[a-zA-Z_]([a-zA-Z0-9_]*)('\x5C'[a-zA-Z_]([a-zA-Z0-9_]*))*);
|
|
||||||
IDENTIFIER {
|
|
||||||
token->opcode = PHANNOT_T_IDENTIFIER;
|
|
||||||
token->value = estrndup(start, YYCURSOR - start);
|
|
||||||
token->len = YYCURSOR - start;
|
|
||||||
q = YYCURSOR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"(" {
|
|
||||||
token->opcode = PHANNOT_T_PARENTHESES_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
")" {
|
|
||||||
token->opcode = PHANNOT_T_PARENTHESES_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"{" {
|
|
||||||
token->opcode = PHANNOT_T_BRACKET_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"}" {
|
|
||||||
token->opcode = PHANNOT_T_BRACKET_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"[" {
|
|
||||||
token->opcode = PHANNOT_T_SBRACKET_OPEN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"]" {
|
|
||||||
token->opcode = PHANNOT_T_SBRACKET_CLOSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"@" {
|
|
||||||
token->opcode = PHANNOT_T_AT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"=" {
|
|
||||||
token->opcode = PHANNOT_T_EQUALS;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
":" {
|
|
||||||
token->opcode = PHANNOT_T_COLON;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"," {
|
|
||||||
token->opcode = PHANNOT_T_COMMA;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[ \t\r]+ {
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[\n] {
|
|
||||||
s->active_line++;
|
|
||||||
token->opcode = PHANNOT_T_IGNORE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
"\000" {
|
|
||||||
status = PHANNOT_SCANNER_RETCODE_EOF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
[^] {
|
|
||||||
status = PHANNOT_SCANNER_RETCODE_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
dnl config.m4 for extension r3
|
|
||||||
|
|
||||||
PHP_ARG_WITH(r3, for r3 support,
|
|
||||||
[ --with-r3 Include r3 support])
|
|
||||||
|
|
||||||
dnl PHP_ARG_ENABLE(r3, whether to enable r3 support,
|
|
||||||
dnl Make sure that the comment is aligned:
|
|
||||||
dnl [ --enable-r3 Enable r3 support])
|
|
||||||
|
|
||||||
if test "$PHP_R3" != "no"; then
|
|
||||||
SEARCH_PATH="/usr/local /usr"
|
|
||||||
SEARCH_FOR="/include/r3/r3.h"
|
|
||||||
if test -r $PHP_R3/$SEARCH_FOR; then
|
|
||||||
R3_DIR=$PHP_R3
|
|
||||||
else
|
|
||||||
AC_MSG_CHECKING([for r3 files in default path])
|
|
||||||
for i in $SEARCH_PATH ; do
|
|
||||||
if test -r $i/$SEARCH_FOR; then
|
|
||||||
R3_DIR=$i
|
|
||||||
AC_MSG_RESULT(found in $i)
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$R3_DIR"; then
|
|
||||||
AC_MSG_RESULT([not found])
|
|
||||||
AC_MSG_ERROR([Please reinstall the r3 distribution])
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo $R3_DIR
|
|
||||||
dnl # --with-r3 -> add include path
|
|
||||||
PHP_ADD_INCLUDE($R3_DIR/include)
|
|
||||||
|
|
||||||
LIBNAME=r3
|
|
||||||
LIBSYMBOL=r3_route_create
|
|
||||||
|
|
||||||
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
|
|
||||||
[
|
|
||||||
PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $R3_DIR/lib, R3_SHARED_LIBADD)
|
|
||||||
AC_DEFINE(HAVE_R3LIB,1,[ ])
|
|
||||||
],[
|
|
||||||
AC_MSG_ERROR([wrong r3 lib version or lib not found])
|
|
||||||
],[
|
|
||||||
-L$R3_DIR/lib -lm
|
|
||||||
])
|
|
||||||
|
|
||||||
PHP_SUBST(R3_SHARED_LIBADD)
|
|
||||||
|
|
||||||
PHP_NEW_EXTENSION(r3, [ct_helper.c hash.c php_expandable_mux.c php_r3.c r3_controller.c r3_functions.c r3_mux.c r3_persistent.c], $ext_shared)
|
|
||||||
fi
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include "php_r3.h"
|
#include "php_r3.h"
|
||||||
// #include "ct_helper.h"
|
// #include "ct_helper.h"
|
||||||
#include "r3_functions.h"
|
// #include "r3_functions.h"
|
||||||
// #include "r3_mux.h"
|
// #include "r3_mux.h"
|
||||||
// #include "php_expandable_mux.h"
|
// #include "php_expandable_mux.h"
|
||||||
// #include "r3_controller.h"
|
// #include "r3_controller.h"
|
||||||
|
@ -104,3 +104,33 @@ PHP_MSHUTDOWN_FUNCTION(r3) {
|
||||||
PHP_RINIT_FUNCTION(r3) {
|
PHP_RINIT_FUNCTION(r3) {
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r3_compile(array $routes, string $path);
|
||||||
|
*/
|
||||||
|
PHP_FUNCTION(r3_match)
|
||||||
|
{
|
||||||
|
zval *z_routes;
|
||||||
|
char *path;
|
||||||
|
int path_len;
|
||||||
|
|
||||||
|
/* parse parameters */
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "as",
|
||||||
|
&z_routes,
|
||||||
|
&path, &path_len ) == FAILURE) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
zval *z_route;
|
||||||
|
z_route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
|
||||||
|
if ( z_route != NULL ) {
|
||||||
|
*return_value = *z_route;
|
||||||
|
zval_copy_ctor(return_value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
RETURN_NULL();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,8 @@ zval * call_mux_method(zval * object , char * method_name , int method_name_len,
|
||||||
|
|
||||||
zend_class_entry ** get_pattern_compiler_ce(TSRMLS_D);
|
zend_class_entry ** get_pattern_compiler_ce(TSRMLS_D);
|
||||||
|
|
||||||
*/
|
|
||||||
extern zend_class_entry *ce_r3_exception;
|
extern zend_class_entry *ce_r3_exception;
|
||||||
|
*/
|
||||||
|
|
||||||
extern zend_module_entry r3_module_entry;
|
extern zend_module_entry r3_module_entry;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ void r3_init_exception(TSRMLS_D);
|
||||||
|
|
||||||
void r3_mux_le_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
|
void r3_mux_le_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
|
||||||
|
|
||||||
// PHP_FUNCTION(r3_match);
|
PHP_FUNCTION(r3_match);
|
||||||
|
|
||||||
#define phpext_r3_ptr &r3_module_entry
|
#define phpext_r3_ptr &r3_module_entry
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ vim:fdm=marker:et:sw=4:ts=4:sts=4:
|
||||||
|
|
||||||
// #include "r3_persistent.h"
|
// #include "r3_persistent.h"
|
||||||
// #include "php_expandable_mux.h"
|
// #include "php_expandable_mux.h"
|
||||||
#include "hash.h"
|
// #include "hash.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new_dst = ht_copy_fun_t(NULL, src);
|
* new_dst = ht_copy_fun_t(NULL, src);
|
||||||
|
@ -407,8 +407,8 @@ PHP_FUNCTION(r3_match)
|
||||||
}
|
}
|
||||||
|
|
||||||
zval *z_route;
|
zval *z_route;
|
||||||
z_R3Route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
|
z_route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
|
||||||
if ( z_R3Route != NULL ) {
|
if ( z_route != 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 *R3Route = NULL;
|
zval *route = 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
|
||||||
R3Route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
|
route = 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 ( R3Route ) {
|
if ( route ) {
|
||||||
*return_value = *route;
|
*return_value = *route;
|
||||||
zval_copy_ctor(return_value);
|
zval_copy_ctor(return_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// R3Route not found
|
// route 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 R3Route option is provided
|
// check conditions only when route 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 R3Route zval
|
// Returns compiled route 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_R3Route = NULL; // will be an array
|
zval *z_compiled_route = 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_R3Route == NULL ) {
|
if ( z_compiled_route == 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 R3Route item
|
// zval for route 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_R3Route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
|
zval *z_compiled_route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
|
||||||
|
|
||||||
|
|
||||||
if ( z_compiled_R3Route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
|
if ( z_compiled_route == 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 R3Route and append to mux->routes
|
// create new route 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 R3Route options
|
// Merge the mount options with the route 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_R3Route = NULL;
|
zval **z_route = 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_R3Route ) == SUCCESS ) {
|
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_route ) == 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,"R3Route sort failed.");
|
// php_error(E_ERROR,"route 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_R3Route = NULL;
|
zval *z_return_route = 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_R3Route || Z_TYPE_P(z_return_route) == IS_NULL ) {
|
if ( ! z_return_route || 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 R3Route vars");
|
php_error(E_ERROR, "require route 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 R3Route vars[0]");
|
php_error(E_ERROR, "require route vars[0]");
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +955,7 @@ PHP_METHOD(Mux, dispatch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( z_return_R3Route ) {
|
if ( z_return_route ) {
|
||||||
*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_R3Route = NULL;
|
zval *z_route = 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_R3Route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
|
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);
|
||||||
if ( z_R3Route != NULL ) {
|
if ( z_route != 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 R3Route pattern", 0 TSRMLS_CC);
|
zend_throw_exception(ce_r3_exception, "Can not compile route 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_R3Route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
|
zval *z_compiled_route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
|
||||||
if ( z_compiled_R3Route == NULL ) {
|
if ( z_compiled_route == NULL ) {
|
||||||
zend_throw_exception(ce_r3_exception, "Unable to compile R3Route pattern.", 0 TSRMLS_CC);
|
zend_throw_exception(ce_r3_exception, "Unable to compile route 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 R3Route to our static R3Route hash
|
// if there is no option specified in z_options, we can add the route to our static route 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_R3Route = NULL;
|
zval *id_route = 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);
|
||||||
|
|
11
r3.pc.in
11
r3.pc.in
|
@ -1,11 +0,0 @@
|
||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
includedir=@includedir@/r3
|
|
||||||
libdir=@libdir@
|
|
||||||
|
|
||||||
Name: r3
|
|
||||||
Description: High-performance URL router library
|
|
||||||
Version: @PACKAGE_VERSION@
|
|
||||||
Requires: libpcre2-8
|
|
||||||
Libs: -L${libdir} -lr3
|
|
||||||
CFlags: -I${includedir}
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
i=10
|
|
||||||
while [ $i -gt 0 ] ; do
|
|
||||||
bash tests/bench
|
|
||||||
i=$(($i - 1))
|
|
||||||
done
|
|
|
@ -1,27 +1,17 @@
|
||||||
add_library(r3 STATIC
|
cmake_minimum_required(VERSION 2.8)
|
||||||
edge.c
|
|
||||||
match_entry.c
|
|
||||||
memory.c
|
|
||||||
node.c
|
|
||||||
slug.c
|
|
||||||
str.c
|
|
||||||
token.c)
|
|
||||||
|
|
||||||
target_compile_definitions(r3
|
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||||
PRIVATE
|
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
|
||||||
_GNU_SOURCE)
|
|
||||||
|
|
||||||
target_include_directories(r3
|
set(R3_SRCS node.c str.c list.c token.c edge.c)
|
||||||
PUBLIC
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -pipe -g3 -funroll-loops -O0")
|
||||||
${PCRE2_INCLUDE_DIR}
|
|
||||||
${PROJECT_BINARY_DIR}
|
|
||||||
${PROJECT_SOURCE_DIR}/3rdparty
|
|
||||||
${PROJECT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
target_link_libraries(r3
|
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
||||||
PUBLIC
|
set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
||||||
${PCRE2_LIBRARIES})
|
|
||||||
|
|
||||||
install(
|
# add_library(r3 SHARED ${R3_SRCS})
|
||||||
TARGETS r3
|
add_library(r3 STATIC ${R3_SRCS})
|
||||||
DESTINATION lib)
|
target_link_libraries(r3 ${LIBS})
|
||||||
|
install (TARGETS r3 DESTINATION lib)
|
||||||
|
# target_link_libraries(r3 cblas)
|
||||||
|
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
|
||||||
|
|
|
@ -1,32 +1,5 @@
|
||||||
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
lib_LTLIBRARIES=libr3.la
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS)
|
libr3_la_SOURCES=node.c edge.c list.c str.c token.c
|
||||||
MAYBE_COVERAGE=--coverage
|
libr3_la_LIBADD=$(DEPS_LIBS)
|
||||||
|
AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include
|
||||||
noinst_LTLIBRARIES = libr3core.la
|
|
||||||
# lib_LIBRARIES = libr3.a
|
|
||||||
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c memory.c
|
|
||||||
|
|
||||||
if ENABLE_JSON
|
|
||||||
libr3core_la_SOURCES += json.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
if COND_GCOV
|
|
||||||
# MAYBE_COVERAGE=--coverage --no-inline
|
|
||||||
AM_CFLAGS += $(MAYBE_COVERAGE)
|
|
||||||
endif
|
|
||||||
|
|
||||||
MOSTLYCLEANFILES = *.gcov *.gcda *.gcno
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# libr3_la_LDFLAGS = -export-symbols-regex '^r3_|^match_'
|
|
||||||
|
|
||||||
# libr3_la_LIBADD=$(DEPS_LIBS) $(LIBOBJS) $(ALLOCA)
|
|
||||||
# libr3core_la_LIBADD=$(DEPS_LIBS)
|
|
||||||
# libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
|
|
||||||
|
|
||||||
if ENABLE_GRAPHVIZ
|
|
||||||
libr3core_la_SOURCES += gvc.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
# AM_CFLAGS=$(DEPS_CFLAGS)
|
# AM_CFLAGS=$(DEPS_CFLAGS)
|
||||||
|
|
109
src/edge.c
109
src/edge.c
|
@ -1,88 +1,79 @@
|
||||||
/*
|
/*
|
||||||
* edge.c
|
* edge.c
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* 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 <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
// Jemalloc memory management
|
// Jemalloc memory management
|
||||||
// #include <jemalloc/jemalloc.h>
|
#include <jemalloc/jemalloc.h>
|
||||||
|
|
||||||
|
// PCRE
|
||||||
|
#include <pcre.h>
|
||||||
|
|
||||||
|
// Judy array
|
||||||
|
// #include <Judy.h>
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "r3_define.h"
|
||||||
|
#include "r3_str.h"
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_slug.h"
|
#include "str_array.h"
|
||||||
#include "slug.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child)
|
|
||||||
{
|
|
||||||
e->pattern.base = (char*) pattern;
|
|
||||||
e->pattern.len = (unsigned int)pattern_len;
|
|
||||||
// e->opcode = 0;
|
|
||||||
e->child = child;
|
|
||||||
e->has_slug = r3_path_contains_slug_char(e->pattern.base, e->pattern.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child)
|
|
||||||
// {
|
|
||||||
// R3Edge * e = (R3Edge*) malloc( sizeof(R3Edge) );
|
|
||||||
// CHECK_PTR(e);
|
|
||||||
// e->pattern = (char*) pattern;
|
|
||||||
// e->pattern_len = pattern_len;
|
|
||||||
// e->opcode = 0;
|
|
||||||
// e->child = child;
|
|
||||||
// e->has_slug = r3_path_contains_slug_char(e->pattern);
|
|
||||||
// return e;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* r3_edge_branch splits the edge and append the rest part as the child of the
|
* branch the edge pattern at "dl" offset
|
||||||
* first level child
|
|
||||||
*
|
|
||||||
* branch the edge pattern at "dl" offset,
|
|
||||||
* and insert a dummy child between the edges.
|
|
||||||
*
|
|
||||||
* A -> [EDGE: abcdefg] -> B -> [EDGE:branch1], [EDGE:branch2]
|
|
||||||
* A -> [EDGE: abcd] -> B1 -> [efg] -> B2 (new child with copied data from B)
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
R3Node * r3_edge_branch(R3Edge *e, int dl) {
|
void r3_edge_branch(edge *e, int dl) {
|
||||||
R3Node * new_child;
|
node *c1; // child 1, child 2
|
||||||
R3Edge * new_edge;
|
edge *e1; // edge 1, edge 2
|
||||||
|
char * s1 = e->pattern + dl;
|
||||||
|
int s1_len = 0;
|
||||||
|
|
||||||
// the rest string
|
edge **tmp_edges = e->child->edges;
|
||||||
const char * s1 = e->pattern.base + dl;
|
int tmp_r3_edge_len = e->child->edge_len;
|
||||||
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);
|
c1 = r3_tree_create(3);
|
||||||
|
s1_len = e->pattern_len - dl;
|
||||||
|
e1 = r3_edge_create(my_strndup(s1, s1_len), s1_len, c1);
|
||||||
|
// printf("edge left: %s\n", e1->pattern);
|
||||||
|
|
||||||
new_edge = r3_node_append_edge(new_child);
|
// Migrate the child edges to the new edge we just created.
|
||||||
r3_edge_initl(new_edge, s1, s1_len, e->child);
|
for ( int i = 0 ; i < tmp_r3_edge_len ; i++ ) {
|
||||||
e->child = new_child;
|
r3_tree_append_edge(c1, tmp_edges[i]);
|
||||||
|
e->child->edges[i] = NULL;
|
||||||
|
}
|
||||||
|
e->child->edge_len = 0;
|
||||||
|
e->child->endpoint--;
|
||||||
|
|
||||||
// truncate the original edge pattern
|
info("branched pattern: %s\n", e1->pattern);
|
||||||
e->pattern.len = dl;
|
|
||||||
return new_child;
|
r3_tree_append_edge(e->child, e1);
|
||||||
|
c1->endpoint++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_edge_free(R3Edge * e) {
|
|
||||||
if (e) {
|
edge * r3_edge_create(char * pattern, int pattern_len, node * child) {
|
||||||
if ( e->child ) {
|
edge * e = (edge*) malloc( sizeof(edge) );
|
||||||
r3_tree_free(e->child);
|
e->pattern = pattern;
|
||||||
}
|
e->pattern_len = pattern_len;
|
||||||
// free itself
|
e->child = child;
|
||||||
// free(e);
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r3_edge_free(edge * e) {
|
||||||
|
if (e->pattern) {
|
||||||
|
free(e->pattern);
|
||||||
|
}
|
||||||
|
if ( e->child ) {
|
||||||
|
r3_tree_free(e->child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
117
src/gvc.c
117
src/gvc.c
|
@ -1,117 +0,0 @@
|
||||||
/*
|
|
||||||
* gvz.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
#include <gvc.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "r3.h"
|
|
||||||
#include "r3_gvc.h"
|
|
||||||
|
|
||||||
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) {
|
|
||||||
if (!n)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for ( int i = 0 ; i < n->edges.size ; i++ ) {
|
|
||||||
edge * e = n->edges.entries + i;
|
|
||||||
(*node_cnt)++;
|
|
||||||
|
|
||||||
Agnode_t *agn_child = NULL;
|
|
||||||
Agedge_t *agn_edge = NULL;
|
|
||||||
|
|
||||||
char *nodename = NULL;
|
|
||||||
if ( e && e->child && e->child->combined_pattern ) {
|
|
||||||
int r = asprintf(&nodename,"%s", e->child->combined_pattern);
|
|
||||||
if (r) {};
|
|
||||||
} else {
|
|
||||||
int r = asprintf(&nodename,"#%d", *node_cnt);
|
|
||||||
if (r) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
agn_child = agnode(g, nodename, 1);
|
|
||||||
agn_edge = agedge(g, ag_parent_node, agn_child, 0, 1);
|
|
||||||
agsafeset(agn_edge, "label", e->pattern, "");
|
|
||||||
if (e->child && e->child->endpoint) {
|
|
||||||
agsafeset(agn_child, "shape", "doublecircle", "");
|
|
||||||
}
|
|
||||||
r3_tree_build_ag_nodes(g, agn_child, e->child, node_cnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a tree to tree graph image via graphviz (dot)
|
|
||||||
*/
|
|
||||||
int r3_tree_render(const node * tree, const char *layout, const char * format, FILE *fp)
|
|
||||||
{
|
|
||||||
Agraph_t *g;
|
|
||||||
/* set up a graphviz context - but only once even for multiple graphs */
|
|
||||||
GVC_t *gvc = NULL;
|
|
||||||
gvc = gvContext();
|
|
||||||
/* Create a simple digraph */
|
|
||||||
// g = agopen("g", Agdirected, 0);
|
|
||||||
g = agopen("g", Agundirected, 0);
|
|
||||||
|
|
||||||
// create self node
|
|
||||||
Agnode_t *ag_root = agnode(g, "{root}", 1);
|
|
||||||
int n = 0;
|
|
||||||
r3_tree_build_ag_nodes(g, ag_root, tree, &n);
|
|
||||||
gvLayout(gvc, g, layout);
|
|
||||||
gvRender(gvc, g, format, fp);
|
|
||||||
gvFreeLayout(gvc, g);
|
|
||||||
agclose(g);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a tree to tree graph image via graphviz (dot)
|
|
||||||
*/
|
|
||||||
int r3_tree_render_dot(const node * tree, const char *layout, FILE *fp)
|
|
||||||
{
|
|
||||||
return r3_tree_render(tree, layout, "dot", fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a tree to tree graph image via graphviz (dot)
|
|
||||||
*/
|
|
||||||
int r3_tree_render_file(const node * tree, const char * format, const char * filename)
|
|
||||||
{
|
|
||||||
Agraph_t *g;
|
|
||||||
|
|
||||||
GVC_t *gvc = NULL;
|
|
||||||
gvc = gvContext();
|
|
||||||
/*
|
|
||||||
// set up a graphviz context - but only once even for multiple graphs
|
|
||||||
static GVC_t *gvc;
|
|
||||||
if (!gvc) {
|
|
||||||
gvc = gvContext();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Create a simple digraph */
|
|
||||||
// g = agopen("g", Agdirected, 0);
|
|
||||||
g = agopen("g", Agundirected, 0);
|
|
||||||
|
|
||||||
// create self node
|
|
||||||
Agnode_t *ag_root = agnode(g, "{root}", 1);
|
|
||||||
int n = 0;
|
|
||||||
r3_tree_build_ag_nodes(g, ag_root, tree, &n);
|
|
||||||
|
|
||||||
gvLayout(gvc, g, "dot");
|
|
||||||
gvRenderFilename(gvc, g, format, filename);
|
|
||||||
gvFreeLayout(gvc, g);
|
|
||||||
|
|
||||||
agclose(g);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
97
src/json.c
97
src/json.c
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* json.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
#include <json-c/json.h>
|
|
||||||
#include "r3.h"
|
|
||||||
#include "r3_json.h"
|
|
||||||
|
|
||||||
json_object * r3_route_to_json_object(const R3Route * r) {
|
|
||||||
json_object *obj;
|
|
||||||
|
|
||||||
obj = json_object_new_object();
|
|
||||||
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));
|
|
||||||
|
|
||||||
|
|
||||||
if (r->host) {
|
|
||||||
json_object_object_add(obj, "host", json_object_new_string(r->host.base));
|
|
||||||
}
|
|
||||||
if (r->remote_addr_pattern) {
|
|
||||||
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern.base));
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
json_object * r3_edge_to_json_object(const R3Edge * e) {
|
|
||||||
json_object *obj;
|
|
||||||
|
|
||||||
obj = json_object_new_object();
|
|
||||||
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, "slug", json_object_new_boolean(e->has_slug));
|
|
||||||
|
|
||||||
if (e->child) {
|
|
||||||
json_object *node_obj = r3_node_to_json_object(e->child);
|
|
||||||
json_object_object_add(obj, "child", node_obj);
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
json_object * r3_node_to_json_object(const R3Node * n) {
|
|
||||||
json_object *obj;
|
|
||||||
|
|
||||||
obj = json_object_new_object();
|
|
||||||
|
|
||||||
if (n->combined_pattern) {
|
|
||||||
json_object_object_add(obj, "re", json_object_new_string(n->combined_pattern));
|
|
||||||
}
|
|
||||||
json_object_object_add(obj, "endpoint", json_object_new_int(n->endpoint));
|
|
||||||
json_object_object_add(obj, "compare", json_object_new_int(n->compare_type));
|
|
||||||
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ( n->edge_len > 0 ) {
|
|
||||||
json_object *edges_array = json_object_new_array();
|
|
||||||
json_object_object_add(obj, "edges", edges_array);
|
|
||||||
for (i = 0 ; i < n->edge_len ; i++ ) {
|
|
||||||
json_object *edge_json_obj = r3_edge_to_json_object(n->edges.entries + i);
|
|
||||||
json_object_array_add(edges_array, edge_json_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( n->route_len > 0 ) {
|
|
||||||
json_object *routes_array = json_object_new_array();
|
|
||||||
json_object_object_add(obj, "routes", routes_array);
|
|
||||||
for (i = 0; i < n->route_len; i++ ) {
|
|
||||||
json_object *route_json_obj = r3_route_to_json_object(n->routes.entries + i);
|
|
||||||
json_object_array_add(routes_array, route_json_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char * r3_node_to_json_string_ext(const R3Node * n, int options) {
|
|
||||||
json_object *obj = r3_node_to_json_object(n);
|
|
||||||
return json_object_to_json_string_ext(obj, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * r3_node_to_json_pretty_string(const R3Node * 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * r3_node_to_json_string(const R3Node * n) {
|
|
||||||
json_object *obj = r3_node_to_json_object(n);
|
|
||||||
return json_object_to_json_string(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
153
src/list.c
153
src/list.c
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* list.c Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* list.c
|
||||||
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
@ -8,114 +9,120 @@
|
||||||
|
|
||||||
/* Naive linked list implementation */
|
/* Naive linked list implementation */
|
||||||
|
|
||||||
list *
|
list *
|
||||||
list_create()
|
list_create()
|
||||||
{
|
{
|
||||||
list *l = (list *) malloc(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;
|
||||||
pthread_mutex_init(&(l->mutex), NULL);
|
pthread_mutex_init(&(l->mutex), NULL);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
list_free(l)
|
list_free(l)
|
||||||
list *l;
|
list *l;
|
||||||
{
|
{
|
||||||
if (l) {
|
list_item *li, *tmp;
|
||||||
list_item *li, *tmp;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(l->mutex));
|
pthread_mutex_lock(&(l->mutex));
|
||||||
|
|
||||||
if (l != NULL) {
|
if (l != NULL) {
|
||||||
li = l->head;
|
li = l->head;
|
||||||
while (li != NULL) {
|
while (li != NULL) {
|
||||||
tmp = li->next;
|
tmp = li->next;
|
||||||
li = tmp;
|
free(li);
|
||||||
}
|
li = tmp;
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(l->mutex));
|
|
||||||
pthread_mutex_destroy(&(l->mutex));
|
|
||||||
free(l);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&(l->mutex));
|
||||||
|
pthread_mutex_destroy(&(l->mutex));
|
||||||
|
free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_item * list_add_element(list * l, void * ptr)
|
list_item *
|
||||||
|
list_add_element(l, ptr)
|
||||||
|
list *l;
|
||||||
|
void *ptr;
|
||||||
{
|
{
|
||||||
list_item *li;
|
list_item *li;
|
||||||
|
|
||||||
pthread_mutex_lock(&(l->mutex));
|
pthread_mutex_lock(&(l->mutex));
|
||||||
|
|
||||||
li = (list_item *) malloc(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;
|
||||||
|
|
||||||
if (l->tail == NULL) {
|
if (l->tail == NULL) {
|
||||||
l->head = l->tail = li;
|
l->head = l->tail = li;
|
||||||
} else {
|
}
|
||||||
l->tail = li;
|
else {
|
||||||
}
|
l->tail = li;
|
||||||
l->count++;
|
}
|
||||||
|
l->count++;
|
||||||
|
|
||||||
pthread_mutex_unlock(&(l->mutex));
|
pthread_mutex_unlock(&(l->mutex));
|
||||||
|
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
list_remove_element(l, ptr)
|
list_remove_element(l, ptr)
|
||||||
list *l;
|
list *l;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
list_item *li = l->head;
|
list_item *li = l->head;
|
||||||
|
|
||||||
pthread_mutex_lock(&(l->mutex));
|
pthread_mutex_lock(&(l->mutex));
|
||||||
|
|
||||||
while (li != NULL) {
|
while (li != NULL) {
|
||||||
if (li->value == ptr) {
|
if (li->value == ptr) {
|
||||||
if (li->prev == NULL) {
|
if (li->prev == NULL) {
|
||||||
l->head = li->next;
|
l->head = li->next;
|
||||||
} else {
|
}
|
||||||
li->prev->next = li->next;
|
else {
|
||||||
}
|
li->prev->next = li->next;
|
||||||
|
}
|
||||||
|
|
||||||
if (li->next == NULL) {
|
if (li->next == NULL) {
|
||||||
l->tail = li->prev;
|
l->tail = li->prev;
|
||||||
} else {
|
}
|
||||||
li->next->prev = li->prev;
|
else {
|
||||||
}
|
li->next->prev = li->prev;
|
||||||
l->count--;
|
}
|
||||||
free(li);
|
l->count--;
|
||||||
result = 1;
|
free(li);
|
||||||
break;
|
result = 1;
|
||||||
}
|
break;
|
||||||
li = li->next;
|
|
||||||
}
|
}
|
||||||
|
li = li->next;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&(l->mutex));
|
pthread_mutex_unlock(&(l->mutex));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
list_each_element(l, func)
|
list_each_element(l, func)
|
||||||
list *l;
|
list *l;
|
||||||
int (*func) (list_item *);
|
int (*func)(list_item *);
|
||||||
{
|
{
|
||||||
list_item *li;
|
list_item *li;
|
||||||
|
|
||||||
pthread_mutex_lock(&(l->mutex));
|
pthread_mutex_lock(&(l->mutex));
|
||||||
|
|
||||||
li = l->head;
|
li = l->head;
|
||||||
while (li != NULL) {
|
while (li != NULL) {
|
||||||
if (func(li) == 1) {
|
if (func(li) == 1) {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
li = li->next;
|
|
||||||
}
|
}
|
||||||
|
li = li->next;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&(l->mutex));
|
pthread_mutex_unlock(&(l->mutex));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* match_entry.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "r3.h"
|
|
||||||
|
|
||||||
match_entry * match_entry_createl(const char * path, int path_len) {
|
|
||||||
match_entry * entry = r3_mem_alloc( sizeof(match_entry) );
|
|
||||||
memset(entry, 0, sizeof(*entry));
|
|
||||||
r3_vector_reserve(&entry->vars.tokens, 3);
|
|
||||||
entry->path.base = path;
|
|
||||||
entry->path.len = path_len;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void match_entry_free(match_entry * entry) {
|
|
||||||
assert(entry);
|
|
||||||
free(entry->vars.tokens.entries);
|
|
||||||
free(entry);
|
|
||||||
}
|
|
45
src/memory.c
45
src/memory.c
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
1183
src/node.c
1183
src/node.c
File diff suppressed because it is too large
Load diff
|
@ -1,19 +0,0 @@
|
||||||
#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 */
|
|
191
src/slug.c
191
src/slug.c
|
@ -1,191 +0,0 @@
|
||||||
/*
|
|
||||||
* slug.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "r3.h"
|
|
||||||
#include "r3_slug.h"
|
|
||||||
#include "slug.h"
|
|
||||||
#include "r3_debug.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
r3_slug_t * r3_slug_new(const char * path, int path_len) {
|
|
||||||
r3_slug_t * s = malloc(sizeof(r3_slug_t));
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
s->path = (char*) path;
|
|
||||||
s->path_len = path_len;
|
|
||||||
|
|
||||||
s->begin = NULL;
|
|
||||||
s->end = NULL;
|
|
||||||
s->len = 0;
|
|
||||||
|
|
||||||
s->pattern = NULL;
|
|
||||||
s->pattern_len = 0;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void r3_slug_free(r3_slug_t * s) {
|
|
||||||
free(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return 1 means OK
|
|
||||||
* Return 0 means Empty
|
|
||||||
* Return -1 means Error
|
|
||||||
*/
|
|
||||||
int r3_slug_check(r3_slug_t *s) {
|
|
||||||
// if it's empty
|
|
||||||
if (s->begin == NULL && s->len == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (s->begin && s->begin == s->end && s->len == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the head is defined, we should also have end pointer
|
|
||||||
if (s->begin && s->end == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char * r3_slug_to_str(const r3_slug_t *s) {
|
|
||||||
char *str = NULL;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r3_slug_t * r3_slug_parse_next(r3_slug_t *s, char **errstr) {
|
|
||||||
return r3_slug_parse(s->end, s->path_len - (s->end - s->begin), errstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Return 0 => Empty, slug not found
|
|
||||||
Return 1 => Slug found
|
|
||||||
Return -1 => Slug parsing error
|
|
||||||
*/
|
|
||||||
|
|
||||||
int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *offset, char **errstr) {
|
|
||||||
s->path = (char*) needle;
|
|
||||||
s->path_len = needle_len;
|
|
||||||
|
|
||||||
if (offset == NULL) {
|
|
||||||
offset = (char*) needle; // from the begining of the needle
|
|
||||||
}
|
|
||||||
|
|
||||||
// there is no slug
|
|
||||||
if (!r3_path_contains_slug_char(offset, needle_len - (offset-needle))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cnt = 0;
|
|
||||||
int state = 0;
|
|
||||||
const char * p = offset;
|
|
||||||
|
|
||||||
while( (p-needle) < needle_len) {
|
|
||||||
// escape one character
|
|
||||||
if (*p == '\\' ) {
|
|
||||||
p++; p++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// slug starts with '{'
|
|
||||||
if (state == 0 && *p == '{') {
|
|
||||||
s->begin = ++p;
|
|
||||||
state++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// in the middle of the slug (pattern)
|
|
||||||
if (state == 1 && *p == ':') {
|
|
||||||
// start from next
|
|
||||||
s->pattern = ++p;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// slug closed.
|
|
||||||
if (state == 1 && *p == '}') {
|
|
||||||
s->end = p;
|
|
||||||
s->len = s->end - s->begin;
|
|
||||||
if (s->pattern) {
|
|
||||||
s->pattern_len = p - s->pattern;
|
|
||||||
}
|
|
||||||
cnt++;
|
|
||||||
state--;
|
|
||||||
p++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// might be inside the pattern
|
|
||||||
if ( *p == '{' ) {
|
|
||||||
state++;
|
|
||||||
} else if ( *p == '}' ) {
|
|
||||||
state--;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (state != 0) {
|
|
||||||
if (errstr) {
|
|
||||||
char *err = NULL;
|
|
||||||
int r = asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state);
|
|
||||||
if (r) {};
|
|
||||||
*errstr = err;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
info("found slug\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* provide a quick way to count slugs, simply search for '{'
|
|
||||||
*/
|
|
||||||
int r3_slug_count(const char * needle, int len, char **errstr) {
|
|
||||||
int cnt = 0;
|
|
||||||
int state = 0;
|
|
||||||
char * p = (char*) needle;
|
|
||||||
|
|
||||||
while( (p-needle) < len) {
|
|
||||||
if (*p == '\\' ) {
|
|
||||||
p++; p++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == 1 && *p == '}') {
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
if ( *p == '{' ) {
|
|
||||||
state++;
|
|
||||||
} else if ( *p == '}' ) {
|
|
||||||
state--;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
};
|
|
||||||
info("FOUND PATTERN: '%s' (%d), STATE: %d\n", needle, len, state);
|
|
||||||
if (state != 0) {
|
|
||||||
if (errstr) {
|
|
||||||
char *err = NULL;
|
|
||||||
int r = asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state);
|
|
||||||
if (r) {};
|
|
||||||
*errstr = err;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
59
src/slug.h
59
src/slug.h
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* slug.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#ifndef SLUG_H
|
|
||||||
#define SLUG_H
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/**
|
|
||||||
* source path
|
|
||||||
*/
|
|
||||||
const char * path;
|
|
||||||
|
|
||||||
int path_len;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* slug start pointer
|
|
||||||
*/
|
|
||||||
const char * begin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* slug end pointer
|
|
||||||
*/
|
|
||||||
const char * end;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* slug length
|
|
||||||
*/
|
|
||||||
int len;
|
|
||||||
|
|
||||||
// slug pattern pointer if we have one
|
|
||||||
const char * pattern;
|
|
||||||
|
|
||||||
// the length of custom pattern, if the pattern is found.
|
|
||||||
int pattern_len;
|
|
||||||
|
|
||||||
} r3_slug_t;
|
|
||||||
|
|
||||||
|
|
||||||
r3_slug_t * r3_slug_new(const char * path, int path_len);
|
|
||||||
|
|
||||||
int r3_slug_check(r3_slug_t *s);
|
|
||||||
|
|
||||||
int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *offset, char **errstr);
|
|
||||||
|
|
||||||
char * r3_slug_to_str(const r3_slug_t *s);
|
|
||||||
|
|
||||||
void r3_slug_free(r3_slug_t * s);
|
|
||||||
|
|
||||||
static inline int r3_path_contains_slug_char(const char *str, unsigned int len) {
|
|
||||||
for (unsigned int i = 0; i < len; i++) {
|
|
||||||
if (str[i] == '{') return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !SLUG_H */
|
|
305
src/str.c
305
src/str.c
|
@ -1,227 +1,114 @@
|
||||||
/*
|
/*
|
||||||
* str.c
|
* str.c
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* 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 <assert.h>
|
#include <assert.h>
|
||||||
#include "r3.h"
|
#include "r3_str.h"
|
||||||
#include "r3_slug.h"
|
#include "str_array.h"
|
||||||
#include "str.h"
|
#include "r3_define.h"
|
||||||
#include "slug.h"
|
|
||||||
|
|
||||||
static const char * strnchr(const char* str, unsigned int len, int ch) {
|
int strndiff(char * d1, char * d2, unsigned int n) {
|
||||||
for (unsigned int i = 0; i < len; i++) {
|
char * o = d1;
|
||||||
if (str[i] == ch) return str + i;
|
while ( *d1 == *d2 && n-- > 0 ) {
|
||||||
|
d1++;
|
||||||
|
d2++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return d1 - o;
|
||||||
}
|
|
||||||
|
|
||||||
int r3_pattern_to_opcode(const char * pattern, unsigned int len) {
|
|
||||||
if ( strncmp(pattern, "\\w+",len) == 0 ) {
|
|
||||||
return OP_EXPECT_MORE_WORDS;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "[0-9a-z]+",len) == 0 || strncmp(pattern, "[a-z0-9]+",len) == 0 ) {
|
|
||||||
return OP_EXPECT_MORE_WORDS;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "[a-z]+",len) == 0 ) {
|
|
||||||
return OP_EXPECT_MORE_ALPHA;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "\\d+", len) == 0 ) {
|
|
||||||
return OP_EXPECT_MORE_DIGITS;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "[0-9]+", len) == 0 ) {
|
|
||||||
return OP_EXPECT_MORE_DIGITS;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "[^/]+", len) == 0 ) {
|
|
||||||
return OP_EXPECT_NOSLASH;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
|
|
||||||
return OP_EXPECT_NODASH;
|
|
||||||
}
|
|
||||||
if ( strncmp(pattern, ".*", len) == 0 ) {
|
|
||||||
return OP_GREEDY_ANY;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int strdiff(char * d1, char * d2) {
|
||||||
|
char * o = d1;
|
||||||
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr) {
|
while( *d1 == *d2 ) {
|
||||||
char * s1 = offset;
|
d1++;
|
||||||
char * s2 = offset;
|
d2++;
|
||||||
|
|
||||||
short found_s1 = 0;
|
|
||||||
short found_s2 = 0;
|
|
||||||
|
|
||||||
while( s1 >= needle && (s1 - needle < needle_len) ) {
|
|
||||||
if ( *s1 == '{' ) {
|
|
||||||
found_s1 = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s1--;
|
|
||||||
}
|
}
|
||||||
|
return d1 - o;
|
||||||
const char * end = needle + needle_len;
|
|
||||||
while( (s2 + 1) < end ) {
|
|
||||||
if ( *s2 == '}' ) {
|
|
||||||
found_s2 = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
if (found_s1 && found_s2) {
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
if (found_s1 || found_s2) {
|
|
||||||
// wrong slug pattern
|
|
||||||
if(errstr) {
|
|
||||||
int r = asprintf(errstr, "Incomplete slug pattern");
|
|
||||||
if (r) {};
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len) {
|
|
||||||
const char *c;
|
|
||||||
const char *s2;
|
|
||||||
int cnt = 0;
|
|
||||||
if ((c = strnchr(s1, str_len, '{'))) {
|
|
||||||
// find closing '}'
|
|
||||||
s2 = c;
|
|
||||||
unsigned int j = str_len - (c - s1);
|
|
||||||
for (unsigned int i = 0; i < j; i++) {
|
|
||||||
if (*s2 == '{' )
|
|
||||||
cnt++;
|
|
||||||
else if (*s2 == '}' )
|
|
||||||
cnt--;
|
|
||||||
if (cnt == 0)
|
|
||||||
break;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (cnt!=0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(len) {
|
|
||||||
*len = s2 - c + 1;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* given a slug string, duplicate the pattern string of the slug
|
* provide a quick way to count slugs, simply search for '{'
|
||||||
*/
|
*/
|
||||||
const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len) {
|
int count_slug(char * p, int len) {
|
||||||
const char *c;
|
int s = 0;
|
||||||
const char *s2;
|
while( len-- ) {
|
||||||
unsigned int cnt = 1;
|
if ( *p == '{' )
|
||||||
if ( (c = strnchr(s1, str_len, ':')) ) {
|
s++;
|
||||||
c++;
|
p++;
|
||||||
// find closing '}'
|
|
||||||
s2 = c;
|
|
||||||
unsigned int j = str_len - (c - s1);
|
|
||||||
for (unsigned int i = 0; i < j; i++) {
|
|
||||||
if (*s2 == '{' )
|
|
||||||
cnt++;
|
|
||||||
else if (*s2 == '}' )
|
|
||||||
cnt--;
|
|
||||||
if (cnt == 0)
|
|
||||||
break;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
if (cnt!=0) {
|
return s;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*len = s2 - c;
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool contains_slug(char * str) {
|
||||||
/**
|
return strchr(str, '{') != NULL ? TRUE : FALSE;
|
||||||
* given a slug string, duplicate the parameter name string of the slug
|
|
||||||
*/
|
|
||||||
const char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len) {
|
|
||||||
const char * c;
|
|
||||||
const char * s2;
|
|
||||||
unsigned int plholder;
|
|
||||||
if ((c = r3_slug_find_placeholder(s1, str_len, &plholder))) {
|
|
||||||
c++;
|
|
||||||
if (( s2 = strnchr(c, plholder, ':') )) {
|
|
||||||
*len = s2 - c;
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
*len = plholder - 2;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param char * sep separator
|
* @param char * sep separator
|
||||||
*/
|
*/
|
||||||
char * r3_slug_compile(const char * str, unsigned int len)
|
char * compile_slug(char * str, int len)
|
||||||
{
|
{
|
||||||
const char *s1 = NULL;
|
char *s1 = NULL, *s2 = NULL, *i = NULL, *o = NULL;
|
||||||
char *o = NULL;
|
char *pat = NULL;
|
||||||
const char *pat = NULL;
|
|
||||||
char sep = '/';
|
char sep = '/';
|
||||||
|
|
||||||
|
// find '{'
|
||||||
|
s1 = strchr(str, '{');
|
||||||
|
|
||||||
// append prefix
|
if ( s1 == NULL ) {
|
||||||
unsigned int s1_len;
|
return my_strdup(str);
|
||||||
s1 = r3_slug_find_placeholder(str, len, &s1_len);
|
}
|
||||||
|
|
||||||
if ( !s1 ) {
|
if ( (s1 - str) > 0 ) {
|
||||||
return strndup(str,len);
|
sep = *(s1-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char * out = NULL;
|
char * out = NULL;
|
||||||
if (!(out = calloc(1, sizeof(char) * 200))) {
|
if ((out = calloc(sizeof(char),128)) == NULL) {
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// append prefix
|
||||||
o = out;
|
o = out;
|
||||||
strncat(o, "^", 1);
|
strncat(o, str, s1 - str);
|
||||||
o++;
|
|
||||||
|
|
||||||
strncat(o, str, s1 - str); // string before slug
|
|
||||||
o += (s1 - str);
|
o += (s1 - str);
|
||||||
|
|
||||||
|
// start after ':'
|
||||||
|
if ( NULL != (pat = strchr(s1, ':')) ) {
|
||||||
|
pat++;
|
||||||
|
|
||||||
unsigned int pat_len;
|
// this slug contains a pattern
|
||||||
pat = r3_slug_find_pattern(s1, s1_len, &pat_len);
|
s2 = strchr(pat, '}');
|
||||||
|
|
||||||
if (pat) {
|
|
||||||
*o = '(';
|
*o = '(';
|
||||||
o++;
|
o++;
|
||||||
strncat(o, pat, pat_len );
|
|
||||||
o += pat_len;
|
strncat(o, pat, (s2 - pat) );
|
||||||
|
o += (s2 - pat);
|
||||||
|
|
||||||
*o = ')';
|
*o = ')';
|
||||||
o++;
|
o++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// should return a '[^/]+' pattern
|
||||||
|
// strncat(c, "([^%c]+)", strlen("([^%c]+)") );
|
||||||
|
// snprintf(pat, 128, "([^%c]+)", sep);
|
||||||
sprintf(o, "([^%c]+)", sep);
|
sprintf(o, "([^%c]+)", sep);
|
||||||
o+= strlen("([^*]+)");
|
o+= sizeof("([^%c]+)");
|
||||||
|
}
|
||||||
|
|
||||||
|
s2++;
|
||||||
|
while( (s2 - str) > len ) {
|
||||||
|
*o = *s2;
|
||||||
|
s2++;
|
||||||
|
o++;
|
||||||
}
|
}
|
||||||
s1 += s1_len;
|
|
||||||
strncat(o, s1, len - (s1 - str)); // string after slug
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +117,61 @@ char * ltrim_slash(char* str)
|
||||||
{
|
{
|
||||||
char * p = str;
|
char * p = str;
|
||||||
while (*p == '/') p++;
|
while (*p == '/') p++;
|
||||||
return strdup(p);
|
return my_strdup(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
char** str_split(char* a_str, const char a_delim)
|
||||||
|
{
|
||||||
|
char** result = 0;
|
||||||
|
size_t count = 0;
|
||||||
|
char* tmp = a_str;
|
||||||
|
char* last_comma = 0;
|
||||||
|
char delim[2];
|
||||||
|
delim[0] = a_delim;
|
||||||
|
delim[1] = 0;
|
||||||
|
|
||||||
|
/* Count how many elements will be extracted. */
|
||||||
|
while (*tmp)
|
||||||
|
{
|
||||||
|
if (a_delim == *tmp)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
last_comma = tmp;
|
||||||
|
}
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add space for trailing token. */
|
||||||
|
count += last_comma < (a_str + strlen(a_str) - 1);
|
||||||
|
|
||||||
|
/* Add space for terminating null string so caller
|
||||||
|
knows where the list of returned strings ends. */
|
||||||
|
count++;
|
||||||
|
|
||||||
|
result = malloc(sizeof(char*) * count);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
size_t idx = 0;
|
||||||
|
char* token = strtok(a_str, delim);
|
||||||
|
|
||||||
|
while (token)
|
||||||
|
{
|
||||||
|
assert(idx < count);
|
||||||
|
*(result + idx++) = my_strdup(token);
|
||||||
|
token = strtok(0, delim);
|
||||||
|
}
|
||||||
|
assert(idx == count - 1);
|
||||||
|
*(result + idx) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_repeat(char *s, char *c, int len) {
|
||||||
|
while(len--) {
|
||||||
|
s[len - 1] = *c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_indent(int level) {
|
void print_indent(int level) {
|
||||||
|
@ -240,36 +181,28 @@ void print_indent(int level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *my_strdup(const char *s) {
|
||||||
|
|
||||||
#ifndef HAVE_STRDUP
|
|
||||||
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 = malloc(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];
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
char *my_strndup(const char *s, int n) {
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
|
||||||
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 = malloc(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];
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
14
src/str.h
14
src/str.h
|
@ -1,14 +0,0 @@
|
||||||
#ifndef R3_STR_INTERN_H
|
|
||||||
#define R3_STR_INTERN_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void print_indent(int level);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
127
src/token.c
127
src/token.c
|
@ -1,54 +1,59 @@
|
||||||
/*
|
/*
|
||||||
* token.c
|
* token.c
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
* Copyright (C) 2014 c9s <c9s@c9smba.local>
|
||||||
*
|
*
|
||||||
* 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_slug.h"
|
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "memory.h"
|
#include "r3_str.h"
|
||||||
|
|
||||||
|
|
||||||
|
str_array * str_array_create(int cap) {
|
||||||
|
str_array * list = (str_array*) malloc( sizeof(str_array) );
|
||||||
|
list->len = 0;
|
||||||
|
list->cap = cap;
|
||||||
|
list->tokens = (char**) malloc( sizeof(char*) * cap);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
void str_array_free(str_array *l) {
|
void str_array_free(str_array *l) {
|
||||||
assert(l);
|
for ( int i = 0; i < l->len ; i++ ) {
|
||||||
free(l->tokens.entries);
|
char * t = l->tokens[ i ];
|
||||||
}
|
free(t);
|
||||||
|
|
||||||
bool str_array_append(str_array * l, const char * token, unsigned int len) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void str_array_dump_slugs(const str_array *l) {
|
|
||||||
if (l->tokens.size) {
|
|
||||||
printf("[");
|
|
||||||
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 ) {
|
|
||||||
printf(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("]\n");
|
|
||||||
} else {
|
|
||||||
printf("[]\n");
|
|
||||||
}
|
}
|
||||||
|
free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void str_array_dump(const str_array *l) {
|
bool str_array_is_full(str_array * l) {
|
||||||
|
return l->len >= l->cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool str_array_resize(str_array *l, int new_cap) {
|
||||||
|
l->tokens = realloc(l->tokens, sizeof(char**) * new_cap);
|
||||||
|
l->cap = new_cap;
|
||||||
|
return l->tokens != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool str_array_append(str_array * l, char * token) {
|
||||||
|
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;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_array_dump(str_array *l) {
|
||||||
printf("[");
|
printf("[");
|
||||||
for ( int i = 0; i < l->tokens.size ; i++ ) {
|
for ( int i = 0; i < l->len ; i++ ) {
|
||||||
printf("\"%*.*s\"", l->tokens.entries[i].len,l->tokens.entries[i].len,l->tokens.entries[i].base );
|
printf("\"%s\"", l->tokens[i] );
|
||||||
// printf("\"%s\"", l->tokens.entries[i] );
|
if ( i + 1 != l->len ) {
|
||||||
if ( i + 1 != l->tokens.size ) {
|
|
||||||
printf(", ");
|
printf(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,3 +63,55 @@ void str_array_dump(const str_array *l) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to split route path into a string array, not for performance.
|
||||||
|
* hence this function should be safe.
|
||||||
|
*
|
||||||
|
* Split "/path/foo/{id}" into [ "/path" , "/foo" , "/{id}" ]
|
||||||
|
* Split "/path/bar/{id}" into [ "/path" , "/foo" , "/{id}" ]
|
||||||
|
* Split "/blog/post/{id}" into [ "/blog" , "/post" , "/{id}" ]
|
||||||
|
* Split "/blog/{id}" into [ "/blog" , "/{id}" ]
|
||||||
|
* Split "/blog" into [ "/blog" ]
|
||||||
|
* Split "/b" into [ "/b" ]
|
||||||
|
* Split "/{id}" into [ "/{id}" ]
|
||||||
|
*
|
||||||
|
* @param char* pattern
|
||||||
|
* @param int pattern_len
|
||||||
|
*
|
||||||
|
* @return char**
|
||||||
|
*/
|
||||||
|
str_array * split_route_pattern(char *pattern, int pattern_len) {
|
||||||
|
char *s1, *p = pattern;
|
||||||
|
|
||||||
|
str_array * str_array = str_array_create( 20 );
|
||||||
|
|
||||||
|
s1 = p;
|
||||||
|
p++;
|
||||||
|
while (*p && (p - pattern) < pattern_len ) {
|
||||||
|
|
||||||
|
// a slug
|
||||||
|
if ( *p == '{' ) {
|
||||||
|
// find closing '}'
|
||||||
|
while (*p != '}') {
|
||||||
|
p++;
|
||||||
|
assert(p - pattern < pattern_len ); // throw exception
|
||||||
|
}
|
||||||
|
p++; // contains the '}'
|
||||||
|
// printf("==> %s\n", my_strndup(s1, p-s1) );
|
||||||
|
str_array_append(str_array, my_strndup(s1, p-s1) );
|
||||||
|
s1 = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if ( *p == '/' ) {
|
||||||
|
// printf("==> %s\n", my_strndup(s1, p-s1) );
|
||||||
|
str_array_append(str_array, my_strndup(s1, p-s1) );
|
||||||
|
s1 = p;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( p-s1 > 0 ) {
|
||||||
|
str_array_append(str_array, my_strndup(s1, p-s1) );
|
||||||
|
}
|
||||||
|
return str_array;
|
||||||
|
}
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
function(add_r3_test NAME)
|
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||||
add_executable(${NAME} ${ARGN})
|
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
||||||
|
find_package(Check REQUIRED)
|
||||||
|
find_package(PCRE REQUIRED)
|
||||||
|
# find_package(Judy REQUIRED)
|
||||||
|
|
||||||
target_include_directories(${NAME}
|
if (NOT CHECK_FOUND)
|
||||||
PRIVATE
|
message(STATUS "Skipping unit tests, Check library not found!")
|
||||||
${CHECK_INCLUDE_DIRS}
|
else (NOT CHECK_FOUND)
|
||||||
${PROJECT_BINARY_DIR}
|
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3)
|
||||||
${PROJECT_SOURCE_DIR}/src)
|
|
||||||
|
|
||||||
target_link_libraries(${NAME}
|
include_directories(${CHECK_INCLUDE_DIRS})
|
||||||
${CHECK_LDFLAGS}
|
# include_directories("${PROJECT_SOURCE_DIR}/include/r2")
|
||||||
r3)
|
add_executable(test_r3 test_tree.c)
|
||||||
|
target_link_libraries(test_r3 ${TEST_LIBS})
|
||||||
|
|
||||||
add_test(NAME ${NAME} COMMAND ${NAME})
|
add_custom_command(
|
||||||
endfunction()
|
TARGET test_r3 POST_BUILD
|
||||||
|
COMMENT "Running unit tests"
|
||||||
|
COMMAND test_r3
|
||||||
|
)
|
||||||
|
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,63 +1,14 @@
|
||||||
TESTS =
|
# INCLUDES = @CHECK_CFLAGS@
|
||||||
|
if HAVE_CHECK
|
||||||
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`
|
TESTS = check_tree
|
||||||
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
|
else
|
||||||
|
TESTS =
|
||||||
if USE_JEMALLOC
|
|
||||||
AM_CFLAGS += -ljemalloc
|
|
||||||
endif
|
endif
|
||||||
|
# noinst_PROGRAMS = $(TESTS)
|
||||||
noinst_HEADERS = \
|
|
||||||
bench.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
dist_noinst_DATA = \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
|
|
||||||
TESTS += check_slug
|
|
||||||
check_slug_SOURCES = check_slug.c
|
|
||||||
|
|
||||||
TESTS += check_tree
|
|
||||||
check_tree_SOURCES = check_tree.c
|
|
||||||
|
|
||||||
TESTS += check_routes
|
|
||||||
check_routes_SOURCES = check_routes.c
|
|
||||||
|
|
||||||
TESTS += check_str_array
|
|
||||||
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
|
|
||||||
TESTS += check_json
|
|
||||||
check_json_SOURCES = check_json.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
if ENABLE_GRAPHVIZ
|
|
||||||
TESTS += check_gvc
|
|
||||||
check_gvc_SOURCES = check_gvc.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
check_PROGRAMS = $(TESTS)
|
check_PROGRAMS = $(TESTS)
|
||||||
|
check_tree_SOURCES = check_tree.c
|
||||||
noinst_PROGRAMS = bench
|
check_tree_LDADD=$(DEPS_LIBS) -L$(top_builddir)/src -lcheck -lr3
|
||||||
bench_SOURCES = bench.c
|
check_tree_CFLAGS=$(DEPS_CFLAGS) @CHECK_CFLAGS@
|
||||||
|
|
||||||
# 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
|
||||||
|
|
479
tests/bench.c
479
tests/bench.c
|
@ -1,479 +0,0 @@
|
||||||
/*
|
|
||||||
* bench.c
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
|
|
||||||
|
|
||||||
#include "r3.h"
|
|
||||||
#include "r3_slug.h"
|
|
||||||
#include "bench.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long unixtime() {
|
|
||||||
struct timeval tp;
|
|
||||||
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
|
||||||
return tp.tv_sec;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double microtime() {
|
|
||||||
struct timeval tp;
|
|
||||||
long sec = 0L;
|
|
||||||
double msec = 0.0;
|
|
||||||
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
|
|
||||||
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
|
|
||||||
sec = tp.tv_sec;
|
|
||||||
if (msec >= 1.0)
|
|
||||||
msec -= (long) msec;
|
|
||||||
return sec + msec;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bench_start(bench *b) {
|
|
||||||
b->start = microtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void bench_stop(bench *b) {
|
|
||||||
b->end = microtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
double bench_iteration_speed(bench *b) {
|
|
||||||
return (b->N * b->R) / (b->end - b->start);
|
|
||||||
}
|
|
||||||
|
|
||||||
double bench_duration(bench *b) {
|
|
||||||
return (b->end - b->start);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bench_print_summary(bench *b) {
|
|
||||||
printf("%ld runs, ", b->R);
|
|
||||||
printf("%ld iterations each run, ", b->N);
|
|
||||||
printf("finished in %lf seconds\n", bench_duration(b) );
|
|
||||||
printf("%.2f i/sec\n", bench_iteration_speed(b) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine multiple benchmark result into one measure entry.
|
|
||||||
*
|
|
||||||
* bench_append_csv("benchmark.csv", 3, &b1, &b2)
|
|
||||||
*/
|
|
||||||
void bench_append_csv(char *filename, int countOfB, ...) {
|
|
||||||
FILE *fp = fopen(filename, "a+");
|
|
||||||
if(!fp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long ts = unixtime();
|
|
||||||
fprintf(fp, "%ld", ts);
|
|
||||||
|
|
||||||
|
|
||||||
int i;
|
|
||||||
bench * b;
|
|
||||||
va_list vl;
|
|
||||||
va_start(vl,countOfB);
|
|
||||||
for (i=0 ; i < countOfB ; i++) {
|
|
||||||
b = va_arg(vl, bench*);
|
|
||||||
fprintf(fp, ",%.2f", bench_iteration_speed(b) );
|
|
||||||
}
|
|
||||||
va_end(vl);
|
|
||||||
|
|
||||||
fprintf(fp, "\n");
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
R3Node * n = r3_tree_create(1);
|
|
||||||
|
|
||||||
int route_data = 999;
|
|
||||||
|
|
||||||
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/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/foo/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/bar/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/baz/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/corge", &route_data);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/qux/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/quux/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/grault/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/corge/garply/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/foo/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/bar/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/baz/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/qux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/quux/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/corge/garply", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/grault/garply/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/foo/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/bar/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/baz/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/qux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/corge", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/quux/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/corge/grault", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/foo", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/bar", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/baz", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/qux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/quux", NULL);
|
|
||||||
r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
|
||||||
|
|
||||||
MEASURE(tree_compile)
|
|
||||||
r3_tree_compile(n, NULL);
|
|
||||||
END_MEASURE(tree_compile)
|
|
||||||
|
|
||||||
R3Node * m;
|
|
||||||
m = r3_tree_match(n , "/qux/bar/corge", NULL);
|
|
||||||
assert(m != NULL);
|
|
||||||
assert( *((int*) m->data) == 999 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BENCHMARK(str_dispatch)
|
|
||||||
r3_tree_matchl(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
|
|
||||||
END_BENCHMARK(str_dispatch)
|
|
||||||
BENCHMARK_SUMMARY(str_dispatch);
|
|
||||||
|
|
||||||
BENCHMARK(str_match_entry)
|
|
||||||
match_entry * e = match_entry_createl("/qux/bar/corge", strlen("/qux/bar/corge") );
|
|
||||||
r3_tree_match_entry(n , e);
|
|
||||||
match_entry_free(e);
|
|
||||||
END_BENCHMARK(str_match_entry)
|
|
||||||
BENCHMARK_SUMMARY(str_match_entry);
|
|
||||||
|
|
||||||
|
|
||||||
R3Node * tree2 = r3_tree_create(1);
|
|
||||||
r3_tree_insert_path(tree2, "/post/{year}/{month}", NULL);
|
|
||||||
r3_tree_compile(tree2, NULL);
|
|
||||||
// r3_tree_dump(tree2,0);
|
|
||||||
|
|
||||||
BENCHMARK(pcre_dispatch)
|
|
||||||
r3_tree_matchl(tree2, "/post/2014/12", strlen("/post/2014/12"), NULL);
|
|
||||||
END_BENCHMARK(pcre_dispatch)
|
|
||||||
BENCHMARK_SUMMARY(pcre_dispatch);
|
|
||||||
|
|
||||||
|
|
||||||
BENCHMARK_RECORD_CSV("bench_str.csv", 4, BR(str_dispatch), BR(pcre_dispatch), BR(tree_compile), BR(str_match_entry) );
|
|
||||||
|
|
||||||
r3_tree_free(tree2);
|
|
||||||
r3_tree_free(n);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* bench.h
|
|
||||||
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the MIT license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BENCH_H
|
|
||||||
#define BENCH_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define MICRO_IN_SEC 1000000.00
|
|
||||||
#define SEC_IN_MIN 60
|
|
||||||
#define NUL '\0'
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
long N; // N for each run
|
|
||||||
long R; // runs
|
|
||||||
double secs;
|
|
||||||
double start;
|
|
||||||
double end;
|
|
||||||
} bench;
|
|
||||||
|
|
||||||
unsigned long unixtime();
|
|
||||||
|
|
||||||
double microtime();
|
|
||||||
|
|
||||||
void bench_start(bench *b);
|
|
||||||
|
|
||||||
void bench_stop(bench *b);
|
|
||||||
|
|
||||||
double bench_iteration_speed(bench *b);
|
|
||||||
|
|
||||||
void bench_print_summary(bench *b);
|
|
||||||
|
|
||||||
double bench_duration(bench *b);
|
|
||||||
|
|
||||||
void bench_append_csv(char *filename, int countOfB, ...);
|
|
||||||
|
|
||||||
#define MEASURE(B) \
|
|
||||||
bench B; B.N = 1; B.R = 1; \
|
|
||||||
printf("Measuring " #B "...\n"); \
|
|
||||||
bench_start(&B);
|
|
||||||
|
|
||||||
#define END_MEASURE(B) \
|
|
||||||
bench_stop(&B);
|
|
||||||
|
|
||||||
#define BENCHMARK(B) \
|
|
||||||
bench B; B.N = 5000000; B.R = 3; \
|
|
||||||
printf("Benchmarking " #B "...\n"); \
|
|
||||||
bench_start(&B); \
|
|
||||||
for (int _r = 0; _r < B.R ; _r++ ) { \
|
|
||||||
for (int _i = 0; _i < B.N ; _i++ ) {
|
|
||||||
|
|
||||||
#define END_BENCHMARK(B) \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
bench_stop(&B);
|
|
||||||
|
|
||||||
#define BENCHMARK_SUMMARY(B) bench_print_summary(&B);
|
|
||||||
|
|
||||||
#define BENCHMARK_RECORD_CSV(filename, countOfB, ...) \
|
|
||||||
bench_append_csv(filename, countOfB, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define BR(b) &b
|
|
||||||
|
|
||||||
#endif /* !BENCH_H */
|
|
50
tests/bench_str.csv
Normal file
50
tests/bench_str.csv
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
1400242718,5649455.80
|
||||||
|
1400242784,5775186.12
|
||||||
|
1400242814,5653481.02
|
||||||
|
1400242868,5857187.70
|
||||||
|
1400242938,5732228.92
|
||||||
|
1400243193,5959689.05
|
||||||
|
1400243423,5717292.34
|
||||||
|
1400243528,5669803.44
|
||||||
|
1400243702,5880318.26
|
||||||
|
1400243875,5789509.57
|
||||||
|
1400243912,5889038.56
|
||||||
|
1400243951,5922317.92
|
||||||
|
1400243971,6069795.56
|
||||||
|
1400243982,5904973.70
|
||||||
|
1400243985,5888983.99
|
||||||
|
1400244196,5174852.68
|
||||||
|
1400244284,5821697.95
|
||||||
|
1400244307,6012282.29
|
||||||
|
1400244516,5929306.97
|
||||||
|
1400244550,5858897.69
|
||||||
|
1400244556,5998727.11
|
||||||
|
1400244574,5846792.25
|
||||||
|
1400244592,5930319.69
|
||||||
|
1400244599,5910137.48
|
||||||
|
1400244639,5936452.01
|
||||||
|
1400244648,5978607.43
|
||||||
|
1400244653,5956364.63
|
||||||
|
1400244657,5911318.61
|
||||||
|
1400244829,6362496.45
|
||||||
|
1400244887,6330902.59
|
||||||
|
1400244895,6390983.42
|
||||||
|
1400244908,6380415.58
|
||||||
|
1400244914,6346830.19
|
||||||
|
1400244932,6610181.08
|
||||||
|
1400245102,6404550.11
|
||||||
|
1400245168,6085174.66
|
||||||
|
1400245176,6400679.76
|
||||||
|
1400245216,6416409.15
|
||||||
|
1400245227,6485899.37
|
||||||
|
1400245230,5862573.02
|
||||||
|
1400245233,6526163.60
|
||||||
|
1400245281,6205337.09
|
||||||
|
1400245289,6217947.43
|
||||||
|
1400245311,6423151.81
|
||||||
|
1400251162,5826610.20
|
||||||
|
1400251172,6039034.62
|
||||||
|
1400251256,6219533.32
|
||||||
|
1400251264,6015717.76
|
||||||
|
1400278620,5733465.40
|
||||||
|
1400279249,6306920.57
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue