Compare commits

..

3 commits

Author SHA1 Message Date
c9s
cebf4cfba0 Add ip_mask 2014-06-13 19:38:04 +08:00
c9s
5a536b9145 Add ip_addr and ip_mask field to route struct 2014-06-12 22:34:11 +08:00
c9s
b9dc94bbee Add ip cmp function 2014-06-12 19:01:19 +08:00
98 changed files with 1578 additions and 12060 deletions

View file

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

View file

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

5
.gitignore vendored
View file

@ -51,8 +51,3 @@ autoscan.log
r3.pc
stamp-h1
tests/bench_str.csv
tests/check_host
config.h.in
examples/simple
examples/simple_cpp

View file

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

View file

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

View file

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

View file

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

View file

@ -1,111 +1,39 @@
language: c
sudo: required
services:
- docker
git:
depth: 1
compiler:
- gcc
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
- compiler: gcc
env: CONFIGURE_OPTION='--enable-debug --enable-gcov --with-malloc=jemalloc' COVERALLS=yes VALGRIND=no DEBUG=yes
- compiler: gcc
env: CONFIGURE_OPTION='--enable-debug --enable-gcov' COVERALLS=yes VALGRIND=yes DEBUG=yes LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/
# -D_BSD_SOURCE=1 is for asprintf
- compiler: clang
env: ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/local/clang-3.4/bin/llvm-symbolizer CFLAGS='-fsanitize=address -g -O1 -D_BSD_SOURCE=1'
install:
- docker exec -t build bash -c "cd /travis && .travis-ci/install.sh"
- sudo apt-get update -qq
- sudo apt-get install -qq automake pkg-config build-essential libtool automake autoconf m4 gnulib
- sudo apt-get install -qq check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1
- sudo apt-get install -qq graphviz-dev graphviz
- if [ "x$COVERALLS" == xyes ]; then sudo pip install cpp-coveralls; fi
- if [ "x$VALGRIND" == xyes ]; then sudo apt-get install valgrind; fi
before_script:
- sudo ldconfig
script:
- docker exec -t build bash -c "cd /travis && .travis-ci/script-$TYPE.sh"
- ./autogen.sh
- ./configure --enable-check $CONFIGURE_OPTION
- make V=1
- sudo make install
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
# XXX: tracing memory leak, disabled for some mystery reason for automake...
# - if [ "x$VALGRIND" == xyes && "x$DEBUG" == xyes ]; then valgrind ./tests/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
after_success:
- docker exec -t build bash -c "cd /travis && .travis-ci/after_success.sh"
- if [ x$COVERALLS == xyes ]; then coveralls --exclude php --exclude 3rdparty; fi
cache:
apt: true

14
3rdparty/Makefile.am vendored Normal file
View file

@ -0,0 +1,14 @@
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
noinst_LTLIBRARIES = libr3ext.la
libr3ext_la_SOURCES = zmalloc.c
libr3ext_la_LIBADD=$(DEPS_LIBS)
# noinst_LIBRARIES = libr3ext.la
libr3ext_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/3rdparty -Wall -std=c99
noinst_HEADERS = \
zmalloc.h \
$(NULL)

368
3rdparty/zmalloc.c vendored Normal file
View file

@ -0,0 +1,368 @@
/* zmalloc - total amount of allocated memory aware version of malloc()
*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
/* This function provide us access to the original libc free(). This is useful
* for instance to free results obtained by backtrace_symbols(). We need
* to define this function before including zmalloc.h that may shadow the
* free implementation if we use jemalloc or another non standard allocator. */
void zlibc_free(void *ptr) {
free(ptr);
}
#include <string.h>
#include <pthread.h>
#include "config.h"
#include "zmalloc.h"
#ifdef HAVE_MALLOC_SIZE
#define PREFIX_SIZE (0)
#else
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
#define PREFIX_SIZE (sizeof(long long))
#else
#define PREFIX_SIZE (sizeof(size_t))
#endif
#endif
/* Explicitly override malloc/free etc when using tcmalloc. */
#if defined(USE_TCMALLOC)
#define malloc(size) tc_malloc(size)
#define calloc(count,size) tc_calloc(count,size)
#define realloc(ptr,size) tc_realloc(ptr,size)
#define free(ptr) tc_free(ptr)
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
#include <jemalloc/jemalloc.h>
#define malloc(size) je_malloc(size)
#define calloc(count,size) je_calloc(count,size)
#define realloc(ptr,size) je_realloc(ptr,size)
#define free(ptr) je_free(ptr)
#endif
#ifdef HAVE_ATOMIC
#define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
#define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
#else
#define update_zmalloc_stat_add(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory += (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
#define update_zmalloc_stat_sub(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory -= (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
#endif
#define update_zmalloc_stat_alloc(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_add(_n); \
} else { \
used_memory += _n; \
} \
} while(0)
#define update_zmalloc_stat_free(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_sub(_n); \
} else { \
used_memory -= _n; \
} \
} while(0)
static size_t used_memory = 0;
static int zmalloc_thread_safe = 0;
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
static void zmalloc_default_oom(size_t size) {
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
size);
fflush(stderr);
abort();
}
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
void *zmalloc(size_t size) {
void *ptr = malloc(size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
void *zcalloc(size_t size) {
void *ptr = calloc(1, size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
void *zrealloc(void *ptr, size_t size) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
#endif
size_t oldsize;
void *newptr;
if (ptr == NULL) return zmalloc(size);
#ifdef HAVE_MALLOC_SIZE
oldsize = zmalloc_size(ptr);
newptr = realloc(ptr,size);
if (!newptr) zmalloc_oom_handler(size);
update_zmalloc_stat_free(oldsize);
update_zmalloc_stat_alloc(zmalloc_size(newptr));
return newptr;
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
newptr = realloc(realptr,size+PREFIX_SIZE);
if (!newptr) zmalloc_oom_handler(size);
*((size_t*)newptr) = size;
update_zmalloc_stat_free(oldsize);
update_zmalloc_stat_alloc(size);
return (char*)newptr+PREFIX_SIZE;
#endif
}
/* Provide zmalloc_size() for systems where this function is not provided by
* malloc itself, given that in that case we store a header with this
* information as the first bytes of every allocation. */
#ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr) {
void *realptr = (char*)ptr-PREFIX_SIZE;
size_t size = *((size_t*)realptr);
/* Assume at least that all the allocations are padded at sizeof(long) by
* the underlying allocator. */
if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
return size+PREFIX_SIZE;
}
#endif
void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
size_t oldsize;
#endif
if (ptr == NULL) return;
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_free(zmalloc_size(ptr));
free(ptr);
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
free(realptr);
#endif
}
char *zstrdup(const char *s) {
size_t l = strlen(s)+1;
char *p = zmalloc(l);
memcpy(p,s,l);
return p;
}
char * zstrndup (const char *s, size_t n)
{
char *result;
size_t len = strlen (s);
if (n < len)
len = n;
result = (char *) zmalloc (len + 1);
if (!result)
return 0;
result[len] = '\0';
return (char *) memcpy (result, s, len);
}
size_t zmalloc_used_memory(void) {
size_t um;
if (zmalloc_thread_safe) {
#ifdef HAVE_ATOMIC
um = __sync_add_and_fetch(&used_memory, 0);
#else
pthread_mutex_lock(&used_memory_mutex);
um = used_memory;
pthread_mutex_unlock(&used_memory_mutex);
#endif
}
else {
um = used_memory;
}
return um;
}
void zmalloc_enable_thread_safeness(void) {
zmalloc_thread_safe = 1;
}
void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
zmalloc_oom_handler = oom_handler;
}
/* Get the RSS information in an OS-specific way.
*
* WARNING: the function zmalloc_get_rss() is not designed to be fast
* and may not be called in the busy loops where Redis tries to release
* memory expiring or swapping out objects.
*
* For this kind of "fast RSS reporting" usages use instead the
* function RedisEstimateRSS() that is a much faster (and less precise)
* version of the function. */
#if defined(HAVE_PROC_STAT)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
size_t zmalloc_get_rss(void) {
int page = sysconf(_SC_PAGESIZE);
size_t rss;
char buf[4096];
char filename[256];
int fd, count;
char *p, *x;
snprintf(filename,256,"/proc/%d/stat",getpid());
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
if (read(fd,buf,4096) <= 0) {
close(fd);
return 0;
}
close(fd);
p = buf;
count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
while(p && count--) {
p = strchr(p,' ');
if (p) p++;
}
if (!p) return 0;
x = strchr(p,' ');
if (!x) return 0;
*x = '\0';
rss = strtoll(p,NULL,10);
rss *= page;
return rss;
}
#elif defined(HAVE_TASKINFO)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/task.h>
#include <mach/mach_init.h>
size_t zmalloc_get_rss(void) {
task_t task = MACH_PORT_NULL;
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
return 0;
task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
return t_info.resident_size;
}
#else
size_t zmalloc_get_rss(void) {
/* If we can't get the RSS in an OS-specific way for this system just
* return the memory usage we estimated in zmalloc()..
*
* Fragmentation will appear to be always 1 (no fragmentation)
* of course... */
return zmalloc_used_memory();
}
#endif
/* Fragmentation = RSS / allocated-bytes */
float zmalloc_get_fragmentation_ratio(size_t rss) {
return (float)rss/zmalloc_used_memory();
}
#if defined(HAVE_PROC_SMAPS)
size_t zmalloc_get_private_dirty(void) {
char line[1024];
size_t pd = 0;
FILE *fp = fopen("/proc/self/smaps","r");
if (!fp) return 0;
while(fgets(line,sizeof(line),fp) != NULL) {
if (strncmp(line,"Private_Dirty:",14) == 0) {
char *p = strchr(line,'k');
if (p) {
*p = '\0';
pd += strtol(line+14,NULL,10) * 1024;
}
}
}
fclose(fp);
return pd;
}
#else
size_t zmalloc_get_private_dirty(void) {
return 0;
}
#endif

86
3rdparty/zmalloc.h vendored Normal file
View file

@ -0,0 +1,86 @@
#ifndef ZMALLOC_H
#define ZMALLOC_H
/* zmalloc - total amount of allocated memory aware version of malloc()
*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Double expansion needed for stringification of macro values. */
#define __xstr(s) __str(s)
#define __str(s) #s
#if defined(USE_TCMALLOC)
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
#include <google/tcmalloc.h>
#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) tc_malloc_size(p)
#else
#error "Newer version of tcmalloc required"
#endif
#elif defined(USE_JEMALLOC) && (JEMALLOC_VERSION_MAJOR > 2)
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
#include <jemalloc/jemalloc.h>
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) je_malloc_usable_size(p)
#else
#error "Newer version of jemalloc required"
#endif
#elif defined(__APPLE__)
#include <malloc/malloc.h>
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) malloc_size(p)
#endif
#ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc"
#endif
void *zmalloc(size_t size);
void *zcalloc(size_t size);
void *zrealloc(void *ptr, size_t size);
void zfree(void *ptr);
char *zstrdup(const char *s);
char *zstrndup(const char *s, size_t n);
size_t zmalloc_used_memory(void);
void zmalloc_enable_thread_safeness(void);
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
float zmalloc_get_fragmentation_ratio(size_t rss);
size_t zmalloc_get_rss(void);
size_t zmalloc_get_private_dirty(void);
void zlibc_free(void *ptr);
#ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr);
#endif
#endif // ZMALLOC_H

View file

@ -3,20 +3,6 @@
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

View file

@ -1,49 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project(r3 VERSION 2.0.0)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)
set(CMAKE_C_STANDARD 99)
find_package(Check)
find_package(PCRE2 REQUIRED)
include(CheckSymbolExists)
include(CheckIncludeFile)
check_symbol_exists(strdup string.h HAVE_STRDUP)
check_symbol_exists(strndup string.h HAVE_STRNDUP)
check_include_file(stdbool.h HAVE_STDBOOL_H)
configure_file(config.h.cmake config.h)
add_subdirectory(src)
install(
FILES
include/memory.h
include/r3.h
include/r3_list.h
include/r3_slug.h
include/r3_gvc.h
include/r3_json.h
include/str_array.h
include/r3.hpp
DESTINATION include/r3)
# Configure substitutions for r3.pc. The variables set here must match the
# @<values>@ in r3.pc.in.
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix ${prefix})
set(includedir ${prefix}/include)
set(libdir ${prefix}/lib)
set(PACKAGE_VERSION ${PROJECT_VERSION})
configure_file(r3.pc.in r3.pc @ONLY)
install(
FILES
${PROJECT_BINARY_DIR}/r3.pc
DESTINATION lib/pkgconfig)
if(CHECK_FOUND)
enable_testing()
add_subdirectory(tests)
else()
message(STATUS "Skipping unit tests, Check library not found!")
endif()

View file

@ -1,15 +1,11 @@
SUBDIRS=src . examples
if ENABLE_CHECK
SUBDIRS += tests
endif
SUBDIRS=3rdparty src . tests examples
lib_LTLIBRARIES = libr3.la
libr3_la_SOURCES =
libr3_la_LIBADD = src/libr3core.la
libr3_la_LIBADD = 3rdparty/libr3ext.la src/libr3core.la
libr3_la_LDFLAGS =
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS)
@ -17,8 +13,6 @@ ACLOCAL_AMFLAGS=-I m4
if ENABLE_DEBUG
AM_CFLAGS += -ggdb -fprofile-arcs -ftest-coverage
else
AM_CFLAGS += -O2
endif
if USE_JEMALLOC
@ -27,10 +21,10 @@ endif
r3_includedir = $(includedir)/r3
r3_include_HEADERS = \
include/memory.h \
include/r3.h \
include/r3_define.h \
include/r3_list.h \
include/r3_slug.h \
include/r3_str.h \
include/r3_gvc.h \
include/r3_json.h \
include/str_array.h \

View file

@ -1,12 +1,12 @@
R3
================
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=2.0)](https://travis-ci.org/c9s/r3)
[![Build Status](https://travis-ci.org/c9s/r3.svg?branch=master)](https://travis-ci.org/c9s/r3)
[![Coverage Status](https://coveralls.io/repos/c9s/r3/badge.svg)](https://coveralls.io/r/c9s/r3)
[![Coverage Status](https://coveralls.io/repos/c9s/r3/badge.png)](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.
It compiles your route 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.
@ -25,7 +25,7 @@ Requirement
### Runtime Requirement
* pcre2
* pcre
* (optional) graphviz version 2.38.0 (20140413.2041)
* (optional) libjson-c-dev
@ -43,11 +43,11 @@ API
#include <r3/r3.h>
// create a router tree with 10 children capacity (this capacity can grow dynamically)
R3Node *n = r3_tree_create(10);
n = r3_tree_create(10);
int route_data = 3;
// insert the R3Route path into the router tree
// insert the route 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 );
@ -61,7 +61,7 @@ r3_tree_insert_pathl(n, "/user/{id:\\d+}", strlen("/user/{id:\\d+}"), &route_dat
// if you want to catch error, you may call the extended path function for insertion
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);
node *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);
@ -83,9 +83,9 @@ if (err != 0) {
r3_tree_dump(n, 0);
// match a route
R3Node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
if (matched_node) {
int ret = *( (int*) matched_node->data );
int ret = *( (*int) matched_node->data );
}
// release the tree
@ -114,18 +114,18 @@ 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:
When using `match_entry`, you may match the route with `r3_tree_match_entry` function:
```c
R3Node * matched_node = r3_tree_match_entry(n, entry);
node *matched_node = r3_tree_match_entry(n, entry);
```
**Release Memory**
**Release Memroy**
To release the memory, you may call `r3_tree_free(R3Node *tree)` to release the whole tree structure,
To release the memory, you may call `r3_tree_free(node *tree)` to release the whole tree structure,
`node*`, `edge*`, `route*` objects that were inserted into the tree will be freed.
@ -141,7 +141,7 @@ n = r3_tree_create(10);
int route_data = 3;
// insert the R3Route path into the router tree
// insert the route path into the router tree
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/post", sizeof("/blog/post") - 1, &route_data );
char *errstr = NULL;
@ -156,15 +156,15 @@ if (err != 0) {
// in your http server handler
// create the match entry for capturing dynamic variables.
match_entry * entry = match_entry_create("/blog/post");
match_entry * entry = match_entry_create("/foo/bar");
entry->request_method = METHOD_GET;
R3Route *matched_R3Route = r3_tree_match_route(n, entry);
route *matched_route = 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_route_free(r1);
r3_tree_free(n);
```
@ -179,7 +179,7 @@ To specify the pattern of a slug, you may write a colon to separate the slug nam
"/user/{userId:\\d+}"
The above R3Route will use `\d+` as its pattern.
The above route will use `\d+` as its pattern.
Optimization
@ -187,13 +187,13 @@ 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.
By using this method, r3 reduces the matching overhead of pcre library.
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+`, `[^-]+` or `.*`.
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+` or `[^-]+`
Slugs without specified regular expression will be compiled into the `[^/]+` pattern. therefore, it's optimized too.
Complex regular expressions will still use libpcre2 to match URL (partially).
Complex regular expressions will still use libpcre to match URL (partially).
Performance
@ -206,7 +206,7 @@ And here is the result of the router journey:
omg 9932.9 (±4.8%) i/s - 49873 in 5.033452s
r3 uses the same R3Route path data for benchmarking, and here is the benchmark:
r3 uses the same route path data for benchmarking, and here is the benchmark:
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
11460057.83 i/sec
@ -214,7 +214,7 @@ r3 uses the same R3Route path data for benchmarking, and here is the benchmark:
### The Route Paths Of Benchmark
The R3Route path generator is from <https://github.com/stevegraham/rails/pull/1>:
The route path generator is from <https://github.com/stevegraham/rails/pull/1>:
```ruby
#!/usr/bin/env ruby
@ -242,7 +242,7 @@ Function prefix mapping
Rendering Routes With Graphviz
---------------------------------------
The `r3_tree_render_file` API let you render the whole R3Route trie into a image.
The `r3_tree_render_file` API let you render the whole route trie into a image.
To use graphviz, you need to enable graphviz while you run `configure`:
@ -254,7 +254,7 @@ Here is the sample code of generating graph output:
```c
R3Node * n = r3_tree_create(1);
node * n = r3_tree_create(1);
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
@ -280,7 +280,7 @@ r3_tree_free(n);
```
![Imgur](http://imgur.com/HrUoEbI.png)
![Imgur](http://i.imgur.com/hA8QXRi.png)
Or you can even export it with dot format:
@ -300,13 +300,13 @@ digraph g {
### Graphviz Related Functions
```c
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
int r3_tree_render_file(const node * 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(const node * 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_dot(const node * tree, const char *layout, FILE *fp);
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
int r3_tree_render_file(const node * tree, const char * format, const char * filename);
```
@ -347,7 +347,7 @@ $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 R3Route conditions
list($error, $message) = r3_validate($route); // validate route conditions
if ( $error ) {
echo $message; // "Method not allowed", "...";
}
@ -356,7 +356,7 @@ if ( $error ) {
Install
----------------------
sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
sudo apt-get install check libpcre3 libpcre3-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
@ -364,8 +364,7 @@ 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
sudo apt-get install build-essential autoconf automake libpcre3-dev pkg-config debhelper libtool check
dpkg-buildpackage -b -us -uc
sudo gdebi ../libr3*.deb
@ -383,10 +382,6 @@ And we support debian-based distro now!
./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
---------------------------
@ -397,16 +392,6 @@ Binding For Other Languages
* 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

View file

@ -11,8 +11,6 @@
<script>
$.get('bench_str.csv', function(data) {
var options = {
chart: {
zoomType: 'x',
@ -149,18 +147,8 @@
};
var lines = data.split(/\n/);
// keep window size to 60 records
lines = lines.splice(-60);
$(lines).each(function(i,line) {
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);

View file

@ -584,63 +584,3 @@
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

@ -1,54 +0,0 @@
# - Try to find the CHECK libraries
# Once done this will define
#
# CHECK_FOUND - system has check
# CHECK_INCLUDE_DIRS - the check include directory
# CHECK_LIBRARIES - check library
#
# Copyright (c) 2007 Daniel Gollub <gollub@b1-systems.de>
# Copyright (c) 2007-2009 Bjoern Ricks <bjoern.ricks@gmail.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE( FindPkgConfig )
IF ( Check_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "REQUIRED" )
ELSE( Check_FIND_REQUIRED )
SET( _pkgconfig_REQUIRED "" )
ENDIF ( Check_FIND_REQUIRED )
IF ( CHECK_MIN_VERSION )
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
ELSE ( CHECK_MIN_VERSION )
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
ENDIF ( CHECK_MIN_VERSION )
# Look for CHECK include dir and libraries
IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
FIND_PATH( CHECK_INCLUDE_DIRS check.h )
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
SET( CHECK_FOUND 1 )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
ENDIF ( NOT Check_FIND_QUIETLY )
ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
IF ( Check_FIND_REQUIRED )
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
ELSE ( Check_FIND_REQUIRED )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE( STATUS "Could NOT find CHECK" )
ENDIF ( NOT Check_FIND_QUIETLY )
ENDIF ( Check_FIND_REQUIRED )
ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
# Hide advanced variables from CMake GUIs
MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES )

View file

@ -1,44 +0,0 @@
# - Try to find jemalloc headers and libraries.
#
# Usage of this module as follows:
#
# find_package(JeMalloc)
#
# Variables used by this module, they can change the default behaviour and need
# to be set before calling find_package:
#
# JEMALLOC_ROOT_DIR Set this variable to the root installation of
# jemalloc if the module has problems finding
# the proper installation path.
#
# Variables defined by this module:
#
# JEMALLOC_FOUND System has jemalloc libs/headers
# JEMALLOC_LIBRARIES The jemalloc library/libraries
# JEMALLOC_INCLUDE_DIR The location of jemalloc headers
find_path(JEMALLOC_ROOT_DIR
NAMES include/jemalloc/jemalloc.h
)
find_library(JEMALLOC_LIBRARIES
NAMES jemalloc
HINTS ${JEMALLOC_ROOT_DIR}/lib
)
find_path(JEMALLOC_INCLUDE_DIR
NAMES jemalloc/jemalloc.h
HINTS ${JEMALLOC_ROOT_DIR}/include
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JeMalloc DEFAULT_MSG
JEMALLOC_LIBRARIES
JEMALLOC_INCLUDE_DIR
)
mark_as_advanced(
JEMALLOC_ROOT_DIR
JEMALLOC_LIBRARIES
JEMALLOC_INCLUDE_DIR
)

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 judy
# Find the native Judy headers and libraries.
#
# Judy_INCLUDE_DIRS - where to find judy.h, etc.
# Judy_LIBRARIES - List of libraries when using judy.
# Judy_FOUND - True if judy found.
# Look for the header file.
FIND_PATH(Judy_INCLUDE_DIR NAMES Judy.h)
# Look for the library.
FIND_LIBRARY(Judy_LIBRARY NAMES judy)
# Handle the QUIETLY and REQUIRED arguments and set Judy_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Judy DEFAULT_MSG Judy_LIBRARY Judy_INCLUDE_DIR)
# Copy the results to the output variables.
IF(Judy_FOUND)
SET(Judy_LIBRARIES ${Judy_LIBRARY})
SET(Judy_INCLUDE_DIRS ${Judy_INCLUDE_DIR})
ELSE(Judy_FOUND)
SET(Judy_LIBRARIES)
SET(Judy_INCLUDE_DIRS)
ENDIF(Judy_FOUND)
MARK_AS_ADVANCED(Judy_INCLUDE_DIRS Judy_LIBRARIES)

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 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,3 +0,0 @@
#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
#cmakedefine HAVE_STRNDUP @HAVE_STRNDUP@
#cmakedefine HAVE_STDBOOL_H @HAVE_STDBOOL_H@

View file

@ -1,16 +1,13 @@
AC_INIT([r3], 2.0.0)
AC_INIT([r3], 1.3.0)
AC_PREREQ([2.64])
AC_USE_SYSTEM_EXTENSIONS
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_MACRO_DIR([m4])
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
# older debian
AC_PROG_LIBTOOL
@ -23,6 +20,8 @@ AC_C_INLINE
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr])
PKG_PROG_PKG_CONFIG
@ -73,14 +72,14 @@ AM_CONDITIONAL(USE_JEMALLOC, test "x$have_jemalloc" = "xyes")
# AC_DEFINE(USE_JEMALLOC, test "x$found_jemalloc" = "xyes" , "use jemalloc")
PKG_CHECK_MODULES(DEPS, [libpcre2-8])
PKG_CHECK_MODULES(DEPS, [libpcre])
AC_SUBST(DEPS_CFLAGS)
AC_SUBST(DEPS_LIBS)
AC_ARG_ENABLE(debug,AS_HELP_STRING([--enable-debug],[enable debug]))
if test "x$enable_debug" = "xyes"; then
AC_DEFINE(DEBUG, 1, "debug")
AC_DEFINE(ENABLE_DEBUG, 1, "debug")
fi
AM_CONDITIONAL(ENABLE_DEBUG, test "x$enable_debug" = "xyes")
@ -116,21 +115,20 @@ 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"]
)]
[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")
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
AC_CONFIG_FILES([
r3.pc
Makefile
3rdparty/Makefile
src/Makefile
tests/Makefile
examples/Makefile

View file

View file

@ -2,7 +2,7 @@ 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
libtool, libpcre3-dev, pkg-config, check
Standards-Version: 3.9.4
Section: libs
Homepage: https://github.com/c9s/r3
@ -13,7 +13,7 @@ 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
performance, thus, it's implemented in C. It compiles your route paths into
a prefix trie.
.
This package contains header files for libr3.
@ -24,5 +24,5 @@ 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
performance, thus, it's implemented in C. It compiles your route paths into
a prefix trie.

View file

View file

View file

@ -1,7 +1,5 @@
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
noinst_PROGRAMS = simple
simple_SOURCES = simple.c
simple_cpp_SOURCES = simple_cpp.cpp

View file

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

View file

@ -1,6 +1,6 @@
/*
* bench.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,7 +10,7 @@
int main()
{
R3Node * n = r3_tree_create(3);
node * n = r3_tree_create(3);
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
@ -44,16 +44,15 @@ int main()
return 1;
}
R3Node *m;
node *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);
printf("Matched! %s\n", e->path);
}
match_entry_free(e);
r3_tree_free(n);
return 0;
}

View file

@ -1,97 +0,0 @@
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <r3.hpp>
using namespace std;
void example_1() {
// create a router tree with 10 children capacity (this capacity can grow dynamically)
r3::Tree tree(10);
// insert the R3Route path into the router tree
int route_data_1 = 1;
tree.insert_path("/bar", &route_data_1); // ignore the length of path
int route_data_2 = 2;
tree.insert_pathl("/zoo", strlen("/zoo"), &route_data_2);
int route_data_3 = 3;
tree.insert_pathl("/foo/bar", strlen("/foo/bar"), &route_data_3);
int route_data_4 = 4;
tree.insert_pathl("/post/{id}", strlen("/post/{id}") , &route_data_4);
int route_data_5 = 5;
tree.insert_pathl("/user/{id:\\d+}", strlen("/user/{id:\\d+}"),
&route_data_5);
// if you want to catch error, you may call the extended path function for insertion
int data = 10;
char* errstr;
r3::Node ret = tree.insert_pathl("/foo/{name:\\d{5}",
strlen("/foo/{name:\\d{5}"), &data, &errstr);
if (ret == NULL) {
// failed insertion
cout << "error: " << errstr << endl;
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
}
// let's compile the tree!
int err = tree.compile(&errstr);
if (err != 0) {
cout << "error: " << errstr << endl;
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
}
// dump the compiled tree
tree.dump(0);
// match a route
r3::Node matched_node = tree.matchl("/foo/bar", strlen("/foo/bar"));
if (matched_node) {
int ret = *static_cast<int*>(matched_node.data());
cout << "match path ret: " << ret << endl;
}
r3::MatchEntry entry("/foo/bar");
matched_node = tree.match_entry(entry);
if (matched_node) {
int ret = *static_cast<int*>(matched_node.data());
cout << "match entry ret: " << ret << endl;
}
}
void example_2() {
// create a router tree with 10 children capacity (this capacity can grow dynamically)
r3::Tree tree(10);
// insert the R3Route path into the router tree
int route_data = 1;
tree.insert_routel(METHOD_GET | METHOD_POST, "/blog/post",
sizeof("/blog/post") - 1, &route_data);
char* errstr;
int err = tree.compile(&errstr);
if (err != 0) {
cout << "errstr: " << errstr << endl;
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
}
// in your http server handler
// create the match entry for capturing dynamic variables.
r3::MatchEntry entry("/blog/post");
entry.set_request_method(METHOD_GET);
r3::Route matched_route = tree.match_route(entry);
if (matched_route) {
int ret = *static_cast<int*>(matched_route.data());
cout << "match route ret: " << ret << endl;
}
}
int main() {
example_1();
example_2();
return 0;
}

View file

@ -10,7 +10,7 @@ puts <<END
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "zmalloc.h"
START_TEST (test_routes)

View file

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

View file

@ -1,6 +1,6 @@
/*
* r3.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,24 +10,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.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 <pcre.h>
#include <stdbool.h>
#include "r3_define.h"
#include "str_array.h"
#include "r3_slug.h"
#include "memory.h"
#ifdef __cplusplus
extern "C" {
@ -36,99 +22,126 @@ extern "C" {
struct _edge;
struct _node;
struct _route;
typedef struct _edge R3Edge;
typedef struct _node R3Node;
typedef struct _R3Route R3Route;
typedef struct _edge edge;
typedef struct _node node;
typedef struct _route route;
struct _node {
R3_VECTOR(R3Edge) edges;
R3_VECTOR(R3Route) routes;
char * combined_pattern;
pcre2_code * pcre_pattern;
pcre2_match_data * match_data;
struct _node {
edge ** edges;
// edge ** edge_table;
// 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
unsigned char compare_type; // compare_type: pcre, opcode, string
unsigned char edge_len;
unsigned char endpoint; // endpoint, should be zero for non-endpoint nodes
unsigned char ov_cnt; // capture vector array size for pcre
// the pointer of R3Route data
// almost less than 255
unsigned char edge_cap;
unsigned char route_len;
unsigned char route_cap;
// <-- here comes a char[1] struct padding for alignment since we have 4 char above.
/** compile-time variables here.... **/
/* the combined regexp pattern string from pattern_tokens */
pcre * pcre_pattern;
pcre_extra * pcre_extra;
route ** routes;
char * combined_pattern;
/**
* the pointer of route 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
#define r3_node_edge_pattern(node,i) node->edges[i]->pattern
#define r3_node_edge_pattern_len(node,i) node->edges[i]->pattern_len
struct _edge {
r3_iovec_t pattern; // 8 bytes
R3Node * child; // 8 bytes
unsigned int opcode; // 4byte
unsigned int has_slug; // 4byte
char * pattern; // 8 bytes
node * child; // 8 bytes
unsigned char pattern_len; // 1 byte
unsigned char opcode:4; // 4 bit
unsigned char has_slug:1; // 1 bit
};
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
struct _route {
char * path;
int path_len;
int request_method; // can be (GET || POST)
char * host; // required host name
int host_len;
void * data;
r3_iovec_t remote_addr_pattern;
char * ip_addr;
char * ip_mask;
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)
// todo: take of this
char * remote_addr_pattern;
int remote_addr_pattern_len;
};
typedef struct _R3Entry match_entry;
struct _R3Entry {
str_array vars;
r3_iovec_t path; // current path to dispatch
int request_method; // current request method
typedef struct {
str_array * vars;
const char * path; // current path to dispatch
int path_len; // the length of the current path
int request_method; // current request method
void * data; // R3Route ptr
void * data; // route ptr
r3_iovec_t host; // the request host
r3_iovec_t remote_addr;
char * host; // the request host
int host_len;
int http_scheme;
};
char * remote_addr;
int remote_addr_len;
} match_entry;
R3Node * r3_tree_create(int cap);
// R3Node * r3_node_create();
void r3_tree_free(R3Node * tree);
R3Edge * r3_node_connectl(R3Node * n, const char * pat, int len, int strdup, R3Node *child);
node * r3_tree_create(int cap);
node * r3_node_create();
void r3_tree_free(node * tree);
edge * r3_node_connectl(node * n, const char * pat, int len, int strdup, node *child);
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
R3Edge * r3_node_find_edge(const R3Node * n, const char * pat, unsigned int pat_len);
edge * r3_node_find_edge(const node * n, const char * pat, int pat_len);
R3Edge * r3_node_append_edge(R3Node *n);
void r3_node_append_edge(node *n, edge *child);
R3Edge * r3_node_find_common_prefix(R3Node *n, const char *path, int path_len, int *prefix_len, char **errstr);
R3Node * r3_tree_insert_pathl(R3Node *tree, const char *path, int path_len, void * data);
edge * r3_node_find_common_prefix(node *n, const char *path, int path_len, int *prefix_len, char **errstr);
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, 0, 0, data, NULL)
node * r3_tree_insert_pathl(node *tree, const char *path, int path_len, void * data);
#define r3_tree_insert_pathl(tree, path, path_len, data) r3_tree_insert_pathl_ex(tree, path, path_len, NULL , data, NULL)
R3Route * r3_tree_insert_routel(R3Node * tree, int method, const char *path, int path_len, void *data);
route * r3_tree_insert_routel(node *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);
route * r3_tree_insert_routel_ex(node *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_path(n,p,d) r3_tree_insert_pathl_ex(n,p,strlen(p), NULL, d, NULL)
#define r3_tree_insert_route(n,method,path,data) r3_tree_insert_routel(n, method, path, strlen(path), data)
@ -136,51 +149,49 @@ R3Route * r3_tree_insert_routel_ex(R3Node * tree, int method, const char *path,
/**
* 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);
node * r3_tree_insert_pathl_ex(node *tree, const char *path, int path_len, route * route, void * data, char ** errstr);
void r3_tree_dump(const R3Node * n, int level);
void r3_tree_dump(const node * n, int level);
R3Edge * r3_node_find_edge_str(const R3Node * n, const char * str, int str_len);
edge * r3_node_find_edge_str(const node * n, const char * str, int str_len);
int r3_tree_compile(R3Node *n, char** errstr);
int r3_tree_compile(node *n, char** errstr);
int r3_tree_compile_patterns(R3Node * n, char** errstr);
int r3_tree_compile_patterns(node * n, char** errstr);
R3Node * r3_tree_matchl(const R3Node * n, const char * path, unsigned int path_len, match_entry * entry);
node * r3_tree_matchl(const node * n, const char * path, 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)
// node * r3_tree_match_entry(node * n, match_entry * entry);
#define r3_tree_match_entry(n, entry) r3_tree_matchl(n, entry->path, entry->path_len, entry)
bool r3_node_has_slug_edges(const R3Node *n);
bool r3_node_has_slug_edges(const node *n);
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child);
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child);
void r3_edge_initl(R3Edge *e, const char * pattern, int pattern_len, R3Node * child);
node * r3_edge_branch(edge *e, int dl);
R3Node * r3_edge_branch(R3Edge *e, int dl);
void r3_edge_free(R3Edge * edge);
void r3_edge_free(edge * edge);
R3Route * r3_route_create(const char * path);
route * r3_route_create(const char * path);
// R3Route * r3_route_createl(const char * path, int path_len);
route * 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_node_append_route(node * n, route * route);
void r3_route_free(R3Route * route);
void r3_route_free(route * route);
int r3_route_cmp(const R3Route *r1, const match_entry *r2);
int r3_route_cmp(const route *r1, const match_entry *r2);
R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry);
route * r3_tree_match_route(const node *n, match_entry * entry);
#define r3_route_create(p) r3_route_createl(p, strlen(p))
@ -193,16 +204,13 @@ R3Route * r3_tree_match_route(const R3Node *n, match_entry * entry);
#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);
int r3_pattern_to_opcode(const char * pattern, int pattern_len);
enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE };
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH,
OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA, OP_GREEDY_ANY};
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH, OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA };
@ -213,7 +221,8 @@ match_entry * match_entry_createl(const char * path, int path_len);
void match_entry_free(match_entry * entry);
int r3_ip_cmp(const char* a, const char* b);
int r3_ip_mask_cmp(const char *a, const char* mask_str, const char* b);
#ifdef __cplusplus
}

View file

@ -8,7 +8,7 @@
#define R3_HPP
#include <cstring>
#include "r3.h"
#include <r3.h>
namespace r3 {
template <typename T>
@ -37,8 +37,8 @@ namespace r3 {
private:
T* p_;
};
typedef Base<R3Node> Node;
typedef Base<R3Route> Route;
typedef Base<node> Node;
typedef Base<route> Route;
class MatchEntry : public Base<match_entry> {
public:
@ -69,7 +69,7 @@ namespace r3 {
MatchEntry& operator =(const MatchEntry&);
};
class Tree : public Base<R3Node> {
class Tree : public Base<node> {
public:
explicit Tree(int cap)
: Base(r3_tree_create(cap)) {
@ -90,13 +90,13 @@ namespace r3 {
}
Node insert_path(const char* path, void* data, char** errstr = NULL) {
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), 0, 0,
return r3_tree_insert_pathl_ex(get(), path, std::strlen(path), NULL,
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,
return r3_tree_insert_pathl_ex(get(), path, path_len, NULL, data,
errstr);
}

37
include/r3_define.h Normal file
View file

@ -0,0 +1,37 @@
/*
* r3_define.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#ifndef DEFINE_H
#define DEFINE_H
#include <stdbool.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 */

View file

@ -1,6 +1,6 @@
/*
* r3_gvc.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -11,7 +11,7 @@
#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);
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);

View file

@ -1,6 +1,6 @@
/*
* r3_json.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -11,13 +11,13 @@
#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);
json_object * r3_edge_to_json_object(const edge * e);
json_object * r3_node_to_json_object(const node * n);
json_object * r3_route_to_json_object(const route * 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);
const char * r3_node_to_json_string_ext(const node * n, int options);
const char * r3_node_to_json_pretty_string(const node * n);
const char * r3_node_to_json_string(const node * n);

View file

@ -1,6 +1,6 @@
/*
* r3_list.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/

View file

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

35
include/r3_str.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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.h"
#include "config.h"
char * r3_slug_compile(const char * str, int len);
char * r3_slug_find_pattern(const char *s1, int *len);
char * r3_slug_find_placeholder(const char *s1, int *len);
char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **errstr);
void str_repeat(char *s, const char *c, int len);
void print_indent(int level);
#ifndef HAVE_STRDUP
char *strdup(const char *s);
#endif
#ifndef HAVE_STRNDUP
char *strndup(const char *s, int n);
#endif
#endif /* !STR_H */

View file

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

View file

@ -1,9 +0,0 @@
{
"name": "r3",
"version": "2.0.0",
"repo": "brendanashworth/r3",
"description": "high-performance path dispatching library",
"keywords": ["path", "dispatch", "performance", "r3", "c9s"],
"license": "MIT",
"src": ["include/memory.h", "include/r3.h", "include/r3.hpp", "include/r3_gvc.h", "include/r3_json.h", "include/r3_list.h", "include/r3_slug.h", "include/str_array.h", "src/edge.c", "src/gvc.c", "src/json.c", "src/list.c", "src/match_entry.c", "src/node.c", "src/slug.c", "src/slug.h", "src/str.c", "src/token.c"]
}

View file

@ -1,40 +0,0 @@
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
typedef struct _phannot_parser_token {
char *token;
int opcode;
int token_len;
int free_flag;
} phannot_parser_token;
typedef struct _phannot_parser_status {
zval *ret;
phannot_scanner_state *scanner_state;
phannot_scanner_token *token;
int status;
zend_uint syntax_error_len;
char *syntax_error;
} phannot_parser_status;
#define PHANNOT_PARSING_OK 1
#define PHANNOT_PARSING_FAILED 0
extern int phannot_parse_annotations(zval *result, zval *view_code, zval *template_path, zval *line TSRMLS_DC);
int phannot_internal_parse_annotations(zval **result, zval *view_code, zval *template_path, zval *line, zval **error_msg TSRMLS_DC);

View file

@ -1,441 +0,0 @@
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
const phannot_token_names phannot_tokens[] =
{
{ "INTEGER", PHANNOT_T_INTEGER },
{ "DOUBLE", PHANNOT_T_DOUBLE },
{ "STRING", PHANNOT_T_STRING },
{ "IDENTIFIER", PHANNOT_T_IDENTIFIER },
{ "@", PHANNOT_T_AT },
{ ",", PHANNOT_T_COMMA },
{ "=", PHANNOT_T_EQUALS },
{ ":", PHANNOT_T_COLON },
{ "(", PHANNOT_T_PARENTHESES_OPEN },
{ ")", PHANNOT_T_PARENTHESES_CLOSE },
{ "{", PHANNOT_T_BRACKET_OPEN },
{ "}", PHANNOT_T_BRACKET_CLOSE },
{ "[", PHANNOT_T_SBRACKET_OPEN },
{ "]", PHANNOT_T_SBRACKET_CLOSE },
{ "ARBITRARY TEXT", PHANNOT_T_ARBITRARY_TEXT },
{ NULL, 0 }
};
/**
* Wrapper to alloc memory within the parser
*/
static void *phannot_wrapper_alloc(size_t bytes){
return emalloc(bytes);
}
/**
* Wrapper to free memory within the parser
*/
static void phannot_wrapper_free(void *pointer){
efree(pointer);
}
/**
* Creates a parser_token to be passed to the parser
*/
static void phannot_parse_with_token(void* phannot_parser, int opcode, int parsercode, phannot_scanner_token *token, phannot_parser_status *parser_status){
phannot_parser_token *pToken;
pToken = emalloc(sizeof(phannot_parser_token));
pToken->opcode = opcode;
pToken->token = token->value;
pToken->token_len = token->len;
pToken->free_flag = 1;
phannot_(phannot_parser, parsercode, pToken, parser_status);
token->value = NULL;
token->len = 0;
}
/**
* Creates an error message when it's triggered by the scanner
*/
static void phannot_scanner_error_msg(phannot_parser_status *parser_status, zval **error_msg TSRMLS_DC){
int error_length;
char *error, *error_part;
phannot_scanner_state *state = parser_status->scanner_state;
ALLOC_INIT_ZVAL(*error_msg);
if (state->start) {
error_length = 128 + state->start_length + Z_STRLEN_P(state->active_file);
error = emalloc(sizeof(char) * error_length);
if (state->start_length > 16) {
error_part = estrndup(state->start, 16);
snprintf(error, 64 + state->start_length, "Scanning error before '%s...' in %s on line %d", error_part, Z_STRVAL_P(state->active_file), state->active_line);
efree(error_part);
} else {
snprintf(error, error_length - 1, "Scanning error before '%s' in %s on line %d", state->start, Z_STRVAL_P(state->active_file), state->active_line);
}
error[error_length - 1] = '\0';
ZVAL_STRING(*error_msg, error, 1);
} else {
error_length = sizeof(char) * (64 + Z_STRLEN_P(state->active_file));
error = emalloc(error_length);
snprintf(error, error_length - 1, "Scanning error near to EOF in %s", Z_STRVAL_P(state->active_file));
ZVAL_STRING(*error_msg, error, 1);
error[error_length - 1] = '\0';
}
efree(error);
}
/**
* Receives the comment tokenizes and parses it
*/
int phannot_parse_annotations(zval *result, zval *comment, zval *file_path, zval *line TSRMLS_DC){
zval *error_msg = NULL;
ZVAL_NULL(result);
if (Z_TYPE_P(comment) != IS_STRING) {
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), ZEND_STRL("Comment must be a string"), 0 TSRMLS_CC);
return FAILURE;
}
if(phannot_internal_parse_annotations(&result, comment, file_path, line, &error_msg TSRMLS_CC) == FAILURE){
if (error_msg != NULL) {
// phalcon_throw_exception_string(phalcon_annotations_exception_ce, Z_STRVAL_P(error_msg), Z_STRLEN_P(error_msg), 1 TSRMLS_CC);
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), Z_STRVAL_P(error_msg), Z_STRLEN_P(error_msg) , 0 TSRMLS_CC);
}
else {
// phalcon_throw_exception_string(phalcon_annotations_exception_ce, ZEND_STRL("There was an error parsing annotation"), 1 TSRMLS_CC);
zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), ZEND_STRL("There was an error parsing annotation") , 0 TSRMLS_CC);
}
return FAILURE;
}
return SUCCESS;
}
/**
* Remove comment separators from a docblock
*/
void phannot_remove_comment_separators(zval *return_value, char *comment, int length, int *start_lines) {
int start_mode = 1, j, i, open_parentheses;
smart_str processed_str = {0};
char ch;
(*start_lines) = 0;
for (i = 0; i < length; i++) {
ch = comment[i];
if (start_mode) {
if (ch == ' ' || ch == '*' || ch == '/' || ch == '\t' || ch == 11) {
continue;
}
start_mode = 0;
}
if (ch == '@') {
smart_str_appendc(&processed_str, ch);
i++;
open_parentheses = 0;
for (j = i; j < length; j++) {
ch = comment[j];
if (start_mode) {
if (ch == ' ' || ch == '*' || ch == '/' || ch == '\t' || ch == 11) {
continue;
}
start_mode = 0;
}
if (open_parentheses == 0) {
if (isalnum(ch) || '_' == ch || '\\' == ch) {
smart_str_appendc(&processed_str, ch);
continue;
}
if (ch == '(') {
smart_str_appendc(&processed_str, ch);
open_parentheses++;
continue;
}
} else {
smart_str_appendc(&processed_str, ch);
if (ch == '(') {
open_parentheses++;
} else if (ch == ')') {
open_parentheses--;
} else if (ch == '\n') {
(*start_lines)++;
start_mode = 1;
}
if (open_parentheses > 0) {
continue;
}
}
i = j;
smart_str_appendc(&processed_str, ' ');
break;
}
}
if (ch == '\n') {
(*start_lines)++;
start_mode = 1;
}
}
smart_str_0(&processed_str);
if (processed_str.len) {
RETURN_STRINGL(processed_str.c, processed_str.len, 0);
} else {
RETURN_EMPTY_STRING();
}
}
/**
* Parses a comment returning an intermediate array representation
*/
int phannot_internal_parse_annotations(zval **result, zval *comment, zval *file_path, zval *line, zval **error_msg TSRMLS_DC) {
char *error;
phannot_scanner_state *state;
phannot_scanner_token token;
int scanner_status, status = SUCCESS, start_lines, error_length;
phannot_parser_status *parser_status = NULL;
void* phannot_parser;
zval processed_comment;
/**
* Check if the comment has content
*/
if (!Z_STRVAL_P(comment)) {
ZVAL_BOOL(*result, 0);
return FAILURE;
}
if (Z_STRLEN_P(comment) < 2) {
ZVAL_BOOL(*result, 0);
return SUCCESS;
}
/**
* Remove comment separators
*/
phannot_remove_comment_separators(&processed_comment, Z_STRVAL_P(comment), Z_STRLEN_P(comment), &start_lines);
if (Z_STRLEN(processed_comment) < 2) {
ZVAL_BOOL(*result, 0);
efree(Z_STRVAL(processed_comment));
return SUCCESS;
}
/**
* Start the reentrant parser
*/
phannot_parser = phannot_Alloc(phannot_wrapper_alloc);
parser_status = emalloc(sizeof(phannot_parser_status));
state = emalloc(sizeof(phannot_scanner_state));
parser_status->status = PHANNOT_PARSING_OK;
parser_status->scanner_state = state;
parser_status->ret = NULL;
parser_status->token = &token;
parser_status->syntax_error = NULL;
/**
* Initialize the scanner state
*/
state->active_token = 0;
state->start = Z_STRVAL(processed_comment);
state->start_length = 0;
state->mode = PHANNOT_MODE_RAW;
state->active_file = file_path;
token.value = NULL;
token.len = 0;
/**
* Possible start line
*/
if (Z_TYPE_P(line) == IS_LONG) {
state->active_line = Z_LVAL_P(line) - start_lines;
} else {
state->active_line = 1;
}
state->end = state->start;
while(0 <= (scanner_status = phannot_get_token(state, &token))) {
state->active_token = token.opcode;
state->start_length = (Z_STRVAL(processed_comment) + Z_STRLEN(processed_comment) - state->start);
switch (token.opcode) {
case PHANNOT_T_IGNORE:
break;
case PHANNOT_T_AT:
phannot_(phannot_parser, PHANNOT_AT, NULL, parser_status);
break;
case PHANNOT_T_COMMA:
phannot_(phannot_parser, PHANNOT_COMMA, NULL, parser_status);
break;
case PHANNOT_T_EQUALS:
phannot_(phannot_parser, PHANNOT_EQUALS, NULL, parser_status);
break;
case PHANNOT_T_COLON:
phannot_(phannot_parser, PHANNOT_COLON, NULL, parser_status);
break;
case PHANNOT_T_PARENTHESES_OPEN:
phannot_(phannot_parser, PHANNOT_PARENTHESES_OPEN, NULL, parser_status);
break;
case PHANNOT_T_PARENTHESES_CLOSE:
phannot_(phannot_parser, PHANNOT_PARENTHESES_CLOSE, NULL, parser_status);
break;
case PHANNOT_T_BRACKET_OPEN:
phannot_(phannot_parser, PHANNOT_BRACKET_OPEN, NULL, parser_status);
break;
case PHANNOT_T_BRACKET_CLOSE:
phannot_(phannot_parser, PHANNOT_BRACKET_CLOSE, NULL, parser_status);
break;
case PHANNOT_T_SBRACKET_OPEN:
phannot_(phannot_parser, PHANNOT_SBRACKET_OPEN, NULL, parser_status);
break;
case PHANNOT_T_SBRACKET_CLOSE:
phannot_(phannot_parser, PHANNOT_SBRACKET_CLOSE, NULL, parser_status);
break;
case PHANNOT_T_NULL:
phannot_(phannot_parser, PHANNOT_NULL, NULL, parser_status);
break;
case PHANNOT_T_TRUE:
phannot_(phannot_parser, PHANNOT_TRUE, NULL, parser_status);
break;
case PHANNOT_T_FALSE:
phannot_(phannot_parser, PHANNOT_FALSE, NULL, parser_status);
break;
case PHANNOT_T_INTEGER:
phannot_parse_with_token(phannot_parser, PHANNOT_T_INTEGER, PHANNOT_INTEGER, &token, parser_status);
break;
case PHANNOT_T_DOUBLE:
phannot_parse_with_token(phannot_parser, PHANNOT_T_DOUBLE, PHANNOT_DOUBLE, &token, parser_status);
break;
case PHANNOT_T_STRING:
phannot_parse_with_token(phannot_parser, PHANNOT_T_STRING, PHANNOT_STRING, &token, parser_status);
break;
case PHANNOT_T_IDENTIFIER:
phannot_parse_with_token(phannot_parser, PHANNOT_T_IDENTIFIER, PHANNOT_IDENTIFIER, &token, parser_status);
break;
/*case PHANNOT_T_ARBITRARY_TEXT:
phannot_parse_with_token(phannot_parser, PHANNOT_T_ARBITRARY_TEXT, PHANNOT_ARBITRARY_TEXT, &token, parser_status);
break;*/
default:
parser_status->status = PHANNOT_PARSING_FAILED;
if (!*error_msg) {
error_length = sizeof(char) * (48 + Z_STRLEN_P(state->active_file));
error = emalloc(error_length);
snprintf(error, error_length - 1, "Scanner: unknown opcode %d on in %s line %d", token.opcode, Z_STRVAL_P(state->active_file), state->active_line);
error[error_length - 1] = '\0';
ALLOC_INIT_ZVAL(*error_msg);
ZVAL_STRING(*error_msg, error, 1);
efree(error);
}
break;
}
if (parser_status->status != PHANNOT_PARSING_OK) {
status = FAILURE;
break;
}
state->end = state->start;
}
if (status != FAILURE) {
switch (scanner_status) {
case PHANNOT_SCANNER_RETCODE_ERR:
case PHANNOT_SCANNER_RETCODE_IMPOSSIBLE:
if (!*error_msg) {
phannot_scanner_error_msg(parser_status, error_msg TSRMLS_CC);
}
status = FAILURE;
break;
default:
phannot_(phannot_parser, 0, NULL, parser_status);
}
}
state->active_token = 0;
state->start = NULL;
if (parser_status->status != PHANNOT_PARSING_OK) {
status = FAILURE;
if (parser_status->syntax_error) {
if (!*error_msg) {
ALLOC_INIT_ZVAL(*error_msg);
ZVAL_STRING(*error_msg, parser_status->syntax_error, 1);
}
efree(parser_status->syntax_error);
}
}
phannot_Free(phannot_parser, phannot_wrapper_free);
if (status != FAILURE) {
if (parser_status->status == PHANNOT_PARSING_OK) {
if (parser_status->ret) {
ZVAL_ZVAL(*result, parser_status->ret, 0, 0);
ZVAL_NULL(parser_status->ret);
zval_ptr_dtor(&parser_status->ret);
} else {
array_init(*result);
}
}
}
efree(Z_STRVAL(processed_comment));
efree(parser_status);
efree(state);
return status;
}

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,687 +0,0 @@
/* Driver template for the LEMON parser generator.
** The author disclaims copyright to this source code.
*/
/* First off, code is include which follows the "include" declaration
** in the input file. */
#include <stdio.h>
%%
/* Next is all token values, in a form suitable for use by makeheaders.
** This section will be null unless lemon is run with the -m switch.
*/
/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
%%
/* Make sure the INTERFACE macro is defined.
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/* The next thing included is series of defines which control
** various aspects of the generated parser.
** YYCODETYPE is the data type used for storing terminal
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 terminals
** and nonterminals. "int" is used otherwise.
** YYNOCODE is a number of type YYCODETYPE which corresponds
** to no legal terminal or nonterminal number. This
** number is used to fill in empty slots of the hash
** table.
** YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
** original value of the token will not parse.
** YYACTIONTYPE is the data type used for storing terminal
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 rules and
** states combined. "int" is used otherwise.
** ParseTOKENTYPE is the data type used for minor tokens given
** directly to the parser from the tokenizer.
** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
** which is ParseTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
** YYSTACKDEPTH is the maximum depth of the parser's stack.
** ParseARG_SDECL A static variable declaration for the %extra_argument
** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser
** ParseARG_FETCH Code to extract %extra_argument from yypParser
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
*/
%%
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
/* Next are that tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
**
** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
** token onto the stack and goto state N.
**
** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
**
** N == YYNSTATE+YYNRULE A syntax error has occurred.
**
** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
**
** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
** slots in the yy_action[] table.
**
** The action table is constructed as a single large table named yy_action[].
** Given state S and lookahead X, the action is computed as
**
** yy_action[ yy_shift_ofst[S] + X ]
**
** If the index value yy_shift_ofst[S]+X is out of range or if the value
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
** and that yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
** YY_SHIFT_USE_DFLT.
**
** The following are the tables generated in this section:
**
** yy_action[] A single table containing all actions.
** yy_lookahead[] A table containing the lookahead for each entry in
** yy_action. Used to detect hash collisions.
** yy_shift_ofst[] For each state, the offset into yy_action for
** shifting terminals.
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
%%
#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
**
** %fallback ID X Y Z.
**
** appears in the grammer, then ID becomes a fallback token for X, Y,
** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
** but it does not parse, the type of the token is changed to ID and
** the parse is retried before an error is thrown.
*/
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
%%
};
#endif /* YYFALLBACK */
/* The following structure represents a single element of the
** parser's stack. Information stored includes:
**
** + The state number for the parser at this level of the stack.
**
** + The value of the token stored at this level of the stack.
** (In other words, the "major" token.)
**
** + The semantic value stored at this level of the stack. This is
** the information used by the action routines in the grammar.
** It is sometimes called the "minor" token.
*/
struct yyStackEntry {
int stateno; /* The state-number */
int major; /* The major token value. This is the code
** number for the token at this stack level */
YYMINORTYPE minor; /* The user-supplied minor token value. This
** is the value of the token */
};
typedef struct yyStackEntry yyStackEntry;
/* The state of the parser is completely contained in an instance of
** the following structure */
struct yyParser {
int yyidx; /* Index of top element in stack */
int yyerrcnt; /* Shifts left before out of the error */
ParseARG_SDECL /* A place to hold %extra_argument */
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
};
typedef struct yyParser yyParser;
#ifndef NDEBUG
#include <stdio.h>
static FILE *yyTraceFILE = 0;
static char *yyTracePrompt = 0;
#endif /* NDEBUG */
#ifndef NDEBUG
/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
** by making either argument NULL
**
** Inputs:
** <ul>
** <li> A FILE* to which trace output should be written.
** If NULL, then tracing is turned off.
** <li> A prefix string written at the beginning of every
** line of trace output. If NULL, then tracing is
** turned off.
** </ul>
**
** Outputs:
** None.
*/
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
static const char *yyTokenName[] = {
%%
};
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *yyRuleName[] = {
%%
};
#endif /* NDEBUG */
/*
** This function returns the symbolic name associated with a token
** value.
*/
const char *ParseTokenName(int tokenType){
#ifndef NDEBUG
if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
return yyTokenName[tokenType];
}else{
return "Unknown";
}
#else
return "";
#endif
}
/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
**
** Inputs:
** A pointer to the function used to allocate memory.
**
** Outputs:
** A pointer to a parser. This pointer is used in subsequent calls
** to Parse and ParseFree.
*/
void *ParseAlloc(void *(*mallocProc)(size_t)){
yyParser *pParser;
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
}
return pParser;
}
/* The following function deletes the value associated with a
** symbol. The symbol can be either a terminal or nonterminal.
** "yymajor" is the symbol code, and "yypminor" is a pointer to
** the value.
*/
static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
switch( yymajor ){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
%%
default: break; /* If no destructor action specified: do nothing */
}
}
/*
** Pop the parser's stack once.
**
** If there is a destructor routine associated with the token which
** is popped from the stack, then call it.
**
** Return the major token number for the symbol popped.
*/
static int yy_pop_parser_stack(yyParser *pParser){
YYCODETYPE yymajor;
yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
if( pParser->yyidx<0 ) return 0;
#ifndef NDEBUG
if( yyTraceFILE && pParser->yyidx>=0 ){
fprintf(yyTraceFILE,"%sPopping %s\n",
yyTracePrompt,
yyTokenName[yytos->major]);
}
#endif
yymajor = yytos->major;
yy_destructor( yymajor, &yytos->minor);
pParser->yyidx--;
return yymajor;
}
/*
** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
** Inputs:
** <ul>
** <li> A pointer to the parser. This should be a pointer
** obtained from ParseAlloc.
** <li> A pointer to a function used to reclaim memory obtained
** from malloc.
** </ul>
*/
void ParseFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
if( pParser==0 ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
(*freeProc)((void*)pParser);
}
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
**
** If the look-ahead token is YYNOCODE, then check to see if the action is
** independent of the look-ahead. If it is, return the action, otherwise
** return YY_NO_ACTION.
*/
static int yy_find_shift_action(
yyParser *pParser, /* The parser */
int iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
/* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
i = yy_shift_ofst[stateno];
if( i==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
return YY_NO_ACTION;
}
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
int iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
&& (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
}
#endif
return yy_find_shift_action(pParser, iFallback);
}
#endif
return yy_default[stateno];
}else{
return yy_action[i];
}
}
/*
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
**
** If the look-ahead token is YYNOCODE, then check to see if the action is
** independent of the look-ahead. If it is, return the action, otherwise
** return YY_NO_ACTION.
*/
static int yy_find_reduce_action(
yyParser *pParser, /* The parser */
int iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
i = yy_reduce_ofst[stateno];
if( i==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
return YY_NO_ACTION;
}
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
return yy_default[stateno];
}else{
return yy_action[i];
}
}
/*
** Perform a shift action.
*/
static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */
int yyNewState, /* The new state to shift in */
int yyMajor, /* The major token to shift in */
YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
){
yyStackEntry *yytos;
yypParser->yyidx++;
if( yypParser->yyidx>=YYSTACKDEPTH ){
ParseARG_FETCH;
yypParser->yyidx--;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
return;
}
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = yyNewState;
yytos->major = yyMajor;
yytos->minor = *yypMinor;
#ifndef NDEBUG
if( yyTraceFILE && yypParser->yyidx>0 ){
int i;
fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
for(i=1; i<=yypParser->yyidx; i++)
fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
fprintf(yyTraceFILE,"\n");
}
#endif
}
/* The following table contains information about every rule that
** is used during the reduce.
*/
static struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
%%
};
static void yy_accept(yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
*/
static void yy_reduce(
yyParser *yypParser, /* The parser */
int yyruleno /* Number of the rule by which to reduce */
){
int yygoto; /* The next state */
int yyact; /* The next action */
YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
ParseARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0
&& yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
#endif /* NDEBUG */
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
** follows:
** case 0:
** #line <lineno> <grammarfile>
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
%%
};
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yypParser,yygoto);
if( yyact < YYNSTATE ){
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}else if( yyact == YYNSTATE + YYNRULE + 1 ){
yy_accept(yypParser);
}
}
/*
** The following code executes when the parse fails
*/
static void yy_parse_failed(
yyParser *yypParser /* The parser */
){
ParseARG_FETCH;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
/*
** The following code executes when a syntax error first occurs.
*/
static void yy_syntax_error(
yyParser *yypParser, /* The parser */
int yymajor, /* The major type of the error token */
YYMINORTYPE yyminor /* The minor type of the error token */
){
ParseARG_FETCH;
#define TOKEN (yyminor.yy0)
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
/*
** The following is executed when the parser accepts
*/
static void yy_accept(
yyParser *yypParser /* The parser */
){
ParseARG_FETCH;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser accepts */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
/* The main parser program.
** The first argument is a pointer to a structure obtained from
** "ParseAlloc" which describes the current state of the parser.
** The second argument is the major token number. The third is
** the minor token. The fourth optional argument is whatever the
** user wants (and specified in the grammar) and is available for
** use by the action routines.
**
** Inputs:
** <ul>
** <li> A pointer to the parser (an opaque structure.)
** <li> The major token number.
** <li> The minor token number.
** <li> An option argument of a grammar-specified type.
** </ul>
**
** Outputs:
** None.
*/
void Parse(
void *yyp, /* The parser */
int yymajor, /* The major token code number */
ParseTOKENTYPE yyminor /* The value for the token */
ParseARG_PDECL /* Optional %extra_argument parameter */
){
YYMINORTYPE yyminorunion;
int yyact; /* The parser action. */
int yyendofinput; /* True if we are at the end of input */
int yyerrorhit = 0; /* True if yymajor has invoked an error */
yyParser *yypParser; /* The parser */
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
if( yymajor==0 ) return;
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
yypParser->yystack[0].major = 0;
}
yyminorunion.yy0 = yyminor;
yyendofinput = (yymajor==0);
ParseARG_STORE;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
}
#endif
do{
yyact = yy_find_shift_action(yypParser,yymajor);
if( yyact<YYNSTATE ){
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
if( yyendofinput && yypParser->yyidx>=0 ){
yymajor = 0;
}else{
yymajor = YYNOCODE;
}
}else if( yyact < YYNSTATE + YYNRULE ){
yy_reduce(yypParser,yyact-YYNSTATE);
}else if( yyact == YY_ERROR_ACTION ){
int yymx;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
}
#endif
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
** * Call the %syntax_error function.
**
** * Begin popping the stack until we enter a state where
** it is legal to shift the error symbol, then shift
** the error symbol.
**
** * Set the error count to three.
**
** * Begin accepting and shifting new tokens. No new error
** processing will occur until three tokens have been
** shifted successfully.
**
*/
if( yypParser->yyerrcnt<0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yymx = yypParser->yystack[yypParser->yyidx].major;
if( yymx==YYERRORSYMBOL || yyerrorhit ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yymajor,&yyminorunion);
yymajor = YYNOCODE;
}else{
while(
yypParser->yyidx >= 0 &&
yymx != YYERRORSYMBOL &&
(yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
){
yy_pop_parser_stack(yypParser);
}
if( yypParser->yyidx < 0 || yymajor==0 ){
yy_destructor(yymajor,&yyminorunion);
yy_parse_failed(yypParser);
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
YYMINORTYPE u2;
u2.YYERRSYMDT = 0;
yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
}
}
yypParser->yyerrcnt = 3;
yyerrorhit = 1;
#else /* YYERRORSYMBOL is not defined */
/* This is what we do if the grammar does not define ERROR:
**
** * Report an error message, and throw away the input token.
**
** * If the input token is $, then fail the parse.
**
** As before, subsequent error messages are suppressed until
** three input tokens have been successfully shifted.
*/
if( yypParser->yyerrcnt<=0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yypParser->yyerrcnt = 3;
yy_destructor(yymajor,&yyminorunion);
if( yyendofinput ){
yy_parse_failed(yypParser);
}
yymajor = YYNOCODE;
#endif
}else{
yy_accept(yypParser);
yymajor = YYNOCODE;
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
return;
}

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
#define PHANNOT_COMMA 1
#define PHANNOT_AT 2
#define PHANNOT_IDENTIFIER 3
#define PHANNOT_PARENTHESES_OPEN 4
#define PHANNOT_PARENTHESES_CLOSE 5
#define PHANNOT_STRING 6
#define PHANNOT_EQUALS 7
#define PHANNOT_COLON 8
#define PHANNOT_INTEGER 9
#define PHANNOT_DOUBLE 10
#define PHANNOT_NULL 11
#define PHANNOT_FALSE 12
#define PHANNOT_TRUE 13
#define PHANNOT_BRACKET_OPEN 14
#define PHANNOT_BRACKET_CLOSE 15
#define PHANNOT_SBRACKET_OPEN 16
#define PHANNOT_SBRACKET_CLOSE 17

View file

@ -1,335 +0,0 @@
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
%token_prefix PHANNOT_
%token_type {phannot_parser_token*}
%default_type {zval*}
%extra_argument {phannot_parser_status *status}
%name phannot_
%left COMMA .
%include {
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "ext/standard/php_smart_str.h"
#include "Zend/zend_exceptions.h"
#include "parser.h"
#include "scanner.h"
#include "annot.h"
static zval *phannot_ret_literal_zval(int type, phannot_parser_token *T)
{
zval *ret;
MAKE_STD_ZVAL(ret);
array_init(ret);
add_assoc_long(ret, "type", type);
if (T) {
add_assoc_stringl(ret, "value", T->token, T->token_len, 0);
efree(T);
}
return ret;
}
static zval *phannot_ret_array(zval *items)
{
zval *ret;
MAKE_STD_ZVAL(ret);
array_init(ret);
add_assoc_long(ret, "type", PHANNOT_T_ARRAY);
if (items) {
add_assoc_zval(ret, "items", items);
}
return ret;
}
static zval *phannot_ret_zval_list(zval *list_left, zval *right_list)
{
zval *ret;
HashPosition pos;
HashTable *list;
MAKE_STD_ZVAL(ret);
array_init(ret);
if (list_left) {
list = Z_ARRVAL_P(list_left);
if (zend_hash_index_exists(list, 0)) {
zend_hash_internal_pointer_reset_ex(list, &pos);
for (;; zend_hash_move_forward_ex(list, &pos)) {
zval ** item;
if (zend_hash_get_current_data_ex(list, (void**) &item, &pos) == FAILURE) {
break;
}
Z_ADDREF_PP(item);
add_next_index_zval(ret, *item);
}
zval_ptr_dtor(&list_left);
} else {
add_next_index_zval(ret, list_left);
}
}
add_next_index_zval(ret, right_list);
return ret;
}
static zval *phannot_ret_named_item(phannot_parser_token *name, zval *expr)
{
zval *ret;
MAKE_STD_ZVAL(ret);
array_init(ret);
add_assoc_zval(ret, "expr", expr);
if (name != NULL) {
add_assoc_stringl(ret, "name", name->token, name->token_len, 0);
efree(name);
}
return ret;
}
static zval *phannot_ret_annotation(phannot_parser_token *name, zval *arguments, phannot_scanner_state *state)
{
zval *ret;
MAKE_STD_ZVAL(ret);
array_init(ret);
add_assoc_long(ret, "type", PHANNOT_T_ANNOTATION);
if (name) {
add_assoc_stringl(ret, "name", name->token, name->token_len, 0);
efree(name);
}
if (arguments) {
add_assoc_zval(ret, "arguments", arguments);
}
Z_ADDREF_P(state->active_file);
add_assoc_zval(ret, "file", state->active_file);
add_assoc_long(ret, "line", state->active_line);
return ret;
}
}
%syntax_error {
if (status->scanner_state->start_length) {
{
char *token_name = NULL;
const phannot_token_names *tokens = phannot_tokens;
int token_found = 0;
int active_token = status->scanner_state->active_token;
int near_length = status->scanner_state->start_length;
if (active_token) {
do {
if (tokens->code == active_token) {
token_found = 1;
token_name = tokens->name;
break;
}
++tokens;
} while (tokens[0].code != 0);
}
if (!token_name) {
token_found = 0;
token_name = estrndup("UNKNOWN", strlen("UNKNOWN"));
}
status->syntax_error_len = 128 + strlen(token_name) + Z_STRLEN_P(status->scanner_state->active_file);
status->syntax_error = emalloc(sizeof(char) * status->syntax_error_len);
if (near_length > 0) {
if (status->token->value) {
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s(%s), near to '%s' in %s on line %d", token_name, status->token->value, status->scanner_state->start, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
} else {
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s, near to '%s' in %s on line %d", token_name, status->scanner_state->start, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
}
} else {
if (active_token != PHANNOT_T_IGNORE) {
if (status->token->value) {
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s(%s), at the end of docblock in %s on line %d", token_name, status->token->value, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
} else {
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected token %s, at the end of docblock in %s on line %d", token_name, Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
}
} else {
snprintf(status->syntax_error, status->syntax_error_len, "Syntax error, unexpected EOF, at the end of docblock in %s on line %d", Z_STRVAL_P(status->scanner_state->active_file), status->scanner_state->active_line);
}
status->syntax_error[status->syntax_error_len-1] = '\0';
}
if (!token_found) {
if (token_name) {
efree(token_name);
}
}
}
} else {
status->syntax_error_len = 48 + Z_STRLEN_P(status->scanner_state->active_file);
status->syntax_error = emalloc(sizeof(char) * status->syntax_error_len);
sprintf(status->syntax_error, "Syntax error, unexpected EOF in %s", Z_STRVAL_P(status->scanner_state->active_file));
}
status->status = PHANNOT_PARSING_FAILED;
}
%token_destructor {
if ($$) {
if ($$->free_flag) {
efree($$->token);
}
efree($$);
}
}
program ::= annotation_language(Q) . {
status->ret = Q;
}
%destructor annotation_language { zval_ptr_dtor(&$$); }
annotation_language(R) ::= annotation_list(L) . {
R = L;
}
%destructor annotation_list { zval_ptr_dtor(&$$); }
annotation_list(R) ::= annotation_list(L) annotation(S) . {
R = phannot_ret_zval_list(L, S);
}
annotation_list(R) ::= annotation(S) . {
R = phannot_ret_zval_list(NULL, S);
}
%destructor annotation { zval_ptr_dtor(&$$); }
annotation(R) ::= AT IDENTIFIER(I) PARENTHESES_OPEN argument_list(L) PARENTHESES_CLOSE . {
R = phannot_ret_annotation(I, L, status->scanner_state);
}
annotation(R) ::= AT IDENTIFIER(I) PARENTHESES_OPEN PARENTHESES_CLOSE . {
R = phannot_ret_annotation(I, NULL, status->scanner_state);
}
annotation(R) ::= AT IDENTIFIER(I) . {
R = phannot_ret_annotation(I, NULL, status->scanner_state);
}
%destructor argument_list { zval_ptr_dtor(&$$); }
argument_list(R) ::= argument_list(L) COMMA argument_item(I) . {
R = phannot_ret_zval_list(L, I);
}
argument_list(R) ::= argument_item(I) . {
R = phannot_ret_zval_list(NULL, I);
}
%destructor argument_item { zval_ptr_dtor(&$$); }
argument_item(R) ::= expr(E) . {
R = phannot_ret_named_item(NULL, E);
}
argument_item(R) ::= STRING(S) EQUALS expr(E) . {
R = phannot_ret_named_item(S, E);
}
argument_item(R) ::= STRING(S) COLON expr(E) . {
R = phannot_ret_named_item(S, E);
}
argument_item(R) ::= IDENTIFIER(I) EQUALS expr(E) . {
R = phannot_ret_named_item(I, E);
}
argument_item(R) ::= IDENTIFIER(I) COLON expr(E) . {
R = phannot_ret_named_item(I, E);
}
%destructor expr { zval_ptr_dtor(&$$); }
expr(R) ::= annotation(S) . {
R = S;
}
expr(R) ::= array(A) . {
R = A;
}
expr(R) ::= IDENTIFIER(I) . {
R = phannot_ret_literal_zval(PHANNOT_T_IDENTIFIER, I);
}
expr(R) ::= INTEGER(I) . {
R = phannot_ret_literal_zval(PHANNOT_T_INTEGER, I);
}
expr(R) ::= STRING(S) . {
R = phannot_ret_literal_zval(PHANNOT_T_STRING, S);
}
expr(R) ::= DOUBLE(D) . {
R = phannot_ret_literal_zval(PHANNOT_T_DOUBLE, D);
}
expr(R) ::= NULL . {
R = phannot_ret_literal_zval(PHANNOT_T_NULL, NULL);
}
expr(R) ::= FALSE . {
R = phannot_ret_literal_zval(PHANNOT_T_FALSE, NULL);
}
expr(R) ::= TRUE . {
R = phannot_ret_literal_zval(PHANNOT_T_TRUE, NULL);
}
array(R) ::= BRACKET_OPEN argument_list(A) BRACKET_CLOSE . {
R = phannot_ret_array(A);
}
array(R) ::= SBRACKET_OPEN argument_list(A) SBRACKET_CLOSE . {
R = phannot_ret_array(A);
}

View file

@ -1,478 +0,0 @@
State 0:
program ::= * annotation_language
annotation_language ::= * annotation_list
annotation_list ::= * annotation_list annotation
annotation_list ::= * annotation
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
AT shift 16
program accept
annotation_language shift 23
annotation_list shift 9
annotation shift 24
State 1:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= AT IDENTIFIER PARENTHESES_OPEN * argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= AT IDENTIFIER PARENTHESES_OPEN * PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_list ::= * argument_list COMMA argument_item
argument_list ::= * argument_item
argument_item ::= * expr
argument_item ::= * STRING EQUALS expr
argument_item ::= * STRING COLON expr
argument_item ::= * IDENTIFIER EQUALS expr
argument_item ::= * IDENTIFIER COLON expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 12
PARENTHESES_CLOSE shift 22
STRING shift 14
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
argument_list shift 10
argument_item shift 17
expr shift 28
array shift 31
State 2:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_list ::= * argument_list COMMA argument_item
argument_list ::= * argument_item
argument_item ::= * expr
argument_item ::= * STRING EQUALS expr
argument_item ::= * STRING COLON expr
argument_item ::= * IDENTIFIER EQUALS expr
argument_item ::= * IDENTIFIER COLON expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= BRACKET_OPEN * argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 12
STRING shift 14
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
argument_list shift 11
argument_item shift 17
expr shift 28
array shift 31
State 3:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_list ::= * argument_list COMMA argument_item
argument_list ::= * argument_item
argument_item ::= * expr
argument_item ::= * STRING EQUALS expr
argument_item ::= * STRING COLON expr
argument_item ::= * IDENTIFIER EQUALS expr
argument_item ::= * IDENTIFIER COLON expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
array ::= SBRACKET_OPEN * argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 12
STRING shift 14
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
argument_list shift 13
argument_item shift 17
expr shift 28
array shift 31
State 4:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_list ::= argument_list COMMA * argument_item
argument_item ::= * expr
argument_item ::= * STRING EQUALS expr
argument_item ::= * STRING COLON expr
argument_item ::= * IDENTIFIER EQUALS expr
argument_item ::= * IDENTIFIER COLON expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 12
STRING shift 14
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
argument_item shift 27
expr shift 28
array shift 31
State 5:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_item ::= STRING EQUALS * expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 32
STRING shift 34
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
expr shift 29
array shift 31
State 6:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_item ::= IDENTIFIER EQUALS * expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 32
STRING shift 34
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
expr shift 18
array shift 31
State 7:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_item ::= STRING COLON * expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 32
STRING shift 34
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
expr shift 21
array shift 31
State 8:
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
argument_item ::= IDENTIFIER COLON * expr
expr ::= * annotation
expr ::= * array
expr ::= * IDENTIFIER
expr ::= * INTEGER
expr ::= * STRING
expr ::= * DOUBLE
expr ::= * NULL
expr ::= * FALSE
expr ::= * TRUE
array ::= * BRACKET_OPEN argument_list BRACKET_CLOSE
array ::= * SBRACKET_OPEN argument_list SBRACKET_CLOSE
AT shift 16
IDENTIFIER shift 32
STRING shift 34
INTEGER shift 33
DOUBLE shift 35
NULL shift 36
FALSE shift 37
TRUE shift 38
BRACKET_OPEN shift 2
SBRACKET_OPEN shift 3
annotation shift 30
expr shift 20
array shift 31
State 9:
(1) annotation_language ::= annotation_list *
annotation_list ::= annotation_list * annotation
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= * AT IDENTIFIER
AT shift 16
annotation shift 25
{default} reduce 1
State 10:
annotation ::= AT IDENTIFIER PARENTHESES_OPEN argument_list * PARENTHESES_CLOSE
argument_list ::= argument_list * COMMA argument_item
COMMA shift 4
PARENTHESES_CLOSE shift 26
State 11:
argument_list ::= argument_list * COMMA argument_item
array ::= BRACKET_OPEN argument_list * BRACKET_CLOSE
COMMA shift 4
BRACKET_CLOSE shift 39
State 12:
argument_item ::= IDENTIFIER * EQUALS expr
argument_item ::= IDENTIFIER * COLON expr
(16) expr ::= IDENTIFIER *
EQUALS shift 6
COLON shift 8
{default} reduce 16
State 13:
argument_list ::= argument_list * COMMA argument_item
array ::= SBRACKET_OPEN argument_list * SBRACKET_CLOSE
COMMA shift 4
SBRACKET_CLOSE shift 19
State 14:
argument_item ::= STRING * EQUALS expr
argument_item ::= STRING * COLON expr
(18) expr ::= STRING *
EQUALS shift 5
COLON shift 7
{default} reduce 18
State 15:
annotation ::= AT IDENTIFIER * PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= AT IDENTIFIER * PARENTHESES_OPEN PARENTHESES_CLOSE
(6) annotation ::= AT IDENTIFIER *
PARENTHESES_OPEN shift 1
{default} reduce 6
State 16:
annotation ::= AT * IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE
annotation ::= AT * IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE
annotation ::= AT * IDENTIFIER
IDENTIFIER shift 15
State 17:
(8) argument_list ::= argument_item *
{default} reduce 8
State 18:
(12) argument_item ::= IDENTIFIER EQUALS expr *
{default} reduce 12
State 19:
(24) array ::= SBRACKET_OPEN argument_list SBRACKET_CLOSE *
{default} reduce 24
State 20:
(13) argument_item ::= IDENTIFIER COLON expr *
{default} reduce 13
State 21:
(11) argument_item ::= STRING COLON expr *
{default} reduce 11
State 22:
(5) annotation ::= AT IDENTIFIER PARENTHESES_OPEN PARENTHESES_CLOSE *
{default} reduce 5
State 23:
(0) program ::= annotation_language *
{default} reduce 0
State 24:
(3) annotation_list ::= annotation *
{default} reduce 3
State 25:
(2) annotation_list ::= annotation_list annotation *
{default} reduce 2
State 26:
(4) annotation ::= AT IDENTIFIER PARENTHESES_OPEN argument_list PARENTHESES_CLOSE *
{default} reduce 4
State 27:
(7) argument_list ::= argument_list COMMA argument_item *
{default} reduce 7
State 28:
(9) argument_item ::= expr *
{default} reduce 9
State 29:
(10) argument_item ::= STRING EQUALS expr *
{default} reduce 10
State 30:
(14) expr ::= annotation *
{default} reduce 14
State 31:
(15) expr ::= array *
{default} reduce 15
State 32:
(16) expr ::= IDENTIFIER *
{default} reduce 16
State 33:
(17) expr ::= INTEGER *
{default} reduce 17
State 34:
(18) expr ::= STRING *
{default} reduce 18
State 35:
(19) expr ::= DOUBLE *
{default} reduce 19
State 36:
(20) expr ::= NULL *
{default} reduce 20
State 37:
(21) expr ::= FALSE *
{default} reduce 21
State 38:
(22) expr ::= TRUE *
{default} reduce 22
State 39:
(23) array ::= BRACKET_OPEN argument_list BRACKET_CLOSE *
{default} reduce 23

View file

@ -1,605 +0,0 @@
/* Generated by re2c 0.13.5 on Sun Feb 16 21:59:06 2014 */
#line 1 "scanner.re"
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "scanner.h"
#define YYCTYPE unsigned char
#define YYCURSOR (s->start)
#define YYLIMIT (s->end)
#define YYMARKER q
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token) {
char next, *q = YYCURSOR, *start = YYCURSOR;
int status = PHANNOT_SCANNER_RETCODE_IMPOSSIBLE;
while (PHANNOT_SCANNER_RETCODE_IMPOSSIBLE == status) {
if (s->mode == PHANNOT_MODE_RAW) {
if (*YYCURSOR == '\n') {
s->active_line++;
}
next = *(YYCURSOR+1);
if (*YYCURSOR == '\0' || *YYCURSOR == '@') {
if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z')) {
s->mode = PHANNOT_MODE_ANNOTATION;
continue;
}
}
++YYCURSOR;
token->opcode = PHANNOT_T_IGNORE;
return 0;
} else {
#line 65 "scanner.c"
{
YYCTYPE yych;
unsigned int yyaccept = 0;
static const unsigned char yybm[] = {
0, 96, 96, 96, 96, 96, 96, 96,
96, 104, 96, 96, 96, 104, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
104, 96, 32, 96, 96, 96, 96, 64,
96, 96, 96, 96, 96, 96, 96, 96,
240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 96, 96, 96, 96, 96, 96,
96, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 96, 0, 96, 96, 112,
96, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 112, 112, 112, 112, 112,
112, 112, 112, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96,
};
yych = *YYCURSOR;
switch (yych) {
case 0x00: goto yy38;
case '\t':
case '\r':
case ' ': goto yy34;
case '\n': goto yy36;
case '"': goto yy10;
case '\'': goto yy11;
case '(': goto yy14;
case ')': goto yy16;
case ',': goto yy32;
case '-': goto yy2;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': goto yy4;
case ':': goto yy30;
case '=': goto yy28;
case '@': goto yy26;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z': goto yy13;
case 'F':
case 'f': goto yy8;
case 'N':
case 'n': goto yy6;
case 'T':
case 't': goto yy9;
case '[': goto yy22;
case '\\': goto yy12;
case ']': goto yy24;
case '{': goto yy18;
case '}': goto yy20;
default: goto yy40;
}
yy2:
++YYCURSOR;
if (yybm[0+(yych = *YYCURSOR)] & 128) {
goto yy71;
}
yy3:
#line 182 "scanner.re"
{
status = PHANNOT_SCANNER_RETCODE_ERR;
break;
}
#line 201 "scanner.c"
yy4:
yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
goto yy72;
yy5:
#line 66 "scanner.re"
{
token->opcode = PHANNOT_T_INTEGER;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
#line 215 "scanner.c"
yy6:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'U') goto yy66;
if (yych == 'u') goto yy66;
goto yy44;
yy7:
#line 108 "scanner.re"
{
token->opcode = PHANNOT_T_IDENTIFIER;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
#line 231 "scanner.c"
yy8:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'A') goto yy61;
if (yych == 'a') goto yy61;
goto yy44;
yy9:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'R') goto yy57;
if (yych == 'r') goto yy57;
goto yy44;
yy10:
yyaccept = 2;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= 0x00) goto yy3;
goto yy55;
yy11:
yyaccept = 2;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= 0x00) goto yy3;
goto yy50;
yy12:
yych = *++YYCURSOR;
if (yych <= '^') {
if (yych <= '@') goto yy3;
if (yych <= 'Z') goto yy43;
goto yy3;
} else {
if (yych == '`') goto yy3;
if (yych <= 'z') goto yy43;
goto yy3;
}
yy13:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
goto yy44;
yy14:
++YYCURSOR;
#line 116 "scanner.re"
{
token->opcode = PHANNOT_T_PARENTHESES_OPEN;
return 0;
}
#line 276 "scanner.c"
yy16:
++YYCURSOR;
#line 121 "scanner.re"
{
token->opcode = PHANNOT_T_PARENTHESES_CLOSE;
return 0;
}
#line 284 "scanner.c"
yy18:
++YYCURSOR;
#line 126 "scanner.re"
{
token->opcode = PHANNOT_T_BRACKET_OPEN;
return 0;
}
#line 292 "scanner.c"
yy20:
++YYCURSOR;
#line 131 "scanner.re"
{
token->opcode = PHANNOT_T_BRACKET_CLOSE;
return 0;
}
#line 300 "scanner.c"
yy22:
++YYCURSOR;
#line 136 "scanner.re"
{
token->opcode = PHANNOT_T_SBRACKET_OPEN;
return 0;
}
#line 308 "scanner.c"
yy24:
++YYCURSOR;
#line 141 "scanner.re"
{
token->opcode = PHANNOT_T_SBRACKET_CLOSE;
return 0;
}
#line 316 "scanner.c"
yy26:
++YYCURSOR;
#line 146 "scanner.re"
{
token->opcode = PHANNOT_T_AT;
return 0;
}
#line 324 "scanner.c"
yy28:
++YYCURSOR;
#line 151 "scanner.re"
{
token->opcode = PHANNOT_T_EQUALS;
return 0;
}
#line 332 "scanner.c"
yy30:
++YYCURSOR;
#line 156 "scanner.re"
{
token->opcode = PHANNOT_T_COLON;
return 0;
}
#line 340 "scanner.c"
yy32:
++YYCURSOR;
#line 161 "scanner.re"
{
token->opcode = PHANNOT_T_COMMA;
return 0;
}
#line 348 "scanner.c"
yy34:
++YYCURSOR;
yych = *YYCURSOR;
goto yy42;
yy35:
#line 166 "scanner.re"
{
token->opcode = PHANNOT_T_IGNORE;
return 0;
}
#line 359 "scanner.c"
yy36:
++YYCURSOR;
#line 171 "scanner.re"
{
s->active_line++;
token->opcode = PHANNOT_T_IGNORE;
return 0;
}
#line 368 "scanner.c"
yy38:
++YYCURSOR;
#line 177 "scanner.re"
{
status = PHANNOT_SCANNER_RETCODE_EOF;
break;
}
#line 376 "scanner.c"
yy40:
yych = *++YYCURSOR;
goto yy3;
yy41:
++YYCURSOR;
yych = *YYCURSOR;
yy42:
if (yybm[0+yych] & 8) {
goto yy41;
}
goto yy35;
yy43:
yyaccept = 1;
YYMARKER = ++YYCURSOR;
yych = *YYCURSOR;
yy44:
if (yybm[0+yych] & 16) {
goto yy43;
}
if (yych != '\\') goto yy7;
yy45:
++YYCURSOR;
yych = *YYCURSOR;
if (yych <= '^') {
if (yych <= '@') goto yy46;
if (yych <= 'Z') goto yy47;
} else {
if (yych == '`') goto yy46;
if (yych <= 'z') goto yy47;
}
yy46:
YYCURSOR = YYMARKER;
if (yyaccept <= 2) {
if (yyaccept <= 1) {
if (yyaccept <= 0) {
goto yy5;
} else {
goto yy7;
}
} else {
goto yy3;
}
} else {
if (yyaccept <= 4) {
if (yyaccept <= 3) {
goto yy60;
} else {
goto yy65;
}
} else {
goto yy69;
}
}
yy47:
yyaccept = 1;
YYMARKER = ++YYCURSOR;
yych = *YYCURSOR;
if (yych <= '[') {
if (yych <= '9') {
if (yych <= '/') goto yy7;
goto yy47;
} else {
if (yych <= '@') goto yy7;
if (yych <= 'Z') goto yy47;
goto yy7;
}
} else {
if (yych <= '_') {
if (yych <= '\\') goto yy45;
if (yych <= '^') goto yy7;
goto yy47;
} else {
if (yych <= '`') goto yy7;
if (yych <= 'z') goto yy47;
goto yy7;
}
}
yy49:
++YYCURSOR;
yych = *YYCURSOR;
yy50:
if (yybm[0+yych] & 32) {
goto yy49;
}
if (yych <= 0x00) goto yy46;
if (yych <= '[') goto yy52;
++YYCURSOR;
yych = *YYCURSOR;
if (yych == '\n') goto yy46;
goto yy49;
yy52:
++YYCURSOR;
#line 99 "scanner.re"
{
token->opcode = PHANNOT_T_STRING;
token->value = estrndup(q, YYCURSOR - q - 1);
token->len = YYCURSOR - q - 1;
q = YYCURSOR;
return 0;
}
#line 477 "scanner.c"
yy54:
++YYCURSOR;
yych = *YYCURSOR;
yy55:
if (yybm[0+yych] & 64) {
goto yy54;
}
if (yych <= 0x00) goto yy46;
if (yych <= '[') goto yy52;
++YYCURSOR;
yych = *YYCURSOR;
if (yych == '\n') goto yy46;
goto yy54;
yy57:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'U') goto yy58;
if (yych != 'u') goto yy44;
yy58:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'E') goto yy59;
if (yych != 'e') goto yy44;
yy59:
yyaccept = 3;
yych = *(YYMARKER = ++YYCURSOR);
if (yybm[0+yych] & 16) {
goto yy43;
}
if (yych == '\\') goto yy45;
yy60:
#line 93 "scanner.re"
{
token->opcode = PHANNOT_T_TRUE;
return 0;
}
#line 514 "scanner.c"
yy61:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'L') goto yy62;
if (yych != 'l') goto yy44;
yy62:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'S') goto yy63;
if (yych != 's') goto yy44;
yy63:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'E') goto yy64;
if (yych != 'e') goto yy44;
yy64:
yyaccept = 4;
yych = *(YYMARKER = ++YYCURSOR);
if (yybm[0+yych] & 16) {
goto yy43;
}
if (yych == '\\') goto yy45;
yy65:
#line 88 "scanner.re"
{
token->opcode = PHANNOT_T_FALSE;
return 0;
}
#line 543 "scanner.c"
yy66:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'L') goto yy67;
if (yych != 'l') goto yy44;
yy67:
yyaccept = 1;
yych = *(YYMARKER = ++YYCURSOR);
if (yych == 'L') goto yy68;
if (yych != 'l') goto yy44;
yy68:
yyaccept = 5;
yych = *(YYMARKER = ++YYCURSOR);
if (yybm[0+yych] & 16) {
goto yy43;
}
if (yych == '\\') goto yy45;
yy69:
#line 83 "scanner.re"
{
token->opcode = PHANNOT_T_NULL;
return 0;
}
#line 567 "scanner.c"
yy70:
yych = *++YYCURSOR;
if (yych <= '/') goto yy46;
if (yych <= '9') goto yy73;
goto yy46;
yy71:
yyaccept = 0;
YYMARKER = ++YYCURSOR;
yych = *YYCURSOR;
yy72:
if (yybm[0+yych] & 128) {
goto yy71;
}
if (yych == '.') goto yy70;
goto yy5;
yy73:
++YYCURSOR;
yych = *YYCURSOR;
if (yych <= '/') goto yy75;
if (yych <= '9') goto yy73;
yy75:
#line 75 "scanner.re"
{
token->opcode = PHANNOT_T_DOUBLE;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
#line 597 "scanner.c"
}
#line 187 "scanner.re"
}
}
return status;
}

View file

@ -1,83 +0,0 @@
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
#define PHANNOT_SCANNER_RETCODE_EOF -1
#define PHANNOT_SCANNER_RETCODE_ERR -2
#define PHANNOT_SCANNER_RETCODE_IMPOSSIBLE -3
/** Modes */
#define PHANNOT_MODE_RAW 0
#define PHANNOT_MODE_ANNOTATION 1
#define PHANNOT_T_IGNORE 297
#define PHANNOT_T_DOCBLOCK_ANNOTATION 299
#define PHANNOT_T_ANNOTATION 300
/* Literals & Identifiers */
#define PHANNOT_T_INTEGER 301
#define PHANNOT_T_DOUBLE 302
#define PHANNOT_T_STRING 303
#define PHANNOT_T_NULL 304
#define PHANNOT_T_FALSE 305
#define PHANNOT_T_TRUE 306
#define PHANNOT_T_IDENTIFIER 307
#define PHANNOT_T_ARRAY 308
#define PHANNOT_T_ARBITRARY_TEXT 309
/* Operators */
#define PHANNOT_T_AT '@'
#define PHANNOT_T_DOT '.'
#define PHANNOT_T_COMMA ','
#define PHANNOT_T_EQUALS '='
#define PHANNOT_T_COLON ':'
#define PHANNOT_T_BRACKET_OPEN '{'
#define PHANNOT_T_BRACKET_CLOSE '}'
#define PHANNOT_T_SBRACKET_OPEN '['
#define PHANNOT_T_SBRACKET_CLOSE ']'
#define PHANNOT_T_PARENTHESES_OPEN '('
#define PHANNOT_T_PARENTHESES_CLOSE ')'
/* List of tokens and their names */
typedef struct _phannot_token_names {
char *name;
unsigned int code;
} phannot_token_names;
/* Active token state */
typedef struct _phannot_scanner_state {
char* start;
char* end;
int active_token;
unsigned int start_length;
int mode;
unsigned int active_line;
zval *active_file;
} phannot_scanner_state;
/* Extra information tokens */
typedef struct _phannot_scanner_token {
char *value;
int opcode;
int len;
} phannot_scanner_token;
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token);
extern const phannot_token_names phannot_tokens[];

View file

@ -1,193 +0,0 @@
/*
+------------------------------------------------------------------------+
| Phalcon Framework |
+------------------------------------------------------------------------+
| Copyright (c) 2011-2014 Phalcon Team (http://www.phalconphp.com) |
+------------------------------------------------------------------------+
| This source file is subject to the New BSD License that is bundled |
| with this package in the file docs/LICENSE.txt. |
| |
| If you did not receive a copy of the license and are unable to |
| obtain it through the world-wide-web, please send an email |
| to license@phalconphp.com so we can send you a copy immediately. |
+------------------------------------------------------------------------+
| Authors: Andres Gutierrez <andres@phalconphp.com> |
| Eduar Carvajal <eduar@phalconphp.com> |
+------------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "scanner.h"
#define YYCTYPE unsigned char
#define YYCURSOR (s->start)
#define YYLIMIT (s->end)
#define YYMARKER q
int phannot_get_token(phannot_scanner_state *s, phannot_scanner_token *token) {
char next, *q = YYCURSOR, *start = YYCURSOR;
int status = PHANNOT_SCANNER_RETCODE_IMPOSSIBLE;
while (PHANNOT_SCANNER_RETCODE_IMPOSSIBLE == status) {
if (s->mode == PHANNOT_MODE_RAW) {
if (*YYCURSOR == '\n') {
s->active_line++;
}
next = *(YYCURSOR+1);
if (*YYCURSOR == '\0' || *YYCURSOR == '@') {
if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z')) {
s->mode = PHANNOT_MODE_ANNOTATION;
continue;
}
}
++YYCURSOR;
token->opcode = PHANNOT_T_IGNORE;
return 0;
} else {
/*!re2c
re2c:indent:top = 2;
re2c:yyfill:enable = 0;
INTEGER = [\-]?[0-9]+;
INTEGER {
token->opcode = PHANNOT_T_INTEGER;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
DOUBLE = ([\-]?[0-9]+[\.][0-9]+);
DOUBLE {
token->opcode = PHANNOT_T_DOUBLE;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
'null' {
token->opcode = PHANNOT_T_NULL;
return 0;
}
'false' {
token->opcode = PHANNOT_T_FALSE;
return 0;
}
'true' {
token->opcode = PHANNOT_T_TRUE;
return 0;
}
STRING = (["] ([\\]["]|[\\].|[\001-\377]\[\\"])* ["])|(['] ([\\][']|[\\].|[\001-\377]\[\\'])* [']);
STRING {
token->opcode = PHANNOT_T_STRING;
token->value = estrndup(q, YYCURSOR - q - 1);
token->len = YYCURSOR - q - 1;
q = YYCURSOR;
return 0;
}
IDENTIFIER = ('\x5C'?[a-zA-Z_]([a-zA-Z0-9_]*)('\x5C'[a-zA-Z_]([a-zA-Z0-9_]*))*);
IDENTIFIER {
token->opcode = PHANNOT_T_IDENTIFIER;
token->value = estrndup(start, YYCURSOR - start);
token->len = YYCURSOR - start;
q = YYCURSOR;
return 0;
}
"(" {
token->opcode = PHANNOT_T_PARENTHESES_OPEN;
return 0;
}
")" {
token->opcode = PHANNOT_T_PARENTHESES_CLOSE;
return 0;
}
"{" {
token->opcode = PHANNOT_T_BRACKET_OPEN;
return 0;
}
"}" {
token->opcode = PHANNOT_T_BRACKET_CLOSE;
return 0;
}
"[" {
token->opcode = PHANNOT_T_SBRACKET_OPEN;
return 0;
}
"]" {
token->opcode = PHANNOT_T_SBRACKET_CLOSE;
return 0;
}
"@" {
token->opcode = PHANNOT_T_AT;
return 0;
}
"=" {
token->opcode = PHANNOT_T_EQUALS;
return 0;
}
":" {
token->opcode = PHANNOT_T_COLON;
return 0;
}
"," {
token->opcode = PHANNOT_T_COMMA;
return 0;
}
[ \t\r]+ {
token->opcode = PHANNOT_T_IGNORE;
return 0;
}
[\n] {
s->active_line++;
token->opcode = PHANNOT_T_IGNORE;
return 0;
}
"\000" {
status = PHANNOT_SCANNER_RETCODE_EOF;
break;
}
[^] {
status = PHANNOT_SCANNER_RETCODE_ERR;
break;
}
*/
}
}
return status;
}

View file

@ -1,50 +0,0 @@
dnl config.m4 for extension r3
PHP_ARG_WITH(r3, for r3 support,
[ --with-r3 Include r3 support])
dnl PHP_ARG_ENABLE(r3, whether to enable r3 support,
dnl Make sure that the comment is aligned:
dnl [ --enable-r3 Enable r3 support])
if test "$PHP_R3" != "no"; then
SEARCH_PATH="/usr/local /usr"
SEARCH_FOR="/include/r3/r3.h"
if test -r $PHP_R3/$SEARCH_FOR; then
R3_DIR=$PHP_R3
else
AC_MSG_CHECKING([for r3 files in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
R3_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$R3_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the r3 distribution])
fi
echo $R3_DIR
dnl # --with-r3 -> add include path
PHP_ADD_INCLUDE($R3_DIR/include)
LIBNAME=r3
LIBSYMBOL=r3_route_create
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
[
PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $R3_DIR/lib, R3_SHARED_LIBADD)
AC_DEFINE(HAVE_R3LIB,1,[ ])
],[
AC_MSG_ERROR([wrong r3 lib version or lib not found])
],[
-L$R3_DIR/lib -lm
])
PHP_SUBST(R3_SHARED_LIBADD)
PHP_NEW_EXTENSION(r3, [ct_helper.c hash.c php_expandable_mux.c php_r3.c r3_controller.c r3_functions.c r3_mux.c r3_persistent.c], $ext_shared)
fi

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,3 +104,33 @@ 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_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_R3Route = php_r3_match(z_routes, path, path_len TSRMLS_CC);
if ( z_R3Route != NULL ) {
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;
@ -438,7 +438,7 @@ PHP_FUNCTION(r3_persistent_dispatch)
char *ns, *filename, *path;
int ns_len, filename_len, path_len;
zval *mux = NULL;
zval *R3Route = NULL;
zval *route = 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
R3Route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
route = call_mux_method(mux, "dispatch" , sizeof("dispatch"), 1 , z_path, NULL, NULL TSRMLS_CC);
zval_ptr_dtor(&z_path);
if ( R3Route ) {
if ( route ) {
*return_value = *route;
zval_copy_ctor(return_value);
return;
}
// R3Route not found
// route 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 R3Route option is provided
// check conditions only when route option is provided
if ( zend_hash_index_find( Z_ARRVAL_PP(z_route_pp), 3, (void**) &z_route_options_pp) == SUCCESS ) {
if ( zend_hash_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 R3Route zval
// Returns compiled route 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_R3Route = NULL; // will be an array
zval *z_compiled_route = NULL; // will be an array
zend_call_method( NULL, *ce_pattern_compiler, NULL, "compile", strlen("compile"), &z_compiled_route, 2, z_pattern, z_options TSRMLS_CC );
if ( z_compiled_R3Route == NULL ) {
if ( z_compiled_route == 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 R3Route item
// zval for route 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_R3Route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
zval *z_compiled_route = compile_route_pattern(z_new_pattern, *z_route_options, ce_pattern_compiler TSRMLS_CC);
if ( z_compiled_R3Route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
if ( z_compiled_route == NULL || Z_TYPE_P(z_compiled_route) == IS_NULL ) {
php_error( E_ERROR, "Cannot compile pattern: %s", new_pattern);
}
@ -535,7 +535,7 @@ PHP_METHOD(Mux, mount) {
Z_ADDREF_P(z_compiled_route);
Z_ADDREF_P(z_new_routes);
// create new R3Route and append to mux->routes
// create new route and append to mux->routes
add_index_bool(z_new_routes, 0 , 1); // pcre flag == false
add_index_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 R3Route options
// Merge the mount options with the route 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_R3Route = NULL;
zval **z_route = NULL;
z_routes_by_id = zend_read_property( ce_r3_mux , this_ptr, "routesById", sizeof("routesById")-1, 1 TSRMLS_CC);
// php_var_dump(&z_routes_by_id, 1 TSRMLS_CC);
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_R3Route ) == SUCCESS ) {
if ( zend_hash_find( Z_ARRVAL_P(z_routes_by_id) , route_id, route_id_len + 1, (void**) &z_route ) == SUCCESS ) {
*return_value = **z_route;
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,"R3Route sort failed.");
// php_error(E_ERROR,"route sort failed.");
// zend_update_property(ce_r3_mux, getThis(), "routes", sizeof("routes")-1, z_routes TSRMLS_CC);
}
@ -843,7 +843,7 @@ PHP_METHOD(Mux, dispatch) {
int path_len;
zval *z_path;
zval *z_return_R3Route = NULL;
zval *z_return_route = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) {
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_R3Route || Z_TYPE_P(z_return_route) == IS_NULL ) {
if ( ! z_return_route || Z_TYPE_P(z_return_route) == IS_NULL ) {
zval_ptr_dtor(&z_path);
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 R3Route vars");
php_error(E_ERROR, "require route 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 R3Route vars[0]");
php_error(E_ERROR, "require route vars[0]");
RETURN_FALSE;
}
@ -955,7 +955,7 @@ PHP_METHOD(Mux, dispatch) {
}
}
if ( z_return_R3Route ) {
if ( z_return_route ) {
*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_R3Route = NULL;
zval *z_route = NULL;
if ( zend_hash_find( Z_ARRVAL_P( zend_read_property(ce_r3_mux, this_ptr, "staticRoutes", sizeof("staticRoutes") - 1, 1 TSRMLS_CC) ), path, path_len, (void**)&z_route_pp) == SUCCESS ) {
if ( Z_TYPE_PP(z_route_pp) != IS_NULL ) {
*return_value = **z_route_pp;
@ -981,8 +981,8 @@ PHP_METHOD(Mux, match) {
return;
}
}
z_R3Route = php_r3_match(zend_read_property(ce_r3_mux , this_ptr , "routes", sizeof("routes")-1, 1 TSRMLS_CC), path, path_len TSRMLS_CC);
if ( z_R3Route != NULL ) {
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 ) {
*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 R3Route pattern", 0 TSRMLS_CC);
zend_throw_exception(ce_r3_exception, "Can not compile route 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_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);
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);
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 R3Route to our static R3Route hash
// if there is no option specified in z_options, we can add the route to our static route hash
if ( zend_hash_num_elements(Z_ARRVAL_P(z_options)) ) {
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_R3Route = NULL;
zval *id_route = NULL;
ALLOC_ZVAL(id_route);
ZVAL_COPY_VALUE(id_route, z_new_route);
zval_copy_ctor(id_route);

View file

@ -6,6 +6,6 @@ libdir=@libdir@
Name: r3
Description: High-performance URL router library
Version: @PACKAGE_VERSION@
Requires: libpcre2-8
Libs: -L${libdir} -lr3
Requires:
Libs: -L${libdir} -lr3 -lpcre
CFlags: -I${includedir}

View file

@ -1,27 +0,0 @@
add_library(r3 STATIC
edge.c
match_entry.c
memory.c
node.c
slug.c
str.c
token.c)
target_compile_definitions(r3
PRIVATE
_GNU_SOURCE)
target_include_directories(r3
PUBLIC
${PCRE2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/3rdparty
${PROJECT_SOURCE_DIR}/include)
target_link_libraries(r3
PUBLIC
${PCRE2_LIBRARIES})
install(
TARGETS r3
DESTINATION lib)

View file

@ -1,10 +1,10 @@
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -Wall -std=c99
AM_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -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
libr3core_la_SOURCES = node.c edge.c str.c token.c match_entry.c slug.c ip.c
if ENABLE_JSON
libr3core_la_SOURCES += json.c
@ -23,7 +23,7 @@ MOSTLYCLEANFILES = *.gcov *.gcda *.gcno
# 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
# libr3core_la_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/3rdparty -Wall -std=c99
if ENABLE_GRAPHVIZ
libr3core_la_SOURCES += gvc.c

View file

@ -1,6 +1,6 @@
/*
* edge.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -13,76 +13,95 @@
// Jemalloc memory management
// #include <jemalloc/jemalloc.h>
// PCRE
#include <pcre.h>
// Judy array
// #include <Judy.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "slug.h"
#include "zmalloc.h"
#define CHECK_PTR(ptr) if (ptr == NULL) return NULL;
edge * r3_edge_createl(const char * pattern, int pattern_len, node * child) {
edge * e = (edge*) zmalloc( sizeof(edge) );
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;
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.base, e->pattern.len);
e->has_slug = r3_path_contains_slug_char(e->pattern);
return e;
}
// R3Edge * r3_edge_createl(const char * pattern, int pattern_len, R3Node * child)
// {
// R3Edge * e = (R3Edge*) malloc( sizeof(R3Edge) );
// CHECK_PTR(e);
// e->pattern = (char*) pattern;
// e->pattern_len = pattern_len;
// e->opcode = 0;
// e->child = child;
// e->has_slug = r3_path_contains_slug_char(e->pattern);
// return e;
// }
/**
* r3_edge_branch splits the edge and append the rest part as the child of the
* first level child
*
* branch the edge pattern at "dl" offset,
* and insert a dummy child between the edges.
* 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)
*
* A -> [prefix..suffix] -> B
* A -> [prefix] -> B -> [suffix] -> New Child (Copy Data, Edges from B)
*
*/
R3Node * r3_edge_branch(R3Edge *e, int dl) {
R3Node * new_child;
R3Edge * new_edge;
// the rest string
const char * s1 = e->pattern.base + dl;
int s1_len = e->pattern.len - dl;
node * r3_edge_branch(edge *e, int dl) {
node *new_child;
edge *e1;
char * s1 = e->pattern + dl;
int s1_len = 0;
// the suffix edge of the leaf
new_child = r3_tree_create(3);
s1_len = e->pattern_len - dl;
e1 = r3_edge_createl(zstrndup(s1, s1_len), s1_len, new_child);
new_edge = r3_node_append_edge(new_child);
r3_edge_initl(new_edge, s1, s1_len, e->child);
e->child = new_child;
// Migrate the child edges to the new edge we just created.
for ( int i = 0 ; i < e->child->edge_len ; i++ ) {
r3_node_append_edge(new_child, e->child->edges[i]);
e->child->edges[i] = NULL;
}
e->child->edge_len = 0;
// Migrate the child routes
for ( int i = 0 ; i < e->child->route_len ; i++ ) {
r3_node_append_route(new_child, e->child->routes[i]);
e->child->routes[i] = NULL;
}
e->child->route_len = 0;
// Migrate the endpoint
new_child->endpoint = e->child->endpoint;
e->child->endpoint = 0; // reset endpoint
// Migrate the data
new_child->data = e->child->data; // copy data pointer
e->child->data = NULL;
r3_node_append_edge(e->child, e1);
// truncate the original edge pattern
e->pattern.len = dl;
char *oldpattern = e->pattern;
e->pattern = zstrndup(e->pattern, dl);
e->pattern_len = dl;
zfree(oldpattern);
return new_child;
}
void r3_edge_free(R3Edge * e) {
if (e) {
if ( e->child ) {
r3_tree_free(e->child);
}
// free itself
// free(e);
void r3_edge_free(edge * e) {
zfree(e->pattern);
if ( e->child ) {
r3_tree_free(e->child);
}
// free itself
zfree(e);
}

View file

@ -1,6 +1,6 @@
/*
* gvz.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,25 +10,24 @@
#include <stdlib.h>
#include "r3.h"
#include "r3_gvc.h"
#include "zmalloc.h"
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int * node_cnt) {
if (!n)
return;
void r3_tree_build_ag_nodes(Agraph_t * g, Agnode_t * ag_parent_node, const node * n, int node_cnt) {
edge * e;
for ( int i = 0 ; i < n->edges.size ; i++ ) {
edge * e = n->edges.entries + i;
(*node_cnt)++;
for ( int i = 0 ; i < n->edge_len ; i++ ) {
e = n->edges[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) {};
asprintf(&nodename,"%s", e->child->combined_pattern);
} else {
int r = asprintf(&nodename,"#%d", *node_cnt);
if (r) {};
asprintf(&nodename,"#%d", node_cnt);
}
agn_child = agnode(g, nodename, 1);
@ -53,13 +52,11 @@ int r3_tree_render(const node * tree, const char *layout, const char * format, F
GVC_t *gvc = NULL;
gvc = gvContext();
/* Create a simple digraph */
// g = agopen("g", Agdirected, 0);
g = agopen("g", Agundirected, 0);
g = agopen("g", Agdirected, 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);
r3_tree_build_ag_nodes(g, ag_root, tree, 0);
gvLayout(gvc, g, layout);
gvRender(gvc, g, format, fp);
gvFreeLayout(gvc, g);
@ -99,13 +96,11 @@ int r3_tree_render_file(const node * tree, const char * format, const char * fil
*/
/* Create a simple digraph */
// g = agopen("g", Agdirected, 0);
g = agopen("g", Agundirected, 0);
g = agopen("g", Agdirected, 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);
r3_tree_build_ag_nodes(g, ag_root, tree, 0);
gvLayout(gvc, g, "dot");
gvRenderFilename(gvc, g, format, filename);

48
src/ip.c Normal file
View file

@ -0,0 +1,48 @@
/*
* ip.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
// #include "ip.h"
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
int r3_ip_cmp(const char* a, const char* b) {
long al = inet_addr(a);
long bl = inet_addr(b);
return al == bl;
}
int r3_ip_mask_cmp(const char *a, const char* b, const char* mask_str) {
long m = inet_addr(mask_str);
long al = inet_addr(a);
long bl = inet_addr(b);
return !((al ^ bl) & m);
}
/*
long in;
in = inet_addr("192.168.1.1");
printf("My unreadable addres is %ld\n", in);
in = inet_addr("8.8.8.8");
printf("My unreadable addres is %ld\n", in);
printf("My unreadable addres is %u %d\n", inet_addr("255.255.255.255"), 2 << 16 );
printf("My unreadable addres is %u %d\n", inet_addr("255.0.0.0") , (2 << 7) - 1 );
printf("My unreadable addres is %u %d\n", inet_addr("255.255.0.0") , (2 << 15) - 1 );
printf("My unreadable addres is %u %d\n", inet_addr("255.255.255.0") , (2 << 23) - 1 );
printf("My unreadable addres is %u\n", inet_addr("255.255.255.0") & inet_addr("192.168.0.1") );
struct in_addr in2;
in2.s_addr = inet_addr("192.168.0.1");
char *dot_ip = inet_ntoa(in2);
printf("%s\n", dot_ip);
*/

View file

@ -1,6 +1,6 @@
/*
* json.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -9,29 +9,29 @@
#include "r3.h"
#include "r3_json.h"
json_object * r3_route_to_json_object(const R3Route * r) {
json_object * r3_route_to_json_object(const route * 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, "path", json_object_new_string(r->path));
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));
json_object_object_add(obj, "host", json_object_new_string(r->host));
}
if (r->remote_addr_pattern) {
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern.base));
json_object_object_add(obj, "remote_addr_pattern", json_object_new_string(r->remote_addr_pattern));
}
return obj;
}
json_object * r3_edge_to_json_object(const R3Edge * e) {
json_object * r3_edge_to_json_object(const edge * 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, "pattern", json_object_new_string(e->pattern));
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));
@ -42,7 +42,7 @@ json_object * r3_edge_to_json_object(const R3Edge * e) {
return obj;
}
json_object * r3_node_to_json_object(const R3Node * n) {
json_object * r3_node_to_json_object(const node * n) {
json_object *obj;
obj = json_object_new_object();
@ -60,7 +60,7 @@ json_object * r3_node_to_json_object(const R3Node * n) {
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 *edge_json_obj = r3_edge_to_json_object(n->edges[i]);
json_object_array_add(edges_array, edge_json_obj);
}
}
@ -69,7 +69,7 @@ json_object * r3_node_to_json_object(const R3Node * n) {
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 *route_json_obj = r3_route_to_json_object(n->routes[i]);
json_object_array_add(routes_array, route_json_obj);
}
}
@ -79,17 +79,17 @@ json_object * r3_node_to_json_object(const R3Node * n) {
}
const char * r3_node_to_json_string_ext(const R3Node * n, int options) {
const char * r3_node_to_json_string_ext(const node * 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) {
const char * r3_node_to_json_pretty_string(const node * 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) {
const char * r3_node_to_json_string(const node * n) {
json_object *obj = r3_node_to_json_object(n);
return json_object_to_json_string(obj);
}

View file

@ -1,17 +1,18 @@
/*
* list.c Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* list.c Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#include <stdlib.h>
#include "r3_list.h"
#include "zmalloc.h"
/* Naive linked list implementation */
list *
list_create()
{
list *l = (list *) malloc(sizeof(list));
list *l = (list *) zmalloc(sizeof(list));
l->count = 0;
l->head = NULL;
l->tail = NULL;
@ -37,7 +38,7 @@ list_free(l)
}
pthread_mutex_unlock(&(l->mutex));
pthread_mutex_destroy(&(l->mutex));
free(l);
zfree(l);
}
}
@ -47,7 +48,7 @@ list_item * list_add_element(list * l, void * ptr)
pthread_mutex_lock(&(l->mutex));
li = (list_item *) malloc(sizeof(list_item));
li = (list_item *) zmalloc(sizeof(list_item));
li->value = ptr;
li->next = NULL;
li->prev = l->tail;
@ -88,7 +89,7 @@ list_remove_element(l, ptr)
li->next->prev = li->prev;
}
l->count--;
free(li);
zfree(li);
result = 1;
break;
}

View file

@ -1,28 +1,34 @@
/*
* match_entry.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcre.h>
#include <assert.h>
#include <stdbool.h>
#include "r3.h"
#include "zmalloc.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;
match_entry * entry = zmalloc(sizeof(match_entry));
if(!entry)
return NULL;
entry->vars = str_array_create(3);
entry->path = path;
entry->path_len = path_len;
entry->data = NULL;
return entry;
}
void match_entry_free(match_entry * entry) {
assert(entry);
free(entry->vars.tokens.entries);
free(entry);
if (entry->vars) {
str_array_free(entry->vars);
}
zfree(entry);
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,6 +1,6 @@
/*
* slug.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -9,14 +9,14 @@
#include <stdlib.h>
#include <string.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "slug.h"
#include "r3_debug.h"
#include "zmalloc.h"
r3_slug_t * r3_slug_new(const char * path, int path_len) {
r3_slug_t * s = malloc(sizeof(r3_slug_t));
r3_slug_t * s = zmalloc(sizeof(r3_slug_t));
if (!s)
return NULL;
s->path = (char*) path;
@ -32,7 +32,7 @@ r3_slug_t * r3_slug_new(const char * path, int path_len) {
}
void r3_slug_free(r3_slug_t * s) {
free(s);
zfree(s);
}
@ -60,8 +60,7 @@ int r3_slug_check(r3_slug_t *s) {
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) {};
asprintf(&str, "slug: '%.*s', pattern: '%.*s', path: '%.*s'", s->len, s->begin, s->pattern_len, s->pattern, s->path_len, s->path);
return str;
}
@ -86,7 +85,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
}
// there is no slug
if (!r3_path_contains_slug_char(offset, needle_len - (offset-needle))) {
if (!r3_path_contains_slug_char(offset)) {
return 0;
}
@ -140,8 +139,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
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) {};
asprintf(&err, "Incomplete slug pattern. PATH (%d): '%s', OFFSET: %ld, STATE: %d", needle_len, needle, p - needle, state);
*errstr = err;
}
return -1;
@ -154,7 +152,7 @@ int r3_slug_parse(r3_slug_t *s, const char *needle, int needle_len, const char *
/**
* provide a quick way to count slugs, simply search for '{'
*/
int r3_slug_count(const char * needle, int len, char **errstr) {
int slug_count(const char * needle, int len, char **errstr) {
int cnt = 0;
int state = 0;
char * p = (char*) needle;
@ -179,8 +177,7 @@ int r3_slug_count(const char * needle, int len, char **errstr) {
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) {};
asprintf(&err, "Incomplete slug pattern. PATTERN (%d): '%s', OFFSET: %ld, STATE: %d", len, needle, p - needle, state);
*errstr = err;
}
return -1;

View file

@ -1,11 +1,11 @@
/*
* slug.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#ifndef SLUG_H
#define SLUG_H
#ifndef R3_SLUG_H
#define R3_SLUG_H
typedef struct {
/**
@ -49,11 +49,10 @@ 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;
int slug_count(const char * needle, int len, char **errstr);
static inline int r3_path_contains_slug_char(const char * str) {
return strchr(str, '{') != NULL ? 1 : 0;
}
#endif /* !SLUG_H */

113
src/str.c
View file

@ -1,6 +1,6 @@
/*
* str.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,18 +10,11 @@
#include <string.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
#include "str.h"
#include "r3_str.h"
#include "slug.h"
#include "zmalloc.h"
static const char * strnchr(const char* str, unsigned int len, int ch) {
for (unsigned int i = 0; i < len; i++) {
if (str[i] == ch) return str + i;
}
return NULL;
}
int r3_pattern_to_opcode(const char * pattern, unsigned int len) {
int r3_pattern_to_opcode(const char * pattern, int len) {
if ( strncmp(pattern, "\\w+",len) == 0 ) {
return OP_EXPECT_MORE_WORDS;
}
@ -43,9 +36,6 @@ int r3_pattern_to_opcode(const char * pattern, unsigned int len) {
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
return OP_EXPECT_NODASH;
}
if ( strncmp(pattern, ".*", len) == 0 ) {
return OP_GREEDY_ANY;
}
return 0;
}
@ -81,23 +71,21 @@ char * r3_inside_slug(const char * needle, int needle_len, char *offset, char **
if (found_s1 || found_s2) {
// wrong slug pattern
if(errstr) {
int r = asprintf(errstr, "Incomplete slug pattern");
if (r) {};
asprintf(errstr, "Incomplete slug pattern");
}
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;
char * r3_slug_find_placeholder(const char *s1, int *len) {
char *c;
char *s2;
int cnt = 0;
if ((c = strnchr(s1, str_len, '{'))) {
if ( NULL != (c = strchr(s1, '{')) ) {
// find closing '}'
s2 = c;
unsigned int j = str_len - (c - s1);
for (unsigned int i = 0; i < j; i++) {
while(*s2) {
if (*s2 == '{' )
cnt++;
else if (*s2 == '}' )
@ -122,16 +110,15 @@ const char * r3_slug_find_placeholder(const char *s1, unsigned int str_len, unsi
/**
* given a slug string, duplicate the pattern string of the slug
*/
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, ':')) ) {
char * r3_slug_find_pattern(const char *s1, int *len) {
char *c;
char *s2;
int cnt = 1;
if ( NULL != (c = strchr(s1, ':')) ) {
c++;
// find closing '}'
s2 = c;
unsigned int j = str_len - (c - s1);
for (unsigned int i = 0; i < j; i++) {
while(s2) {
if (*s2 == '{' )
cnt++;
else if (*s2 == '}' )
@ -144,57 +131,31 @@ const char * r3_slug_find_pattern(const char *s1, unsigned int str_len, unsigned
} else {
return NULL;
}
if (cnt!=0) {
return NULL;
}
*len = s2 - c;
return c;
}
/**
* 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 * r3_slug_compile(const char * str, unsigned int len)
char * r3_slug_compile(const char * str, int len)
{
const char *s1 = NULL;
char *o = NULL;
const char *pat = NULL;
char *s1 = NULL, *o = NULL;
char *pat = NULL;
char sep = '/';
// append prefix
unsigned int s1_len;
s1 = r3_slug_find_placeholder(str, len, &s1_len);
int s1_len;
s1 = r3_slug_find_placeholder(str, &s1_len);
if ( !s1 ) {
return strndup(str,len);
if ( s1 == NULL ) {
return zstrdup(str);
}
char * out = NULL;
if (!(out = calloc(1, sizeof(char) * 200))) {
if ((out = zcalloc(sizeof(char) * 200)) == NULL) {
return (NULL);
}
@ -206,8 +167,8 @@ char * r3_slug_compile(const char * str, unsigned int len)
o += (s1 - str);
unsigned int pat_len;
pat = r3_slug_find_pattern(s1, s1_len, &pat_len);
int pat_len;
pat = r3_slug_find_pattern(s1, &pat_len);
if (pat) {
*o = '(';
@ -221,7 +182,7 @@ char * r3_slug_compile(const char * str, unsigned int len)
o+= strlen("([^*]+)");
}
s1 += s1_len;
strncat(o, s1, len - (s1 - str)); // string after slug
strncat(o, s1, strlen(s1));
return out;
}
@ -230,7 +191,13 @@ char * ltrim_slash(char* str)
{
char * p = str;
while (*p == '/') p++;
return strdup(p);
return zstrdup(p);
}
void str_repeat(char *s, const char *c, int len) {
while(len--) {
s[len - 1] = *c;
}
}
void print_indent(int level) {
@ -240,16 +207,14 @@ void print_indent(int level) {
}
}
#ifndef HAVE_STRDUP
char *strdup(const char *s) {
char *zstrdup(const char *s) {
char *out;
int count = 0;
while( s[count] )
++count;
++count;
out = malloc(sizeof(char) * count);
out = zmalloc(sizeof(char) * count);
out[--count] = 0;
while( --count >= 0 )
out[count] = s[count];
@ -257,16 +222,14 @@ char *strdup(const char *s) {
}
#endif
#ifndef HAVE_STRNDUP
char *strndup(const char *s, int n) {
char *zstrndup(const char *s, int n) {
char *out;
int count = 0;
while( count < n && s[count] )
++count;
++count;
out = malloc(sizeof(char) * count);
out = zmalloc(sizeof(char) * count);
out[--count] = 0;
while( --count >= 0 )
out[count] = s[count];

View file

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

View file

@ -1,54 +1,64 @@
/*
* token.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* 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 "r3_str.h"
#include "str_array.h"
#include "memory.h"
#include "zmalloc.h"
str_array * str_array_create(int cap) {
str_array * list = (str_array*) zmalloc( sizeof(str_array) );
if (!list)
return NULL;
list->len = 0;
list->cap = cap;
list->tokens = (char**) zmalloc( sizeof(char*) * cap);
return list;
}
void str_array_free(str_array *l) {
assert(l);
free(l->tokens.entries);
}
bool str_array_append(str_array * l, const char * token, unsigned int len) {
r3_vector_reserve(&l->tokens, l->tokens.size + 1);
r3_iovec_t *temp = l->tokens.entries + l->tokens.size++;
memset(temp, 0, sizeof(*temp));
temp->base = token;
temp->len = len;
return true;
}
void str_array_dump_slugs(const str_array *l) {
if (l->tokens.size) {
printf("[");
for ( int i = 0; i < l->tokens.size ; i++ ) {
printf("\"%*.*s\"", l->slugs.entries[i].len,l->slugs.entries[i].len,l->slugs.entries[i].base );
if ( i + 1 != l->tokens.size ) {
printf(", ");
}
for ( int i = 0; i < l->len ; i++ ) {
if (l->tokens[ i ]) {
zfree(l->tokens[i]);
}
printf("]\n");
} else {
printf("[]\n");
}
zfree(l);
}
bool str_array_is_full(const str_array * l) {
return l->len >= l->cap;
}
bool str_array_resize(str_array * l, int new_cap) {
l->tokens = zrealloc(l->tokens, sizeof(char**) * new_cap);
l->cap = new_cap;
return l->tokens != NULL;
}
bool str_array_append(str_array * l, char * token) {
if ( str_array_is_full(l) ) {
bool ret = str_array_resize(l, l->cap + 20);
if (ret == FALSE ) {
return FALSE;
}
}
l->tokens[ l->len++ ] = token;
return TRUE;
}
void str_array_dump(const str_array *l) {
printf("[");
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 ) {
for ( int i = 0; i < l->len ; i++ ) {
printf("\"%s\"", l->tokens[i] );
if ( i + 1 != l->len ) {
printf(", ");
}
}

View file

@ -1,27 +0,0 @@
function(add_r3_test NAME)
add_executable(${NAME} ${ARGN})
target_include_directories(${NAME}
PRIVATE
${CHECK_INCLUDE_DIRS}
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/src)
target_link_libraries(${NAME}
${CHECK_LDFLAGS}
r3)
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,6 +1,6 @@
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_CFLAGS=$(DEPS_CFLAGS) $(GVC_DEPS_CFLAGS) $(JSONC_CFLAGS) @CHECK_CFLAGS@ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/src -I$(top_builddir)/3rdparty -Wall -std=c99 -ggdb -Wall
AM_LDFLAGS=$(DEPS_LIBS) $(GVC_DEPS_LIBS) $(JSONC_LIBS) @CHECK_LIBS@ $(top_builddir)/libr3.la
if USE_JEMALLOC
@ -27,18 +27,6 @@ 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
@ -61,3 +49,4 @@ bench_SOURCES = bench.c
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir)/include
# AM_CFLAGS=$(DEPS_CFLAGS) -I$(top_builddir) -I$(top_builddir)/include
CLEANFILES = check_tree.log

View file

@ -1,6 +1,6 @@
/*
* bench.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -12,14 +12,15 @@
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "zmalloc.h"
#include "bench.h"
unsigned long unixtime() {
struct timeval tp;
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
return tp.tv_sec;
}
return 0;
@ -29,7 +30,7 @@ double microtime() {
struct timeval tp;
long sec = 0L;
double msec = 0.0;
if (gettimeofday((struct timeval *) &tp, (NULL)) == 0) {
if (gettimeofday((struct timeval *) &tp, (NUL)) == 0) {
msec = (double) (tp.tv_usec / MICRO_IN_SEC);
sec = tp.tv_sec;
if (msec >= 1.0)
@ -95,7 +96,7 @@ void bench_append_csv(char *filename, int countOfB, ...) {
int main()
{
R3Node * n = r3_tree_create(1);
node * n = r3_tree_create(1);
int route_data = 999;
@ -440,7 +441,7 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
r3_tree_compile(n, NULL);
END_MEASURE(tree_compile)
R3Node * m;
node *m;
m = r3_tree_match(n , "/qux/bar/corge", NULL);
assert(m != NULL);
assert( *((int*) m->data) == 999 );
@ -460,10 +461,9 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
BENCHMARK_SUMMARY(str_match_entry);
R3Node * tree2 = r3_tree_create(1);
node * 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);

View file

@ -1,6 +1,6 @@
/*
* bench.h
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/

View file

@ -1,6 +1,6 @@
/*
* check_gvc.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,7 +10,7 @@
#include <stdlib.h>
#include "r3.h"
#include "r3_gvc.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "bench.h"
START_TEST (test_gvc_render_dot)

View file

@ -1,92 +0,0 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_hosts)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
char * host0 = "foo.com";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
route->host.base = host0;
route->host.len = strlen(host0);
char * uri1 = "/bar";
char * host1 = "*.bar.com";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->host.base = host1;
route->host.len = strlen(host1);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->host.base = host0;
entry->host.len = strlen(host0);
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "www.bar.com";
entry->host.len = strlen("www.bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "bar.com";
entry->host.len = strlen("bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = ".bar.com";
entry->host.len = strlen(".bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->host.base = "a.bar.com";
entry->host.len = strlen("a.bar.com");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 host tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_hosts);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -1,105 +0,0 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_http_scheme)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->http_scheme = SCHEME_HTTPS;
char * uri2 = "/boo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
route->http_scheme = SCHEME_HTTP | SCHEME_HTTPS;
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->http_scheme = SCHEME_HTTPS;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/boo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->http_scheme = SCHEME_HTTP;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->http_scheme = SCHEME_HTTPS;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 remote_addr tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_http_scheme);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -1,6 +1,6 @@
/*
* check_json.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -10,13 +10,13 @@
#include <stdlib.h>
#include <json-c/json.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "r3_json.h"
#include "zmalloc.h"
START_TEST (test_json_encode)
{
R3Node * n;
node * n;
n = r3_tree_create(10);
ck_assert(n);

View file

@ -1,216 +0,0 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (test_remote_addrs)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
route->remote_addr_v4 = 0;
route->remote_addr_v4_bits = 0;
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
route->remote_addr_v4 = inet_network("127.0.0.1");
route->remote_addr_v4_bits = 32;
char * uri2 = "/boo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
route->remote_addr_v4 = inet_network("127.0.0.1");
route->remote_addr_v4_bits = 24;
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "127.0.0.2";
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.0.1";
entry->remote_addr.len = sizeof("127.0.0.1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.0.2";
entry->remote_addr.len = sizeof("127.0.0.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.1.2";
entry->remote_addr.len = sizeof("127.0.1.2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/boo");
entry->remote_addr.base = "127.0.1.333"; // invalid ip address
entry->remote_addr.len = sizeof("127.0.1.333") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
void parse_ipv6(const char *ipv6, int nmask, R3Route * route)
{
struct in6_addr addr6;
int ret = inet_pton(AF_INET6, ipv6, (void *)&addr6);
ck_assert(ret == 1);
for (int i = 0; i < 4; i++) {
route->remote_addr_v6[i] = ntohl(addr6.__in6_u.__u6_addr32[i]);
if (nmask >= 32) {
route->remote_addr_v6_bits[i] = 32;
} else if (nmask > 0) {
route->remote_addr_v6_bits[i] = nmask;
} else {
route->remote_addr_v6_bits[i] = 0;
}
nmask -= 32;
}
}
START_TEST (test_remote_addrs_ipv6)
{
R3Node * n = r3_tree_create(10);
R3Route * route = NULL;
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo";
route = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
parse_ipv6("fe80:fe80::1", 128, route); // "fe80:fe80::1"
char * uri1 = "/bar";
route = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
parse_ipv6("fe80:fe80::", 32, route); // "fe80:fe80::/32"
char * uri2 = "/goo";
route = r3_tree_insert_routel(n, 0, uri2, strlen(uri2), &uri2);
parse_ipv6("::1", 128, route); // "::1"
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe80:fe80::1";
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe80:fe80::2";
entry->remote_addr.len = sizeof("fe80:fe80::2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/foo");
entry->remote_addr.base = "fe88:fe80::1";
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "fe80:fe80::1";
entry->remote_addr.len = sizeof("fe80:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
entry = match_entry_create("/bar");
entry->remote_addr.base = "fe88:fe80::1";
entry->remote_addr.len = sizeof("fe88:fe80::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
entry = match_entry_create("/goo");
entry->remote_addr.base = "::1";
entry->remote_addr.len = sizeof("::1") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri2);
match_entry_free(entry);
entry = match_entry_create("/goo");
entry->remote_addr.base = "::2";
entry->remote_addr.len = sizeof("::2") - 1;
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route == NULL);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 remote_addr tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_remote_addrs);
tcase_add_test(tcase, test_remote_addrs_ipv6);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -7,12 +7,13 @@
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "zmalloc.h"
START_TEST (test_routes)
{
R3Node * n = r3_tree_create(10);
R3Node * m = NULL;
node * n = r3_tree_create(10);
node * m = NULL;
char *data0 = "/foo/bar/baz";
r3_tree_insert_path(n, "/foo/bar/baz", (void*) data0);

View file

@ -1,117 +0,0 @@
#include "config.h"
#include <stdio.h>
#include <check.h>
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
START_TEST (greedy_pattern)
{
R3Node * n = r3_tree_create(10);
match_entry * entry;
R3Route *matched_route;
char * uri0 = "/foo{:.*}";
r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/bar/foo/mmasdfasdfasd/f/asdf/as/df");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST (common_pattern)
{
R3Node * n = r3_tree_create(10);
match_entry * entry;
R3Route *r, *matched_route;
char * uri0 = "/foo/{slug}";
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
ck_assert(r != NULL);
char * uri1 = "/foo/{slug}/bar";
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
ck_assert(r != NULL);
char * err = NULL;
r3_tree_compile(n, &err);
ck_assert(err == NULL);
entry = match_entry_create("/foo/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri0);
match_entry_free(entry);
entry = match_entry_create("/foo/bar/bar");
matched_route = r3_tree_match_route(n, entry);
ck_assert(matched_route != NULL);
ck_assert(matched_route->data == &uri1);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST (incomplete_pattern)
{
R3Node * n = r3_tree_create(10);
R3Route * r;
char * uri0 = "{slug";
r = r3_tree_insert_routel(n, 0, uri0, strlen(uri0), &uri0);
ck_assert(r == NULL);
char * uri1 = "/foo/{slug";
r = r3_tree_insert_routel(n, 0, uri1, strlen(uri1), &uri1);
ck_assert(r == NULL);
r3_tree_free(n);
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 routes2 tests");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, greedy_pattern);
tcase_add_test(tcase, common_pattern);
tcase_add_test(tcase, incomplete_pattern);
suite_add_tcase(suite, tcase);
return suite;
}
int main (int argc, char *argv[]) {
int number_failed;
Suite *suite = r3_suite();
SRunner *runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
return number_failed;
}

View file

@ -1,6 +1,6 @@
/*
* check_slug.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -9,9 +9,9 @@
#include <check.h>
#include <stdlib.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "zmalloc.h"
#include "slug.h"
#include "r3_debug.h"
START_TEST (test_pattern_to_opcode)
{
@ -27,75 +27,46 @@ START_TEST (test_r3_slug_compile)
char * path = "/user/{id}";
char * c = NULL;
ck_assert_str_eq( c = r3_slug_compile(path, strlen(path) ) , "^/user/([^/]+)" );
free(c);
zfree(c);
char * path2 = "/what/{id}-foo";
ck_assert_str_eq( c = r3_slug_compile(path2, strlen(path2) ) , "^/what/([^/]+)-foo" );
free(c);
zfree(c);
char * path3 = "-{id}";
ck_assert_str_eq( c = r3_slug_compile(path3, strlen(path3)), "^-([^/]+)" );
free(c);
zfree(c);
char * path4 = "-{idx:\\d{3}}";
ck_assert_str_eq( c = r3_slug_compile(path4, strlen(path4)), "^-(\\d{3})" );
free(c);
zfree(c);
}
END_TEST
START_TEST (test_contains_slug)
{
char *test_str = "/user/{id}/{name}";
ck_assert( r3_path_contains_slug_char(test_str, strlen(test_str)) );
ck_assert( r3_path_contains_slug_char("/user/{id}/{name}") );
}
END_TEST
START_TEST (test_r3_slug_find_pattern)
{
unsigned int len;
char *test_str = "{name:\\s+}";
const char * namerex = r3_slug_find_pattern(test_str, strlen(test_str), &len);
int len;
char * namerex = r3_slug_find_pattern("{name:\\s+}", &len);
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
}
END_TEST
START_TEST (test_r3_slug_find_name)
{
unsigned int len;
char *test_str = "{name:\\s+}";
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
ck_assert( strncmp(namerex, "name", len) == 0 );
}
END_TEST
START_TEST (test_r3_slug_find_name_without_pattern)
{
unsigned int len;
char *test_str = "{name}";
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
ck_assert( strncmp(namerex, "name", len) == 0 );
}
END_TEST
START_TEST (test_r3_slug_find_name_with_multiple_slug)
{
unsigned int len;
char *test_str = "{name}/{name2}";
const char * namerex = r3_slug_find_name(test_str, strlen(test_str), &len);
ck_assert( strncmp(namerex, "name", len) == 0 );
}
END_TEST
START_TEST (test_r3_slug_find_placeholder)
{
unsigned int slug_len = 0;
const char * slug;
char *test_str = "/user/{name:\\s+}/to/{id}";
slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len);
int slug_len = 0;
char * slug;
slug = r3_slug_find_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
test_str = "/user/{idx:\\d{3}}/to/{idy:\\d{3}}";
slug = r3_slug_find_placeholder(test_str, strlen(test_str), &slug_len);
slug = r3_slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
}
@ -105,7 +76,7 @@ START_TEST (test_r3_inside_slug)
{
char * pattern = "/user/{name:\\s+}/to/{id}";
char * offset = strchr(pattern, '{') + 2;
ck_assert( r3_inside_slug(pattern, strlen(pattern), offset, NULL) != NULL );
ck_assert( (int)r3_inside_slug(pattern, strlen(pattern), offset, NULL) );
ck_assert( *(r3_inside_slug(pattern, strlen(pattern), offset, NULL)) == '{' );
ck_assert( ! r3_inside_slug(pattern, strlen(pattern), pattern, NULL) );
}
@ -116,9 +87,9 @@ START_TEST (test_incomplete_slug)
int cnt = 0;
char * errstr = NULL;
char * pattern = "/user/{name:\\d{3}}/to/{id";
cnt = r3_slug_count(pattern, strlen(pattern), &errstr);
cnt = slug_count(pattern, strlen(pattern), &errstr);
ck_assert_int_eq(cnt, -1);
ck_assert(errstr != NULL);
ck_assert(errstr);
printf("%s\n",errstr);
free(errstr);
}
@ -167,22 +138,22 @@ END_TEST
START_TEST (test_r3_slug_count)
START_TEST (test_slug_count)
{
int cnt = 0;
char * pattern = "/user/{name:\\s+}/to/{id}";
char * errstr = NULL;
cnt = r3_slug_count(pattern, strlen(pattern), &errstr);
cnt = slug_count(pattern, strlen(pattern), &errstr);
ck_assert_int_eq(cnt, 2);
if(errstr) free(errstr);
char * pattern2 = "/user/{name:\\d{3}}/to/{id}";
cnt = r3_slug_count(pattern2, strlen(pattern2), &errstr);
cnt = slug_count(pattern2, strlen(pattern2), &errstr);
ck_assert_int_eq(cnt, 2);
if(errstr) free(errstr);
char * pattern3 = "/user/{name:\\d{3}}/to/{id}";
cnt = r3_slug_count(pattern3, strlen(pattern3), &errstr);
cnt = slug_count(pattern3, strlen(pattern3), &errstr);
ck_assert_int_eq(cnt, 2);
if(errstr) free(errstr);
}
@ -190,9 +161,8 @@ END_TEST
START_TEST (test_r3_slug_find_placeholder_with_broken_slug)
{
unsigned int slug_len = 0;
char *sl_test = "/user/{name:\\s+/to/{id";
const char * slug = r3_slug_find_placeholder(sl_test, strlen(sl_test), &slug_len);
int slug_len = 0;
char * slug = r3_slug_find_placeholder("/user/{name:\\s+/to/{id", &slug_len);
ck_assert(slug == 0);
}
END_TEST
@ -207,14 +177,10 @@ Suite* r3_suite (void) {
tcase_add_test(tcase, test_r3_slug_find_pattern);
tcase_add_test(tcase, test_r3_slug_find_placeholder);
tcase_add_test(tcase, test_r3_slug_find_placeholder_with_broken_slug);
tcase_add_test(tcase, test_r3_slug_count);
tcase_add_test(tcase, test_slug_count);
tcase_add_test(tcase, test_r3_slug_compile);
tcase_add_test(tcase, test_pattern_to_opcode);
tcase_add_test(tcase, test_incomplete_slug);
tcase_add_test(tcase, test_r3_slug_find_name);
tcase_add_test(tcase, test_r3_slug_find_name_without_pattern);
tcase_add_test(tcase, test_r3_slug_find_name_with_multiple_slug);
// tcase_add_test(tcase, test_slug_parse_with_pattern);
// tcase_add_test(tcase, test_slug_parse_without_pattern);

View file

@ -1,6 +1,6 @@
/*
* check_str_array.c
* Copyright (C) 2014 c9s <yoanlin93@gmail.com>
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
@ -8,59 +8,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <check.h>
#include "str_array.h"
#include "r3.h"
#include "r3_str.h"
#include "zmalloc.h"
START_TEST (test_str_array)
{
str_array *vars = r3_mem_alloc(sizeof(str_array));
memset(vars, 0, sizeof(*vars));
str_array * l = str_array_create(3);
ck_assert(l);
char *test_str = "abc";
ck_assert( str_array_append(vars, test_str, strlen(test_str)));
ck_assert( vars->tokens.size == 1 );
ck_assert(str_array_append(l, zstrdup("abc")));
ck_assert( l->len == 1 );
char *test_str1 = "foo";
ck_assert( str_array_append(vars, test_str1, strlen(test_str1)));
ck_assert( vars->tokens.size == 2 );
ck_assert(str_array_append(l, zstrdup("foo") ));
ck_assert( l->len == 2 );
char *test_str2 = "bar";
ck_assert( str_array_append(vars, test_str2, strlen(test_str2)));
ck_assert( vars->tokens.size == 3 );
ck_assert( str_array_append(l, zstrdup("bar") ) );
ck_assert( l->len == 3 );
char *test_str3 = "zoo";
ck_assert( str_array_append(vars, test_str3, strlen(test_str3)));
ck_assert( vars->tokens.size == 4 );
ck_assert( str_array_append(l, zstrdup("zoo") ) );
ck_assert( l->len == 4 );
str_array_free(vars);
free(vars);
}
END_TEST
START_TEST (test_access_macros)
{
str_array *vars = r3_mem_alloc(sizeof(str_array));
memset(vars, 0, sizeof(*vars));
ck_assert( str_array_len(vars) == 0);
ck_assert( str_array_cap(vars) == 0);
r3_vector_reserve(&vars->tokens, 4);
ck_assert( str_array_len(vars) == 0);
ck_assert( str_array_cap(vars) == 4);
char *token1 = "first";
char *token2 = "second";
ck_assert( str_array_append(vars, token1, strlen(token1)));
ck_assert( str_array_append(vars, token2, strlen(token2)));
ck_assert( str_array_len(vars) == 2);
ck_assert( str_array_cap(vars) == 4);
ck_assert( strncmp(str_array_fetch(vars,0).base, "first", 5) == 0);
ck_assert( str_array_fetch(vars,0).len == 5);
ck_assert( strncmp(str_array_fetch(vars,1).base, "second", 6) == 0);
ck_assert( str_array_fetch(vars,1).len == 6);
str_array_free(vars);
free(vars);
ck_assert( str_array_resize(l, l->cap * 2) );
str_array_free(l);
}
END_TEST
@ -68,7 +38,6 @@ Suite* r3_suite (void) {
Suite *suite = suite_create("str_array test");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_str_array);
tcase_add_test(tcase, test_access_macros);
suite_add_tcase(suite, tcase);
return suite;
}

View file

@ -4,37 +4,32 @@
#include <stdlib.h>
#include <assert.h>
#include "r3.h"
#include "r3_slug.h"
#include "r3_str.h"
#include "zmalloc.h"
#include "bench.h"
#include "../src/r3_debug.h"
#define SAFE_FREE(ptr) if(ptr) free(ptr);
#define STR(str) str, sizeof(str)-1
START_TEST (test_find_common_prefix)
{
char *test_str = "/foo/{slug}";
R3Node * n = r3_tree_create(10);
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("/foo/{slug}"), sizeof("/foo/{slug}")-1, NULL);
r3_node_append_edge(n,e);
char *errstr = NULL;
int prefix_len = 0;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
errstr = NULL;
char *test_pref1 = "/foo";
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 4);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref2 = "/foo/";
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo/", sizeof("/foo/")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr);
@ -42,40 +37,35 @@ START_TEST (test_find_common_prefix)
errstr = NULL;
prefix_len = 0;
char *test_pref3 = "/foo/{slog}";
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo/{slog}", sizeof("/foo/{slog}")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref4 = "/foo/{bar}";
ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo/{bar}", sizeof("/foo/{bar}")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref5 = "/foo/bar";
ret_edge = r3_node_find_common_prefix(n, test_pref5, strlen(test_pref5), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo/bar", sizeof("/foo/bar")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref6 = "/bar/";
ret_edge = r3_node_find_common_prefix(n, test_pref6, strlen(test_pref6), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/bar/", sizeof("/bar/")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 1);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref7 = "{bar}";
ret_edge = r3_node_find_common_prefix(n, test_pref7, strlen(test_pref7), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "{bar}", sizeof("{bar}")-1, &prefix_len, &errstr);
ck_assert(ret_edge == NULL);
ck_assert_int_eq(prefix_len, 0);
SAFE_FREE(errstr);
@ -91,34 +81,30 @@ END_TEST
START_TEST (test_find_common_prefix_after)
{
char *test_str = "{slug}/foo";
R3Node * n = r3_tree_create(10);
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("{slug}/foo"), sizeof("{slug}/foo")-1, NULL);
r3_node_append_edge(n,e);
int prefix_len = 0;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
char *errstr = NULL;
errstr = NULL;
char *test_pref1 = "/foo";
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo", sizeof("/foo")-1, &prefix_len, &errstr);
ck_assert(ret_edge == NULL);
ck_assert_int_eq(prefix_len, 0);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref2 = "{slug}/bar";
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "{slug}/bar", sizeof("{slug}/bar")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 7);
SAFE_FREE(errstr);
errstr = NULL;
char *test_pref3 = "{slug}/foo";
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "{slug}/foo", sizeof("{slug}/foo")-1, &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 10);
SAFE_FREE(errstr);
@ -132,18 +118,16 @@ END_TEST
START_TEST (test_find_common_prefix_double_middle)
{
char *test_str = "{slug}/foo/{name}";
R3Node * n = r3_tree_create(10);
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("{slug}/foo/{name}"), sizeof("{slug}/foo/{name}")-1, NULL);
r3_node_append_edge(n,e);
int prefix_len;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
char *errstr;
errstr = NULL;
char *test_pref1 = "{slug}/foo/{number}";
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "{slug}/foo/{number}", sizeof("{slug}/foo/{number}")-1, &prefix_len, &errstr);
ck_assert(ret_edge);
ck_assert_int_eq(prefix_len, 11);
SAFE_FREE(errstr);
@ -156,25 +140,22 @@ END_TEST
START_TEST (test_find_common_prefix_middle)
{
R3Node * n = r3_tree_create(10);
char *test_str = "/foo/{slug}/hate";
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("/foo/{slug}/hate"), sizeof("/foo/{slug}/hate")-1, NULL);
r3_node_append_edge(n,e);
int prefix_len;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
char *errstr = NULL;
errstr = NULL;
char *test_str1 = "/foo/{slug}/bar";
ret_edge = r3_node_find_common_prefix(n, test_str1, strlen(test_str1), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/foo/{slug}/bar", sizeof("/foo/{slug}/bar")-1, &prefix_len, &errstr);
ck_assert(ret_edge);
ck_assert_int_eq(prefix_len, 12);
SAFE_FREE(errstr);
errstr = NULL;
char *test_str2 = "/fo/{slug}/bar";
ret_edge = r3_node_find_common_prefix(n, test_str2, strlen(test_str2), &prefix_len, &errstr);
ret_edge = r3_node_find_common_prefix(n, "/fo/{slug}/bar", sizeof("/fo/{slug}/bar")-1, &prefix_len, &errstr);
ck_assert(ret_edge);
ck_assert_int_eq(prefix_len, 3);
SAFE_FREE(errstr);
@ -185,13 +166,12 @@ END_TEST
START_TEST (test_find_common_prefix_same_pattern)
{
R3Node * n = r3_tree_create(10);
char *test_str = "/foo/{slug:xxx}/hate";
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("/foo/{slug:xxx}/hate"), sizeof("/foo/{slug:xxx}/hate")-1, NULL);
r3_node_append_edge(n,e);
int prefix_len;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
prefix_len = 0;
ret_edge = r3_node_find_common_prefix(n, "/foo/{slug:yyy}/hate", sizeof("/foo/{slug:yyy}/hate")-1, &prefix_len, NULL);
@ -210,13 +190,12 @@ END_TEST
START_TEST (test_find_common_prefix_same_pattern2)
{
R3Node * n = r3_tree_create(10);
char *test_str = "{slug:xxx}/hate";
R3Edge * e = r3_node_append_edge(n);
r3_edge_initl(e, test_str, strlen(test_str), NULL);
node * n = r3_tree_create(10);
edge * e = r3_edge_createl(zstrdup("{slug:xxx}/hate"), sizeof("{slug:xxx}/hate")-1, NULL);
r3_node_append_edge(n,e);
int prefix_len;
R3Edge *ret_edge = NULL;
edge *ret_edge = NULL;
prefix_len = 0;
ret_edge = r3_node_find_common_prefix(n, "{slug:yyy}/hate", sizeof("{slug:yyy}/hate")-1, &prefix_len, NULL);
@ -227,59 +206,7 @@ START_TEST (test_find_common_prefix_same_pattern2)
}
END_TEST
START_TEST (test_find_common_prefix_multi_edge)
{
R3Node * n = r3_tree_create(10);
char *test_str1 = "{id}/foo";
R3Edge * e1 = r3_node_append_edge(n);
r3_edge_initl(e1, test_str1, strlen(test_str1), NULL);
char *test_str2 = "{id2}/bar";
R3Edge * e2 = r3_node_append_edge(n);
r3_edge_initl(e2, test_str2, strlen(test_str2), NULL);
R3Edge *ret_edge = NULL;
int prefix_len = 0;
char *errstr = NULL;
char *test_pref1 = "{id}";
ret_edge = r3_node_find_common_prefix(n, test_pref1, strlen(test_pref1), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 4);
ck_assert(ret_edge == e1);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref2 = "{id}/foo";
ret_edge = r3_node_find_common_prefix(n, test_pref2, strlen(test_pref2), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 8);
ck_assert(ret_edge == e1);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref3 = "{id2}";
ret_edge = r3_node_find_common_prefix(n, test_pref3, strlen(test_pref3), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 5);
ck_assert(ret_edge == e2);
SAFE_FREE(errstr);
prefix_len = 0;
errstr = NULL;
char *test_pref4 = "{id2}/bar";
ret_edge = r3_node_find_common_prefix(n, test_pref4, strlen(test_pref4), &prefix_len, &errstr);
ck_assert(ret_edge != NULL);
ck_assert_int_eq(prefix_len, 9);
ck_assert(ret_edge == e2);
SAFE_FREE(errstr);
r3_tree_free(n);
}
END_TEST
@ -297,15 +224,15 @@ END_TEST
START_TEST (test_node_construct_and_free)
{
R3Node * n = r3_tree_create(10);
R3Node * another_tree = r3_tree_create(3);
node * n = r3_tree_create(10);
node * another_tree = r3_tree_create(3);
r3_tree_free(n);
r3_tree_free(another_tree);
}
END_TEST
static R3Node * create_simple_str_tree() {
R3Node * n;
static node * create_simple_str_tree() {
node * n;
n = r3_tree_create(10);
r3_tree_insert_path(n, "/zoo", NULL);
r3_tree_insert_path(n, "/foo", NULL);
@ -318,8 +245,8 @@ static R3Node * create_simple_str_tree() {
START_TEST (test_compile)
{
R3Node *n;
R3Node *m;
node *n;
node *m;
n = create_simple_str_tree();
@ -331,49 +258,41 @@ START_TEST (test_compile)
r3_tree_insert_path(n, "/{id}", NULL);
r3_tree_compile(n, NULL);
r3_tree_compile(n, NULL); // test double compile
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
match_entry * entry;
entry = match_entry_createl( "foo" , strlen("/foo") );
m = r3_tree_matchl( n , "/foo", strlen("/foo"), entry);
ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/zoo" , strlen("/zoo") );
m = r3_tree_matchl( n , "/zoo", strlen("/zoo"), entry);
ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/bar" , strlen("/bar") );
m = r3_tree_matchl( n , "/bar", strlen("/bar"), entry);
ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/xxx" , strlen("/xxx") );
m = r3_tree_matchl( n , "/xxx", strlen("/xxx"), entry);
ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/foo/xxx" , strlen("/foo/xxx") );
m = r3_tree_matchl( n , "/foo/xxx", strlen("/foo/xxx"), entry);
ck_assert( m );
match_entry_free(entry);
entry = match_entry_createl( "/some_id" , strlen("/some_id") );
m = r3_tree_matchl( n , "/some_id", strlen("/some_id"), entry);
ck_assert( m );
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST (test_incomplete_slug_path)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
R3Node * ret_node;
node * ret_node;
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
ret_node = r3_tree_insert_path(n, "/post/{handle", NULL);
@ -400,7 +319,7 @@ START_TEST (test_incomplete_slug_path)
ck_assert(ret_node);
// OK to insert, but should return error when compiling patterns
R3Node * ret_node2 = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy:aaa}", NULL);
node * ret_node2 = r3_tree_insert_path(n, "/users/{idx:\\d{3}}/{idy:aaa}", NULL);
ck_assert(ret_node2);
ck_assert(ret_node2 != ret_node); // make sure it's another node
@ -409,7 +328,7 @@ START_TEST (test_incomplete_slug_path)
r3_tree_compile(n, &errstr);
ck_assert(errstr == NULL); // no error
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
r3_tree_free(n);
}
@ -418,7 +337,7 @@ END_TEST
START_TEST (test_pcre_patterns_insert)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
// r3_tree_insert_path(n, "/foo-{user}-{id}", NULL, NULL);
r3_tree_insert_path(n, "/post/{handle:\\d+}-{id:\\d+}", NULL);
@ -433,7 +352,7 @@ START_TEST (test_pcre_patterns_insert)
// r3_tree_dump(n, 0);
R3Node *matched;
node *matched;
matched = r3_tree_match(n, "/post/foo", NULL);
@ -465,53 +384,12 @@ START_TEST (test_pcre_patterns_insert)
END_TEST
/**
* Test for root '/'
*/
START_TEST (test_root_match)
{
R3Node * n = r3_tree_create(10);
int a = 10;
int b = 20;
int c = 30;
r3_tree_insert_path(n, "/", &a);
r3_tree_insert_path(n, "/foo", &b);
r3_tree_insert_path(n, "/bar", &c);
char *errstr = NULL;
r3_tree_compile(n, &errstr);
// r3_tree_dump(n, 0);
R3Node *matched;
matched = r3_tree_match(n, "/", NULL);
ck_assert(matched);
ck_assert(matched->data == &a);
ck_assert(matched->endpoint > 0);
matched = r3_tree_match(n, "/foo", NULL);
ck_assert(matched);
ck_assert(matched->data == &b);
ck_assert(matched->endpoint > 0);
matched = r3_tree_match(n, "/bar", NULL);
ck_assert(matched);
ck_assert(matched->data == &c);
ck_assert(matched->endpoint > 0);
r3_tree_free(n);
}
END_TEST
/**
* Test for \d{2}/\d{2}
*/
START_TEST (test_pcre_patterns_insert_2)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy:\\d{2}}", NULL);
r3_tree_insert_path(n, "/zoo", NULL);
r3_tree_insert_path(n, "/foo", NULL);
@ -520,13 +398,11 @@ START_TEST (test_pcre_patterns_insert_2)
char *errstr = NULL;
r3_tree_compile(n, &errstr);
// r3_tree_dump(n, 0);
R3Node *matched;
r3_tree_dump(n, 0);
node *matched;
matched = r3_tree_match(n, "/post/11/22", NULL);
ck_assert(matched);
ck_assert((int)matched);
ck_assert(matched->endpoint > 0);
r3_tree_free(n);
}
END_TEST
@ -535,14 +411,14 @@ END_TEST
*/
START_TEST (test_pcre_patterns_insert_3)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
printf("Inserting /post/{idx:\\d{2}}/{idy}\n");
r3_tree_insert_path(n, "/post/{idx:\\d{2}}/{idy}", NULL);
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
printf("Inserting /zoo\n");
r3_tree_insert_path(n, "/zoo", NULL);
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
r3_tree_insert_path(n, "/foo", NULL);
r3_tree_insert_path(n, "/bar", NULL);
@ -550,12 +426,12 @@ START_TEST (test_pcre_patterns_insert_3)
char *errstr = NULL;
r3_tree_compile(n, &errstr);
// r3_tree_dump(n, 0);
R3Node *matched;
r3_tree_dump(n, 0);
node *matched;
matched = r3_tree_match(n, "/post/11/22", NULL);
ck_assert(matched);
ck_assert((int)matched);
matched = r3_tree_match(n, "/post/11", NULL);
ck_assert(!matched);
@ -567,8 +443,6 @@ START_TEST (test_pcre_patterns_insert_3)
matched = r3_tree_match(n, "/post/113", NULL);
ck_assert(!matched);
*/
r3_tree_free(n);
}
END_TEST
@ -576,12 +450,12 @@ END_TEST
START_TEST (test_insert_pathl_fail)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
R3Node * ret;
node * ret;
char *errstr = NULL;
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, &errstr);
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, NULL, &errstr);
ck_assert(ret == NULL);
ck_assert(errstr != NULL);
printf("%s\n", errstr); // Returns Incomplete slug pattern. PATTERN (16): '/foo/{name:\d{5}', OFFSET: 16, STATE: 1
@ -595,31 +469,14 @@ START_TEST (test_insert_pathl_fail)
}
END_TEST
START_TEST (test_insert_pathl_fail2)
{
R3Node * n = r3_tree_create(10);
char *errstr = NULL;
R3Node * ret;
ret = r3_tree_insert_pathl_ex(n, "/foo", strlen("/foo"), 0, 0, 0, NULL);
ck_assert(ret);
/* Insert an incomplete pattern without requesting an error string */
ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), 0, 0, 0, NULL);
ck_assert(ret == NULL);
r3_tree_compile(n, &errstr);
ck_assert(errstr == NULL);
r3_tree_free(n);
}
END_TEST
START_TEST (test_insert_pathl)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
R3Node * ret;
node * ret;
ret = r3_tree_insert_path(n, "/foo/bar", NULL);
ck_assert(ret);
@ -655,7 +512,8 @@ START_TEST (test_insert_pathl)
char * errstr = NULL;
r3_tree_compile(n, &errstr);
ck_assert(errstr == NULL);
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
r3_tree_free(n);
}
END_TEST
@ -664,9 +522,9 @@ END_TEST
START_TEST (test_compile_fail)
{
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
R3Node * ret;
node * ret;
ret = r3_tree_insert_path(n, "/foo/{idx}/{idy:)}", NULL);
ck_assert(ret);
@ -680,7 +538,7 @@ START_TEST (test_compile_fail)
fprintf(stderr, "Compile failed: %s\n", errstr);
free(errstr);
// r3_tree_dump(n, 0);
r3_tree_dump(n, 0);
r3_tree_free(n);
}
END_TEST
@ -709,9 +567,7 @@ END_TEST
START_TEST(test_route_cmp)
{
R3Node * n = r3_tree_create(10);
char *test_str = "/blog/post";
R3Route *r1 = r3_node_append_route(n,test_str, strlen(test_str),0,0);
route *r1 = r3_route_create("/blog/post");
match_entry * m = match_entry_create("/blog/post");
fail_if( r3_route_cmp(r1, m) == -1, "should match");
@ -728,8 +584,8 @@ START_TEST(test_route_cmp)
m->request_method = METHOD_POST | METHOD_GET;
fail_if( r3_route_cmp(r1, m) == -1, "should match");
r3_route_free(r1);
match_entry_free(m);
r3_tree_free(n);
}
END_TEST
@ -738,17 +594,16 @@ START_TEST(test_pcre_pattern_simple)
{
match_entry * entry;
entry = match_entry_createl( "/user/123" , strlen("/user/123") );
R3Node * n = r3_tree_create(10);
node * n = r3_tree_create(10);
r3_tree_insert_path(n, "/user/{id:\\d+}", NULL);
r3_tree_insert_path(n, "/user", NULL);
r3_tree_compile(n, NULL);
// r3_tree_dump(n, 0);
R3Node *matched;
node *matched;
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
ck_assert(matched);
ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
match_entry_free(entry);
ck_assert(entry->vars->len > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123");
r3_tree_free(n);
}
END_TEST
@ -757,9 +612,8 @@ END_TEST
START_TEST(test_pcre_pattern_more)
{
match_entry * entry;
entry = match_entry_create( "/user/123" );
entry->request_method = 0;
R3Node * n = r3_tree_create(10);
entry = match_entry_createl( "/user/123" , strlen("/user/123") );
node * n = r3_tree_create(10);
int var0 = 5;
int var1 = 100;
@ -776,54 +630,53 @@ START_TEST(test_pcre_pattern_more)
r3_tree_insert_path(n, "/user3/{id:\\d{3}}", &var3);
r3_tree_insert_path(n, "/user", &var0);
r3_tree_compile(n, NULL);
// r3_tree_dump(n, 0);
R3Node *matched;
r3_tree_dump(n, 0);
node *matched;
matched = r3_tree_match(n, "/user/123", entry);
matched = r3_tree_matchl(n, "/user/123", strlen("/user/123"), entry);
ck_assert(matched);
ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
ck_assert(entry->vars->len > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123");
info("matched %p\n", matched->data);
info("matched %p\n", matched->data);
ck_assert_int_eq( *((int*) matched->data), var1);
matched = r3_tree_matchl(n, "/user2/123", strlen("/user2/123"), entry);
ck_assert(matched);
ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
info("matched %p\n", matched->data);
ck_assert(entry->vars->len > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123");
ck_assert_int_eq( *((int*)matched->data), var2);
matched = r3_tree_matchl(n, "/user3/123", strlen("/user3/123"), entry);
ck_assert(matched);
ck_assert(entry->vars.tokens.size > 0);
ck_assert_str_eq(entry->vars.tokens.entries[0].base,"123");
info("matched %p\n", matched->data);
ck_assert(entry->vars->len > 0);
ck_assert_str_eq(entry->vars->tokens[0],"123");
ck_assert_int_eq( *((int*)matched->data), var3);
match_entry_free(entry);
r3_tree_free(n);
}
END_TEST
START_TEST(test_insert_pathl_before_root)
START_TEST(test_ip_cmp)
{
char *errstr = NULL;
int var1 = 22;
int var2 = 33;
int var3 = 44;
R3Node * n = r3_tree_create(3);
r3_tree_insert_pathl_ex(n, STR("/blog/post"), 0, 0, &var1, NULL);
r3_tree_insert_pathl_ex(n, STR("/blog"), 0, 0, &var2, NULL);
r3_tree_insert_pathl_ex(n, STR("/"), 0, 0, &var3, NULL);
ck_assert(r3_ip_cmp("127.0.0.1","127.0.0.1"));
ck_assert(!r3_ip_cmp("127.0.0.1","220.12.12.12"));
}
END_TEST
errstr = NULL;
r3_tree_compile(n, &errstr);
r3_tree_dump(n, 0);
r3_tree_free(n);
START_TEST(test_ip_mask_cmp)
{
ck_assert( r3_ip_mask_cmp("127.123.123.123" , "127.0.0.1" , "255.0.0.0" ));
ck_assert( r3_ip_mask_cmp("192.168.123.123" , "192.168.0.1" , "255.0.0.0" ));
ck_assert( r3_ip_mask_cmp("192.168.123.123" , "192.168.0.1" , "255.255.0.0" ));
ck_assert( r3_ip_mask_cmp("192.168.123.123" , "192.168.123.1" , "255.255.255.0" ));
ck_assert(!r3_ip_mask_cmp("127.123.123.123" , "127.0.0.1", "255.255.0.0" ));
ck_assert(!r3_ip_mask_cmp("127.123.123.123" , "127.0.0.1", "255.255.255.0" ));
}
END_TEST
@ -834,12 +687,12 @@ START_TEST(test_insert_route)
int var2 = 33;
R3Node * n = r3_tree_create(2);
node * n = r3_tree_create(2);
r3_tree_insert_route(n, METHOD_GET, "/blog/post", &var1);
r3_tree_insert_route(n, METHOD_POST, "/blog/post", &var2);
match_entry * entry;
R3Route *r;
route *r;
entry = match_entry_create("/blog/post");
entry->request_method = METHOD_GET;
@ -864,41 +717,33 @@ START_TEST(test_insert_route)
}
END_TEST
Suite* r3_suite (void) {
Suite *suite = suite_create("r3 core tests");
TCase *tcase = tcase_create("common_prefix_testcase");
TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_find_common_prefix);
tcase_add_test(tcase, test_find_common_prefix_after);
tcase_add_test(tcase, test_find_common_prefix_double_middle);
tcase_add_test(tcase, test_find_common_prefix_middle);
tcase_add_test(tcase, test_find_common_prefix_same_pattern);
tcase_add_test(tcase, test_find_common_prefix_same_pattern2);
tcase_add_test(tcase, test_find_common_prefix_multi_edge);
suite_add_tcase(suite, tcase);
tcase = tcase_create("insert_testcase");
tcase_add_test(tcase, test_insert_pathl);
tcase_add_test(tcase, test_insert_pathl_fail);
tcase_add_test(tcase, test_insert_pathl_fail2);
tcase_add_test(tcase, test_node_construct_and_free);
suite_add_tcase(suite, tcase);
tcase = tcase_create("compile_testcase");
tcase_add_test(tcase, test_compile);
tcase_add_test(tcase, test_compile_fail);
tcase_add_test(tcase, test_route_cmp);
tcase_add_test(tcase, test_insert_route);
tcase_add_test(tcase, test_insert_pathl_before_root);
suite_add_tcase(suite, tcase);
tcase = tcase_create("pcre_pattern_testcase");
tcase_add_test(tcase, test_pcre_pattern_simple);
tcase_add_test(tcase, test_pcre_pattern_more);
tcase_add_test(tcase, test_pcre_patterns_insert);
tcase_add_test(tcase, test_pcre_patterns_insert_2);
tcase_add_test(tcase, test_root_match);
tcase_add_test(tcase, test_pcre_patterns_insert_3);
tcase_add_test(tcase, test_incomplete_slug_path);
tcase_add_test(tcase, test_ip_cmp);
tcase_add_test(tcase, test_ip_mask_cmp);
suite_add_tcase(suite, tcase);
return suite;