Compare commits

...

765 commits

Author SHA1 Message Date
Lily Tsuru ade1527bef Add pcre2 include dir (required for non-system PCRE2 installations) 2023-12-24 23:13:53 -05:00
c9s c1aab00c40
Merge pull request #157 from Nordix/cmake-corrections 2023-11-12 22:51:25 +08:00
Björn Svensson 9887545ab0 Install headers in correct path when using CMake
pkg-config provides users with the include path `../include/r3`
while CMake installs the headers directly under `../include/`.
This corrects the installation path to match the generated r3.pc
and to get the same result as when using autoconf.
2023-11-03 09:49:16 +01:00
Björn Svensson c105117b40
Use PCRE2 instead of PCRE (#153)
PCRE is now at end of life and is no longer actively maintained.
Lift the dependency to the next major version, i.e. PCRE2.

Implementation notes:
- Removed the pcre study option since:
  "The new API ... was simplified by abolishing the separate "study" optimizing
  function; in PCRE2, patterns are automatically optimized where possible."
- If asprintf() fails the content of the 'strp' variable is undefined.
  Lets check the return value and return NULL upon error.
- Pattern and subject can straightforwardly be cast to PCRE2_SPTR since we
  only work with 8-bit code units.
2023-10-23 12:38:24 +02:00
Björn Svensson 9168f7e4d4 Support C23 projects
Don't define true/false/bool when r3 is used by C23 projects
since C23 already has a bool type and predefined constants.
2023-10-23 10:45:18 +02:00
Björn Svensson 58d8b0c028 Use coverity-scan-action in CI
Simplifies the CI job and adds a cache to avoid downloading the 1GB+
tool archive on every run.
See: https://github.com/vapier/coverity-scan-action

Only run this job when a commit is pushed to the default branch 2.0
(like when a PR is merged) since the required Coverity token/secret
is not available when this job is triggered by forks.
2023-10-23 10:35:38 +02:00
Yo-An Lin 91405adda5
Merge pull request #152 from c9s/c9s-patch-1 2023-02-12 10:52:51 +08:00
Yo-An Lin b6639e557f
Update coverity.yml 2022-08-24 16:05:06 +08:00
Yo-An Lin c8123430a9
remove coverity env var since it is not working 2022-07-21 00:41:08 +08:00
Bjorn Svensson 9b69f38527
Fix leak in r3_tree_insert_pathl_ex() (#150)
Includes a testcase triggering the issue when building with
the leak sanitizer.

Resource leak (CID 355063) found by Coverity,
2022-07-20 13:23:45 +02:00
Yo-An Lin 25cc816025
Fix coverity token variable (#151) 2022-07-20 13:08:42 +02:00
Yo-An Lin edbeb0631d
Merge pull request #149 from Nordix/coverity-in-ci
Add Coverity Scan to CI
2022-07-19 17:20:04 +08:00
Björn Svensson 04d52a6dd1 Fix Coverity warning
The return value was checked on all calls to r3_slug_find_placeholder()
except in one place, which triggered a Coverity warning.

This adds a check (assert), and enables the other asserts for non-debug
builds to catch segmentation faults early.
2021-11-10 22:20:46 +01:00
Björn Svensson cfed420cd3 Add Coverity Scan to CI 2021-11-10 22:20:34 +01:00
Yo-An Lin 76e2770304
Merge pull request #148 from Nordix/faulty-slug-in-insert-route
Handle incomplete slug pattern when inserting a route
2021-11-05 09:27:52 +08:00
Yo-An Lin 90450def8b
Merge pull request #147 from Nordix/memory-pool-cleanups
Remove unused memory pool and memory code
2021-11-05 09:26:46 +08:00
Björn Svensson 2f3e0b01ff Handle incomplete slug in insert route 2021-11-04 20:22:10 +01:00
Björn Svensson bf11f8e2e6 Remove unused code in memory.c/.h 2021-11-03 21:58:33 +01:00
Björn Svensson f0dd25bd53 Remove unused memory pool 2021-11-03 21:22:48 +01:00
Yo-An Lin e533bae646
Merge pull request #146 from Nordix/coveralls-action
Use recommended Coveralls GitHub action in CI
2021-10-28 21:14:43 +08:00
Björn Svensson b44f052897 Use recommended Coveralls GitHub action in CI 2021-10-19 11:18:53 +02:00
Yo-An Lin 06c4fc41bf
Merge pull request #140 from Nordix/test-leak-fixes
Correcting leaks in tests
2021-10-19 02:45:18 +08:00
Yo-An Lin 35c5d13df8
Merge pull request #144 from Nordix/migrate-ci-to-github-actions
Add CI via Github Actions
2021-10-19 02:44:40 +08:00
Yo-An Lin 4f3c1cd994
Merge pull request #145 from Nordix/misaligned-address-error
Remove fixed alignment
2021-10-19 02:44:14 +08:00
Björn Svensson 5114d894e5 Remove fixed alignment 2021-10-18 11:36:54 +02:00
Björn Svensson 79a3bc7c50 Add CI via Github Actions
This is an initial setup with similarities to how we test
via TravisCI; build via autotools and build via cmake.
Additional testmatrix for sanitizer testing.
2021-10-18 09:08:42 +02:00
Björn Svensson 9c8feff07f Correcting leaks in tests
A couple of testcases did not free its `match_entry` allocations,
which triggers leak indications.
Visible when build and run using the leak sanitizer, i.e
`CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" cmake ..`
2021-10-14 08:27:19 +02:00
Yo-An Lin b13dc8aa6e
Merge pull request #131 from iresty/feature-ipv6
feature: supported to use ipv6 address match route.
2021-10-14 10:31:23 +08:00
Yo-An Lin eca8d9992e
Merge pull request #143 from Nordix/str_array-fixes
Corrections in `str_array`
2021-10-14 10:29:49 +08:00
Yo-An Lin c9743f3904
Merge pull request #142 from Nordix/invalid-read-corrections
Correcting buffer over-read errors
2021-10-14 10:29:19 +08:00
Björn Svensson 383717a8c7 Update the faulty access macros for str_array
Adds a testcase for the usage of the access macros, and also
updates the testsuite to only include what str_array requires.
This shows that str_array can be used separately by users.
2021-10-13 08:47:20 +02:00
Björn Svensson 673bb2f6d9 Remove declarations for nonexisting functions in str_array.h 2021-10-13 08:47:20 +02:00
Björn Svensson 4babe735e8 Remove cyclic dependency between str_array.h and r3.h
This also makes sure we dont get warnings regarding bool
redefinitions when building with clang.
2021-10-13 08:46:47 +02:00
Björn Svensson 0072b618b6 Check for existence of stdbool.h during CMake builds
The headerfile is searched for during autogen/autoconf builds to
determine when to include stdbool.h.
This let CMake builds have the same behavior.
2021-10-12 10:52:44 +02:00
Björn Svensson 00ec8b7f2b Correct buffer over-read errors
When inserting multiple routes with common slug patterns
there are reads beyond end of strings.

The scenario is added as a testcase and can be triggered by
the address-sanitizer when built using:
`CFLAGS="-fno-omit-frame-pointer -fsanitize=address" cmake ..`

Indicated as a `buffer-overflow`
2021-10-11 10:19:09 +02:00
Yo-An Lin d2fcf2f2d4
Merge pull request #135 from fishgege/patch-1
bugfix: insert path success, but get data failed
2021-10-07 22:08:13 +08:00
Yo-An Lin da0c89b6db
Merge pull request #137 from dthadi3/ppc64le
Travis-ci: added support for ppc64le
2021-10-07 22:07:24 +08:00
Yo-An Lin 3228fb8cb5
Merge pull request #141 from Nordix/multi-edge-corrections
Correcting issue and memory leak when using multiple edges
2021-10-07 22:07:02 +08:00
Björn Svensson ff1ef2c148 Correcting issue with multiple edges
When `r3_node_find_common_prefix()` searches for the common prefix it
selects the first matched edge, which might not be the best match.

This issue gives memoryleaks which can be viewed in legacy
testcase `check_tree::test_insert_pathl()` by building using:
`CFLAGS="-fno-omit-frame-pointer -fsanitize=leak" cmake ..`
See testcase procedures:
    ret = r3_tree_insert_path(n, "/foo/{id}",  NULL);
    ..
    ret = r3_tree_insert_path(n, "/foo/{idx}/{idy}",  NULL);
    ..
    ret = r3_tree_insert_path(n, "/foo/{idx}/{idh}",  NULL); <-- leaks

Also added a testcase that triggers the problem including a leak for
reproduction on baseline.
2021-09-20 16:55:37 +02:00
Devendranath Thadi ac7af9697c Travis-ci: added support for ppc64le 2020-11-18 14:14:29 +00:00
董宇 36198aefba
bugfix: insert path success, but get data failed
background : use  r3_tree_insert_pathl_ex to add path,A : abcdefg   B:abc
When the node A already exists, we set B, then  will split the node and make a branch, suboath_len  is 0 
In this case,  branch a  zero len subpath, which tree's data not set
2019-12-15 13:05:49 +08:00
Yo-An Lin e20e48a5ce
Merge pull request #128 from iresty/bug-end-maybe-0-len
bugfix: the end matching length is 0.
2019-08-06 10:22:30 +08:00
Yuansheng 79fd587615 feature: supported to match ipv6 address. 2019-08-01 21:38:14 -04:00
Yuansheng 1b9e007dfc bugfix: make a try for endpoint. 2019-07-21 08:46:37 -04:00
Yuansheng 81f77ffe5a test: added test cases. 2019-07-21 08:46:37 -04:00
Yuansheng 0d70b8f5de bugfix: the end matching length is 0. 2019-07-21 08:46:37 -04:00
Yo-An Lin 577cfa0ccb
Merge pull request #130 from iresty/typo
change: typo.
2019-07-21 19:30:50 +08:00
Yo-An Lin 3dac164cec
Merge pull request #126 from iresty/optimize-wildcard
optimize: optimized pattern `.*`, which can be used prefix matching.
2019-07-21 19:30:37 +08:00
Yuansheng f8a3741211 change: typo. 2019-07-21 09:14:37 +08:00
Yuansheng 845c47907f test: describe the test case name. 2019-07-21 07:48:11 +08:00
Yuansheng 2ad6b4c4f0 test: skip one test case, will fix it later. 2019-07-20 22:58:17 +08:00
Yuansheng 3364df80ee test: run test case check_routes2. 2019-07-20 22:55:44 +08:00
Yuansheng db91289ab6 change: rename OP_EXPECT_NOLINEBREAKS to OP_GREEDY_ANY. 2019-07-20 10:52:56 -04:00
Yuansheng d516237aab optimize: optimized pattern .*, which can be used prefix matching. 2019-07-20 10:52:56 -04:00
Yo-An Lin 41685d402d
Merge pull request #129 from iresty/make-warning
change: avoided compiling warning.
2019-07-20 18:00:48 +08:00
Yo-An Lin 27d4d3191e
Merge pull request #125 from iresty/feature-scheme
feature: supported to match http scheme.
2019-07-20 17:59:48 +08:00
Yo-An Lin fd34c7244a
Merge branch '2.0' into feature-scheme 2019-07-20 17:56:59 +08:00
Yo-An Lin 2b332bffba
Merge pull request #127 from iresty/check-more
test: run test case `check_remote_addr` in travis.
2019-07-20 17:55:17 +08:00
Yuansheng 91cfc9d282 test: run the test case check_http_scheme. 2019-07-20 07:21:05 +08:00
Yuansheng fdc698f924 change: avoided compiling warning message. 2019-07-20 07:12:37 +08:00
Yuansheng 0485554d44 change(tests/check_slug): avoided compiling warning. 2019-07-20 07:06:56 +08:00
Yuansheng 4b066dd0fc test: run all of the test cases. 2019-07-19 09:15:47 -04:00
Yuansheng 43666a1183 feature: supported to match http scheme. 2019-06-26 23:06:32 +08:00
Yo-An Lin 3f410ef5d4
Merge pull request #124 from iresty/make-WARN
make: avoided the warning message when do make at Ubuntu OS.
2019-06-21 12:55:15 +08:00
Yuansheng 8e18a995d8 make: avoided the warning message when do make.
change: code style, delete some useless spaces(visual code).

eg:

warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result
2019-06-21 10:45:54 +08:00
Yo-An Lin 410f66bc1a
Merge pull request #123 from iresty/feature-remote-ip
feature: supported to match remote ip address.
2019-06-20 11:47:46 +08:00
Yuansheng 848b8efdca feature: supported to match remote ip address. 2019-06-19 23:36:37 -04:00
Yo-An Lin 2a08bc62d5
Merge pull request #122 from iresty/feature-wildcard-host
feature: supported wildcard match way for host.
2019-06-20 11:29:52 +08:00
Yuansheng 917fa6e385 change: removed useless comments. 2019-06-20 11:21:04 +08:00
Yuansheng 4ab222a308 feature: supported wildcard match way for host. 2019-06-19 10:07:14 -04:00
Yo-An Lin 9761bdeec3
Merge pull request #119 from GuacheSuede/patch-1
Quick Includes Bug fix
2019-01-23 23:02:41 +08:00
Sakamoto 69e31ce07a
Quick Includes Bug fix 2019-01-23 01:02:04 +08:00
Yo-An Lin 22a6b99b34
Merge pull request #115 from msteinert/remove-zmalloc
Remove zmalloc
2018-07-10 07:36:49 -07:00
Michael Steinert 8abc03ea56 cmake: Add some comments regarding r3.pc.in 2018-07-10 08:24:05 -05:00
Michael Steinert b3dbf75da5 Remove zmalloc dependency
Zmalloc comes from Redis. It's purpose is to track total allocations so
that a maximum can be set. For more information see the following links:

https://groups.google.com/forum/#!topic/redis-db/dPRdpowqJsY
https://stackoverflow.com/questions/22729730/when-would-one-use-malloc-over-zmalloc

This allocator is slower, not needed, and conflicts with Zlib (when
linking statically). This patch removes Zmalloc in favor of the system
allocator. Application developers can still choose to override the
allocator in their applications, e.g. Jemalloc, TCMalloc, etc.

Fixes #104
2018-07-10 08:20:46 -05:00
Yo-An Lin afd2c486c6
Merge pull request #113 from msteinert/cleanup-cmake
Cleanup cmake
2018-07-10 06:11:41 -07:00
Michael Steinert e701bfd596 Add CMake to the CI matrix 2018-07-05 11:52:34 -05:00
Michael Steinert d1c06cd3e9 Cleanup CMake build files 2018-07-05 11:43:22 -05:00
Michael Steinert 2be2a08750 Fix -Wincompatible-pointer-types warning 2018-07-05 11:43:22 -05:00
Michael Steinert e9afe4b6cf Fix -Wdiscarded-qualifiers warnings 2018-07-05 11:43:22 -05:00
Yo-An Lin 3b9bb5745a
Merge pull request #114 from msteinert/check-tree-fixes
Fix issues with check_tree test
2018-07-06 00:42:01 +08:00
Michael Steinert 179ee52801 Attempt to update CI environment 2018-07-05 11:31:27 -05:00
Michael Steinert 081ccb2bde Fix issues with check_tree test
This patch fixes a few issues in the check_tree test:

* Fix various memory leaks in test code
* Fix a double-free in test code
* Fix a memory leak in r3_tree_compile_patterns

One memory leak remains in the library code but it isn't obvious to me
how to fix it at the moment.
2018-07-05 09:58:20 -05:00
Yo-An Lin cf92c9dc96
Merge pull request #108 from martijnotto/2.0
Initial working version of cmake builds
2018-02-25 02:02:25 +08:00
Martijn Otto 6565274ce8 We need 3rdparty for the normal build as well 2018-02-24 17:53:02 +01:00
Martijn Otto 1fceec760f We need to link to 3rdparty to be able to build the tests 2018-02-24 17:50:33 +01:00
Martijn Otto 2f96c59929 Further WIP, got the tests to link against pthread (was broken due to pkg-config not specifying -pthread as -lpthread and cmake thus not recognizing it as a library) 2018-02-24 17:45:15 +01:00
Martijn Otto a2396fe15b WIP on support for CMake builds, fails to build tests (probably error in FindCheck not declaring dependency on pthread) 2018-02-23 09:39:39 +01:00
Yo-An Lin 2b37680087
Merge pull request #107 from martijnotto/2.0
const correctness, branched assignment, unused variables, non-standard feature test, example UB, incorrect memset declaration
2018-02-21 23:01:03 +08:00
Martijn Otto 59d182b1c1 Use the generated config.h instead to enable feature macros 2018-02-21 15:57:25 +01:00
Martijn Otto 1eeff1598a Fix declaration of memset 2018-02-21 10:04:07 +01:00
Martijn Otto f8131b53d6 Fix UB in examples 2018-02-21 09:50:34 +01:00
Martijn Otto 55de164023 Set the feature test macro before including the header to enable non-standard functions used by libr3 2018-02-21 09:49:54 +01:00
Martijn Otto 8d0b90f6e1 Remove unused variables 2018-02-21 09:14:31 +01:00
Martijn Otto 5cab368af2 Add extra parenthesis around branched assignments 2018-02-21 09:11:53 +01:00
Martijn Otto 021c54308a Fix const correctness warnings 2018-02-20 18:18:43 +01:00
Yo-An Lin 0d78599a57 Merge pull request #103 from yohanboniface/fix-configure
Fix syntax error in configure.ac (fix #96)
2017-08-26 16:56:50 +08:00
Yohan Boniface 234e64f584 Fix syntax error in configure.ac (fix #96) 2017-08-26 10:50:30 +02:00
Yo-An Lin 7e4c74d625 Merge pull request #98 from phynalle/2.0
Add include headers
2017-07-02 10:00:11 +08:00
phynalle 267ab34c36 Add include headers 2016-04-27 03:45:11 +09:00
c9s cefefb239a Fix fprintf warning 2016-04-05 16:59:27 +08:00
c9s 341a29387b Merge branch 'krn_feature' of https://github.com/karantin2020/r3 into 2.0 2016-04-05 16:55:54 +08:00
karantin2020 9411039fce Router match logic corrected 2016-03-26 23:32:37 +05:00
karantin2020 ffc9e8571b Added memory files 2016-03-26 21:34:07 +05:00
karantin2020 75438ef3d3 Changed r3 memory model, made few optimizing 2016-03-22 07:23:37 +05:00
Yo-An Lin 0ba956159c Check is not running, fix check
Also update .travis.yml
2016-03-12 12:46:05 +08:00
Yo-An Lin 5a644ee046 Update README.md 2016-03-12 12:40:21 +08:00
karantin2020 ef910789c0 Added gitignored files 2016-03-08 22:30:44 +05:00
karantin2020 67fa8929f7 Clean heap after use in simple example 2016-03-08 19:52:47 +05:00
karantin2020 839001afec Changed routing example 2016-03-08 19:24:21 +05:00
karantin2020 40e0e1c2a0 Changed slug parsing 2016-03-08 14:51:42 +05:00
karantin2020 b7c0132fa9 Added routing example 2016-03-08 12:17:33 +05:00
karantin2020 400768394d Added slug parser and repaired few memory leaks 2016-03-08 11:19:54 +05:00
c9s c609003c95 optimize c flags for development/production mode 2015-11-21 10:39:49 +08:00
c9s 44ee48724f update link 2015-11-18 14:57:01 +08:00
c9s 82611c93b5 Update readme 2015-11-18 14:56:16 +08:00
c9s daee40756c Add -O2 flag as default 2015-11-18 14:46:18 +08:00
c9s 03031e02aa Fix r3 json writer 2015-11-18 14:27:28 +08:00
c9s c3ef959539 Add route namespace
Summary:

    type route now becomes R3Route

Related issue #63
2015-11-18 14:16:26 +08:00
c9s 29a2a934d0 Update examples in README 2015-11-18 14:09:04 +08:00
c9s ca5ad7497e Update changelog
Related: #63
2015-11-18 12:54:35 +08:00
c9s 49ffb454f7 Add namespace for node/edge structs
node => R3Node
edge => R3Edge

Related issue #63
2015-11-18 12:53:46 +08:00
c9s ef55fb9cdb Another fix for stdbool types 2015-11-17 21:43:10 +08:00
c9s 1f1ab15cdd Fix for stdbool type 2015-11-17 21:40:21 +08:00
c9s b0971e1553 Fix include 2015-11-17 21:35:18 +08:00
c9s c128cdef13 Provide better feature checking for stdbool 2015-11-17 21:31:33 +08:00
c9s 3808cb37aa Move debug macros to private header files 2015-11-17 21:24:36 +08:00
c9s a2f5205bc5 Update benchmark result 2015-11-17 21:18:41 +08:00
c9s 973a2cb85c Move private functions to private header files 2015-11-17 21:17:35 +08:00
c9s 6275e8724c Traivs: Add allow_failures section to matrix 2015-11-17 21:13:38 +08:00
c9s e5ef80a200 Move private function to src/str.h 2015-11-17 21:13:38 +08:00
Yo-An Lin 5e6252d8a3 Merge pull request #91 from RickySu/2.0-fix
add include config.h
2015-11-17 21:08:25 +08:00
c9s 63577cfecc Remove unused str_repeat function 2015-11-17 21:06:59 +08:00
Ricky Su 88dc323f7f add include config.h 2015-11-17 20:59:17 +08:00
c9s 38651578f9 Update matrix 2015-11-17 18:41:58 +08:00
c9s 122d85d9e1 Remove unused str* function decl 2015-11-17 18:33:33 +08:00
c9s 520dba47a5 ASAN test to be allowed failure 2015-11-17 18:32:51 +08:00
c9s dbc18a86c4 __attribute__ 2015-11-17 18:32:51 +08:00
c9s 2484b7328c Add clang compiler to the matrix 2015-11-17 18:32:51 +08:00
c9s af8acd0286 use __attribute aligned to align struct 2015-11-17 18:32:51 +08:00
c9s 35b8bb1cf2 Adjust window size 2015-11-17 18:32:51 +08:00
c9s 84a7d83812 Add padding to node struct 2015-11-17 18:32:51 +08:00
c9s 0407c48884 Add 2.0 to changelog 2015-11-17 18:32:51 +08:00
c9s b52af2acbd Add padding to edge structure 2015-11-17 18:32:51 +08:00
c9s 150f7953a2 Remove unneccessary comments from struct 2015-11-17 18:32:50 +08:00
c9s acb2ff1767 Move variable positions 2015-11-17 18:32:50 +08:00
c9s cd430968ef Add GNU likely/unlikely support 2015-11-17 18:32:50 +08:00
c9s 4ce9068963 Cache pointer of edge 2015-11-17 18:32:50 +08:00
c9s d4850d3564 Make edges as an array
Fixes: #89
2015-11-17 18:32:50 +08:00
c9s 28726b27af Fix r3_str.h header protection 2015-11-17 18:27:25 +08:00
c9s 89e4517772 Fix zero-length path insertion
Fixes: #86, #85
2015-11-17 16:10:26 +08:00
c9s f795785dce Implement faster edge branching 2015-11-17 16:08:01 +08:00
c9s 2f3bcb7116 refactoring testcase group 2015-11-17 15:37:10 +08:00
c9s b70c239b2c Fix benchmark warning 2015-11-17 15:37:10 +08:00
c9s 12947c74d0 update benchmark 2015-11-10 19:59:21 +08:00
c9s 3376d1b771 Judy array is not used. 2015-11-10 19:58:28 +08:00
c9s c18c466a9b use 64 * 3 bytes instead of 220 bytes for combined pattern 2015-11-10 19:56:07 +08:00
c9s fbe3fb66b1 Update benchmark 2015-11-10 19:48:37 +08:00
c9s a2994cfdac Reuse restlen 2015-11-10 19:48:22 +08:00
c9s 34269aa045 Change compare_type from char to int 2015-11-10 19:36:01 +08:00
c9s 0d9fbdbff7 update benchmark result 2015-11-10 19:35:09 +08:00
c9s 659dc19b1b Replace short integer with int to fit into cacheline (assume 64byte) 2015-11-10 19:29:18 +08:00
c9s 5d35d34ab3 Put pcre_extra back 2015-11-10 19:21:53 +08:00
c9s 3e57819bdf update benchmark result 2015-11-10 19:20:48 +08:00
c9s 6234166ffd Update benchmark csv 2015-11-10 19:18:02 +08:00
c9s 5002272a33 Move pointer fields to top of the structure 2015-11-10 18:43:25 +08:00
c9s b6d76f75c1 Update benchmark result on Macbook Pro Retina 2015-11-10 18:29:10 +08:00
c9s 5f39b73211 Add test_root_match test case 2015-10-18 07:39:50 +08:00
Yo-An Lin 031a37514e Merge pull request #83 from sjones608/cplusplus_bool
Don't typedef bool if compiling with C++
2015-10-01 09:56:22 +08:00
Steve Jones d12296af59 Don't typedef bool if compiling with C++
If using the C++ wrapper provided by r3.hpp, you get a compiler
error when r3_define.h tries to typedef bool as C++ already has
native bool type.  Modified the guard around this typedef
to include a check for C++ compilation (!defined(__cplusplus)).
2015-09-28 11:42:45 -05:00
Yo-An Lin eb2ff77e5c Merge pull request #82 from RickySu/memoryleak-fix
fix memory leak
2015-09-11 18:24:07 +08:00
Ricky Su 292b082c78 fix memory leak 2015-09-11 15:14:07 +08:00
Yo-An Lin d9a7deab9a Merge pull request #81 from RickySu/headerfile-fix
add extern c in c++
2015-08-28 14:00:08 +08:00
Ricky Su d5296df683 add extern c in c++ 2015-08-27 13:58:36 +08:00
Yo-An Lin 5eb3e483b3 Merge pull request #80 from RickySu/slug_find_name
add r3_slug_find_name and rename slug_count to r3_slug_count
2015-08-26 22:06:46 +08:00
Ricky Su f445c261c6 add r3_slug_find_name and rename slug_count to r3_slug_count 2015-08-26 22:00:23 +08:00
c9s 3a62cb6559 Fix cmake build 2015-03-05 11:45:39 +08:00
Gasol Wu 85f1b218a5 Make build sucessful 2015-02-12 13:21:50 +08:00
Gasol Wu 50643bb25f Add missing files from Pux 2015-02-12 13:21:50 +08:00
Gasol Wu 868ee4a27b Add workable config.m4 2015-02-12 13:21:50 +08:00
Brendan Ashworth 01239c96f6 Fixes typo 2015-02-12 12:44:41 +08:00
Brendan Ashworth ea286b2c56 Adds clib package.json for dependency management 2015-02-12 12:44:41 +08:00
Yo-An Lin 17276ae8eb Update README.md 2015-01-27 17:35:26 +08:00
Yo-An Lin c7fcba3ee5 Merge pull request #77 from pangyre/patch-1
Update README.md
2014-11-20 15:34:43 +08:00
Ashley Pond V 607a285426 Update README.md
Simple typo, s/Memroy/Memory/;
2014-11-19 19:46:30 -08:00
c9s 82143dfacb use am slient rule 2014-09-27 16:40:06 +08:00
Yo-An Lin 0f01283e78 Merge pull request #74 from PeterDaveHello/patch-1
make CI build faster
2014-08-14 07:06:39 +08:00
Peter Dave Hello 7a39929776 make CI build faster 2014-08-13 14:29:18 +08:00
c9s bd22e7b35c free slug object 2014-08-12 18:03:26 +08:00
Yo-An Lin 21dcdd5807 Merge pull request #70 from tonytonyjan/patch-2
Add a new binding link.
2014-08-09 17:49:45 +08:00
Yo-An Lin 84a27bdf05 Merge pull request #69 from tonytonyjan/patch-1
Update README.md
2014-08-09 17:49:27 +08:00
Yo-An Lin b80270afe9 Merge pull request #72 from kanru/fix-pcre-return-type
Fix pcre_exec's return type
2014-08-09 17:48:52 +08:00
Kan-Ru Chen (陳侃如) 3629452fe0 Fix pcre_exec's return type
According to PCRE_EXEC(3) pcre_exec returns int.

The original code uses char but char could be either signed or
unsigned. On armel and sparc this caused segment fault because
the (rc < 0) error checking was optimized out.
2014-08-04 01:07:37 +08:00
簡煒航 (Jian Weihang) 5d22dc54af Add a new binding link. 2014-07-30 05:28:33 +08:00
簡煒航 (Jian Weihang) 302763b783 Update README.md 2014-07-29 21:47:58 +08:00
Yo-An Lin 8c5b25949e Merge pull request #65 from czchen/feature/pcre
Use Requires for libpcre in r3.pc
2014-07-05 16:04:23 +08:00
Yo-An Lin 3963bddb1f Merge pull request #64 from czchen/feature/debug
Let --enable-debug define DEBUG instead of ENABLE_DEBUG in config.h
2014-07-05 16:03:46 +08:00
ChangZhuo Chen (陳昌倬) b3482c7792 Use Requires for libpcre in r3.pc 2014-07-04 21:27:56 +08:00
ChangZhuo Chen (陳昌倬) 6eb509beb2 Use ##__VA_ARGS__ to avoid build fail 2014-07-04 18:26:32 +08:00
ChangZhuo Chen (陳昌倬) 21d9c486c0 Use DEBUG instead of ENABLE_DEBUG in config.h 2014-07-04 18:25:22 +08:00
c9s 270fd1dd7b Fix image path 2014-06-28 01:25:29 +08:00
c9s 1dca0fb453 update changelogs 2014-06-28 00:54:43 +08:00
c9s 13900d44ba bump version to 1.3.3 2014-06-28 00:53:32 +08:00
c9s da026219be Fix gvc graph generator function 2014-06-28 00:53:04 +08:00
c9s 72f10015d5 Fix copyright email 2014-06-27 13:24:40 +08:00
c9s 1eeae6d26e bump version to 1.3.2 2014-06-27 00:18:22 +08:00
c9s 9a9572a0d5 Fix duplicated symbol define 2014-06-27 00:05:24 +08:00
c9s 04ac654440 Fix Makefile.am for C++ 2014-06-27 00:04:23 +08:00
c9s d00ac51809 Fix cmakelist 2014-06-27 00:04:22 +08:00
Yo-An Lin db35d03217 Merge pull request #62 from caasi/patch-2
Update README.md
2014-06-20 10:28:24 +08:00
caasi Huang 6e468fd5b5 Update README.md
* Try to fix the example: 'Routing with conditions'.
* Add two Node.js bindings.
2014-06-20 03:09:26 +08:00
Yo-An Lin 5e00b60f79 Merge pull request #61 from czchen/feature/ppa
Add ubuntu PPA link
2014-06-19 15:22:01 +08:00
ChangZhuo Chen (陳昌倬) cc253e069a Add ubuntu PPA link 2014-06-18 23:48:17 +08:00
c9s 7754043252 Include 3rdparty CMakeLists.txt 2014-06-18 20:54:46 +08:00
c9s a697301c44 strndup polyfill for cmake 2014-06-18 20:47:06 +08:00
c9s 8ebaac0536 Fix CMakeLists.txt 2014-06-18 20:28:13 +08:00
c9s fb0cb84c3c Put CMakeLists.txt back 2014-06-18 20:28:13 +08:00
c9s 25e3644630 put cmake_modules files back, we can support two build systems 2014-06-18 20:28:13 +08:00
Yo-An Lin 9eab3619c1 Merge pull request #60 from caasi/patch-1
initialize node.data
2014-06-14 05:51:59 +08:00
caasi Huang ce4095af35 initialize node.data 2014-06-14 00:55:24 +08:00
Yo-An Lin 3e03f8ed97 Merge pull request #58 from Ronmi/debian
Rename debian package directory
2014-06-13 10:29:08 +08:00
Ronmi Ren c103f669a0 Rename debian package directory to save package maintainers' life.
See https://github.com/c9s/r3/pull/55#issuecomment-45902891
2014-06-13 09:35:49 +08:00
Yo-An Lin 34e779c84a fix route cmp function 2014-06-12 21:01:16 +08:00
Yo-An Lin f74126e0a8 Merge pull request #57 from whitglint/master
Add C++ example.
2014-06-12 20:35:45 +08:00
whitglint 09cdbfaa60 Fix Travis CI compile error. 2014-06-12 20:05:24 +08:00
whitglint fb65694934 Fix Travis CI compile error. 2014-06-12 19:37:08 +08:00
c9s 98f27dadc9 test matched route data 2014-06-12 18:52:56 +08:00
Yo-An Lin db55c63b9d Merge pull request #56 from Ronmi/debian
Update package dependency and add instruction in readme
2014-06-12 18:48:22 +08:00
c9s 03b5d107cd fix route appending bug reported by @othree 2014-06-12 17:51:43 +08:00
whitglint 360646e680 Add C++ example. 2014-06-12 16:55:44 +08:00
Ronmi Ren a8cd804402 add instruction about packaging in README 2014-06-12 16:30:14 +08:00
Ronmi Ren f21d070803 fix dependency 2014-06-12 16:30:14 +08:00
Yo-An Lin 594d5361dd Merge pull request #55 from Ronmi/debian
Debian packaging for r3
2014-06-12 15:47:13 +08:00
Ronmi Ren 5361a52b58 initial debian packaging 2014-06-12 11:24:44 +08:00
c9s 31974a6e9c fix gvc generate function 2014-06-11 21:54:08 +08:00
c9s 2c5f135600 macro rename 2014-06-10 20:18:59 +08:00
c9s 7f8684d808 put compare_type to the second place 2014-06-10 20:18:18 +08:00
c9s b7a20774f2 struct field bit 2014-06-10 20:16:33 +08:00
c9s 4611566512 fix version 2014-06-08 13:13:31 +08:00
Pedro 4180b30be3 Update README.md 2014-06-07 19:03:23 +08:00
c9s f4b776ce35 clean up bench str 2014-06-05 08:07:04 +08:00
c9s 2e7ec1357d quick "for" statement 2014-06-05 07:45:34 +08:00
c9s e4eada3250 pcre match optimization 2014-06-05 07:43:51 +08:00
c9s 5137d4d8e4 simplify functions to macro 2014-06-04 23:13:08 +08:00
c9s 8e39e58c88 refactoring matchl function 2014-06-04 23:04:04 +08:00
c9s 36a330292b update benchmark 2014-06-04 20:28:50 +08:00
c9s f03fcf7a5b parameter optimization 2014-06-04 20:02:25 +08:00
c9s a1afa303f2 Add run-benchmark script 2014-06-04 20:02:24 +08:00
c9s a7a3621cfe use while instead of for 2014-06-04 20:02:24 +08:00
c9s 190986fb31 use while instead of for loop to simplify execution 2014-06-04 20:02:24 +08:00
Pedro c5ed7e202c Merge pull request #50 from whitglint/master
Add C++ wrapper.
2014-06-04 17:47:22 +08:00
whitglint a361e1fe58 Add r3.hpp to Makefile.am. 2014-06-04 17:24:29 +08:00
whitglint 6834f0eccd Add C++ wrapper. 2014-06-04 16:46:31 +08:00
c9s c5dce1d232 CHECK_PTR 2014-06-04 16:22:28 +08:00
c9s dc61d54530 free tree2 2014-06-04 16:01:19 +08:00
c9s 7171c2b195 reset pcre_extra NULL 2014-06-04 15:59:13 +08:00
c9s 47dcc6921b update README 2014-06-04 14:57:34 +08:00
c9s ea2efdaaea Fix readme 2014-06-04 14:54:42 +08:00
c9s 911eb17bf4 configure.ac fix for debian platform 2014-06-04 14:43:09 +08:00
c9s 4d68ae6841 remove const from errstr 2014-06-04 13:45:28 +08:00
c9s 15ad4b5890 fix sample code 2014-06-03 23:51:26 +08:00
c9s b2946352f1 Add r3_tree_insert_routel_ex for error message 2014-06-03 23:50:02 +08:00
c9s a3c527e1b2 Add const fix 2014-06-03 23:42:40 +08:00
c9s 2ff85c876d Fix simple.c and examples/Makefile.am 2014-06-03 22:41:39 +08:00
c9s db45ae3e53 fix typo 2014-06-03 22:37:09 +08:00
c9s cbd9c1cda8 fix simple 2014-06-03 22:31:30 +08:00
c9s 24db602d1a remove cast 2014-06-03 22:21:40 +08:00
c9s 23cfbe167f const fix 2014-06-03 22:20:54 +08:00
c9s 2aa3509845 Add more const 2014-06-03 22:15:59 +08:00
c9s da87115761 Add Makefile 2014-06-03 22:10:12 +08:00
c9s 4b2a80112e include simple.c 2014-06-03 22:09:49 +08:00
c9s c7220c5616 combine match_entry functions into r3.h 2014-06-03 22:07:46 +08:00
c9s bad59e99be Update include_headers 2014-06-03 22:07:21 +08:00
c9s a736672323 reduce variable declaration 2014-06-03 22:02:47 +08:00
c9s f95cce7407 fix header file include 2014-06-03 21:47:52 +08:00
c9s 5609fd5f9e r3 function prefix
- Remove ltrim_slash.
- Add "r3_" prefix to r3_str.c functions.
2014-06-03 20:50:19 +08:00
c9s 053f9202f6 merge graphviz function prototype into r3.h 2014-06-03 20:47:35 +08:00
c9s 09da7a0b6c update README 2014-06-03 20:44:35 +08:00
c9s 8bb68ab31d update README 2014-06-03 18:52:40 +08:00
c9s 7b65457e52 Update changelog for 1.3.0 2014-06-03 18:48:55 +08:00
c9s f3da92936c README update 2014-06-03 18:42:47 +08:00
c9s 4ac3d74fd3 more graphviz API 2014-06-03 18:41:55 +08:00
c9s b68e14dd66 r3_tree_render_dot(const node * tree, FILE *fp); support 2014-06-03 18:37:36 +08:00
c9s 67366bf688 fix warnings 2014-06-03 18:23:28 +08:00
c9s 8cbce697eb update example code 2014-06-03 18:19:07 +08:00
c9s 12de194a28 update sample code 2014-06-03 18:17:18 +08:00
c9s 65052fbe5c update README 2014-06-03 18:14:52 +08:00
c9s cee5d0a3e0 update benchmark result 2014-06-03 17:01:11 +08:00
Pedro 7c7e8b22e4 update assert statement 2014-06-03 02:13:52 +08:00
Pedro b6bf81e3e9 Replace -1 ret code 2014-06-03 02:09:11 +08:00
c9s db0e1c074f SUBDIRS sequences 2014-06-03 00:47:06 +08:00
c9s f26397c74c update benchmark records 2014-06-02 20:54:42 +08:00
c9s d8945980a7 tighter structure 2014-06-02 20:51:35 +08:00
Pedro 8e3a35b06f Merge pull request #49 from CindyLinz/patch-1
Update r3.h
2014-06-02 17:20:49 +08:00
Cindy Wang 7cae9bf71a Update r3.h
fix comment.. :p
2014-06-02 16:34:02 +08:00
c9s 2890ed142e document return code 2014-06-02 16:24:32 +08:00
c9s af5a89b3ea Add test_insert_pathl_fail test 2014-06-02 16:20:02 +08:00
c9s 712767c5b6 Add more errstr pointer check 2014-06-02 16:15:44 +08:00
c9s ea7fa973cd Add SAFE_FREE for char * errstr 2014-06-02 16:12:27 +08:00
c9s 15021b11c9 reset prefix_len = 0 2014-06-02 16:08:46 +08:00
c9s 1f21ea19a8 Add char ** errstr to r3_node_find_common_prefix 2014-06-02 15:52:40 +08:00
c9s 7cc84867ce let slug_count returns -1 if error occurs 2014-06-02 15:47:02 +08:00
c9s 2774221ab7 return error 2014-06-02 15:12:28 +08:00
c9s 04d8977b21 r3_tree_insert_pathl_ex function 2014-06-02 14:47:46 +08:00
c9s 16d7cc207f clean up debug code 2014-06-02 14:10:29 +08:00
c9s 324d7014b4 update coverall --exlude option 2014-06-02 10:24:23 +08:00
Pedro 33e16138bd Merge pull request #48 from c9s/slug-parser
slug fix and tests
2014-06-02 10:21:48 +08:00
c9s 6333261f28 ck_assert not null 2014-06-02 10:17:35 +08:00
c9s 7d69ec1d81 regenerate tests 2014-06-02 10:15:50 +08:00
c9s dbefe7534e replace ck_assert_int_gt 2014-06-02 10:12:16 +08:00
c9s d370985048 Add endpoint tests 2014-06-02 10:07:50 +08:00
c9s 8c35987760 More and more routes tests 2014-06-02 10:06:10 +08:00
c9s ba1106df4b Add auto-generated route tests 2014-06-02 10:03:58 +08:00
c9s f2c8005707 Test failing test case 2014-06-02 09:51:42 +08:00
c9s 2465ee4ffe fix all tests 2014-06-02 09:49:13 +08:00
c9s 9441f974de test compile fail 2014-06-02 09:48:00 +08:00
c9s fd1e5f7f50 Add r3_node_find_common_prefix test cases 2014-06-02 09:09:41 +08:00
c9s 9f58a5b651 comment for the function 2014-06-02 08:19:44 +08:00
c9s b4ce60de59 separate check_str_array test cases 2014-06-02 08:13:19 +08:00
c9s f3bf32b922 refactor path insert function 2014-06-02 08:04:57 +08:00
c9s f5221fd5c9 another test path 2014-06-02 07:14:16 +08:00
c9s aace74f7a5 more paths tests 2014-06-02 07:13:47 +08:00
c9s 20c6a84f7c continue when escape 2014-06-02 07:10:31 +08:00
c9s b80f90dad9 -D_BSD_SOURCE=1 2014-06-02 07:03:32 +08:00
c9s 7597398c08 include config.h 2014-06-02 06:58:02 +08:00
c9s 2a7998b76f free slug err msg 2014-06-02 06:56:51 +08:00
c9s b2a9ad47d8 fprintf to print error to stderr 2014-06-02 06:53:31 +08:00
c9s 9271f0bf08 free the variable 2014-06-02 06:50:24 +08:00
c9s 57b4fde126 print errmsg 2014-06-02 06:48:00 +08:00
c9s d120389415 more path tests 2014-06-02 06:40:27 +08:00
c9s 17b4201197 more incomplete slug pattern tests 2014-06-02 06:38:50 +08:00
c9s a6be7f5061 static inline 2014-06-02 06:32:30 +08:00
c9s 0eb9cad11c r3_path_contains_slug_char function 2014-06-02 06:27:35 +08:00
c9s 3512bf033a seems like travis dont have libjson-c 2014-06-02 06:16:52 +08:00
c9s 493a9d7d8e Add coverage option to gcc 2014-06-02 06:14:23 +08:00
c9s ee7f1d32f7 install libjson-c 2014-06-02 06:05:20 +08:00
c9s 7cfdfbb3f5 inline static 2014-06-02 06:01:42 +08:00
c9s 44b8068c58 check_json.c 2014-06-02 05:59:57 +08:00
c9s 2e6fc6f0f1 fix warnings 2014-06-02 05:57:18 +08:00
c9s f9b7dd8522 fix prototype 2014-06-02 05:56:46 +08:00
c9s 00c364dacb const 2014-06-02 05:55:45 +08:00
c9s c801164c88 contains_slug_char declare 2014-06-02 05:53:39 +08:00
c9s fcc00deadb Merge branch 'slugfix' of github.com:c9s/r3 into slugfix 2014-06-02 05:50:49 +08:00
c9s 20e3f1a3ba asprintf returns memory pointer which is from malloc() not zmalloc() 2014-06-02 05:48:27 +08:00
c9s 8775c3ff85 wtf 2014-06-02 05:31:47 +08:00
c9s d4d1a59728 fix autotools for check 2014-06-02 05:23:00 +08:00
c9s 359d9df369 improve r3_slug_parse function 2014-06-02 05:02:37 +08:00
c9s 6dfd37d43d move slug related functions to slug.c and slug.h 2014-06-02 04:52:41 +08:00
c9s 2a75861741 Fix gvc graph 2014-06-02 01:35:58 +08:00
c9s 80b9f00739 update 2014-06-02 01:24:49 +08:00
c9s 24b84d068d Merge branch 'master' into slugfix
Conflicts:
	tests/check_slug.c
2014-06-02 01:23:10 +08:00
c9s 0636c9dad3 fix slug compile pattern 2014-06-02 01:21:02 +08:00
c9s 39fc24e3fa fix pattern compiler 2014-06-02 01:05:57 +08:00
c9s c52639c431 slug parser 2014-06-02 01:01:29 +08:00
c9s e1e5c3a4ae test incomplete slug 2014-06-02 00:27:30 +08:00
c9s 258128f30d slug_count return errstr 2014-06-02 00:22:12 +08:00
c9s da2f2311c9 CHECK_PTR macro to check pointer 2014-06-01 21:58:29 +08:00
c9s 70693ea1f2 errstr parameter in slug 2014-06-01 20:51:47 +08:00
c9s 2858ede695 Update new combined graphviz image 2014-06-01 20:30:22 +08:00
c9s dc407f2cac fix 2014-06-01 20:23:11 +08:00
c9s 8d2a473f54 Merge branch 'master' of github.com:c9s/r3
Conflicts:
	include/r3.h
2014-06-01 20:20:51 +08:00
c9s 779d9a9859 Merge branch 'feature/json' 2014-06-01 20:19:30 +08:00
c9s 76182660f9 remove trailing newline 2014-06-01 20:15:25 +08:00
c9s c5501ab5f6 fix configure options:
1. fix --enable-json
2. fix --enable-graphviz
2014-06-01 20:14:56 +08:00
c9s 8f9c2acc5c include config.h 2014-06-01 19:49:56 +08:00
c9s 9820384ed5 take off useless header files 2014-06-01 19:45:56 +08:00
c9s 7d6209d99c build with 3rdparty objects
use -static linking when linking libr3

AM_CFLAGS and AM_LDFLAGS are Makefile.am scope options

disable valgrind tracing check-tree

Makefile.am fix

Add json support

remove useless c files
2014-06-01 19:43:45 +08:00
Pedro 93c3d0769b Merge pull request #44 from whitglint/master
Add extern "C".
2014-06-01 17:00:07 +08:00
whitglint 9417bc76eb Add extern "C". 2014-06-01 16:48:54 +08:00
c9s 7cdfaa0f7f Add AC_PROG_INSTALL 2014-06-01 16:39:32 +08:00
c9s b139d8d3f2 add const to node 2014-06-01 14:54:16 +08:00
c9s 7d69e79535 gvc fix 2014-06-01 14:53:12 +08:00
c9s 6e6de35fd0 fix tests for graphviz 2014-06-01 14:41:45 +08:00
c9s adde7bc361 remove unused variables 2014-06-01 14:35:29 +08:00
c9s 8ee11aaa6f reduce variables and add const char* to insert_pathl. 2014-06-01 14:33:56 +08:00
c9s f5f24aa15e fix readme 2014-06-01 03:04:59 +08:00
c9s 998560634e remove unused variable and add const 2014-06-01 02:58:03 +08:00
c9s 40fa19002a Add const for slug_compile 2014-06-01 02:56:29 +08:00
c9s bc27293f36 more const 2014-06-01 02:54:48 +08:00
c9s 8f8dbd520b remove const from match_entry pointer 2014-06-01 02:39:39 +08:00
Pedro 89fb801cfd Merge pull request #43 from c9s/errno
errno support
2014-06-01 02:33:13 +08:00
c9s 2df5c11d09 use ck_assert 2014-06-01 02:29:12 +08:00
c9s a946a79223 include assert.h 2014-06-01 02:28:58 +08:00
c9s 4c26995e41 assert errno == NULL 2014-06-01 02:13:38 +08:00
c9s f670f08639 update error code for compile function 2014-06-01 02:08:16 +08:00
c9s 1a4eb14a05 error code support
- return error code if compilation error occurs
- use asprintf to sprint errstr
2014-06-01 02:03:44 +08:00
c9s 642fdfca88 include assert 2014-06-01 01:40:28 +08:00
c9s fe57cbf54d check pointer 2014-06-01 01:38:22 +08:00
c9s 4bb3ba9d04 assert(entry); 2014-06-01 01:26:59 +08:00
c9s 4f93a530e1 assert free 2014-06-01 01:26:36 +08:00
c9s 188a687150 check the pointer returns from zmalloc 2014-06-01 01:25:34 +08:00
c9s a19d2377cc check the pointer returns from zmalloc 2014-06-01 01:24:57 +08:00
c9s 7d9b6c8889 check match_entry->vars 2014-06-01 01:20:28 +08:00
c9s b61d5a78ae fix match_route 2014-06-01 01:16:53 +08:00
c9s e182dd3a7b remove duplicated edge free function 2014-05-31 19:58:10 +08:00
c9s 9433e2192a route api improvement 2014-05-31 19:56:46 +08:00
c9s 15933a061e update include header files 2014-05-29 10:14:25 +08:00
c9s e74deece23 include assert.h 2014-05-28 23:01:21 +08:00
c9s c58d48f962 Fix include 2014-05-28 21:56:22 +08:00
c9s d400789d96 more const pointers 2014-05-28 21:09:37 +08:00
c9s 072c72621c separate header files 2014-05-28 21:08:06 +08:00
c9s 9cb2f80e1f more const pointers 2014-05-28 21:03:59 +08:00
c9s a2bec00a9e match_entry.c 2014-05-28 21:02:57 +08:00
c9s f5996731ca Add const for pointers 2014-05-28 21:00:02 +08:00
c9s 34ec73ecbc enable -Wall for tests 2014-05-28 20:56:16 +08:00
c9s e12ca5840e Add email to CHANGES.md 2014-05-27 21:17:23 +08:00
c9s 1c1063e3b6 update CHANGES 2014-05-27 21:16:46 +08:00
c9s cd16d67663 fix zcalloc bug 2014-05-27 14:18:45 +08:00
c9s cf734a480c edge branch with routes and other resets 2014-05-27 14:16:42 +08:00
c9s 60821aac0c const pointer 2014-05-27 12:35:17 +08:00
c9s f596c7392d Add const 2014-05-27 12:34:28 +08:00
c9s 10d6a64eac update README 2014-05-27 12:32:07 +08:00
c9s 6cc57d545f const char * 2014-05-27 01:08:31 +08:00
c9s 9f8176447b const char * 2014-05-27 01:08:01 +08:00
c9s 54397987bd Add const 2014-05-27 01:07:33 +08:00
c9s 533eb6b9c3 include stdbool.h 2014-05-27 00:47:59 +08:00
c9s aaf35d22d8 include stdbool.h 2014-05-27 00:47:21 +08:00
c9s f597239986 fix 2014-05-26 21:44:48 +08:00
c9s 7aaed3e5d7 merge str_array.h 2014-05-26 21:39:36 +08:00
c9s a99547bea5 update pc config 2014-05-26 21:29:56 +08:00
c9s 94c71b5431 move frequently used fields to struct head. 2014-05-24 19:04:34 +08:00
c9s ef9962c958 struct field data type improvement for memory usage. 2014-05-24 18:45:43 +08:00
c9s da47f06bdc update benchmakr result 2014-05-24 17:22:29 +08:00
c9s 568400c1b7 Add more benchmark record 2014-05-24 17:16:49 +08:00
c9s 0909ab8af9 put combined_pattern to the end of struct 2014-05-24 17:14:17 +08:00
c9s c1cd7444cb Add struct fields optimization 2014-05-24 17:13:55 +08:00
c9s dcf4bf0f14 update README for steps 2014-05-24 16:28:53 +08:00
c9s 7b70d436e8 update .travis.yml config 2014-05-24 16:27:43 +08:00
c9s c69d483fc7 fix configure script for check 2014-05-24 16:26:47 +08:00
c9s 3104802101 TESTS += benchmark 2014-05-24 16:23:41 +08:00
c9s adc96ae2d2 unset if config.h is not found. 2014-05-24 15:50:12 +08:00
c9s 6f66cc4f7a check check.h automatically 2014-05-24 15:49:47 +08:00
c9s b737fbb130 remove AM_PATH_CHECK 2014-05-24 15:46:45 +08:00
c9s a5217a9362 do not install benchmark to prefix/bin 2014-05-24 15:41:20 +08:00
c9s 6358da7df8 Add --enable-check option 2014-05-24 15:41:02 +08:00
c9s f3c6296a7a Fix the extra "check" checking 2014-05-24 15:30:57 +08:00
Pedro 3fd773f889 Update README.md 2014-05-23 21:03:40 -05:00
c9s 8c7a148014 Update changelog 2014-05-23 23:30:58 +08:00
c9s 186531c5b4 partially 2014-05-23 23:20:32 +08:00
c9s 08bad93d56 update doc 2014-05-23 23:17:58 +08:00
c9s fd0a4f9b02 document about optimization and slug 2014-05-23 23:15:32 +08:00
c9s 591b6cd4c1 when matching pcre do not switch check rc 2014-05-23 23:00:49 +08:00
c9s 628f09a8f4 Add OP_EXPECT_MORE_ALPHA opcode 2014-05-23 22:58:20 +08:00
c9s 5f75677369 do not check benchmark program 2014-05-23 22:50:55 +08:00
c9s 25e107484e Add function prefix description 2014-05-23 22:46:35 +08:00
c9s 6881c47ee6 update legend title 2014-05-23 22:40:12 +08:00
c9s 9a1f7cfced update benchmark records 2014-05-23 17:36:47 +08:00
c9s d02e16a65c improve stack allocation 2014-05-23 16:18:58 +08:00
c9s b394be57cb support simple opcode 2014-05-23 16:18:58 +08:00
c9s 333fabd795 insert path for opcode 2014-05-23 16:18:58 +08:00
c9s dcc57845aa update benchmark result 2014-05-23 16:18:58 +08:00
c9s fe70b55253 Add node type for comparison 2014-05-23 16:18:57 +08:00
c9s 403b1d9ba2 Add opcode to edge 2014-05-23 16:18:57 +08:00
c9s 7d16413cb3 more benchmark result 2014-05-23 16:18:57 +08:00
c9s 52fd5979c0 move ov to stack variable 2014-05-23 16:18:57 +08:00
c9s d6a0d9ba96 more benchmark result 2014-05-23 16:18:57 +08:00
c9s 21f7b2df92 delete old bench_str.csv 2014-05-23 16:18:57 +08:00
c9s be899b7bcb move bench_str.csv 2014-05-23 16:18:57 +08:00
c9s 93f4654c54 pass studied pattern 2014-05-23 16:18:57 +08:00
c9s ad6b7b236f combined_pattern_len is not used 2014-05-23 16:18:57 +08:00
c9s 3f4fcb8c27 remove duplicate header include 2014-05-23 16:18:56 +08:00
c9s c1e5ea4393 Add OP_EXPECT_NODASH opcode 2014-05-23 16:18:56 +08:00
c9s 4d93d217a4 test r3_pattern_to_opcode 2014-05-23 16:18:56 +08:00
c9s a41c9187ac Add some basic opcode 2014-05-23 16:18:56 +08:00
c9s 59e6997959 there is already a pointer guard in zmalloc 2014-05-23 16:18:56 +08:00
c9s c841de166c free old pattern 2014-05-23 16:18:56 +08:00
Pedro 55d74bd133 Merge pull request #38 from czchen/feature/cleanup
Feature/cleanup
2014-05-22 11:31:55 -05:00
c9s 63bf604d9e fix request method code 2014-05-23 00:21:40 +08:00
ChangZhuo Chen (陳昌倬) fb88655df0 Remove CMake related files 2014-05-22 22:53:49 +08:00
ChangZhuo Chen (陳昌倬) b807152490 Remove auto generated test-driver 2014-05-22 22:44:06 +08:00
ChangZhuo Chen (陳昌倬) cacfb32d49 Remove auto generated install-sh 2014-05-22 22:43:55 +08:00
ChangZhuo Chen (陳昌倬) 783c755a8a Remove auto generated config.h & config.h.in 2014-05-22 22:41:47 +08:00
c9s 62bb4e5460 remove unnecessary pointer check 2014-05-22 22:26:46 +08:00
c9s fe5c2381b5 remove point checking in str_array_free 2014-05-22 22:23:47 +08:00
c9s 288cdc91dd R3_LIST_H 2014-05-22 22:22:03 +08:00
c9s 5a10c82ea5 R3_NODE_H as the include guard 2014-05-22 22:21:29 +08:00
c9s 15facc82cc Merge branch 'feature/asan' of https://github.com/czchen/r3 into czchen-feature/asan
Conflicts:
	.travis.yml
2014-05-22 22:07:52 +08:00
ChangZhuo Chen (陳昌倬) fef3361ed2 Set test timeout to 30 2014-05-22 22:06:11 +08:00
c9s 5d82ae0f82 Fix benchmark rendering 2014-05-22 21:57:33 +08:00
c9s fc1a4b762d Separate benchmark application 2014-05-22 21:55:41 +08:00
c9s ce1f3cdc3f Update legend style 2014-05-22 21:44:31 +08:00
c9s e165d8e27a update legend text 2014-05-22 21:38:46 +08:00
c9s 8cea8701f4 set line-width to 1 2014-05-22 21:37:36 +08:00
c9s ebf528281d Add pcre benchmark to chart 2014-05-22 21:37:12 +08:00
c9s fa6a7b77e0 Add pcre_benchmark test case 2014-05-22 21:18:17 +08:00
c9s c9fe373d91 benchmark function improvements 2014-05-22 21:01:25 +08:00
c9s 7f97440c72 Add bench_append_csv to combine multiple benchmark result in one entry 2014-05-22 20:48:01 +08:00
c9s 3879316e08 Add bench_duration function
Conflicts:
	tests/bench_str.csv
2014-05-22 20:32:14 +08:00
c9s 7e44ee01f4 refactor Benchmark related macros
Conflicts:
	tests/bench_str.csv
2014-05-22 20:31:18 +08:00
ChangZhuo Chen (陳昌倬) 291e6add6b Use verbose make 2014-05-22 12:01:27 +08:00
c9s 18b2cf644d update README 2014-05-22 11:59:45 +08:00
c9s f5222c6bc2 update config.h.in 2014-05-22 11:54:42 +08:00
c9s 91097e3119 enable jemalloc only when major version > 2 2014-05-22 11:54:01 +08:00
c9s 9d26a53a08 update Makefile.am 2014-05-22 11:42:19 +08:00
c9s c503a6d5d3 use jemalloc only in jemalloc major version > 2 2014-05-22 11:41:51 +08:00
c9s 1fdfaef16e what if we always use -ljemalloc 2014-05-22 11:34:37 +08:00
c9s aed75694e6 ignore config.h 2014-05-22 11:09:45 +08:00
c9s 06324f48ab delete generated config.h 2014-05-22 11:09:45 +08:00
c9s c1abe926bf Add --with-malloc to travis config 2014-05-22 11:09:44 +08:00
c9s dc24b7cb97 remove jemalloc 2014-05-22 11:09:44 +08:00
c9s a8cec68f72 use -std=c99 2014-05-22 11:09:44 +08:00
c9s 594b10cbcb travis-ci is using jemalloc 2.1+ 2014-05-22 11:09:44 +08:00
c9s 2d4bd48116 Fix autoconf checking 2014-05-22 11:09:44 +08:00
c9s 07ef938e3d check jemalloc version 2014-05-22 11:09:44 +08:00
c9s 4d0c22d8ec fix linking issue 2014-05-22 11:09:44 +08:00
c9s 2c4236f5b8 include zmalloc.h 2014-05-22 11:09:43 +08:00
c9s 03c351dfe0 Update autoheader template 2014-05-22 11:09:43 +08:00
c9s e48538c526 check USE_JEMALLOC flag in Makefile.am 2014-05-22 11:09:43 +08:00
c9s a3866114e3 Add --with-malloc option to check jemalloc 2014-05-22 11:09:43 +08:00
c9s 98a66f0c41 Merge branch 'bugfix-32' 2014-05-22 11:08:56 +08:00
c9s e8653eeb28 include jemalloc.h 2014-05-22 11:06:34 +08:00
c9s eaa11d5380 found flag for slug char 2014-05-22 11:06:34 +08:00
Pedro a80c9378f8 Merge pull request #34 from mattn/am_path_check
AM_PATH_CHECK is deprecated
2014-05-22 01:22:49 +08:00
mattn 7e13b0be9c AM_PATH_CHECK is deprecated, so check it defined 2014-05-22 01:14:37 +09:00
ChangZhuo Chen (陳昌倬) bd95ce9355 Set llvm-symbolizer path 2014-05-21 22:56:08 +08:00
ChangZhuo Chen (陳昌倬) a5ce8b6e08 Add address sanitizer build to travis-ci 2014-05-21 22:56:08 +08:00
c9s f6d2502896 include jemalloc.h 2014-05-21 22:08:25 +08:00
c9s 45690da3dc found flag for slug char 2014-05-21 22:05:10 +08:00
c9s e7aaaac63f delete generated config.h 2014-05-21 21:58:30 +08:00
c9s 33eea25926 check length 2014-05-21 20:30:35 +08:00
Pedro ceb615335b Merge pull request #31 from thedrow/patch-1
Running valgrind in a different build in order to detect memory leaks.
2014-05-21 19:41:40 +08:00
Omer Katz 5dbef0cf24 Seriously travis? sudo won't give me permissions?? 2014-05-21 14:30:06 +03:00
Omer Katz a23c6c4875 Forgot to sudo. 2014-05-21 14:22:24 +03:00
Omer Katz 08a127d30c Making sure that the .so files are on the ldconfig path. 2014-05-21 14:19:13 +03:00
Omer Katz 4e702e92fb Installed the compiled shared libraries globally. 2014-05-21 14:06:23 +03:00
c9s e7c1b3c29d remove benchmark result with debug option 2014-05-21 19:03:05 +08:00
c9s d86f6dd12c Merge remote-tracking branch 'origin/master' into thedrow-patch-1 2014-05-21 18:51:12 +08:00
c9s 79fb3a3b8a check_slug: free memory 2014-05-21 18:50:45 +08:00
c9s 27531aac56 remove benchmark result with debug flags 2014-05-21 18:36:52 +08:00
c9s 7755f3a035 Merge branch 'patch-1' of https://github.com/thedrow/r3 into thedrow-patch-1 2014-05-21 18:35:31 +08:00
c9s 05b698b841 r3_tree_matchl does not return int 2014-05-21 18:31:51 +08:00
c9s b83946e487 check macro PCRE_STUDY_JIT_COMPILE to compile pcre with JIT 2014-05-21 18:28:21 +08:00
c9s 946bac8f3c seems like pcre_free_study is not defined on older ubuntu 2014-05-21 18:26:08 +08:00
c9s 82ea09e146 when we free it, we know it's not NULL 2014-05-21 18:22:11 +08:00
c9s 834d87173a Fix variable name 2014-05-21 18:21:15 +08:00
c9s 175b594234 Fix 2014-05-21 18:20:48 +08:00
c9s 238aee085f use pcre's own functions to free pcre related structures 2014-05-21 18:17:51 +08:00
c9s 6762025fe6 free edge struct 2014-05-21 18:17:51 +08:00
c9s 7d288404c7 libpcre does not use zmalloc 2014-05-21 18:17:51 +08:00
Pedro c281619b57 Merge pull request #28 from thedrow/topic/zmalloc
Added zmalloc from redis in order to support different allocators
2014-05-21 18:17:33 +08:00
Omer Katz 7303bc8f00 More guarding against freeing NULL pointers. 2014-05-21 12:50:56 +03:00
Omer Katz 61b3b24e2e Guarding against freeing NULL pointers. 2014-05-21 12:46:56 +03:00
Omer Katz cd4d4647de Bash is being touchy. 2014-05-21 12:02:52 +03:00
Omer Katz 86cdf3800e Fixed bash syntax errors. 2014-05-21 12:00:18 +03:00
Omer Katz 1c8c63e0a5 Fixed a bash syntax error. 2014-05-21 11:44:24 +03:00
Omer Katz 3ea9354e0b Implemented zstrndup. 2014-05-21 11:39:49 +03:00
Omer Katz e0ed62e308 Running valgrind in a different build in order to detect memory leaks. 2014-05-21 11:29:36 +03:00
Omer Katz e34759c1aa Using zstrndup instead of strndup) 2014-05-21 11:18:12 +03:00
Omer Katz 18a92867fc Removed wrong call to zfree that caused a segfault. 2014-05-21 11:14:12 +03:00
Omer Katz 0e627e33d5 Fixed all warnings from tests. 2014-05-21 10:50:37 +03:00
c9s de5a308002 fix header includes 2014-05-21 14:59:07 +08:00
c9s b1939e287d Merge branch 'topic/zmalloc' of https://github.com/thedrow/r3 into thedrow-topic/zmalloc 2014-05-21 14:51:25 +08:00
c9s 5a84e9aeb2 update pcre match error message 2014-05-21 14:27:04 +08:00
Omer Katz 9c191682da Added zmalloc from redis in order to allow different allocators. 2014-05-20 20:50:15 +03:00
c9s ad8faeb787 Update test results 2014-05-21 01:41:45 +08:00
c9s 0064eb27a1 const to node * n 2014-05-21 01:22:49 +08:00
c9s 0d2ae75bc2 prefetch firstbyte 2014-05-21 01:20:18 +08:00
c9s e9797295b5 Fix endpoint when branching edges 2014-05-21 01:15:54 +08:00
c9s 99198297c2 update test description 2014-05-21 00:55:43 +08:00
c9s aae35c3b90 more test case 2014-05-21 00:49:08 +08:00
c9s 5bd1757e5f function name fix 2014-05-21 00:47:09 +08:00
c9s cae305b92d when child is not endpoint, return NULL 2014-05-21 00:37:27 +08:00
c9s 90890b09e5 put r3_define.h back XD becase we depends on bool 2014-05-21 00:33:19 +08:00
c9s 92e2ddf066 remove r3_define.h 2014-05-20 23:54:57 +08:00
c9s fbbb976768 r3_define.h is removed 2014-05-20 23:54:15 +08:00
c9s 7ba0efc60c use doublecirlce for endpoint nodes 2014-05-20 23:48:35 +08:00
c9s a706b48f14 Add more patterns to gvc paths 2014-05-20 23:39:20 +08:00
c9s 1cbba0a101 no jemalloc for now. 2014-05-20 23:34:54 +08:00
c9s 5183e9a052 merge r3_define.h into r3.h 2014-05-20 23:33:51 +08:00
c9s ee190bc030 delete demo.c 2014-05-20 23:31:27 +08:00
c9s 750a9beaa4 _r3_tree_insert_pathl to r3_tree_insert_pathl_ 2014-05-20 23:30:36 +08:00
c9s 02b4008a69 str_split is unused 2014-05-20 23:29:17 +08:00
c9s 85001c6327 Rename compile_slug to slug_compile 2014-05-20 23:25:55 +08:00
c9s 99819c4bbb move strndiff and strdiff to node.c and make it private 2014-05-20 23:25:12 +08:00
c9s 26c7e8896e Rename count_slug to slug_count 2014-05-20 23:21:15 +08:00
c9s eb81c1cc0b Add coverage report button 2014-05-20 23:11:28 +08:00
Pedro 642300ba7b Merge pull request #25 from czchen/feature/coveralls
Add coveralls.io support
2014-05-20 22:31:20 +08:00
ChangZhuo Chen (陳昌倬) 16427fe42a Add coveralls.io support 2014-05-20 22:05:07 +08:00
c9s 9499432084 remove debug print 2014-05-20 21:41:24 +08:00
c9s 268047c18c Add failing tests for {idx:\d{3}}-{idy:\d{3}} pattern 2014-05-20 21:40:45 +08:00
c9s b3e6321303 more slug compile test 2014-05-20 21:38:59 +08:00
c9s 898ea300a9 Fix placeholder finder 2014-05-20 21:38:37 +08:00
c9s 9caecc8a07 delete config.h.in 2014-05-20 16:38:51 +08:00
c9s a2cf6d2733 Add travis status image 2014-05-20 16:22:46 +08:00
c9s 1d2eb53565 delete config.h since it's autogenerated 2014-05-20 16:21:05 +08:00
c9s de8c26a11a fix tests 2014-05-20 16:18:17 +08:00
c9s a086f9f6e8 Fix memory allocation 2014-05-20 16:16:36 +08:00
c9s e2bf5d5177 Allocation fixes 2014-05-20 15:49:31 +08:00
c9s 155e881d6b enable -ggdb when building test files 2014-05-20 15:34:56 +08:00
c9s 188bb991b9 -ggdb when debug mode is enable (--enable-debug) 2014-05-20 15:34:41 +08:00
c9s 5331d375ac Fix gnu c compiler error when the variable is the same 2014-05-20 15:32:22 +08:00
c9s fd4e89c2f4 check NULL pointer 2014-05-20 15:14:12 +08:00
c9s af3cdbbff4 use ck_assert instead of ck_assert_int_gt 2014-05-20 15:10:09 +08:00
c9s 9d19d233c6 comment regexp symbol 2014-05-20 15:06:52 +08:00
Pedro a588649e14 Merge pull request #24 from czchen/bugfix/travis-ci
Remove AC_CHECK_HEADER_STDBOOL
2014-05-20 14:59:00 +08:00
ChangZhuo Chen (陳昌倬) f6d534d20b Remove AC_CHECK_HEADER_STDBOOL
AC_CHECK_HEADER_STDBOOL is not supported in ubuntu precise which is used
by travis-ci.
2014-05-20 12:08:18 +08:00
c9s 41dc7373f3 comment jemalloc include lines 2014-05-20 01:28:51 +08:00
c9s f4e8d8fdc9 Merge branch 'czchen-feature/export'
struct name does not need to be exported since they are just offset and
size in application binary interface (ABI). As for symbol match_entry,
updated regex will export them.

The command objdump -t libr3.so.0 can be used to see export symbols. If
the second column of a symbol is marked as g, it is exported.
2014-05-20 01:27:16 +08:00
c9s 678d096d07 Merge branch 'feature/export' of https://github.com/czchen/r3 into czchen-feature/export
Conflicts:
	src/Makefile.am
2014-05-20 01:26:40 +08:00
ChangZhuo Chen (陳昌倬) 7bf513d5cd Update export symbols regex to ^r3_|^match_ 2014-05-19 22:32:39 +08:00
c9s 1ec3943591 we don't use list.c for now, so just skip it 2014-05-19 22:00:58 +08:00
ChangZhuo Chen (陳昌倬) bad5cc8966 Export symbols only when it matches regex '^r3_' 2014-05-19 21:43:42 +08:00
c9s 611eee4c05 update gitignore list 2014-05-19 20:08:53 +08:00
c9s a611a1c66d update gitignore list 2014-05-19 20:06:33 +08:00
c9s ebe310b360 delete missing 2014-05-19 20:05:30 +08:00
c9s 57bdaac4cb delete autogen files 2014-05-19 20:04:55 +08:00
c9s c91c8f8f99 delte Makefile.in 2014-05-19 20:04:34 +08:00
c9s 3df4bc0423 delete Makefile.in 2014-05-19 20:04:19 +08:00
c9s 2b61b7abbf delete autogen.sh files 2014-05-19 20:03:34 +08:00
c9s bacbf43d6d delete unused files. 2014-05-19 20:01:12 +08:00
c9s 6ea4405ddf remove paragraph 2014-05-19 13:15:06 +08:00
Pedro e09ddb94e3 Merge pull request #18 from thedrow/patch-1
Formatting optimization of C code in the README file.
2014-05-19 12:49:39 +08:00
Omer Katz c150d27d4b Formatting optimization of C code in the README file. 2014-05-19 07:39:08 +03:00
c9s 32f30db44d update README 2014-05-19 11:45:39 +08:00
c9s d65e25feba travis ci: update dev deps 2014-05-19 11:44:29 +08:00
c9s 2278a0f045 -fprofile-arcs -ftest-coverage for debug mode 2014-05-19 11:38:25 +08:00
c9s 27a7826771 use r3_tree_matchl 2014-05-19 11:04:19 +08:00
c9s 06a128ddaa adjust chart width and height 2014-05-19 11:00:48 +08:00
c9s 05ba288c8f Add GA code 2014-05-19 10:59:54 +08:00
c9s 017fa63d8c show people how to release the tree 2014-05-19 10:53:47 +08:00
c9s 8ba1230610 Add endpoint check 2014-05-19 10:49:47 +08:00
c9s 1be560f69c fix changelogs 2014-05-19 10:40:39 +08:00
c9s 5dbcd77522 Fix markdown 2014-05-19 10:40:02 +08:00
c9s 60b621c77c update changelogs 2014-05-19 10:39:35 +08:00
c9s 401443f7ac Add r3_ prefix to route struct related functions 2014-05-19 10:39:03 +08:00
c9s 2ac6f87422 Fix r3_tree_match_route 2014-05-19 10:34:48 +08:00
c9s c34ae55da2 Add CHANGELOGS 2014-05-19 10:12:57 +08:00
c9s 2084675423 r3_tree_insert_path API changes 2014-05-19 10:12:41 +08:00
Pedro df798bb106 Merge pull request #14 from thedrow/patch-1
The build process also requires pkg-config
2014-05-19 08:53:45 +08:00
Omer Katz 4c390e006c The build process also requires pkg-config
At least on ubuntu.
2014-05-18 23:27:36 +03:00
c9s 33c0c3fea7 Adjust node struct field ordering (for memory alignment) 2014-05-18 20:32:23 +08:00
c9s bada37fd75 Fix warning 2014-05-18 20:16:53 +08:00
c9s 0babb27f56 Add benchmark test back 2014-05-18 20:13:07 +08:00
c9s 4a0412d4e9 check in files (slug tests) 2014-05-18 20:11:07 +08:00
c9s baf23fafb0 fix pattern matching for /user/{id}-{user} 2014-05-18 20:09:42 +08:00
c9s f039cc3c8f Fix child insertion 2014-05-18 20:09:42 +08:00
c9s 7d6113d17d truncate edge pattern in r3_edge_branch 2014-05-18 20:09:42 +08:00
Pedro 51170ebbeb Merge pull request #11 from bfontaine/patch-1
Typo fixed in README.md
2014-05-18 17:11:01 +08:00
Baptiste Fontaine 1993c303f5 Typo fixed in README.md 2014-05-18 10:17:18 +02:00
c9s 4565346298 Fix tests for #10 2014-05-18 15:06:20 +08:00
c9s d4c2c6b47e Add failing test to issue #10 2014-05-18 15:00:11 +08:00
c9s c5198a91c7 use pattern with slug 2014-05-18 14:42:02 +08:00
c9s cda897a9a7 fix slug compilation 2014-05-18 14:30:00 +08:00
c9s f4bb320470 Add one more pcre test 2014-05-18 14:18:47 +08:00
c9s 4871e91054 README 2014-05-18 14:14:04 +08:00
c9s 636f474cbc update 2014-05-18 14:13:04 +08:00
c9s 684eac876c readme update: routeing with conditions 2014-05-18 14:11:53 +08:00
Pedro bcd514989c Merge pull request #9 from czchen/bugfix/dist
Add missing files to Makefile.am
2014-05-18 14:03:57 +08:00
ChangZhuo Chen (陳昌倬) 21c31b37b7 Add missing files to Makefile.am 2014-05-18 13:52:56 +08:00
c9s 4826ba6a83 update example 2014-05-18 13:45:29 +08:00
c9s baf2368726 comments 2014-05-18 13:38:30 +08:00
c9s cde6e5de31 Fix tests 2014-05-18 13:15:53 +08:00
c9s 60991c3d73 condition_* => route_* 2014-05-18 13:06:36 +08:00
c9s fcad767085 fix test_insert_route test 2014-05-18 13:04:17 +08:00
c9s 1632f9807e r3_node_match_condition 2014-05-18 12:56:53 +08:00
c9s 641d1e53d8 fix condition match for request method 2014-05-18 12:49:58 +08:00
c9s 518fad82f2 copy data to condition endpoints 2014-05-18 12:40:06 +08:00
c9s e6c7d3e45e Add r3_tree_match_with_entry function to match with match_entry 2014-05-18 12:32:20 +08:00
c9s 58cd893dea insert conditions at endpoints 2014-05-18 12:28:12 +08:00
c9s e0eca85cbc remove route_split_pattern function 2014-05-18 12:24:07 +08:00
c9s 7687dd3aef clear edge->route when create 2014-05-18 12:00:03 +08:00
c9s a4481a8ecb Add route_cmp function to compare route 2014-05-18 11:59:30 +08:00
c9s 4efd1b9702 r3_tree_insert_pathn to r3_tree_insert_pathl 2014-05-18 11:13:44 +08:00
c9s 08a059465e Append one more argument to r3_tree_insert_pathn 2014-05-18 11:13:02 +08:00
c9s 64acfd8cd6 Rename route_ptr => route 2014-05-18 11:06:24 +08:00
c9s 5ca345d570 Rename route_info to route 2014-05-18 11:05:01 +08:00
c9s eb3ef7df0f rename request_methods to request_method 2014-05-18 11:04:13 +08:00
c9s b25a68eaac Add --enable-debug option + *i is unused. 2014-05-18 11:03:15 +08:00
c9s 9639174f73 Merge branch 'master' into feature/route-info
Conflicts:
	include/r3.h
	tests/bench_str.csv
2014-05-18 10:36:14 +08:00
c9s 1f1faff8b0 Add include header to synopsis 2014-05-18 10:29:36 +08:00
c9s f9ce80ebf3 Add license to readme 2014-05-18 10:28:19 +08:00
c9s 2e6aca1dad update LICENSE 2014-05-18 10:27:53 +08:00
c9s d3218b6331 clean up configure.ac 2014-05-18 10:22:53 +08:00
c9s 1cae209d9f update version 2014-05-18 10:14:08 +08:00
c9s 2e7a3c2736 workable --enable-graphviz 2014-05-18 10:13:51 +08:00
c9s 6c651cb1ef Add lib_LIBRARIES option to Makefile.am 2014-05-18 09:32:14 +08:00
c9s cdbfb2f05b update README 2014-05-18 09:31:08 +08:00
c9s b56a52e1d8 Add --enable-graphviz option for graphviz:
Graphviz API is changed in 2014* version.
And the version on ubuntu 13.10  is 2013*
Which causes build fail.
2014-05-18 09:29:31 +08:00
c9s 607f209425 required dot version 2014-05-18 09:16:47 +08:00
c9s 02197595c9 Rename dl => offset for readiblity 2014-05-18 09:05:55 +08:00
c9s 097a180f8c update record 2014-05-18 08:55:49 +08:00
c9s 4f882b8a7d newrecord~ 2014-05-18 08:33:31 +08:00
c9s c1d90dd138 performance improvement on plain string edge matching 2014-05-18 08:29:26 +08:00
c9s 00c3b32ad5 update benchmark result. 2014-05-18 08:28:45 +08:00
c9s 87f8cb810a Fix image markdown 2014-05-18 08:21:09 +08:00
c9s 48f6255fbc document graphviz feature 2014-05-18 08:19:32 +08:00
c9s 452b53c2f8 Merge branch 'feature/graphviz' 2014-05-18 08:15:54 +08:00
c9s b7d20ecc24 Add gvc_render and gvc_render tests 2014-05-18 08:15:32 +08:00
c9s b7c4829c2b Fix node pattern re-assignment 2014-05-18 08:15:32 +08:00
c9s d46d189e95 fix dep libgvc 2014-05-18 08:15:32 +08:00
c9s 06c3b95e6c Update Makefile.in 2014-05-18 08:15:32 +08:00
c9s 52aa221710 Add gvc.c 2014-05-18 08:15:32 +08:00
c9s 27e8998ab3 Add gvc to configure.ac 2014-05-18 08:15:31 +08:00
c9s 9858c5cd5a Add gvc_render and gvc_render tests 2014-05-18 08:13:58 +08:00
c9s dc861157cf Fix node pattern re-assignment 2014-05-18 08:04:24 +08:00
c9s d462f4d5fa fix dep libgvc 2014-05-18 07:36:17 +08:00
c9s db9c3662f8 Update Makefile.in 2014-05-18 07:35:16 +08:00
c9s 1439401036 Add gvc.c 2014-05-18 07:34:51 +08:00
c9s b7d3e86181 Add gvc to configure.ac 2014-05-18 07:31:37 +08:00
c9s 9bab1bd076 match_entry_createl 2014-05-17 23:54:18 +08:00
Pedro 03888e5c65 Merge pull request #7 from czchen/bugfix/equal
Fix = operator in sh
2014-05-17 23:30:45 +08:00
ChangZhuo Chen (陳昌倬) a7eac661c7 Fix = operator in sh 2014-05-17 22:55:27 +08:00
c9s 639dd1e0e6 intiialize route_info struct 2014-05-17 19:25:25 +08:00
c9s 516ddddda3 Add exec_prefix 2014-05-17 19:05:14 +08:00
c9s 563278fba8 Add route_info structure 2014-05-17 18:57:36 +08:00
c9s c19186ab77 Add more columns to match_entry 2014-05-17 18:56:13 +08:00
c9s 793de786b7 update .travis-ci 2014-05-17 16:06:05 +08:00
c9s d4ece86b36 check in Makefile.in 2014-05-17 16:02:15 +08:00
c9s 397905ed77 check in Makefile.in 2014-05-17 16:02:03 +08:00
c9s f1555ba0d1 Merge branch 'master' of github.com:c9s/r3
Conflicts:
	config.guess
	config.sub
	install-sh
2014-05-17 16:01:35 +08:00
c9s 9ab45c2133 use automake with copy 2014-05-17 16:00:28 +08:00
c9s 5651d95b99 delete links 2014-05-17 15:57:52 +08:00
c9s 57753e8657 check-in install-sh 2014-05-17 15:56:29 +08:00
c9s 3d163d40de Add configure script 2014-05-17 15:55:50 +08:00
c9s 9557af5efa check in missing files 2014-05-17 15:54:38 +08:00
c9s 3b811952d9 gcc test only for now 2014-05-17 15:52:01 +08:00
c9s 8bc6812095 update configure.ac with more configs 2014-05-17 15:50:22 +08:00
c9s 442cca2941 update .travis ci config 2014-05-17 15:45:34 +08:00
c9s 9e020768d9 import m4/* 2014-05-17 15:45:27 +08:00
c9s f4ed38c908 more autoconf steps 2014-05-17 15:40:48 +08:00
c9s 428e7f4cd6 use autoreconf 2014-05-17 15:38:16 +08:00
c9s ff37833aeb require gnulib 2014-05-17 15:36:35 +08:00
c9s 8293e0a786 install m4 2014-05-17 15:36:05 +08:00
c9s dcee860225 update readme 2014-05-17 15:33:12 +08:00
c9s 3ba9d4be0d libtool, automake, autoconf 2014-05-17 15:32:38 +08:00
c9s c0b4e6cbeb build-essential 2014-05-17 15:31:10 +08:00
c9s 7b44ffbcfa Add ACLOCAL_AMFLAGS 2014-05-17 15:30:25 +08:00
c9s c16f5c0475 test build 2014-05-17 15:28:35 +08:00
c9s ec694de68e Add .travis ci config 2014-05-17 15:26:40 +08:00
c9s 88434b2288 delete auto-generated libtool 2014-05-17 15:22:40 +08:00
c9s 65d295b880 partially 2014-05-17 15:20:59 +08:00
c9s ea057921c2 no strndup when truncating pattern 2014-05-17 15:20:28 +08:00
Pedro 4910382090 Update node.c
Fix
2014-05-17 15:16:52 +08:00
Pedro 6c0b3c3e90 Merge pull request #6 from CindyLinz/master
my_strdup / my_strndup  malloc smaller
2014-05-17 15:06:44 +08:00
Pedro 2ca78dd980 Merge pull request #5 from czchen/feature/install
Install headers and r3.pc
2014-05-17 14:46:27 +08:00
Cindy Wang (CindyLinz) 1c9a42dd82 my_strdup / my_strndup malloc smaller 2014-05-17 13:01:33 +08:00
ChangZhuo Chen (陳昌倬) be0cd0df76 Add r3.pc 2014-05-17 11:35:45 +08:00
ChangZhuo Chen (陳昌倬) 0ad579912c Install header files 2014-05-17 11:23:01 +08:00
c9s e3b64f4512 Delete 2014-05-17 09:46:02 +08:00
c9s 16d7225336 update benchmark result 2014-05-17 09:41:00 +08:00
c9s fe9ca48135 update README 2014-05-17 09:39:39 +08:00
c9s 256cb8435a dump pattern if pcre compilation failed. 2014-05-17 08:11:22 +08:00
c9s 4f36b0b27c Fix check tests on linux platform 2014-05-17 08:01:49 +08:00
c9s d30e58176c Adding AC_PROG_CC_STDC to configure.ac to support c99 2014-05-17 07:58:28 +08:00
c9s 6ff8ff66d1 one more scope for benchmarks 2014-05-17 07:53:24 +08:00
c9s 4572f5cb55 update correct testing records 2014-05-17 07:52:03 +08:00
c9s 5a4312d473 clean up 2014-05-17 07:49:17 +08:00
c9s e0c67acc61 rename to benchmark_print_summary 2014-05-17 07:48:57 +08:00
c9s f5863a956d Add benchmark macros 2014-05-17 07:48:22 +08:00
c9s 6747775908 use @CHECK_CFLAGS@ and @CHECK_LIBS@ 2014-05-17 07:28:52 +08:00
c9s 0c6afd03b7 use HAVE_STR*DUP config to check function definitions 2014-05-17 07:26:47 +08:00
c9s 952ec60e99 Fix Makefile.am for check 2014-05-17 07:23:24 +08:00
c9s 6348a305f7 Delete auto-generated config.h 2014-05-17 07:19:16 +08:00
c9s 23ddbf2e81 Add ltmain.sh 2014-05-17 07:19:01 +08:00
c9s 3c8279a53e keep m4/ 2014-05-17 07:18:35 +08:00
c9s a8eb380051 Check funcs & header files 2014-05-17 07:17:44 +08:00
c9s 55e9082c02 delete config.status 2014-05-17 07:17:38 +08:00
c9s bfbb9d38f3 Merge remote-tracking branch 'origin/autotool' 2014-05-17 07:15:42 +08:00
Pedro c182c4efaa Merge pull request #3 from CindyLinz/master
my_strdup / my_strndup   size_t -> int
2014-05-17 05:37:33 +08:00
Cindy Wang (CindyLinz) 1f91b8ea35 my_strdup / my_strndup size_t -> int 2014-05-17 03:17:51 +08:00
Pedro 0cc956aaf7 Merge pull request #2 from CindyLinz/master
token.c include r3_str.h for my_strdup & my_strndup
2014-05-17 03:17:48 +08:00
Cindy Wang (CindyLinz) d5c5a5368f avoid redefines 2014-05-17 02:51:21 +08:00
Cindy Wang (CindyLinz) 823ed29161 token.c include r3_str.h for my_strdup & my_strndup 2014-05-17 01:02:14 +08:00
Pedro c419aeadc9 Merge pull request #1 from CindyLinz/master
self provided strndup & strdup
2014-05-17 00:39:56 +08:00
Cindy Wang (CindyLinz) df4dbbe2a6 self provided strndup & strdup 2014-05-17 00:35:56 +08:00
110 changed files with 18261 additions and 24771 deletions

70
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,70 @@
name: ci
on: [push, pull_request]
jobs:
autotools:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check lcov
- uses: actions/checkout@v2
- name: Build
run: |
./autogen.sh
./configure --enable-check --enable-debug --enable-gcov
make V=1
- name: Install
run: sudo make install
- name: Run tests
run: make check
- name: Collect coverage
run: lcov --capture -d '.' --exclude '/usr*' -o coverage.info
- name: Upload coverage
if: github.repository == 'c9s/r3'
uses: coverallsapp/github-action@1.1.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.info
cmake:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check ninja-build
- uses: actions/checkout@v2
- name: Build and test
run: |
mkdir build && cd build
cmake -GNinja ..
ninja -v
ctest --verbose
sanitizers:
name: ${{ matrix.sanitizer }}-sanitizer [${{ matrix.compiler }}]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
sanitizer: [thread, undefined, leak, address]
steps:
- name: Prepare
run: |
sudo apt update -qq
sudo apt install -qq check
- uses: actions/checkout@v2
- name: Build
env:
CC: ${{ matrix.compiler }}
run: |
mkdir build && cd build
CFLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-sanitize-recover=all -fno-omit-frame-pointer" cmake ..
VERBOSE=1 make all
- name: Test
run: |
cd build
ctest --verbose

21
.github/workflows/coverity.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: coverity
on:
push:
branches: [2.0]
jobs:
analyze:
if: github.repository == 'c9s/r3'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
./autogen.sh
./configure --enable-check
- uses: vapier/coverity-scan-action@v1
with:
project: r3
email: yoanlin93+github@gmail.com
token: ${{ secrets.COVERITY_TOKEN }}

46
.gitignore vendored
View file

@ -17,12 +17,42 @@ tags
*.la
*.dylib
*.o
/aclocal.m4
/autom4te.cache
/compile
/configure
/depcomp
/install-sh
/missing
/stamp-h1
Makefile
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

5
.travis-ci/after_success.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
if [ x$COVERALLS == xyes ]; then
coveralls --exclude php --exclude 3rdparty
fi

24
.travis-ci/install.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/sh
apt-get update -qq
apt-get install -qq \
autoconf \
automake \
build-essential \
check \
clang \
cmake \
graphviz-dev \
libjemalloc-dev \
libpcre2-dev \
libtool \
ninja-build \
pkg-config
if [ x$COVERALLS == xyes ]; then
pip install cpp-coveralls
fi
if [ x$VALGRIND == xyes ]; then
apt-get install valgrind
fi

18
.travis-ci/script-autotools.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/sh
set -ev
./autogen.sh
./configure --enable-check $CONFIGURE_OPTION
make V=1
make install
if [ x$VALGRIND == xyes ]; then
make check
else
make check V=1
fi
# XXX: tracing memory leak, disabled for some mystery reason for automake...
#if [ x$VALGRIND == xyes && x$DEBUG == xyes ]; then
# valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full
#fi

8
.travis-ci/script-cmake.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
set -ev
mkdir build && cd build
cmake -GNinja ..
ninja -v
ctest

111
.travis.yml Normal file
View file

@ -0,0 +1,111 @@
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 Normal file
View file

@ -0,0 +1,72 @@
# 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.

49
CMakeLists.txt Normal file
View file

@ -0,0 +1,49 @@
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()

695
COPYING
View file

@ -1,674 +1,21 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
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.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
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>.
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.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
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.

View file

@ -1 +1,51 @@
SUBDIRS=src tests
SUBDIRS=src . examples
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)

370
README.md
View file

@ -1,20 +1,33 @@
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.
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=2.0)](https://travis-ci.org/c9s/r3)
[![Coverage Status](https://coveralls.io/repos/c9s/r3/badge.svg)](https://coveralls.io/r/c9s/r3)
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
-----------------------
* cmake
### Build Requirement
* autoconf
* automake
* check
* pcre
* jemalloc
* pkg-config
### Runtime Requirement
* pcre2
* (optional) graphviz version 2.38.0 (20140413.2041)
* (optional) libjson-c-dev
Pattern Syntax
-----------------------
@ -23,37 +36,167 @@ Pattern Syntax
/blog/post/{id:\d+} use `\d+` regular expression instead of default.
C API
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
// create a router tree with 10 children capacity (this capacity can grow dynamically)
n = r3_tree_create(10);
int route_data = 3;
// insert the route path into the router tree
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 );
// insert the R3Route path into the router tree
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/post", sizeof("/blog/post") - 1, &route_data );
// let's compile the tree!
r3_tree_compile(n);
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);
// in your http server handler
// match a route
node *matched_node = r3_tree_match(n, "/foo/bar", strlen("/foo/bar") );
matched_node->endpoint; // make sure there is a route end at here.
int ret = *( (*int) matched_node->route_ptr );
// create the match entry for capturing dynamic variables.
match_entry * entry = match_entry_create("/blog/post");
entry->request_method = METHOD_GET;
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.
Benchmark
Optimization
-----------------------
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>:
@ -63,17 +206,15 @@ And here is the result of the router journey:
omg 9932.9 (±4.8%) i/s - 49873 in 5.033452s
r3 uses the same route path data for benchmarking, and here is the benchmark:
r3 uses the same R3Route path data for benchmarking, and here is the benchmark:
5000000 iterations finished in 0.905591 seconds
5521256.22 i/sec
The matching speed of r3 is 527+ times faster than rails' trie router.
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
11460057.83 i/sec
### The benchmarking route paths
### The Route Paths Of Benchmark
The route path generator is from <https://github.com/stevegraham/rails/pull/1>:
The R3Route path generator is from <https://github.com/stevegraham/rails/pull/1>:
```ruby
#!/usr/bin/env ruby
@ -84,24 +225,129 @@ paths.each do |path|
end
```
Function prefix mapping
-----------------------
|Function Prefix |Description |
|------------------|------------------------------------------------------------------------------------|
|`r3_tree_*` |Tree related operations, which require a node to operate a whole tree |
|`r3_node_*` |Single node related operations, which do not go through its own children or parent. |
|`r3_edge_*` |Edge related operations |
|`r3_route_*` |Route related operations, which are needed only when the tree is defined by routes |
|`match_entry_*` |Match entry related operations, a `match_entry` is just like the request parameters |
Rendering Routes With Graphviz
---------------------------------------
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
-----------------------
**not implemented yet**
```php
// Here is the paths data structure
$paths = [
'/blog/post/{id}' => [ 'controller' => 'PostController' , 'action' => 'item' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'list' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'create' , 'method' => 'POST' ] ,
'/blog' => [ 'controller' => 'BlogController' , 'action' => 'list' , 'method' => 'GET' ] ,
'/blog/post/{id}' => [ 'controller' => 'PostController' , 'action' => 'item' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'list' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'create' , 'method' => 'POST' ] ,
'/blog' => [ 'controller' => 'BlogController' , 'action' => 'list' , 'method' => 'GET' ] ,
];
$rs = r3_compile($paths, 'persisten-table-id');
$ret = r3_dispatch($rs, '/blog/post/3' );
list($complete, $route, $variables) = $ret;
// matched conditions aren't done yet
list($error, $message) = r3_validate($route); // validate route conditions
list($error, $message) = r3_validate($route); // validate R3Route conditions
if ( $error ) {
echo $message; // "Method not allowed", "...";
}
@ -110,7 +356,59 @@ if ( $error ) {
Install
----------------------
cmake CMakeLists.txt -Wno-dev
make
sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
sudo apt-get install graphviz-dev graphviz # if you want graphviz
./autogen.sh
./configure && make
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

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@ for l in glibtoolize libtoolize15 libtoolize14 libtoolize ; do
echo "Did not find $l"
done
if [ "x$libtoolize" == "x" ]; then
if [ "x$libtoolize" = "x" ]; then
echo "Can't find libtoolize on your system"
exit 1
fi
@ -30,7 +30,7 @@ $libtoolize -c -f
autoconf -f -W all,no-obsolete
autoheader -f -W all
# automake -a -c -f -W all
automake --add-missing --foreign -c -W all
automake --add-missing --foreign --copy -c -W all
rm -rf autom4te.cache
exit 0

View file

@ -9,7 +9,9 @@
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script>
$.get('tests/bench_str.csv', function(data) {
$.get('bench_str.csv', function(data) {
var options = {
chart: {
@ -60,11 +62,13 @@
}],
legend: {
align: 'left',
align: 'right',
verticalAlign: 'top',
y: 20,
floating: true,
borderWidth: 0
y: 50,
floating: false,
layout: 'vertical',
background: '#fff',
borderWidth: 1,
},
tooltip: {
@ -73,6 +77,7 @@
},
plotOptions: {
/*
area: {
fillColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1},
@ -92,28 +97,82 @@
},
threshold: null
}
*/
},
series: [{
type: 'area',
name: 'Speed',
pointInterval: 1000,
lineWidth: 2,
marker: {
radius: 3
series: [
{
type: 'area',
name: 'string matching',
pointInterval: 1000,
lineWidth: 1,
marker: {
radius: 3
},
pointStart: Date.UTC(2014, 5, 16),
data: []
},
pointStart: Date.UTC(2014, 5, 16),
data: []
}]
{
type: 'area',
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/);
// keep window size to 60 records
lines = lines.splice(-60);
$(lines).each(function(i,line) {
var columns = line.split(/,/);
var i = parseInt(columns[1]);
if(i) {
options.series[0].data.push(i);
if (line == "") {
return;
}
var columns = line.split(/,/);
if (columns.length == 0) {
return;
}
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);
@ -125,7 +184,7 @@
<h1>R3: Router Benchmark</h1>
<div id="chart" style="width: 800px; height: 400px; margin: 0 auto"></div>
<div id="chart" style="width: 100%; height: 450px; margin: 0 auto"></div>
<h2>Data Set</h2>
@ -470,5 +529,16 @@
</pre>
</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>

646
bench_str.csv Normal file
View file

@ -0,0 +1,646 @@
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.

View file

@ -0,0 +1,37 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre2
# Find the native PCRE2 headers and libraries.
#
# PCRE2_INCLUDE_DIRS - where to find pcre2.h, etc.
# PCRE2_LIBRARIES - List of libraries when using pcre2.
# PCRE2_FOUND - True if pcre2 found.
# Look for the header file.
FIND_PATH(PCRE2_INCLUDE_DIR NAMES pcre2.h)
# Look for the library.
FIND_LIBRARY(PCRE2_LIBRARY NAMES pcre2-8)
# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 DEFAULT_MSG PCRE2_LIBRARY PCRE2_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE2_FOUND)
SET(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
SET(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
ELSE(PCRE2_FOUND)
SET(PCRE2_LIBRARIES)
SET(PCRE2_INCLUDE_DIRS)
ENDIF(PCRE2_FOUND)
MARK_AS_ADVANCED(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)

View file

@ -1,37 +0,0 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre
# Find the native PCRE headers and libraries.
#
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
# PCRE_LIBRARIES - List of libraries when using pcre.
# PCRE_FOUND - True if pcre found.
# Look for the header file.
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
# Look for the library.
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE_FOUND)
SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
ELSE(PCRE_FOUND)
SET(PCRE_LIBRARIES)
SET(PCRE_INCLUDE_DIRS)
ENDIF(PCRE_FOUND)
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)

View file

@ -1,63 +0,0 @@
/* 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"

3
config.h.cmake Normal file
View file

@ -0,0 +1,3 @@
#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
#cmakedefine HAVE_STRNDUP @HAVE_STRNDUP@
#cmakedefine HAVE_STDBOOL_H @HAVE_STDBOOL_H@

View file

@ -1,62 +0,0 @@
/* 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

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,138 @@
AC_INIT([r3], 1.0)
AC_INIT([r3], 2.0.0)
AC_PREREQ([2.64])
AC_USE_SYSTEM_EXTENSIONS
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE
AM_SILENT_RULES([yes])
AM_INIT_AUTOMAKE([foreign subdir-objects])
LT_INIT
AC_PROG_CC
AC_PROG_CC_STDC
AC_PROG_CXX
AC_PROG_INSTALL
AC_HEADER_STDBOOL
# AM_PATH_CHECK()
AM_PATH_CHECK(,[have_check="yes"],
AC_MSG_WARN([Check not found; cannot run unit tests!])
[have_check="no"])
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
# older debian
AC_PROG_LIBTOOL
AM_PROG_CC_C_O
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_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_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

7
demo.c
View file

@ -1,7 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
return 0;
}

5
dist-debian/changelog Normal file
View file

@ -0,0 +1,5 @@
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
dist-debian/compat Normal file
View file

@ -0,0 +1 @@
9

28
dist-debian/control Normal file
View file

@ -0,0 +1,28 @@
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.

30
dist-debian/copyright Normal file
View file

@ -0,0 +1,30 @@
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
dist-debian/docs Normal file
View file

@ -0,0 +1 @@
README.md

View file

@ -0,0 +1,2 @@
usr/lib
usr/include

View file

@ -0,0 +1,4 @@
usr/include/*
usr/lib/lib*.a
usr/lib/lib*.so
usr/lib/pkgconfig/*

1
dist-debian/libr3.dirs Normal file
View file

@ -0,0 +1 @@
usr/lib

View file

@ -0,0 +1 @@
usr/lib/lib*.so.*

12
dist-debian/rules Executable file
View file

@ -0,0 +1,12 @@
#!/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

View file

@ -0,0 +1 @@
3.0 (quilt)

7
examples/Makefile.am Normal file
View file

@ -0,0 +1,7 @@
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

95
examples/routing.c Normal file
View file

@ -0,0 +1,95 @@
/*
* check_slug.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#include <stdio.h>
#include <stdlib.h>
#include "../include/r3.h"
void test1(void) {
R3Node *n = r3_tree_create(10);
int route_data1 = 3;
int route_data2 = 44;
int route_data3 = 555;
// insert the R3Route path into the router tree
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog", sizeof("/blog") - 1, &route_data1 );
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/{idl:\\d+}/asf/{id}", strlen("/blog/{idl:\\d+}/asf/{id}"), &route_data2 );
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe", sizeof("/blog3/{idl:\\d{3}}/asd/{id:[0-9]+}/qwe") - 1, &route_data3 );
char *errstr = NULL;
int err = r3_tree_compile(n, &errstr);
if (err != 0) {
// fail
printf("error: %s\n", errstr);
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
}
// r3_tree_dump(n,0);
// in your http server handler
// create the match entry for capturing dynamic variables.
match_entry * entry;
R3Route *matched_route;
int i;
for (int k = 0; k < 3000000; k++) {
// printf("round N%d\n",k);
entry = match_entry_create("/blog/432/asf/678");
entry->request_method = METHOD_GET;
matched_route = r3_tree_match_route(n, entry);
// if (matched_route) {
// printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
// if (entry->vars.tokens.size == entry->vars.slugs.size) {
// for (i = 0; i < entry->vars.tokens.size; i++) {
// // entry->vars.slugs.entries[i];
// // entry->vars.tokens.entries[i];
// printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
// entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
// printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
// entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
// }
// } else {
// // printf("Slugs and tokens sizes are not equal\n");
// // for (i = 0; i < entry->vars.slugs.size; i++) {
// // printf("Slug name is: %*.*s\n",entry->vars.slugs.entries[i].len,
// // entry->vars.slugs.entries[i].len, entry->vars.slugs.entries[i].base);
// // }
// // for (i = 0; i < entry->vars.tokens.size; i++) {
// // printf("Slug value is: %*.*s\n",entry->vars.tokens.entries[i].len,
// // entry->vars.tokens.entries[i].len, entry->vars.tokens.entries[i].base);
// // }
// }
// }
// free the objects at the end
match_entry_free(entry);
}
// entry = match_entry_create("/blog/aaa/asd/123/qwe");
// if (entry != NULL) {
// entry->request_method = METHOD_GET;
// matched_route = r3_tree_match_route(n, entry);
// if (matched_route != NULL) {
// // printf("Routed data is: %d\n", *(int*)matched_route->data); // get the data from matched route
// for (int i = 0; i < entry->vars->len; i++) {
// // entry->vars->slugs[i];
// // entry->vars->tokens[i];
// printf("Slug name is: %s\n",entry->vars->slugs[i]);
// printf("Slug value is: %s\n",entry->vars->tokens[i]);
// }
// }
// }
// // free the objects at the end
// match_entry_free(entry);
r3_tree_free(n);
}
int main (int argc, char *argv[]) {
test1();
}

59
examples/simple.c Normal file
View file

@ -0,0 +1,59 @@
/*
* 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;
}

97
examples/simple_cpp.cpp Normal file
View file

@ -0,0 +1,97 @@
#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;
}

76
gen_route_tests.rb Normal file
View file

@ -0,0 +1,76 @@
#!/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

View file

@ -2,6 +2,5 @@
arr = ["foo", "bar", "baz", "qux", "quux", "corge", "grault", "garply"]
paths = arr.permutation(3).map { |a| "/#{a.join '/'}" }
paths.each do |path|
# puts "r3_tree_insert_path(n, \"#{path}\", NULL);"
puts path
puts "r3_tree_insert_path(n, \"#{path}\", NULL, NULL);"
end

141
include/memory.h Normal file
View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef r3__memory_h
#define r3__memory_h
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
#define R3_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__)
#else
#define R3_GNUC_VERSION 0
#endif
#if __STDC_VERSION__ >= 201112L
#define R3_NORETURN _Noreturn
#elif defined(__clang__) || defined(__GNUC__) && R3_GNUC_VERSION >= 0x20500
// noreturn was not defined before gcc 2.5
#define R3_NORETURN __attribute__((noreturn))
#else
#define R3_NORETURN
#endif
#if !defined(__clang__) && defined(__GNUC__) && R3_GNUC_VERSION >= 0x40900
// returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2)
#define R3_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define R3_RETURNS_NONNULL
#endif
/**
* buffer structure compatible with iovec
*/
typedef struct st_r3_iovec_t {
const char *base;
unsigned int len;
} r3_iovec_t;
#define R3_VECTOR(type) \
struct { \
type *entries; \
unsigned int size; \
unsigned int capacity; \
}
typedef R3_VECTOR(void) r3_vector_t;
/**
* prints an error message and aborts
*/
R3_NORETURN void r3_fatal(const char *msg);
/**
* constructor for r3_iovec_t
*/
static r3_iovec_t r3_iovec_init(const void *base, unsigned int len);
/**
* wrapper of malloc; allocates given size of memory or dies if impossible
*/
R3_RETURNS_NONNULL static void *r3_mem_alloc(unsigned int sz);
/**
* wrapper of realloc; reallocs the given chunk or dies if impossible
*/
static void *r3_mem_realloc(void *oldp, unsigned int sz);
/**
* grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
* @param vector the vector
* @param element_size size of the elements stored in the vector
* @param new_capacity the capacity of the buffer after the function returns
*/
#define r3_vector_reserve(vector, new_capacity) \
r3_vector__reserve((r3_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (new_capacity))
static void r3_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
void r3_vector__expand(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity);
/* inline defs */
inline r3_iovec_t r3_iovec_init(const void *base, unsigned int len)
{
/* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */
r3_iovec_t buf;
buf.base = (char *)base;
buf.len = len;
return buf;
}
inline void *r3_mem_alloc(unsigned int sz)
{
void *p = malloc(sz);
if (p == NULL)
r3_fatal("no memory");
return p;
}
inline void *r3_mem_realloc(void *oldp, unsigned int sz)
{
void *newp = realloc(oldp, sz);
if (newp == NULL) {
r3_fatal("no memory");
return oldp;
}
return newp;
}
inline void r3_vector__reserve(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
{
if (vector->capacity < new_capacity) {
r3_vector__expand(vector, element_size, new_capacity);
}
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,112 +1,225 @@
/*
* r3.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#ifndef NODE_H
#define NODE_H
#ifndef R3_NODE_H
#define R3_NODE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pcre.h>
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.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 "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 _node;
typedef struct _edge edge;
typedef struct _node node;
struct _route;
typedef struct _edge R3Edge;
typedef struct _node R3Node;
typedef struct _R3Route R3Route;
struct _node {
edge ** edges;
int edge_len;
int edge_cap;
/** compile-time variables here.... **/
/* the combined regexp pattern string from pattern_tokens */
struct _node {
R3_VECTOR(R3Edge) edges;
R3_VECTOR(R3Route) routes;
char * combined_pattern;
int combined_pattern_len;
pcre * pcre_pattern;
pcre_extra * pcre_extra;
int ov_cnt;
int * ov;
pcre2_code * pcre_pattern;
pcre2_match_data * match_data;
/**
* the pointer of route structure
*/
void * route_ptr;
// edges are mostly less than 255
unsigned int compare_type; // compare_type: pcre, opcode, string
unsigned int endpoint; // endpoint, should be zero for non-endpoint nodes
int endpoint;
// the pointer of R3Route data
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 {
char * pattern;
int pattern_len;
bool has_slug;
node * child;
r3_iovec_t pattern; // 8 bytes
R3Node * child; // 8 bytes
unsigned int opcode; // 4byte
unsigned int has_slug; // 4byte
};
typedef struct {
str_array * vars;
char * path; // dispatched path
int path_len;
void * route_ptr; // route ptr
} match_entry;
struct _R3Route {
r3_iovec_t path;
R3_VECTOR(r3_iovec_t) slugs;
int request_method; // can be (GET || POST)
r3_iovec_t host; // required host name
void * data;
r3_iovec_t remote_addr_pattern;
unsigned int remote_addr_v4;
int remote_addr_v4_bits;
unsigned int remote_addr_v6[4];
int remote_addr_v6_bits[4];
int http_scheme; // can be (SCHEME_HTTP or SCHEME_HTTPS)
};
typedef struct _R3Entry match_entry;
struct _R3Entry {
str_array vars;
r3_iovec_t path; // current path to dispatch
int request_method; // current request method
void * data; // R3Route ptr
r3_iovec_t host; // the request host
r3_iovec_t remote_addr;
int http_scheme;
};
node * r3_tree_create(int cap);
R3Node * r3_tree_create(int cap);
node * r3_node_create();
// R3Node * r3_node_create();
void r3_tree_free(node * tree);
void r3_tree_free(R3Node * tree);
void r3_edge_free(edge * edge);
R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int strdup, R3Node *child);
edge * r3_tree_add_child(node * n, char * pat , node *child);
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
edge * r3_node_find_edge(node * n, char * pat);
R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len);
void r3_tree_append_edge(node *n, edge *child);
R3Edge * r3_node_append_edge(R3Node *n);
node * r3_tree_insert_path(node *tree, char *route, void * route_ptr);
R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr);
node * r3_tree_insert_pathn(node *tree, char *route, int route_len, void * route_ptr);
R3Node * r3_tree_insert_pathl(R3Node *tree, const char *path, int path_len, void * data);
void r3_tree_dump(node * n, int level);
edge * r3_node_find_edge_str(node * n, char * str, int str_len);
void r3_tree_compile(node *n);
void r3_tree_compile_patterns(node * n);
node * r3_tree_match(node * n, char * path, int path_len, match_entry * entry);
bool r3_node_has_slug_edges(node *n);
node * r3_tree_lookup(node * tree, char * path, int path_len);
edge * r3_edge_create(char * pattern, int pattern_len, node * child);
void r3_edge_branch(edge *e, int dl);
void r3_edge_free(edge * edge);
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, 0, 0, data, NULL)
match_entry * match_entry_create(char * path, int path_len);
R3Route * r3_tree_insert_routel(R3Node * tree, int method, const char *path, int path_len, void *data);
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);
#endif /* !NODE_H */
#ifdef __cplusplus
}
#endif
#endif /* !R3_NODE_H */

140
include/r3.hpp Normal file
View file

@ -0,0 +1,140 @@
/*
* 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

View file

@ -1,36 +0,0 @@
/*
* 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 */

23
include/r3_gvc.h Normal file
View file

@ -0,0 +1,23 @@
/*
* 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 */

24
include/r3_json.h Normal file
View file

@ -0,0 +1,24 @@
/*
* 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 */

View file

@ -1,12 +1,12 @@
/*
* r3_list.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#ifndef LIST_H
#define LIST_H
#ifndef R3_LIST_H
#define R3_LIST_H
#include <pthread.h>
@ -32,4 +32,4 @@ void list_each_element(list *l, int (*func)(list_item *));
#endif /* !LIST_H */
#endif /* !R3_LIST_H */

30
include/r3_slug.h Normal file
View file

@ -0,0 +1,30 @@
/*
* r3_str.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#ifndef R3_SLUG_H
#define R3_SLUG_H
#ifdef __cplusplus
extern "C" {
#endif
char * r3_slug_compile(const char * str, unsigned int len);
const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len);
const char * r3_slug_find_name(const char *s1, unsigned int str_len, unsigned int *len);
const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsigned int *len);
int r3_slug_count(const char * needle, int len, char **errstr);
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr);
#ifdef __cplusplus
}
#endif
#endif /* !R3_SLUG_H */

View file

@ -1,37 +0,0 @@
/*
* 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 */

View file

@ -1,37 +1,41 @@
/*
* str_array.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#ifndef TOKEN_H
#define TOKEN_H
#ifndef STR_ARRAY_H
#define STR_ARRAY_H
#include "r3_define.h"
#include "memory.h"
#if __STDC_VERSION__ <= 201710L
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#elif !defined(bool) && !defined(__cplusplus)
typedef unsigned char bool;
# define bool bool /* For redefinition guards */
# define false 0
# define true 1
#endif
#endif
typedef struct _str_array {
char **tokens;
int len;
int cap;
R3_VECTOR(r3_iovec_t) slugs;
R3_VECTOR(r3_iovec_t) tokens;
} str_array;
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);
bool str_array_append(str_array * l, const char * token, unsigned int len);
void str_array_free(str_array *l);
void str_array_dump(str_array *l);
void str_array_dump_slugs(const str_array *l);
str_array * split_route_pattern(char *pattern, int pattern_len);
void str_array_dump(const str_array *l);
#define str_array_fetch(t,i) t->tokens[i]
#define str_array_len(t) t->len
#define str_array_cap(t) t->cap
#define str_array_fetch(t,i) t->tokens.entries[i]
#define str_array_len(t) t->tokens.size
#define str_array_cap(t) t->tokens.capacity
#endif /* !TOKEN_H */
#endif /* !STR_ARRAY_H */

10075
libtool

File diff suppressed because it is too large Load diff

0
m4/.keep Normal file
View file

17
main.c
View file

@ -1,17 +0,0 @@
#include <stdlib.h>
#include <pcre.h>
#include "main.h"
typedef struct _Node {
char ** patterns;
} Node;
void compile() {
}

6
main.h
View file

@ -1,6 +0,0 @@
#ifndef MAIN_H
#define MAIN_H
void compile();
#endif

9
package.json Normal file
View file

@ -0,0 +1,9 @@
{
"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"]
}

40
php/r3/annotation/annot.h Normal file
View file

@ -0,0 +1,40 @@
/*
+------------------------------------------------------------------------+
| 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);

441
php/r3/annotation/base.c Normal file
View file

@ -0,0 +1,441 @@
/*
+------------------------------------------------------------------------+
| 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;
}

BIN
php/r3/annotation/lemon Executable file

Binary file not shown.

4564
php/r3/annotation/lemon.c Normal file

File diff suppressed because it is too large Load diff

687
php/r3/annotation/lempar.c Normal file
View file

@ -0,0 +1,687 @@
/* 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;
}

1621
php/r3/annotation/parser.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
#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

View file

@ -0,0 +1,335 @@
/*
+------------------------------------------------------------------------+
| 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);
}

View file

@ -0,0 +1,478 @@
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

605
php/r3/annotation/scanner.c Normal file
View file

@ -0,0 +1,605 @@
/* 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;
}

View file

@ -0,0 +1,83 @@
/*
+------------------------------------------------------------------------+
| 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[];

View file

@ -0,0 +1,193 @@
/*
+------------------------------------------------------------------------+
| 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;
}

50
php/r3/config.m4 Normal file
View file

@ -0,0 +1,50 @@
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

View file

@ -14,7 +14,7 @@
#include "php_r3.h"
// #include "ct_helper.h"
// #include "r3_functions.h"
#include "r3_functions.h"
// #include "r3_mux.h"
// #include "php_expandable_mux.h"
// #include "r3_controller.h"
@ -104,33 +104,3 @@ PHP_MSHUTDOWN_FUNCTION(r3) {
PHP_RINIT_FUNCTION(r3) {
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();
}

View file

@ -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);
extern zend_class_entry *ce_r3_exception;
*/
extern zend_class_entry *ce_r3_exception;
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);
PHP_FUNCTION(r3_match);
// PHP_FUNCTION(r3_match);
#define phpext_r3_ptr &r3_module_entry

View file

@ -20,7 +20,7 @@ vim:fdm=marker:et:sw=4:ts=4:sts=4:
// #include "r3_persistent.h"
// #include "php_expandable_mux.h"
// #include "hash.h"
#include "hash.h"
/**
* new_dst = ht_copy_fun_t(NULL, src);
@ -407,8 +407,8 @@ PHP_FUNCTION(r3_match)
}
zval *z_route;
z_route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
if ( z_route != NULL ) {
z_R3Route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
if ( z_R3Route != NULL ) {
*return_value = *z_route;
zval_copy_ctor(return_value);
return;
@ -438,7 +438,7 @@ PHP_FUNCTION(r3_persistent_dispatch)
char *ns, *filename, *path;
int ns_len, filename_len, path_len;
zval *mux = NULL;
zval *route = NULL;
zval *R3Route = NULL;
zval *z_path = NULL;
/* parse parameters */
@ -463,15 +463,15 @@ PHP_FUNCTION(r3_persistent_dispatch)
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
route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
R3Route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
zval_ptr_dtor(&z_path);
if ( route ) {
if ( R3Route ) {
*return_value = *route;
zval_copy_ctor(return_value);
return;
}
// route not found
// R3Route not found
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.
// check conditions only when route option is provided
// check conditions only when R3Route option is provided
if ( zend_hash_index_find( Z_ARRVAL_PP(z_route_pp), 3, (void**) &z_route_options_pp) == SUCCESS ) {
if ( zend_hash_num_elements(Z_ARRVAL_PP(z_route_options_pp)) ) {
if ( 0 == validate_request_method( z_route_options_pp, current_request_method TSRMLS_CC) ) {

View file

@ -81,7 +81,7 @@ zend_class_entry ** get_pattern_compiler_ce(TSRMLS_D) {
return ce_pattern_compiler;
}
// Returns compiled route zval
// Returns compiled R3Route zval
zval * compile_route_pattern(zval *z_pattern, zval *z_options, zend_class_entry **ce_pattern_compiler TSRMLS_DC)
{
// zend_class_entry **ce_pattern_compiler;
@ -92,10 +92,10 @@ zval * compile_route_pattern(zval *z_pattern, zval *z_options, zend_class_entry
}
}
zval *z_compiled_route = NULL; // will be an array
zval *z_compiled_R3Route = NULL; // will be an array
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &z_compiled_route, 2, z_pattern, z_options TSRMLS_CC );
if ( z_compiled_route == NULL ) {
if ( z_compiled_R3Route == NULL ) {
return NULL;
} else if ( Z_TYPE_P(z_compiled_route) == IS_NULL ) {
zval_ptr_dtor(&z_compiled_route);
@ -467,7 +467,7 @@ PHP_METHOD(Mux, mount) {
// zval for new route
zval *z_new_routes;
// zval for route item
// zval for R3Route item
zval **z_is_pcre; // route[0]
zval **z_route_pattern;
zval **z_route_callback;
@ -514,10 +514,10 @@ PHP_METHOD(Mux, mount) {
// $routeArgs = PatternCompiler::compile($newPattern,
// array_merge_recursive($route[3], $options) );
zval *z_compiled_route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
zval *z_compiled_R3Route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
if ( z_compiled_route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
if ( z_compiled_R3Route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
php_error( E_ERROR, "Cannot compile pattern: %s", new_pattern);
}
@ -535,7 +535,7 @@ PHP_METHOD(Mux, mount) {
Z_ADDREF_P(z_compiled_route);
Z_ADDREF_P(z_new_routes);
// create new route and append to mux->routes
// create new R3Route and append to mux->routes
add_index_bool(z_new_routes, 0 , 1); // pcre flag == false
add_index_zval(z_new_routes, 1, *z_compiled_route_pattern);
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);
// Merge the mount options with the route options
// Merge the mount options with the R3Route options
zval *z_new_route_options;
MAKE_STD_ZVAL(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_route = NULL;
zval **z_R3Route = NULL;
z_routes_by_id = zend_read_property( ce_r3_mux , this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
// php_var_dump(&z_routes_by_id, 1 TSRMLS_CC);
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_route ) == SUCCESS ) {
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_R3Route ) == SUCCESS ) {
*return_value = **z_route;
zval_copy_ctor(return_value);
return;
@ -788,7 +788,7 @@ PHP_METHOD(Mux, compile) {
zend_call_method( NULL, NULL, NULL, "usort", strlen("usort"), &rv, 2,
z_routes, z_sort_callback TSRMLS_CC );
zval_ptr_dtor(&z_sort_callback); // recycle sort callback zval
// php_error(E_ERROR,"route sort failed.");
// php_error(E_ERROR,"R3Route sort failed.");
// zend_update_property(ce_r3_mux, getThis(), "routes", sizeof("routes")-1, z_routes TSRMLS_CC);
}
@ -843,7 +843,7 @@ PHP_METHOD(Mux, dispatch) {
int path_len;
zval *z_path;
zval *z_return_route = NULL;
zval *z_return_R3Route = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) {
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_call_method( &this_ptr, ce_r3_mux, &fe, "match", strlen("match"), &z_return_route, 1, z_path, NULL TSRMLS_CC );
if ( ! z_return_route || Z_TYPE_P(z_return_route) == IS_NULL ) {
if ( ! z_return_R3Route || Z_TYPE_P(z_return_route) == IS_NULL ) {
zval_ptr_dtor(&z_path);
RETURN_NULL();
}
@ -908,11 +908,11 @@ PHP_METHOD(Mux, dispatch) {
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 ) {
php_error(E_ERROR, "require route vars");
php_error(E_ERROR, "require R3Route vars");
RETURN_FALSE;
}
if ( zend_hash_index_find( Z_ARRVAL_PP(z_options) , 0 , (void**) &z_route_vars_0 ) == FAILURE ) {
php_error(E_ERROR, "require route vars[0]");
php_error(E_ERROR, "require R3Route vars[0]");
RETURN_FALSE;
}
@ -955,7 +955,7 @@ PHP_METHOD(Mux, dispatch) {
}
}
if ( z_return_route ) {
if ( z_return_R3Route ) {
*return_value = *z_return_route;
zval_copy_ctor(return_value);
}
@ -972,7 +972,7 @@ PHP_METHOD(Mux, match) {
}
zval **z_route_pp = NULL;
zval *z_route = NULL;
zval *z_R3Route = NULL;
if ( zend_hash_find( Z_ARRVAL_P( zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes") - 1, 1 TSRMLS_CC) ), path, path_len, (void**)&z_route_pp) == SUCCESS ) {
if ( Z_TYPE_PP(z_route_pp) != IS_NULL ) {
*return_value = **z_route_pp;
@ -981,8 +981,8 @@ PHP_METHOD(Mux, match) {
return;
}
}
z_route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
if ( z_route != NULL ) {
z_R3Route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
if ( z_R3Route != NULL ) {
*return_value = *z_route;
zval_copy_ctor(return_value);
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 );
if ( rv == NULL || Z_TYPE_P(rv) == IS_NULL ) {
zend_throw_exception(ce_r3_exception, "Can not compile route pattern", 0 TSRMLS_CC);
zend_throw_exception(ce_r3_exception, "Can not compile R3Route pattern", 0 TSRMLS_CC);
RETURN_FALSE;
}
add_next_index_zval(z_routes, rv);
@ -1115,9 +1115,9 @@ inline void mux_add_route(INTERNAL_FUNCTION_PARAMETERS)
MAKE_STD_ZVAL(z_pattern);
ZVAL_STRINGL(z_pattern, pattern, pattern_len, 1);
zval *z_compiled_route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
if ( z_compiled_route == NULL ) {
zend_throw_exception(ce_r3_exception, "Unable to compile route pattern.", 0 TSRMLS_CC);
zval *z_compiled_R3Route = compile_route_pattern(z_pattern, z_options, NULL TSRMLS_CC);
if ( z_compiled_R3Route == NULL ) {
zend_throw_exception(ce_r3_exception, "Unable to compile R3Route pattern.", 0 TSRMLS_CC);
RETURN_FALSE;
}
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_next_index_zval(z_routes, z_new_route);
// if there is no option specified in z_options, we can add the route to our static route hash
// if there is no option specified in z_options, we can add the R3Route to our static R3Route hash
if ( zend_hash_num_elements(Z_ARRVAL_P(z_options)) ) {
zval * z_static_routes = zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes")-1, 1 TSRMLS_CC);
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 *id_route = NULL;
zval *id_R3Route = NULL;
ALLOC_ZVAL(id_route);
ZVAL_COPY_VALUE(id_route, z_new_route);
zval_copy_ctor(id_route);

11
r3.pc.in Normal file
View file

@ -0,0 +1,11 @@
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}

6
run-benchmark Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
i=10
while [ $i -gt 0 ] ; do
bash tests/bench
i=$(($i - 1))
done

View file

@ -1,17 +1,27 @@
cmake_minimum_required(VERSION 2.8)
add_library(r3 STATIC
edge.c
match_entry.c
memory.c
node.c
slug.c
str.c
token.c)
include_directories("${PROJECT_SOURCE_DIR}/include")
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
target_compile_definitions(r3
PRIVATE
_GNU_SOURCE)
set(R3_SRCS node.c str.c list.c token.c edge.c)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -pipe -g3 -funroll-loops -O0")
target_include_directories(r3
PUBLIC
${PCRE2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/3rdparty
${PROJECT_SOURCE_DIR}/include)
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
target_link_libraries(r3
PUBLIC
${PCRE2_LIBRARIES})
# add_library(r3 SHARED ${R3_SRCS})
add_library(r3 STATIC ${R3_SRCS})
target_link_libraries(r3 ${LIBS})
install (TARGETS r3 DESTINATION lib)
# target_link_libraries(r3 cblas)
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
install(
TARGETS r3
DESTINATION lib)

View file

@ -1,5 +1,32 @@
lib_LTLIBRARIES=libr3.la
libr3_la_SOURCES=node.c edge.c list.c str.c token.c
libr3_la_LIBADD=$(DEPS_LIBS)
AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS)
MAYBE_COVERAGE=--coverage
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)

View file

@ -1,79 +1,88 @@
/*
* edge.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* 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>
// 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 "str_array.h"
#include "r3_slug.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;
// }
/**
* branch the edge pattern at "dl" offset
* r3_edge_branch splits the edge and append the rest part as the child of the
* first level child
*
* branch the edge pattern at "dl" offset,
* 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)
*
*/
void r3_edge_branch(edge *e, int dl) {
node *c1; // child 1, child 2
edge *e1; // edge 1, edge 2
char * s1 = e->pattern + dl;
int s1_len = 0;
R3Node * r3_edge_branch(R3Edge *e, int dl) {
R3Node * new_child;
R3Edge * new_edge;
edge **tmp_edges = e->child->edges;
int tmp_r3_edge_len = e->child->edge_len;
// the rest string
const char * s1 = e->pattern.base + dl;
int s1_len = e->pattern.len - dl;
// the suffix edge of the leaf
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_child = r3_tree_create(3);
// Migrate the child edges to the new edge we just created.
for ( int i = 0 ; i < tmp_r3_edge_len ; i++ ) {
r3_tree_append_edge(c1, tmp_edges[i]);
e->child->edges[i] = NULL;
}
e->child->edge_len = 0;
e->child->endpoint--;
info("branched pattern: %s\n", e1->pattern);
r3_tree_append_edge(e->child, e1);
c1->endpoint++;
new_edge = r3_node_append_edge(new_child);
r3_edge_initl(new_edge, s1, s1_len, e->child);
e->child = new_child;
// truncate the original edge pattern
e->pattern.len = dl;
return new_child;
}
edge * r3_edge_create(char * pattern, int pattern_len, node * child) {
edge * e = (edge*) malloc( sizeof(edge) );
e->pattern = pattern;
e->pattern_len = pattern_len;
e->child = child;
return e;
}
void r3_edge_free(edge * e) {
if (e->pattern) {
free(e->pattern);
}
if ( e->child ) {
r3_tree_free(e->child);
void r3_edge_free(R3Edge * e) {
if (e) {
if ( e->child ) {
r3_tree_free(e->child);
}
// free itself
// free(e);
}
}

117
src/gvc.c Normal file
View file

@ -0,0 +1,117 @@
/*
* 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 Normal file
View file

@ -0,0 +1,97 @@
/*
* 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);
}

View file

@ -1,128 +1,121 @@
/*
* list.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* list.c Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#include <stdlib.h>
#include "r3_list.h"
/* Naive linked list implementation */
list *
list *
list_create()
{
list *l = (list *) malloc(sizeof(list));
l->count = 0;
l->head = NULL;
l->tail = NULL;
pthread_mutex_init(&(l->mutex), NULL);
return l;
list *l = (list *) malloc(sizeof(list));
l->count = 0;
l->head = NULL;
l->tail = NULL;
pthread_mutex_init(&(l->mutex), NULL);
return l;
}
void
list_free(l)
list *l;
list *l;
{
list_item *li, *tmp;
pthread_mutex_lock(&(l->mutex));
if (l != NULL) {
li = l->head;
while (li != NULL) {
tmp = li->next;
free(li);
li = tmp;
if (l) {
list_item *li, *tmp;
pthread_mutex_lock(&(l->mutex));
if (l != NULL) {
li = l->head;
while (li != NULL) {
tmp = li->next;
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(l, ptr)
list *l;
void *ptr;
list_item * list_add_element(list * l, void * ptr)
{
list_item *li;
pthread_mutex_lock(&(l->mutex));
li = (list_item *) malloc(sizeof(list_item));
li->value = ptr;
li->next = NULL;
li->prev = l->tail;
if (l->tail == NULL) {
l->head = l->tail = li;
}
else {
l->tail = li;
}
l->count++;
pthread_mutex_unlock(&(l->mutex));
return li;
list_item *li;
pthread_mutex_lock(&(l->mutex));
li = (list_item *) malloc(sizeof(list_item));
li->value = ptr;
li->next = NULL;
li->prev = l->tail;
if (l->tail == NULL) {
l->head = l->tail = li;
} else {
l->tail = li;
}
l->count++;
pthread_mutex_unlock(&(l->mutex));
return li;
}
int
list_remove_element(l, ptr)
list *l;
void *ptr;
list *l;
void *ptr;
{
int result = 0;
list_item *li = l->head;
pthread_mutex_lock(&(l->mutex));
while (li != NULL) {
if (li->value == ptr) {
if (li->prev == NULL) {
l->head = li->next;
}
else {
li->prev->next = li->next;
}
if (li->next == NULL) {
l->tail = li->prev;
}
else {
li->next->prev = li->prev;
}
l->count--;
free(li);
result = 1;
break;
int result = 0;
list_item *li = l->head;
pthread_mutex_lock(&(l->mutex));
while (li != NULL) {
if (li->value == ptr) {
if (li->prev == NULL) {
l->head = li->next;
} else {
li->prev->next = li->next;
}
if (li->next == NULL) {
l->tail = li->prev;
} else {
li->next->prev = li->prev;
}
l->count--;
free(li);
result = 1;
break;
}
li = li->next;
}
li = li->next;
}
pthread_mutex_unlock(&(l->mutex));
return result;
pthread_mutex_unlock(&(l->mutex));
return result;
}
void
list_each_element(l, func)
list *l;
int (*func)(list_item *);
list *l;
int (*func) (list_item *);
{
list_item *li;
pthread_mutex_lock(&(l->mutex));
li = l->head;
while (li != NULL) {
if (func(li) == 1) {
break;
list_item *li;
pthread_mutex_lock(&(l->mutex));
li = l->head;
while (li != NULL) {
if (func(li) == 1) {
break;
}
li = li->next;
}
li = li->next;
}
pthread_mutex_unlock(&(l->mutex));
pthread_mutex_unlock(&(l->mutex));
}

28
src/match_entry.c Normal file
View file

@ -0,0 +1,28 @@
/*
* 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 Normal file
View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2014 DeNA Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
void r3_fatal(const char *msg)
{
fprintf(stderr, "fatal:%s\n", msg);
abort();
}
void r3_vector__expand(r3_vector_t *vector, unsigned int element_size, unsigned int new_capacity)
{
void *new_entries;
assert(vector->capacity < new_capacity);
if (!vector->capacity)
vector->capacity = 4;
while (vector->capacity < new_capacity)
vector->capacity *= 2;
new_entries = r3_mem_realloc(vector->entries, element_size * vector->capacity);
vector->entries = new_entries;
}

1191
src/node.c

File diff suppressed because it is too large Load diff

19
src/r3_debug.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef R3_DEBUG_H
#define R3_DEBUG_H
// #define DEBUG 1
#ifdef DEBUG
#define info(fmt, ...) \
do { fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
#define debug(fmt, ...) \
do { fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
__LINE__, __func__, __VA_ARGS__); } while (0)
#else
#define info(...);
#define debug(...);
#endif
#endif /* !DEBUG_H */

191
src/slug.c Normal file
View file

@ -0,0 +1,191 @@
/*
* 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 Normal file
View file

@ -0,0 +1,59 @@
/*
* 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
View file

@ -1,114 +1,227 @@
/*
* str.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* 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_str.h"
#include "str_array.h"
#include "r3_define.h"
#include "r3.h"
#include "r3_slug.h"
#include "str.h"
#include "slug.h"
int strndiff(char * d1, char * d2, unsigned int n) {
char * o = d1;
while ( *d1 == *d2 && n-- > 0 ) {
d1++;
d2++;
static const char * strnchr(const char* str, unsigned int len, int ch) {
for (unsigned int i = 0; i < len; i++) {
if (str[i] == ch) return str + i;
}
return d1 - o;
return NULL;
}
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;
while( *d1 == *d2 ) {
d1++;
d2++;
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr) {
char * s1 = offset;
char * s2 = offset;
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;
}
/**
* provide a quick way to count slugs, simply search for '{'
* given a slug string, duplicate the pattern string of the slug
*/
int count_slug(char * p, int len) {
int s = 0;
while( len-- ) {
if ( *p == '{' )
s++;
p++;
const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned int *len) {
const char *c;
const char *s2;
unsigned int cnt = 1;
if ( (c = strnchr(s1, str_len, ':')) ) {
c++;
// 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;
}
return s;
if (cnt!=0) {
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
*/
char * compile_slug(char * str, int len)
char * r3_slug_compile(const char * str, unsigned int len)
{
char *s1 = NULL, *s2 = NULL, *i = NULL, *o = NULL;
char *pat = NULL;
const char *s1 = NULL;
char *o = NULL;
const char *pat = NULL;
char sep = '/';
// find '{'
s1 = strchr(str, '{');
if ( s1 == NULL ) {
return my_strdup(str);
}
// append prefix
unsigned int s1_len;
s1 = r3_slug_find_placeholder(str, len, &s1_len);
if ( (s1 - str) > 0 ) {
sep = *(s1-1);
if ( !s1 ) {
return strndup(str,len);
}
char * out = NULL;
if ((out = calloc(sizeof(char),128)) == NULL) {
if (!(out = calloc(1, sizeof(char) * 200))) {
return (NULL);
}
// append prefix
o = out;
strncat(o, str, s1 - str);
strncat(o, "^", 1);
o++;
strncat(o, str, s1 - str); // string before slug
o += (s1 - str);
// start after ':'
if ( NULL != (pat = strchr(s1, ':')) ) {
pat++;
// this slug contains a pattern
s2 = strchr(pat, '}');
unsigned int pat_len;
pat = r3_slug_find_pattern(s1, s1_len, &pat_len);
if (pat) {
*o = '(';
o++;
strncat(o, pat, (s2 - pat) );
o += (s2 - pat);
strncat(o, pat, pat_len );
o += pat_len;
*o = ')';
o++;
} else {
// should return a '[^/]+' pattern
// strncat(c, "([^%c]+)", strlen("([^%c]+)") );
// snprintf(pat, 128, "([^%c]+)", sep);
sprintf(o, "([^%c]+)", sep);
o+= sizeof("([^%c]+)");
}
s2++;
while( (s2 - str) > len ) {
*o = *s2;
s2++;
o++;
o+= strlen("([^*]+)");
}
s1 += s1_len;
strncat(o, s1, len - (s1 - str)); // string after slug
return out;
}
@ -117,61 +230,7 @@ char * ltrim_slash(char* str)
{
char * p = str;
while (*p == '/') 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;
}
return strdup(p);
}
void print_indent(int level) {
@ -181,28 +240,36 @@ void print_indent(int level) {
}
}
char *my_strdup(const char *s) {
#ifndef HAVE_STRDUP
char *strdup(const char *s) {
char *out;
int count = 0;
while( s[count] )
++count;
++count;
out = malloc(sizeof(char*) * count);
out = malloc(sizeof(char) * count);
out[--count] = 0;
while( --count >= 0 )
out[count] = s[count];
return out;
}
#endif
char *my_strndup(const char *s, int n) {
#ifndef HAVE_STRNDUP
char *strndup(const char *s, int n) {
char *out;
int count = 0;
while( count < n && s[count] )
++count;
++count;
out = malloc(sizeof(char*) * count);
out = malloc(sizeof(char) * count);
out[--count] = 0;
while( --count >= 0 )
out[count] = s[count];
return out;
}
#endif

14
src/str.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef R3_STR_INTERN_H
#define R3_STR_INTERN_H
#ifdef __cplusplus
extern "C" {
#endif
void print_indent(int level);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,59 +1,54 @@
/*
* token.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
*
* Distributed under terms of the MIT license.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
#include "str_array.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;
}
#include "memory.h"
void str_array_free(str_array *l) {
for ( int i = 0; i < l->len ; i++ ) {
char * t = l->tokens[ i ];
free(t);
}
free(l);
assert(l);
free(l->tokens.entries);
}
bool str_array_is_full(str_array * l) {
return l->len >= l->cap;
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;
}
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;
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");
}
l->tokens[ l->len++ ] = token;
return TRUE;
}
void str_array_dump(str_array *l) {
void str_array_dump(const str_array *l) {
printf("[");
for ( int i = 0; i < l->len ; i++ ) {
printf("\"%s\"", l->tokens[i] );
if ( i + 1 != l->len ) {
for ( int i = 0; i < l->tokens.size ; i++ ) {
printf("\"%*.*s\"", l->tokens.entries[i].len,l->tokens.entries[i].len,l->tokens.entries[i].base );
// printf("\"%s\"", l->tokens.entries[i] );
if ( i + 1 != l->tokens.size ) {
printf(", ");
}
}
@ -63,55 +58,3 @@ void str_array_dump(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;
}

View file

@ -1,24 +1,27 @@
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
find_package(Check REQUIRED)
find_package(PCRE REQUIRED)
# find_package(Judy REQUIRED)
function(add_r3_test NAME)
add_executable(${NAME} ${ARGN})
if (NOT CHECK_FOUND)
message(STATUS "Skipping unit tests, Check library not found!")
else (NOT CHECK_FOUND)
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3)
target_include_directories(${NAME}
PRIVATE
${CHECK_INCLUDE_DIRS}
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/src)
include_directories(${CHECK_INCLUDE_DIRS})
# include_directories("${PROJECT_SOURCE_DIR}/include/r2")
add_executable(test_r3 test_tree.c)
target_link_libraries(test_r3 ${TEST_LIBS})
target_link_libraries(${NAME}
${CHECK_LDFLAGS}
r3)
add_custom_command(
TARGET test_r3 POST_BUILD
COMMENT "Running unit tests"
COMMAND test_r3
)
endif (NOT CHECK_FOUND)
add_test(NAME ${NAME} COMMAND ${NAME})
endfunction()
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)

View file

@ -1,14 +1,63 @@
# INCLUDES = @CHECK_CFLAGS@
if HAVE_CHECK
TESTS = check_tree
else
TESTS =
TESTS =
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -Wall -std=c99 -ggdb `pkg-config --cflags --libs check`
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
if USE_JEMALLOC
AM_CFLAGS += -ljemalloc
endif
# noinst_PROGRAMS = $(TESTS)
check_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
check_tree_LDADD=$(DEPS_LIBS) -L$(top_builddir)/src -lcheck -lr3
check_tree_CFLAGS=$(DEPS_CFLAGS) @CHECK_CFLAGS@
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)
noinst_PROGRAMS = bench
bench_SOURCES = bench.c
# 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

479
tests/bench.c Normal file
View file

@ -0,0 +1,479 @@
/*
* 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;
}

68
tests/bench.h Normal file
View file

@ -0,0 +1,68 @@
/*
* 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 */

View file

@ -1,50 +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
1 1400242718 5649455.80
2 1400242784 5775186.12
3 1400242814 5653481.02
4 1400242868 5857187.70
5 1400242938 5732228.92
6 1400243193 5959689.05
7 1400243423 5717292.34
8 1400243528 5669803.44
9 1400243702 5880318.26
10 1400243875 5789509.57
11 1400243912 5889038.56
12 1400243951 5922317.92
13 1400243971 6069795.56
14 1400243982 5904973.70
15 1400243985 5888983.99
16 1400244196 5174852.68
17 1400244284 5821697.95
18 1400244307 6012282.29
19 1400244516 5929306.97
20 1400244550 5858897.69
21 1400244556 5998727.11
22 1400244574 5846792.25
23 1400244592 5930319.69
24 1400244599 5910137.48
25 1400244639 5936452.01
26 1400244648 5978607.43
27 1400244653 5956364.63
28 1400244657 5911318.61
29 1400244829 6362496.45
30 1400244887 6330902.59
31 1400244895 6390983.42
32 1400244908 6380415.58
33 1400244914 6346830.19
34 1400244932 6610181.08
35 1400245102 6404550.11
36 1400245168 6085174.66
37 1400245176 6400679.76
38 1400245216 6416409.15
39 1400245227 6485899.37
40 1400245230 5862573.02
41 1400245233 6526163.60
42 1400245281 6205337.09
43 1400245289 6217947.43
44 1400245311 6423151.81
45 1400251162 5826610.20
46 1400251172 6039034.62
47 1400251256 6219533.32
48 1400251264 6015717.76
49 1400278620 5733465.40
50 1400279249 6306920.57

Some files were not shown because too many files have changed in this diff Show more