extended glob matcher with brzozowski derivative (#111)
This commit is contained in:
parent
0c9c76599d
commit
4d6d741357
17 changed files with 1228 additions and 390 deletions
|
@ -18,8 +18,6 @@ if (I18N AND GETTEXT_FOUND AND LIBINTL_LIB_FOUND)
|
|||
set (ENABLE_NLS 1)
|
||||
endif ()
|
||||
|
||||
cr_find_package (PCRE PKGCONFIG libpcre)
|
||||
|
||||
# Check for functions
|
||||
|
||||
check_function_exists(strtok_s HAVE_STRTOK_S)
|
||||
|
|
|
@ -30,10 +30,6 @@ set(ENV{CRITERION_NO_EARLY_EXIT} "1")
|
|||
set(ENV{CRITERION_JOBS} "1")
|
||||
set(ENV{CRITERION_DISABLE_TIME_MEASUREMENTS} "1")
|
||||
|
||||
if (NOT ENABLE_PATTERN_TESTS)
|
||||
set(ENV{CRITERION_TESTS_PATTERN} "off")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
if (ENV{MINGW} STREQUAL "")
|
||||
set (MINGW_HOME "C:/MinGW")
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
# Copyright (C) 2007-2009 LuaDist.
|
||||
# Created by Peter Kapec <kapecp@gmail.com>
|
||||
# Redistribution and use of this file is allowed according to the terms of the MIT license.
|
||||
# For details see the COPYRIGHT file distributed with LuaDist.
|
||||
# Note:
|
||||
# Searching headers and libraries is very simple and is NOT as powerful as scripts
|
||||
# distributed with CMake, because LuaDist defines directories to search for.
|
||||
# Everyone is encouraged to contact the author with improvements. Maybe this file
|
||||
# becomes part of CMake distribution sometimes.
|
||||
|
||||
# - Find pcre
|
||||
# Find the native PCRE headers and libraries.
|
||||
#
|
||||
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
|
||||
# PCRE_LIBRARIES - List of libraries when using pcre.
|
||||
# PCRE_FOUND - True if pcre found.
|
||||
|
||||
# Look for the header file.
|
||||
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
|
||||
|
||||
# Look for the library.
|
||||
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
|
||||
|
||||
# Copy the results to the output variables.
|
||||
IF(PCRE_FOUND)
|
||||
SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
|
||||
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
|
||||
ELSE(PCRE_FOUND)
|
||||
SET(PCRE_LIBRARIES)
|
||||
SET(PCRE_INCLUDE_DIRS)
|
||||
ENDIF(PCRE_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)
|
|
@ -79,7 +79,7 @@ macro (cr_find_package _PKG)
|
|||
|
||||
if (${_PKG_UP}_PKG_FOUND)
|
||||
if (${_PKG_UP}_PKG_LIBRARY_DIRS)
|
||||
link_directories(${PCRE_PKG_LIBRARY_DIRS})
|
||||
link_directories(${${_PKG_UP}_PKG_LIBRARY_DIRS})
|
||||
endif ()
|
||||
set (${_PKG_UP}_LIBRARIES ${${_PKG_UP}_PKG_LIBRARIES})
|
||||
set (${_PKG_UP}_INCLUDE_DIRS ${${_PKG_UP}_PKG_INCLUDE_DIRS})
|
||||
|
|
|
@ -97,7 +97,6 @@ cr_link_libraries(criterion rt IF HAVE_CLOCK_GETTIME)
|
|||
cr_link_libraries(criterion anl IF HAVE_GETADDRINFO_A)
|
||||
cr_link_libraries(criterion ws2_32 mswsock IF WIN32)
|
||||
|
||||
cr_link_package(criterion PCRE)
|
||||
cr_link_package(criterion LIBINTL)
|
||||
|
||||
if (COVERALLS)
|
||||
|
|
|
@ -43,7 +43,6 @@ Shell Wildcard Pattern
|
|||
----------------------
|
||||
|
||||
Extglob patterns in criterion are matched against a test's string identifier.
|
||||
This feature is only available on \*nix systems where ``PCRE`` is provided.
|
||||
|
||||
In the table below, a ``pattern-list`` is a list of patterns separated by ``|``.
|
||||
Any extglob pattern can be constructed by combining any of the following
|
||||
|
|
|
@ -57,11 +57,9 @@ set(SCRIPTS
|
|||
list
|
||||
fail_fast
|
||||
help
|
||||
pattern
|
||||
)
|
||||
|
||||
if (HAVE_PCRE)
|
||||
set(SCRIPTS ${SCRIPTS} pattern)
|
||||
endif ()
|
||||
|
||||
add_custom_target(criterion_samples)
|
||||
add_dependencies(criterion_tests criterion_samples)
|
||||
|
|
|
@ -69,6 +69,10 @@ set(SOURCE_FILES
|
|||
src/protocol/connect.h
|
||||
src/common.h
|
||||
src/config.h
|
||||
src/string/extglobmatch.c
|
||||
src/string/extglobmatch.h
|
||||
src/string/brz.c
|
||||
src/string/brz.h
|
||||
|
||||
dependencies/nanopb/pb_common.c
|
||||
dependencies/nanopb/pb_common.h
|
||||
|
@ -84,12 +88,6 @@ if (THEORIES)
|
|||
)
|
||||
endif ()
|
||||
|
||||
if (PCRE_FOUND)
|
||||
set (SOURCE_FILES ${SOURCE_FILES}
|
||||
src/string/extmatch.c
|
||||
src/string/extmatch.h
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(INTERFACE_FILES
|
||||
include/criterion/assert.h
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# define CONFIG_H_IN_
|
||||
|
||||
#cmakedefine ENABLE_NLS @ENABLE_NLS@
|
||||
#cmakedefine HAVE_PCRE @HAVE_PCRE@
|
||||
#cmakedefine ENABLE_VALGRIND_ERRORS @ENABLE_VALGRIND_ERRORS@
|
||||
#cmakedefine MINGW_DEFINE_OFF_T @MINGW_DEFINE_OFF_T@
|
||||
#cmakedefine01 HAVE_STRTOK_S
|
||||
|
|
|
@ -54,9 +54,7 @@
|
|||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef HAVE_PCRE
|
||||
#include "string/extmatch.h"
|
||||
#endif
|
||||
#include "string/extglobmatch.h"
|
||||
|
||||
typedef const char *const msg_t;
|
||||
|
||||
|
@ -226,25 +224,23 @@ void run_test_child(struct criterion_test *test,
|
|||
|
||||
s_pipe_handle *g_worker_pipe;
|
||||
|
||||
#ifdef HAVE_PCRE
|
||||
void disable_unmatching(struct criterion_test_set *set) {
|
||||
if (!compile_pattern(criterion_options.pattern)) {
|
||||
exit(3);
|
||||
}
|
||||
FOREACH_SET(struct criterion_suite_set *s, set->suites) {
|
||||
if ((s->suite.data && s->suite.data->disabled) || !s->tests)
|
||||
continue;
|
||||
|
||||
FOREACH_SET(struct criterion_test *test, s->tests) {
|
||||
const char *errmsg;
|
||||
int ret = extmatch(criterion_options.pattern, test->data->identifier_, &errmsg);
|
||||
if (ret == -10) {
|
||||
printf("pattern error: %s\n", errmsg);
|
||||
exit(1);
|
||||
} else if (ret < 0) {
|
||||
int ret = match(test->data->identifier_);
|
||||
if (ret == 0) {
|
||||
test->data->disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
free_pattern();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct criterion_test_set *criterion_initialize(void) {
|
||||
init_i18n();
|
||||
|
@ -420,11 +416,7 @@ cleanup:
|
|||
|
||||
int criterion_run_all_tests(struct criterion_test_set *set) {
|
||||
if (criterion_options.pattern) {
|
||||
#ifdef HAVE_PCRE
|
||||
disable_unmatching(set);
|
||||
#else
|
||||
criterion_perror("Did not filter tests by pattern: Criterion was compiled without extglob support.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
set_runner_process();
|
||||
|
|
700
src/string/brz.c
Normal file
700
src/string/brz.c
Normal file
|
@ -0,0 +1,700 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 George Spelvim <linux@horizon.com>
|
||||
* Copyright (c) 2016 Matthias "ailu" Günzel <a1lu@arcor.de>
|
||||
*
|
||||
* 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 "brz.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define copy_glob(g) (g)->copy(g)
|
||||
#define derive_glob(g, chr) (g)->derive(g,chr)
|
||||
|
||||
static int matches(glob const *self, char const *string);
|
||||
|
||||
static int is_true(glob const *self);
|
||||
static int is_false(glob const *self);
|
||||
static int nullable_char(glob const* self);
|
||||
static int nullable_or(glob const* self);
|
||||
static int nullable_seq(glob const* self);
|
||||
static int nullable_first(glob const* self);
|
||||
static int nullable_not(glob const* self);
|
||||
|
||||
static glob *derive_empty(glob const *self, char const chr);
|
||||
static glob *derive_blank(glob const *self, char const chr);
|
||||
static glob *derive_char(glob const *self, char const chr);
|
||||
static glob *derive_cset(glob const *self, char const chr);
|
||||
static glob *derive_or(glob const *self, char const chr);
|
||||
static glob *derive_seq(glob const *self, char const chr);
|
||||
static glob *derive_plus(glob const *self, char const chr);
|
||||
static glob *derive_at(glob const *self, char const chr);
|
||||
static glob *derive_not(glob const *self, char const chr);
|
||||
static glob *derive_and(glob const *self, char const chr);
|
||||
|
||||
static glob *copy_zero(glob const *cpy);
|
||||
static glob *copy_one(glob const *cpy);
|
||||
static glob *copy_two(glob const *cpy);
|
||||
|
||||
#ifdef _DEBUG_BRZ_
|
||||
#define print_glob_v(g) do{printf(#g" "); (g)->print(g),puts("");}while(0)
|
||||
#define print_glob(g) do{(g)->print(g);}while(0)
|
||||
static void print_empty(glob const *self);
|
||||
static void print_blank(glob const *self);
|
||||
static void print_char(glob const *self);
|
||||
static void print_cset(glob const *self);
|
||||
static void print_or(glob const *self);
|
||||
static void print_and(glob const *self);
|
||||
static void print_star(glob const *self);
|
||||
static void print_plus(glob const *self);
|
||||
static void print_at(glob const *self);
|
||||
static void print_opt(glob const *self);
|
||||
static void print_seq(glob const *self);
|
||||
static void print_not(glob const *self);
|
||||
#endif
|
||||
|
||||
void free_glob(glob *tmp) {
|
||||
glob* first = (glob*)tmp->first;
|
||||
glob* second = (glob*)tmp->second;
|
||||
if (tmp->type != CHAR && tmp->type != CHARSET && first) {
|
||||
free_glob(first);
|
||||
} else if (tmp->type == CHARSET) {
|
||||
free(tmp->cset);
|
||||
}
|
||||
if (second) {
|
||||
free_glob(second);
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
|
||||
static glob *new_glob() {
|
||||
glob* tmp = malloc(sizeof(glob));
|
||||
if (tmp) {
|
||||
tmp->derive = NULL;
|
||||
tmp->nullable = NULL;
|
||||
tmp->first = NULL;
|
||||
tmp->second = NULL;
|
||||
tmp->matches = matches;
|
||||
tmp->type = 0;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Could not allocate glob object.\n");
|
||||
exit(1);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static int matches(glob const *self, char const *string) {
|
||||
if (strlen(string) == 0) {
|
||||
return self->nullable(self);
|
||||
} else {
|
||||
int ret;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
printf("\nstring: ");
|
||||
puts(string);
|
||||
#endif
|
||||
glob *tmp = derive_glob(self, *string);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
print_glob_v(tmp);
|
||||
#endif
|
||||
ret = tmp->matches(tmp,++string);
|
||||
free_glob(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty Set
|
||||
* not nullable
|
||||
* no derivative
|
||||
*/
|
||||
glob *glob_empty() {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = EMPTY;
|
||||
tmp->nullable = is_false;
|
||||
tmp->derive = derive_empty;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_empty;
|
||||
#endif
|
||||
tmp->copy = copy_zero;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty string
|
||||
* is nullable
|
||||
* derivative is Empty set
|
||||
*/
|
||||
glob *glob_blank() {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = BLANK;;
|
||||
tmp->nullable = is_true;
|
||||
tmp->derive = derive_blank;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_blank;
|
||||
#endif
|
||||
tmp->copy = copy_zero;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* single chacacter
|
||||
* nullable for ? and *
|
||||
* derivative: Empty string if chr == c
|
||||
* Empty set otherwise
|
||||
*/
|
||||
glob *glob_char(char const c) {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = CHAR;
|
||||
tmp->nullable = nullable_char;
|
||||
tmp->derive = derive_char;
|
||||
tmp->c = c;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_char;
|
||||
#endif
|
||||
tmp->copy = copy_zero;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* single character
|
||||
* not nullable
|
||||
* derivative: Empty string if chr in [..] or not in [!..]
|
||||
* Empty set otherwise
|
||||
*/
|
||||
glob *glob_cset(char *cset) {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = CHARSET;
|
||||
tmp->nullable = is_false;
|
||||
tmp->derive = derive_cset;
|
||||
tmp->cset = strdup(cset);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_cset;
|
||||
#endif
|
||||
tmp->copy = copy_one;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Choice: E | F
|
||||
* nullable: nullable (E) | nullable(F)
|
||||
* derivative: der(E) | der(F)
|
||||
*
|
||||
* Optimization:
|
||||
* (1) E | Empty -> E
|
||||
*/
|
||||
glob *glob_or(glob const *first, glob const *second) {
|
||||
if (first->type == EMPTY){
|
||||
return copy_glob(second);
|
||||
} else if (second->type == EMPTY) {
|
||||
return copy_glob(first);
|
||||
} else {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = OR;
|
||||
tmp->nullable = nullable_or;
|
||||
tmp->derive = derive_or;
|
||||
|
||||
tmp->first = copy_glob(first);
|
||||
tmp->second = copy_glob(second);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_or;
|
||||
#endif
|
||||
tmp->copy = copy_two;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Intersection: E & F
|
||||
* nullable: nullable (E) & nullable(F)
|
||||
* derivative: der(E) & der(F)
|
||||
*
|
||||
* Optimization:
|
||||
* (1) E & Empty -> Empty
|
||||
*/
|
||||
glob *glob_and(glob const *first, glob const *second) {
|
||||
if (first->type == EMPTY || second->type == EMPTY) {
|
||||
return glob_empty();
|
||||
} else {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = AND;
|
||||
tmp->nullable = nullable_seq;
|
||||
tmp->derive = derive_and;
|
||||
|
||||
tmp->first = copy_glob(first);
|
||||
tmp->second = copy_glob(second);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_and;
|
||||
#endif
|
||||
tmp->copy = copy_two;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
glob *glob_star(glob const *pattern) {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = STAR;
|
||||
tmp->nullable = is_true;
|
||||
tmp->derive = derive_plus;
|
||||
|
||||
tmp->first = copy_glob(pattern);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_star;
|
||||
#endif
|
||||
tmp->copy = copy_one;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Repetition one or more
|
||||
* +(pat)
|
||||
* nullable: nullable(pat)
|
||||
* derivative: der(pat) Star(pat)
|
||||
*
|
||||
*/
|
||||
glob *glob_plus(glob const *pattern) {
|
||||
glob *tmp = glob_star(pattern);
|
||||
tmp->type = PLUS;
|
||||
tmp->nullable = nullable_first;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_plus;
|
||||
#endif
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Repetition one time
|
||||
* @(pat)
|
||||
* nullable: nullable(pat)
|
||||
* derivative: der(pat)
|
||||
*
|
||||
*/
|
||||
glob *glob_at(glob const *pattern) {
|
||||
if (pattern->type == EMPTY) {
|
||||
return glob_empty();
|
||||
} else if (pattern->type == BLANK) {
|
||||
return glob_blank();
|
||||
} else {
|
||||
glob *tmp = glob_opt(pattern);
|
||||
tmp->type = AT;
|
||||
tmp->nullable = nullable_first;
|
||||
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_at;
|
||||
#endif
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Repetition one or zero
|
||||
* ?(pat)
|
||||
* nullable: true
|
||||
* derivative: der(pat)
|
||||
*
|
||||
*/
|
||||
glob *glob_opt(glob const *pattern) {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = OPT;
|
||||
tmp->nullable = is_true;
|
||||
tmp->derive = derive_at;
|
||||
|
||||
tmp->first = copy_glob(pattern);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_opt;
|
||||
#endif
|
||||
tmp->copy = copy_one;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not the pattern
|
||||
* !(pat)
|
||||
* nullable: not nullable(pat)
|
||||
* derivative: not der(pat)
|
||||
*
|
||||
*/
|
||||
glob *glob_not(glob const *pattern) {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = NOT;
|
||||
tmp->nullable = nullable_not;
|
||||
tmp->derive = derive_not;
|
||||
|
||||
tmp->first = copy_glob(pattern);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_not;
|
||||
#endif
|
||||
tmp->copy = copy_one;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sequence E F
|
||||
* nullable: nullable(E) nullable(F)
|
||||
* derivative: nullable(E): Or( Seq(der(E), F), der(F) )
|
||||
* else: Seq( der(E), F )
|
||||
* Optimization:
|
||||
* (1) Empty E -> Empty
|
||||
* (2) E Empty -> Empty
|
||||
* (3) Blank E -> E
|
||||
*/
|
||||
glob *glob_seq(glob const *first, glob const *second) {
|
||||
if (first->type == EMPTY || second->type == EMPTY) {
|
||||
return glob_empty();
|
||||
}else if(first->type == BLANK) {
|
||||
return copy_glob(second);
|
||||
} else {
|
||||
glob *tmp = new_glob();
|
||||
tmp->type = SEQ;
|
||||
tmp->nullable = nullable_seq;
|
||||
tmp->derive = derive_seq;
|
||||
|
||||
tmp->first = copy_glob(first);
|
||||
tmp->second = copy_glob(second);
|
||||
#ifdef _DEBUG_BRZ_
|
||||
tmp->print = print_seq;
|
||||
#endif
|
||||
tmp->copy = copy_two;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int is_false(glob const *self) {
|
||||
(void)(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_true(glob const *self) {
|
||||
(void)(self);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nullable_char(glob const* self) {
|
||||
if (self->c == '?' || self->c == '*') {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int nullable_or(glob const* self) {
|
||||
glob const *first, *second;
|
||||
first = self->first;
|
||||
second = self->second;
|
||||
return first->nullable(first) || second->nullable(second);
|
||||
}
|
||||
|
||||
static int nullable_seq(glob const* self) {
|
||||
glob const *first, *second;
|
||||
first = self->first;
|
||||
second = self->second;
|
||||
return first->nullable(first) && second->nullable(second);
|
||||
}
|
||||
|
||||
static int nullable_first(glob const* self) {
|
||||
glob const *first;
|
||||
first = self->first;
|
||||
return first->nullable(first);
|
||||
}
|
||||
|
||||
static int nullable_not(glob const* self) {
|
||||
return !nullable_first(self);
|
||||
}
|
||||
|
||||
static glob *derive_empty(glob const *self, char const chr) {
|
||||
(void)(chr);
|
||||
(void)(self);
|
||||
return glob_empty();
|
||||
}
|
||||
|
||||
static glob *derive_blank(glob const *self, char const chr) {
|
||||
(void)(self);
|
||||
(void)(chr);
|
||||
return glob_empty();
|
||||
}
|
||||
|
||||
static glob *derive_char(glob const *self, char const chr)
|
||||
{
|
||||
if (self->c == chr || self->c == '?') {
|
||||
return glob_blank();
|
||||
} else if (self->c == '*') {
|
||||
glob *ret = self->copy(self);
|
||||
return ret;
|
||||
}
|
||||
return glob_empty();
|
||||
}
|
||||
|
||||
|
||||
static glob *derive_cset(glob const *self, char const chr) {
|
||||
/* Character class */
|
||||
char *pat = self->cset;
|
||||
int match = 0, inverted = (*pat == '!');
|
||||
char const *class = pat + inverted;
|
||||
unsigned char a = *class++;
|
||||
/*
|
||||
* Iterate over each span in the character class.
|
||||
* A span is either a single character a, or a
|
||||
* range a-b. The first span may begin with ']'.
|
||||
*/
|
||||
do {
|
||||
unsigned char b = a;
|
||||
|
||||
if (a == '\0') /* Malformed */
|
||||
return glob_empty();
|
||||
|
||||
if (class[0] == '-' && class[1] != ']') {
|
||||
b = class[1];
|
||||
|
||||
if (b == '\0') /* malformed */
|
||||
return glob_empty();
|
||||
|
||||
class += 2;
|
||||
}
|
||||
if (a > b) {
|
||||
unsigned char tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
match |= (a <= chr && chr <= b);
|
||||
} while ((a = *class++) && !match);
|
||||
|
||||
if (match == inverted)
|
||||
return glob_empty();
|
||||
else
|
||||
return glob_blank();
|
||||
}
|
||||
|
||||
static glob *derive_and(glob const *self, char const chr) {
|
||||
glob const *first, *second;
|
||||
first = self->first;
|
||||
second = self->second;
|
||||
glob *d1 = derive_glob(first, chr);
|
||||
glob *d2 = derive_glob(second, chr);
|
||||
glob* ret;
|
||||
ret = glob_and(d1, d2);
|
||||
free_glob(d1);
|
||||
free_glob(d2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static glob *derive_or(glob const *self, char const chr) {
|
||||
glob const *first, *second;
|
||||
first = self->first;
|
||||
second = self->second;
|
||||
glob *d1 = derive_glob(first, chr);
|
||||
glob *d2 = derive_glob(second, chr);
|
||||
glob* ret = glob_or(d1, d2);
|
||||
free_glob(d1);
|
||||
free_glob(d2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static glob *derive_plus(glob const *self, char const chr) {
|
||||
glob *ret;
|
||||
glob const *pat;
|
||||
pat = self->pattern;
|
||||
glob *d = derive_glob(pat, chr);
|
||||
glob *s = glob_star(pat);
|
||||
|
||||
ret = glob_seq(d, s);
|
||||
free_glob(s);
|
||||
free_glob(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static glob *derive_seq(glob const *self, char const chr) {
|
||||
glob *ret;
|
||||
glob const *first, *second;
|
||||
first = self->first;
|
||||
second = self->second;
|
||||
if (first->nullable(first)) { // A nullable -> Or( Seq(d1, sec), d2)
|
||||
glob *d1 = derive_glob(first, chr);
|
||||
glob *d2 = derive_glob(second, chr);
|
||||
glob *s = glob_seq(d1, second);
|
||||
ret = glob_or(s, d2);
|
||||
free_glob(s);
|
||||
free_glob(d1);
|
||||
free_glob(d2);
|
||||
} else { // A not nullable
|
||||
glob *derive = derive_glob(first, chr);
|
||||
ret = glob_seq(derive, second);
|
||||
free_glob(derive);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static glob *derive_at(glob const *self, char const chr) {
|
||||
glob const *pat;
|
||||
pat = self->pattern;
|
||||
glob *d = derive_glob(pat, chr);
|
||||
glob *ret;
|
||||
ret = glob_at(d);
|
||||
free_glob(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static glob *derive_not(glob const *self, char const chr) {
|
||||
glob const *pat;
|
||||
pat = self->pattern;
|
||||
glob *d = derive_glob(pat, chr);
|
||||
glob *ret = glob_not(d);
|
||||
free_glob(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static glob *copy_zero(glob const *cpy) {
|
||||
glob *tmp = new_glob();
|
||||
*tmp = *cpy;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static glob *copy_one(glob const *cpy) {
|
||||
glob const *first = cpy->first;
|
||||
glob *tmp = new_glob();
|
||||
*tmp = *cpy;
|
||||
if (cpy->type != CHARSET) {
|
||||
tmp->first = copy_glob(first);
|
||||
} else {
|
||||
tmp->cset = strdup(cpy->cset);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static glob *copy_two(glob const *cpy)
|
||||
{
|
||||
glob const *first = cpy->first;
|
||||
glob const *sec = cpy->second;
|
||||
glob *tmp = new_glob();
|
||||
*tmp = *cpy;
|
||||
tmp->first = copy_glob(first);
|
||||
tmp->second = copy_glob(sec);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG_BRZ_
|
||||
|
||||
static void print_empty(glob const *self)
|
||||
{
|
||||
(void)(self);
|
||||
printf("Empty");
|
||||
}
|
||||
|
||||
static void print_blank(glob const *self)
|
||||
{
|
||||
(void)(self);
|
||||
printf("Blank");
|
||||
}
|
||||
static void print_char(glob const *self)
|
||||
{
|
||||
printf("%c",self->c);
|
||||
}
|
||||
|
||||
static void print_cset(glob const *self)
|
||||
{
|
||||
printf("[%s]",self->cset);
|
||||
}
|
||||
|
||||
static void print_or(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
glob const *sec = self->second;
|
||||
printf("(");
|
||||
print_glob(first);
|
||||
printf(" | ");
|
||||
print_glob(sec);
|
||||
printf(")");
|
||||
}
|
||||
static void print_and(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
glob const *sec = self->second;
|
||||
printf("(");
|
||||
print_glob(first);
|
||||
printf(" & ");
|
||||
print_glob(sec);
|
||||
printf(")");
|
||||
}
|
||||
|
||||
static void print_seq(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
glob const *sec = self->second;
|
||||
print_glob(first);
|
||||
printf(" . ");
|
||||
print_glob(sec);
|
||||
}
|
||||
|
||||
static void print_star(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
printf("*(");
|
||||
print_glob(first);
|
||||
printf(")");
|
||||
}
|
||||
static void print_plus(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
printf("+(");
|
||||
print_glob(first);
|
||||
printf(")");
|
||||
}
|
||||
static void print_at(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
printf("@(");
|
||||
print_glob(first);
|
||||
printf(")");
|
||||
}
|
||||
static void print_opt(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
printf("?(");
|
||||
print_glob(first);
|
||||
printf(")");
|
||||
}
|
||||
static void print_not(glob const *self)
|
||||
{
|
||||
glob const *first = self->first;
|
||||
printf("!(");
|
||||
print_glob(first);
|
||||
printf(")");
|
||||
}
|
||||
|
||||
#endif
|
68
src/string/brz.h
Normal file
68
src/string/brz.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Matthias "ailu" Günzel <a1lu@arcor.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
struct stc_glob;
|
||||
|
||||
typedef int (*match_func)(struct stc_glob const *self, char const *string);
|
||||
typedef struct stc_glob *(*derive_func)(struct stc_glob const *self, char const chr);
|
||||
typedef int (*nullable_func)(struct stc_glob const *self);
|
||||
typedef struct stc_glob *(*copy_func)(struct stc_glob const *cpy);
|
||||
typedef void (*printFunc)(struct stc_glob const *self);
|
||||
|
||||
typedef enum
|
||||
{EMPTY = 0, BLANK, CHAR, CHARSET, OR, AND, STAR, PLUS, AT, OPT, SEQ, NOT}glob_type;
|
||||
|
||||
typedef struct stc_glob {
|
||||
glob_type type;
|
||||
match_func matches;
|
||||
derive_func derive;
|
||||
nullable_func nullable;
|
||||
copy_func copy;
|
||||
#ifdef _DEBUG_BRZ_
|
||||
printFunc print;
|
||||
#endif
|
||||
union {
|
||||
char c;
|
||||
char *cset;
|
||||
struct stc_glob const *first;
|
||||
struct stc_glob const *pattern;
|
||||
};
|
||||
union {
|
||||
struct stc_glob const *second;
|
||||
};
|
||||
}glob;
|
||||
|
||||
void free_glob(glob *tmp);
|
||||
|
||||
glob *glob_empty();
|
||||
glob *glob_blank();
|
||||
glob *glob_char(char c);
|
||||
glob *glob_cset(char* c);
|
||||
glob *glob_or(glob const *first, glob const *second);
|
||||
glob *glob_and(glob const *first, glob const *second);
|
||||
glob *glob_star(glob const *pattern);
|
||||
glob *glob_plus(glob const *pattern);
|
||||
glob *glob_at(glob const *pattern);
|
||||
glob *glob_opt(glob const *pattern);
|
||||
glob *glob_not(glob const *pattern);
|
||||
glob *glob_seq(glob const *first, glob const *second);
|
268
src/string/extglobmatch.c
Normal file
268
src/string/extglobmatch.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2007 Russ Cox.
|
||||
* Copyright (c) 2016 Matthias "ailu" Günzel <a1lu@arcor.de>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "extglobmatch.h"
|
||||
#include "brz.h"
|
||||
|
||||
#define cat_one() do{ \
|
||||
if (atoms > 1) { \
|
||||
--atoms; \
|
||||
glob *b = *--frag; \
|
||||
glob *a = *--frag; \
|
||||
*frag++ = glob_seq(a,b); \
|
||||
free_glob(a); \
|
||||
free_glob(b); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define cat_all() do{ \
|
||||
while (--atoms > 0) { \
|
||||
glob *b = *--frag; \
|
||||
glob *a = *--frag; \
|
||||
*frag++ = glob_seq(a,b); \
|
||||
free_glob(a); \
|
||||
free_glob(b); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
static glob* match_glob = NULL;
|
||||
|
||||
static void cleanup(glob **start, glob **end) {
|
||||
while (start != end)
|
||||
{
|
||||
free_glob(*start);
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_error(char const c) {
|
||||
fprintf(stderr, "pattern error: Unexpected character '%c'\n", c);
|
||||
}
|
||||
|
||||
static glob* handle_operator(char op, glob const* g)
|
||||
{
|
||||
glob* tmp = NULL;
|
||||
switch (op) {
|
||||
case '!': tmp = glob_not(g);
|
||||
break;
|
||||
case '*': tmp = glob_star(g);
|
||||
break;
|
||||
case '+': tmp = glob_plus(g);
|
||||
break;
|
||||
case '@': tmp = glob_at(g);
|
||||
break;
|
||||
case '?': tmp = glob_opt(g);
|
||||
break;
|
||||
}
|
||||
assert(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#define push_frag(f) *frag++ = f
|
||||
#define pop_frag() *--frag
|
||||
#define ARRAY_SIZE 100
|
||||
|
||||
static glob *compile(char const *pat) {
|
||||
glob *frags[ARRAY_SIZE]={0};
|
||||
glob **frag=frags;
|
||||
struct paren {
|
||||
int alter;
|
||||
int atoms;
|
||||
char op;
|
||||
} paren[ARRAY_SIZE], *pa;
|
||||
|
||||
int alter = 0;
|
||||
int atoms = 0;
|
||||
pa = paren;
|
||||
|
||||
assert(pat);
|
||||
|
||||
for (;;) {
|
||||
unsigned char p = *pat++;
|
||||
if(!p)
|
||||
break;
|
||||
switch(p) {
|
||||
case '!':
|
||||
case '?':
|
||||
case '@':
|
||||
case '*':
|
||||
case '+':
|
||||
if (*pat != '(')
|
||||
goto character;
|
||||
if (pa >= paren + ARRAY_SIZE) {
|
||||
fprintf(stderr,"pattern error: to many nested globs.\n");
|
||||
goto error;
|
||||
}
|
||||
cat_one();
|
||||
*pa = (struct paren) {
|
||||
.alter = alter,
|
||||
.atoms = atoms,
|
||||
.op = p
|
||||
};
|
||||
pa++;
|
||||
alter = 0;
|
||||
atoms = 0;
|
||||
p = *pat++;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
print_error(p);
|
||||
goto error;
|
||||
|
||||
case ')': {
|
||||
glob *tmp, *a;
|
||||
if (pa == paren || !atoms) {
|
||||
print_error(p);
|
||||
goto error;
|
||||
}
|
||||
--pa;
|
||||
cat_all();
|
||||
a = pop_frag();
|
||||
tmp = handle_operator(pa->op, a);
|
||||
free_glob(a);
|
||||
push_frag(tmp);
|
||||
|
||||
for (; alter > 0; --alter) {
|
||||
glob *b = pop_frag();
|
||||
glob *a = pop_frag();
|
||||
if (pa->op == '!')
|
||||
push_frag(glob_and(a, b));
|
||||
else
|
||||
push_frag(glob_or(a, b));
|
||||
--atoms;
|
||||
free_glob(a);
|
||||
free_glob(b);
|
||||
}
|
||||
|
||||
atoms = pa->atoms;
|
||||
alter = pa->alter;
|
||||
atoms++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '[': {
|
||||
char *strPat;
|
||||
char const *end;
|
||||
cat_one();
|
||||
end = strchr(pat, ']');
|
||||
if (!end) {
|
||||
fprintf(stderr,"pattern error: Mismatching brackets.\n");
|
||||
goto error;
|
||||
}
|
||||
strPat = strdup(pat);
|
||||
strPat[end-pat]='\0';
|
||||
push_frag(glob_cset(strPat));
|
||||
++atoms;
|
||||
free(strPat);
|
||||
pat = end + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case '|': {
|
||||
glob *a;
|
||||
glob *tmp;
|
||||
char op;
|
||||
if (atoms == 0 || pa == paren) {
|
||||
print_error(p);
|
||||
goto error;
|
||||
}
|
||||
cat_all();
|
||||
a = pop_frag();
|
||||
op = (pa-1)->op;
|
||||
tmp = handle_operator(op, a);
|
||||
free_glob(a);
|
||||
push_frag(tmp);
|
||||
|
||||
++alter;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
p = *pat++;
|
||||
/* FALLTHROUGH */
|
||||
default: /* literal character */
|
||||
character: cat_one();
|
||||
push_frag(glob_char(p));
|
||||
++atoms;
|
||||
}
|
||||
|
||||
}
|
||||
if (pa != paren) {
|
||||
fprintf(stderr,"pattern error: Mismatching parenthesis\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
cat_all();
|
||||
|
||||
return frags[0];
|
||||
|
||||
error:
|
||||
cleanup(frags, frag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int compile_pattern(char const* pattern){
|
||||
match_glob = compile(pattern);
|
||||
return match_glob ? 1 : 0;
|
||||
}
|
||||
|
||||
int match(char const* string){
|
||||
return match_glob->matches(match_glob, string);
|
||||
}
|
||||
|
||||
void free_pattern(){
|
||||
free_glob(match_glob);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_BRZ_
|
||||
|
||||
void print_pattern() {
|
||||
match_glob->print(match_glob);
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("usage: %s \"pattern\" \"string\"\n",argv[0]);
|
||||
return 1;
|
||||
}
|
||||
printf("argv: %s\n", argv[1]);
|
||||
if(compile_pattern(argv[1]))
|
||||
{
|
||||
print_pattern();
|
||||
puts("");
|
||||
puts("");
|
||||
printf("matched: %d\n", match(argv[2]));
|
||||
free_pattern();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright © 2015-2016 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||
* Copyright © 2016 Matthias "ailu" Günzel <a1lu@arcor.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,9 +21,11 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef EXTMATCH_H_
|
||||
# define EXTMATCH_H_
|
||||
#ifndef EXTGLOBMATCH_H
|
||||
#define EXTGLOBMATCH_H
|
||||
|
||||
int extmatch(const char *pattern, const char *string, const char **errmsg);
|
||||
int compile_pattern(char const* pattern);
|
||||
int match(char const* string);
|
||||
void free_pattern();
|
||||
|
||||
#endif /* !EXTMATCH_H_ */
|
||||
#endif /* end of include guard: EXTGLOBMATCH_H */
|
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright © 2015-2016 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <string.h>
|
||||
#include <pcre.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "criterion/internal/common.h"
|
||||
#include "common.h"
|
||||
|
||||
struct context {
|
||||
int depth;
|
||||
char *dst;
|
||||
const char *src;
|
||||
char old, cur;
|
||||
int eos;
|
||||
const char **errmsg;
|
||||
jmp_buf *jmp;
|
||||
};
|
||||
|
||||
void transform_impl(struct context *ctx);
|
||||
|
||||
static inline void transform_rec(struct context *ctx) {
|
||||
struct context new_ctx = {
|
||||
.depth = ctx->depth + 1,
|
||||
.dst = ctx->dst,
|
||||
.src = ctx->src,
|
||||
.old = ctx->old,
|
||||
.eos = ctx->eos,
|
||||
.errmsg = ctx->errmsg,
|
||||
.jmp = ctx->jmp,
|
||||
};
|
||||
transform_impl(&new_ctx);
|
||||
ctx->dst = new_ctx.dst;
|
||||
ctx->src = new_ctx.src;
|
||||
ctx->old = new_ctx.old;
|
||||
ctx->eos = new_ctx.eos;
|
||||
}
|
||||
|
||||
static inline char read_char(struct context *ctx) {
|
||||
char c = *ctx->src;
|
||||
ctx->old = ctx->cur;
|
||||
ctx->cur = c;
|
||||
if (c == '\0')
|
||||
ctx->eos = 1;
|
||||
++ctx->src;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline char peek_char(struct context *ctx) {
|
||||
return *ctx->src;
|
||||
}
|
||||
|
||||
static inline void copy_char(struct context *ctx, char src) {
|
||||
*ctx->dst = src;
|
||||
++ctx->dst;
|
||||
}
|
||||
|
||||
static inline void dup_char(struct context *ctx) {
|
||||
copy_char(ctx, read_char(ctx));
|
||||
}
|
||||
|
||||
static inline void copy_str(struct context *ctx, const char *src) {
|
||||
size_t len = strlen(src);
|
||||
strncpy(ctx->dst, src, len);
|
||||
ctx->dst += len;
|
||||
}
|
||||
|
||||
#define PREPREFIX 0
|
||||
#define POSTPREFIX 1
|
||||
#define PRESUFFIX 2
|
||||
#define POSTSUFFIX 3
|
||||
#define ELSESTR 4
|
||||
|
||||
typedef struct {
|
||||
int (*validator)(struct context *ctx);
|
||||
char *str;
|
||||
} handler_arg;
|
||||
|
||||
static int active(CR_UNUSED struct context *ctx) { return 1; }
|
||||
static int inactive(CR_UNUSED struct context *ctx) { return 0; }
|
||||
|
||||
static int is_eos(struct context *ctx) {
|
||||
return peek_char(ctx) == '\0';
|
||||
}
|
||||
|
||||
static inline void handle_special(struct context *ctx, handler_arg strs[5]) {
|
||||
if (peek_char(ctx) == '(') {
|
||||
if (DEF(strs[0].validator, inactive)(ctx))
|
||||
copy_str(ctx, strs[0].str);
|
||||
dup_char(ctx);
|
||||
if (DEF(strs[1].validator, inactive)(ctx))
|
||||
copy_str(ctx, strs[1].str);
|
||||
|
||||
transform_rec(ctx);
|
||||
|
||||
if (DEF(strs[2].validator, inactive)(ctx))
|
||||
copy_str(ctx,strs[2].str);
|
||||
copy_char(ctx, ')');
|
||||
if (DEF(strs[3].validator, inactive)(ctx))
|
||||
copy_str(ctx, strs[3].str);
|
||||
} else if (DEF(strs[4].validator, inactive)(ctx)) {
|
||||
copy_str(ctx, strs[4].str);
|
||||
}
|
||||
}
|
||||
|
||||
# define Handler(Name, ...) \
|
||||
static void Name(struct context *ctx, CR_UNUSED char c) { \
|
||||
handle_special(ctx, (handler_arg[5]) { \
|
||||
__VA_ARGS__ \
|
||||
}); \
|
||||
}
|
||||
|
||||
# define _ active
|
||||
Handler(handle_plus, [POSTSUFFIX] = {_, "+"}, [ELSESTR] = {_, "+" })
|
||||
Handler(handle_star, [POSTSUFFIX] = {_, "*"}, [ELSESTR] = {_, ".*"})
|
||||
Handler(handle_wild, [POSTSUFFIX] = {_, "?"}, [ELSESTR] = {_, "." })
|
||||
Handler(handle_excl,
|
||||
[POSTPREFIX] = {_, "?!"},
|
||||
[PRESUFFIX] = {is_eos, "$" },
|
||||
[POSTSUFFIX] = {_, ".*"},
|
||||
[ELSESTR] = {_, "!" }
|
||||
)
|
||||
Handler(handle_at, [ELSESTR] = {_, "@"})
|
||||
# undef _
|
||||
|
||||
static void handle_rbra(struct context *ctx, CR_UNUSED char c) {
|
||||
copy_char(ctx, c);
|
||||
if (peek_char(ctx) == '!') {
|
||||
read_char(ctx);
|
||||
copy_char(ctx, '^');
|
||||
}
|
||||
}
|
||||
|
||||
static void escape_char(struct context *ctx, char c) {
|
||||
copy_char(ctx, '\\');
|
||||
copy_char(ctx, c);
|
||||
}
|
||||
|
||||
static void escape_pipe(struct context *ctx, CR_UNUSED char c) {
|
||||
if (ctx->depth == 0)
|
||||
copy_char(ctx, '\\');
|
||||
copy_char(ctx, '|');
|
||||
}
|
||||
|
||||
typedef void (*f_handler)(struct context *, char);
|
||||
|
||||
void transform_impl(struct context *ctx) {
|
||||
static f_handler handlers[] = {
|
||||
['+'] = handle_plus,
|
||||
['*'] = handle_star,
|
||||
['?'] = handle_wild,
|
||||
['!'] = handle_excl,
|
||||
['['] = handle_rbra,
|
||||
['@'] = handle_at,
|
||||
|
||||
['.'] = escape_char,
|
||||
['('] = escape_char,
|
||||
[')'] = escape_char,
|
||||
['|'] = escape_pipe,
|
||||
|
||||
[255] = NULL,
|
||||
};
|
||||
for (char c = read_char(ctx); !ctx->eos; c = read_char(ctx)) {
|
||||
f_handler handler = handlers[(unsigned char) c];
|
||||
|
||||
if (ctx->old == '\\')
|
||||
handler = copy_char;
|
||||
|
||||
if (c == ')' && ctx->depth > 0)
|
||||
return;
|
||||
|
||||
(handler ? handler : copy_char)(ctx, c);
|
||||
|
||||
if (ctx->eos)
|
||||
return;
|
||||
}
|
||||
if (ctx->depth > 0) {
|
||||
*ctx->errmsg = "mismatching parenthesis";
|
||||
longjmp(*ctx->jmp, -1); // abort operation
|
||||
}
|
||||
}
|
||||
|
||||
static int transform(const char *pattern, char *result, const char **errmsg) {
|
||||
jmp_buf jmp;
|
||||
struct context ctx = {
|
||||
.src = pattern,
|
||||
.dst = result,
|
||||
.errmsg = errmsg,
|
||||
.jmp = &jmp,
|
||||
};
|
||||
if (!setjmp(*ctx.jmp)) {
|
||||
copy_char(&ctx, '^');
|
||||
transform_impl(&ctx);
|
||||
copy_char(&ctx, '$');
|
||||
copy_char(&ctx, '\0');
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* let T be the transformation function,
|
||||
* let diff be the function that yields the greatest character difference
|
||||
* before and after its parameter has been transformed by T.
|
||||
*
|
||||
* T('*') = '.*'; diff('*') = 1
|
||||
* T('!()') = '(?!).*' or '(?!$).*'; diff('!()') = 4
|
||||
* T('@') = '' or '@'; diff('@') = 0
|
||||
* T('|') = '|' or '\|'; diff('|') = 1
|
||||
* T('.') = '\.'; diff('.') = 1
|
||||
* T('(') = '\('; diff('(') = 1
|
||||
* T(')') = '\)'; diff(')') = 1
|
||||
* for every other 1 character string s, we have T(s) = s; hence diff(s) = 0
|
||||
*
|
||||
* let num be the function that yields the number of occurences of a string.
|
||||
* let spec be the set {(s, num(s)) | ∀s}
|
||||
* ∀s, length(T(s)) = length(s) + Σ((c_i, n_i) ∈ spec, n_i * diff(c_i))
|
||||
*
|
||||
* let S = {'*', '!()', '|', '.', '(', ')'}.
|
||||
* since ∀s ∉ S, diff(s) = 0, we can simplify the above equation as:
|
||||
*
|
||||
* ∀s, length(T(s)) = length(s) + num('*') + num('|') + num('.')
|
||||
* + num('(') + num(')') + 4 * num('!()').
|
||||
*
|
||||
* We must now find the maximal length L such as ∀s, L >= length(T(s))
|
||||
*
|
||||
* It is immediately apparent that the largest string will depend on the number
|
||||
* of occurrences of '!()'. Hence, ∀s, let u(s) be a string that is a repeating
|
||||
* sequence of '!()' padded by at most two '.', such as length(u(s)) == length(s),
|
||||
*
|
||||
* let N = floor(length(u(s)) / 3),
|
||||
* let Q = length(u(s)) mod 3,
|
||||
* hence num('!()') = N.
|
||||
*
|
||||
* ∀s | length(s) = length(u(s)),
|
||||
* length(T(s)) <= length(T(u(s)))
|
||||
* <= length(u(s)) | the original length
|
||||
* + 4 * N | the expansion of all '!()'
|
||||
* + Q * diff('.') | the expansion of Q '.'
|
||||
* <= 3 * N + Q + 4 * N + Q
|
||||
* <= 7 * N + 4
|
||||
* <= 7 * floor(length(u(s)) / 3) + 4
|
||||
* <= 7 * floor(length(s) / 3) + 4
|
||||
*
|
||||
*/
|
||||
static inline size_t max_length(size_t len) {
|
||||
return 7 * len / 3 + 4;
|
||||
}
|
||||
|
||||
int extmatch(const char *pattern, const char *string, const char **errmsg) {
|
||||
char regex[max_length(strlen(pattern)) + 1];
|
||||
if (transform(pattern, regex, errmsg) != -1) {
|
||||
int erroffset;
|
||||
pcre *preg = pcre_compile(regex, 0, errmsg, &erroffset, NULL);
|
||||
if (preg) {
|
||||
int res = pcre_exec(preg, NULL, string, strlen(string), 0, 0, NULL, 0);
|
||||
pcre_free(preg);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return -10;
|
||||
}
|
|
@ -45,7 +45,6 @@ if (NOT MSVC) # we disable the scripted tests when building with MSVC
|
|||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}"
|
||||
-DCRAM_PATH="${CMAKE_CURRENT_SOURCE_DIR}/cram"
|
||||
-DENABLE_PATTERN_TESTS="${HAVE_PCRE}"
|
||||
-P "${CMAKE_MODULE_PATH}/Cram.cmake"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
Only run on linux
|
||||
|
||||
$ if [ "$CRITERION_TESTS_PATTERN" = "off" ]; then
|
||||
> exit 80
|
||||
> fi
|
||||
|
||||
Selecting misc::passing
|
||||
Testing normal globs
|
||||
|
||||
$ simple.c.bin --pattern '*/passing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
|
@ -14,7 +8,82 @@ Selecting misc::passing
|
|||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
Selecting misc::failing
|
||||
$ simple.c.bin --pattern '*/pa?sing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/passing?' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/*' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34m----\x1b[0m] \x1b[0;1msimple.c\x1b[0m:\x1b[0;31m4\x1b[0m: Assertion failed: The expression 0 is false. (esc)
|
||||
[\x1b[0;31mFAIL\x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m2\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
|
||||
|
||||
Testing character classes
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[pf]assing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[p-s]assing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[!f]ailing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m0\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[p-f]ailing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34m----\x1b[0m] \x1b[0;1msimple.c\x1b[0m:\x1b[0;31m4\x1b[0m: Assertion failed: The expression 0 is false. (esc)
|
||||
[\x1b[0;31mFAIL\x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[!azerty]assing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Testing extended globs
|
||||
|
||||
$ simple.c.bin --pattern '!(*/passing)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
|
@ -25,7 +94,23 @@ Selecting misc::failing
|
|||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
Selecting both misc::passing and misc::failing
|
||||
$ simple.c.bin --pattern '@(misc)/passing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
$ simple.c.bin --pattern '*(misc)/pa+(s)ing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[pf]a@(ss|il)ing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
|
@ -37,17 +122,57 @@ Selecting both misc::passing and misc::failing
|
|||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m2\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
$ simple.c.bin --pattern '!(*/failing|*/fail)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
$ simple.c.bin --pattern 'misc/?(passing)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/?(passing|failing)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34m----\x1b[0m] \x1b[0;1msimple.c\x1b[0m:\x1b[0;31m4\x1b[0m: Assertion failed: The expression 0 is false. (esc)
|
||||
[\x1b[0;31mFAIL\x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m2\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
$ simple.c.bin --pattern 'misc/*!(passing)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34m----\x1b[0m] \x1b[0;1msimple.c\x1b[0m:\x1b[0;31m4\x1b[0m: Assertion failed: The expression 0 is false. (esc)
|
||||
[\x1b[0;31mFAIL\x1b[0m] misc::failing (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;32mPASS\x1b[0m] misc::passing (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m2\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0;31m1\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Testing nested extglob patterns
|
||||
|
||||
$ simple.c.bin --pattern '@(+(nest)ed))' --verbose
|
||||
$ simple.c.bin --pattern '@(+(nest)ed)' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m0\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
Testing one or more
|
||||
|
||||
$ simple.c.bin --pattern '?(*(a|b))' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
|
@ -55,15 +180,7 @@ Testing one or more
|
|||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m0\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
Testing malformed pattern
|
||||
|
||||
$ simple.c.bin --pattern '?(malformed' --verbose
|
||||
pattern error: mismatching parenthesis
|
||||
[1]
|
||||
|
||||
Testing range negation
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[!azerty]assing' --verbose
|
||||
$ simple.c.bin --pattern 'misc/pa@(s|*(s))ing' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;34mRUN \x1b[0m] misc::passing (esc)
|
||||
|
@ -71,20 +188,47 @@ Testing range negation
|
|||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m1\x1b[0;1m | Passing: \x1b[0;32m1\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
Testing unparenthesized pipe
|
||||
|
||||
|
||||
|
||||
Testing malformed pattern
|
||||
|
||||
$ simple.c.bin --pattern '?(malformed' --verbose
|
||||
pattern error: Mismatching parenthesis
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern '(malformed' --verbose
|
||||
pattern error: Unexpected character '('
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern 'misc/passing)' --verbose
|
||||
pattern error: Unexpected character ')'
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[' --verbose
|
||||
pattern error: Mismatching brackets.
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern 'misc/[a-' --verbose
|
||||
pattern error: Mismatching brackets.
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern '|pipe' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m0\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
pattern error: Unexpected character '|'
|
||||
[3]
|
||||
|
||||
|
||||
Testing special char escaping
|
||||
|
||||
$ simple.c.bin --pattern '\!(escaped' --verbose
|
||||
$ simple.c.bin --pattern '\!(escaped)' --verbose
|
||||
pattern error: Unexpected character '('
|
||||
[3]
|
||||
|
||||
$ simple.c.bin --pattern '\!escaped' --verbose
|
||||
[\x1b[0;34m----\x1b[0m] Criterion v2.2.1 (esc)
|
||||
[\x1b[0;34m====\x1b[0m] Running \x1b[0;34m2\x1b[0m tests from \x1b[0;33mmisc\x1b[0m: (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::passing: Test is disabled (esc)
|
||||
[\x1b[0;33mSKIP\x1b[0m] misc::failing: Test is disabled (esc)
|
||||
[\x1b[0;34m====\x1b[0m] \x1b[0;1mSynthesis: Tested: \x1b[0;34m0\x1b[0;1m | Passing: \x1b[0;32m0\x1b[0;1m | Failing: \x1b[0m0\x1b[0;1m | Crashing: \x1b[0m0\x1b[0;1m \x1b[0m (esc)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue