|
#ifndef RREX4_H
|
|
#define RREX4_H
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define R4_DEBUG_a
|
|
|
|
#ifdef R4_DEBUG
|
|
static int _r4_debug = 1;
|
|
#else
|
|
static int _r4_debug = 0;
|
|
#endif
|
|
|
|
static char *_format_function_name(const char *name) {
|
|
static char result[100];
|
|
result[0] = 0;
|
|
|
|
char *new_name = (char *)name;
|
|
new_name += 11;
|
|
if (new_name[0] == '_')
|
|
new_name += 1;
|
|
if (strlen(new_name) == 0) {
|
|
return " -";
|
|
}
|
|
strcpy(result, new_name);
|
|
return result;
|
|
}
|
|
|
|
#define DEBUG_VALIDATE_FUNCTION \
|
|
if (_r4_debug || r4->debug) \
|
|
printf("DEBUG: %s %s <%s> \"%s\"\n", _format_function_name(__func__), \
|
|
r4->valid ? "valid" : "INVALID", r4->expr, r4->str);
|
|
|
|
struct r4_t;
|
|
|
|
void r4_enable_debug() { _r4_debug = true; }
|
|
void r4_disable_debug() { _r4_debug = false; }
|
|
|
|
typedef bool (*r4_function)(struct r4_t *);
|
|
|
|
typedef struct r4_t {
|
|
bool debug;
|
|
bool valid;
|
|
bool in_block;
|
|
bool is_greedy;
|
|
bool in_range;
|
|
unsigned int backtracking;
|
|
unsigned int loop_count;
|
|
unsigned int in_group;
|
|
unsigned int match_count;
|
|
unsigned int validation_count;
|
|
unsigned int start;
|
|
unsigned int end;
|
|
unsigned int length;
|
|
bool (*functions[254])(struct r4_t *);
|
|
bool (*slash_functions[254])(struct r4_t *);
|
|
char *_str;
|
|
char *_expr;
|
|
char *match;
|
|
char *str;
|
|
char *expr;
|
|
char *str_previous;
|
|
char *expr_previous;
|
|
char **matches;
|
|
} r4_t;
|
|
|
|
static bool v4_initiated = false;
|
|
typedef bool (*v4_function_map)(r4_t *);
|
|
v4_function_map v4_function_map_global[256];
|
|
v4_function_map v4_function_map_slash[256];
|
|
v4_function_map v4_function_map_block[256];
|
|
|
|
static void r4_free_matches(r4_t *r) {
|
|
if (!r)
|
|
return;
|
|
if (r->match) {
|
|
free(r->match);
|
|
r->match = NULL;
|
|
}
|
|
if (!r->match_count) {
|
|
return;
|
|
}
|
|
for (unsigned i = 0; i < r->match_count; i++) {
|
|
free(r->matches[i]);
|
|
}
|
|
free(r->matches);
|
|
r->match_count = 0;
|
|
r->matches = NULL;
|
|
}
|
|
|
|
static void r4_free(r4_t *r) {
|
|
if (!r)
|
|
return;
|
|
r4_free_matches(r);
|
|
free(r);
|
|
}
|
|
|
|
static bool r4_backtrack(r4_t *r4);
|
|
static bool r4_validate(r4_t *r4);
|
|
static void r4_match_add(r4_t *r4, char *extracted);
|
|
|
|
static bool r4_validate_literal(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (!r4->valid)
|
|
return false;
|
|
if (*r4->str != *r4->expr) {
|
|
r4->valid = false;
|
|
} else {
|
|
r4->str++;
|
|
}
|
|
r4->expr++;
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_question_mark(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->valid = true;
|
|
r4->expr++;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_plus(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
if (r4->valid == false) {
|
|
return r4_validate(r4);
|
|
}
|
|
char *expr_left = r4->expr_previous;
|
|
char *expr_right = r4->expr;
|
|
char *str = r4->str;
|
|
char *return_expr = NULL;
|
|
if (*expr_right == ')') {
|
|
return_expr = expr_right;
|
|
expr_right++;
|
|
}
|
|
r4->is_greedy = false;
|
|
r4->expr = expr_left;
|
|
while (r4->valid) {
|
|
if (*expr_right) {
|
|
r4->expr = expr_right;
|
|
r4->is_greedy = true;
|
|
if (r4_backtrack(r4)) {
|
|
|
|
if (return_expr) {
|
|
r4->str = str;
|
|
r4->expr = return_expr;
|
|
}
|
|
return r4_validate(r4);
|
|
} else {
|
|
r4->is_greedy = false;
|
|
}
|
|
}
|
|
r4->valid = true;
|
|
r4->expr = expr_left;
|
|
r4->str = str;
|
|
r4_validate(r4);
|
|
str = r4->str;
|
|
}
|
|
r4->is_greedy = true;
|
|
r4->valid = true;
|
|
r4->expr = return_expr ? return_expr : expr_right;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_dollar(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
r4->valid = *r4->str == 0;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_roof(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (r4->str != r4->_str) {
|
|
return false;
|
|
}
|
|
r4->expr++;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_dot(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (*r4->str == 0) {
|
|
return false;
|
|
}
|
|
r4->expr++;
|
|
r4->valid = *r4->str != '\n';
|
|
r4->str++;
|
|
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_asterisk(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
if (r4->valid == false) {
|
|
r4->valid = true;
|
|
return r4->valid;
|
|
// return r4_validate(r4);
|
|
}
|
|
char *expr_left = r4->expr_previous;
|
|
char *expr_right = r4->expr;
|
|
char *str = r4->str;
|
|
char *return_expr = NULL;
|
|
if (*expr_right == ')') {
|
|
return_expr = expr_right;
|
|
expr_right++;
|
|
}
|
|
r4->is_greedy = false;
|
|
r4->expr = expr_left;
|
|
while (r4->valid) {
|
|
if (*expr_right) {
|
|
r4->expr = expr_right;
|
|
r4->is_greedy = true;
|
|
if (r4_backtrack(r4)) {
|
|
|
|
if (return_expr) {
|
|
r4->str = str;
|
|
r4->expr = return_expr;
|
|
}
|
|
return r4_validate(r4);
|
|
} else {
|
|
r4->is_greedy = false;
|
|
}
|
|
}
|
|
r4->valid = true;
|
|
r4->expr = expr_left;
|
|
r4->str = str;
|
|
r4_validate(r4);
|
|
str = r4->str;
|
|
}
|
|
r4->is_greedy = true;
|
|
r4->valid = true;
|
|
r4->expr = return_expr ? return_expr : expr_right;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_pipe(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
if (r4->valid == true) {
|
|
return true;
|
|
} else {
|
|
r4->valid = true;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_digit(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (!isdigit(*r4->str)) {
|
|
r4->valid = false;
|
|
} else {
|
|
r4->str++;
|
|
}
|
|
r4->expr++;
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_not_digit(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (isdigit(*r4->str)) {
|
|
r4->valid = false;
|
|
} else {
|
|
r4->str++;
|
|
}
|
|
r4->expr++;
|
|
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_word(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (!isalpha(*r4->str)) {
|
|
r4->valid = false;
|
|
} else {
|
|
r4->str++;
|
|
}
|
|
r4->expr++;
|
|
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_not_word(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (isalpha(*r4->str)) {
|
|
r4->valid = false;
|
|
} else {
|
|
r4->str++;
|
|
}
|
|
r4->expr++;
|
|
|
|
if (r4->in_block || r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_isrange(char *s) {
|
|
if (!isalnum(*s)) {
|
|
return false;
|
|
}
|
|
if (*(s + 1) != '-') {
|
|
return false;
|
|
}
|
|
return isalnum(*(s + 2));
|
|
}
|
|
|
|
static bool r4_validate_block_open(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
if (r4->valid == false) {
|
|
return false;
|
|
}
|
|
char *expr_self = r4->expr;
|
|
r4->expr++;
|
|
bool reversed = *r4->expr == '^';
|
|
if (reversed) {
|
|
r4->expr++;
|
|
}
|
|
|
|
bool valid_once = false;
|
|
r4->in_block = true;
|
|
while (*r4->expr != ']') {
|
|
r4->valid = true;
|
|
if (r4_isrange(r4->expr)) {
|
|
char s = *r4->expr;
|
|
char e = *(r4->expr + 2);
|
|
r4->expr += 2;
|
|
if (s > e) {
|
|
char tempc = s;
|
|
s = e;
|
|
e = tempc;
|
|
}
|
|
if (*r4->str >= s && *r4->str <= e) {
|
|
if (!reversed) {
|
|
r4->str++;
|
|
}
|
|
valid_once = true;
|
|
break;
|
|
} else {
|
|
r4->expr++;
|
|
}
|
|
} else if (r4_validate(r4)) {
|
|
valid_once = true;
|
|
if (reversed)
|
|
r4->str--;
|
|
break;
|
|
}
|
|
}
|
|
char *expr_end = strchr(r4->expr, ']');
|
|
|
|
r4->expr = expr_end ? expr_end : r4->expr;
|
|
r4->in_block = false;
|
|
r4->valid = expr_end && (!reversed ? valid_once : !valid_once);
|
|
r4->expr++;
|
|
r4->expr_previous = expr_self;
|
|
|
|
if (r4->in_range || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_whitespace(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->valid = strchr("\r\t \n", *r4->str) != NULL;
|
|
r4->expr++;
|
|
if (r4->valid) {
|
|
r4->str++;
|
|
}
|
|
if (r4->in_range || r4->in_block || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_not_whitespace(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->valid = strchr("\r\t \n", *r4->str) == NULL;
|
|
r4->expr++;
|
|
if (r4->valid) {
|
|
r4->str++;
|
|
}
|
|
if (r4->in_range || r4->in_block || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_range(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION;
|
|
if (r4->valid == false) {
|
|
r4->expr++;
|
|
return false;
|
|
}
|
|
char *previous = r4->expr_previous;
|
|
r4->in_range = true;
|
|
r4->expr++;
|
|
unsigned int start = 0;
|
|
while (isdigit(*r4->expr)) {
|
|
start = 10 * start;
|
|
start += *r4->expr - '0';
|
|
r4->expr++;
|
|
}
|
|
if (start != 0)
|
|
start--;
|
|
|
|
unsigned int end = 0;
|
|
bool variable_end_range = false;
|
|
if (*r4->expr == ',') {
|
|
r4->expr++;
|
|
if (!isdigit(*r4->expr)) {
|
|
variable_end_range = true;
|
|
}
|
|
}
|
|
while (isdigit(*r4->expr)) {
|
|
end = end * 10;
|
|
end += *r4->expr - '0';
|
|
r4->expr++;
|
|
}
|
|
r4->expr++;
|
|
|
|
bool valid = true;
|
|
char *expr_right = r4->expr;
|
|
for (unsigned int i = 0; i < start; i++) {
|
|
r4->expr = previous;
|
|
valid = r4_validate(r4);
|
|
if (!*r4->str)
|
|
break;
|
|
if (!valid) {
|
|
break;
|
|
}
|
|
}
|
|
r4->expr = expr_right;
|
|
r4->in_range = false;
|
|
if (!r4->valid)
|
|
return false;
|
|
return r4_validate(r4);
|
|
|
|
for (unsigned int i = start; i < end; i++) {
|
|
r4->expr = previous;
|
|
valid = r4_validate(r4);
|
|
if (!valid) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (variable_end_range) {
|
|
r4->in_range = false;
|
|
valid = r4_validate(r4);
|
|
r4->in_range = true;
|
|
if (valid) {
|
|
break;
|
|
}
|
|
r4->in_range = true;
|
|
valid = r4_validate(r4);
|
|
r4->in_range = false;
|
|
if (!valid) {
|
|
break;
|
|
}
|
|
}
|
|
r4->valid = valid;
|
|
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_group_close(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
return r4->valid;
|
|
}
|
|
|
|
static bool r4_validate_group_open(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
char *expr_previous = r4->expr_previous;
|
|
r4->expr++;
|
|
bool save_match = r4->in_group == 0;
|
|
r4->in_group++;
|
|
char *str_extract_start = r4->str;
|
|
bool valid = r4_validate(r4);
|
|
|
|
if (!valid || *r4->expr != ')') {
|
|
// this is a valid case if not everything between () matches
|
|
r4->in_group--;
|
|
if (save_match == false) {
|
|
r4->valid = true;
|
|
}
|
|
|
|
// Not direct return? Not sure
|
|
return r4_validate(r4);
|
|
}
|
|
if (save_match) {
|
|
char *str_extract_end = r4->str;
|
|
unsigned int extracted_length = str_extract_end - str_extract_start;
|
|
// strlen(str_extract_start) - strlen(str_extract_end);
|
|
char *str_extracted =
|
|
(char *)calloc(sizeof(char), extracted_length + 1);
|
|
strncpy(str_extracted, str_extract_start, extracted_length);
|
|
r4_match_add(r4, str_extracted);
|
|
}
|
|
assert(*r4->expr == ')');
|
|
r4->expr++;
|
|
r4->in_group--;
|
|
r4->expr_previous = expr_previous;
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static bool r4_validate_slash(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
// The handling code for handling slashes is implemented in r4_validate
|
|
char *expr_previous = r4->expr_previous;
|
|
r4->expr++;
|
|
r4_function f = v4_function_map_slash[(int)*r4->expr];
|
|
r4->expr_previous = expr_previous;
|
|
return f(r4);
|
|
}
|
|
|
|
static void r4_match_add(r4_t *r4, char *extracted) {
|
|
r4->matches =
|
|
(char **)realloc(r4->matches, (r4->match_count + 1) * sizeof(char *));
|
|
r4->matches[r4->match_count] = extracted;
|
|
r4->match_count++;
|
|
}
|
|
|
|
static bool r4_validate_word_boundary_start(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
if (!r4->valid) {
|
|
return r4->valid;
|
|
}
|
|
r4->valid =
|
|
isalpha(*r4->str) && (r4->str == r4->_str || !isalpha(*(r4->str - 1)));
|
|
if (r4->in_range || r4->in_block || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
static bool r4_validate_word_boundary_end(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->expr++;
|
|
if (!r4->valid) {
|
|
return r4->valid;
|
|
}
|
|
r4->valid =
|
|
isalpha(*r4->str) && (*(r4->str + 1) == 0 || !isalpha(*(r4->str + 1)));
|
|
if (r4->in_range || r4->in_block || !r4->is_greedy) {
|
|
return r4->valid;
|
|
}
|
|
return r4_validate(r4);
|
|
}
|
|
|
|
static void v4_init_function_maps() {
|
|
if (v4_initiated)
|
|
return;
|
|
v4_initiated = true;
|
|
for (__uint8_t i = 0; i < 255; i++) {
|
|
v4_function_map_global[i] = r4_validate_literal;
|
|
v4_function_map_slash[i] = r4_validate_literal;
|
|
v4_function_map_block[i] = r4_validate_literal;
|
|
}
|
|
v4_function_map_global['*'] = r4_validate_asterisk;
|
|
v4_function_map_global['?'] = r4_validate_question_mark;
|
|
v4_function_map_global['+'] = r4_validate_plus;
|
|
v4_function_map_global['$'] = r4_validate_dollar;
|
|
v4_function_map_global['^'] = r4_validate_roof;
|
|
v4_function_map_global['.'] = r4_validate_dot;
|
|
v4_function_map_global['|'] = r4_validate_pipe;
|
|
v4_function_map_global['\\'] = r4_validate_slash;
|
|
v4_function_map_global['['] = r4_validate_block_open;
|
|
v4_function_map_global['{'] = r4_validate_range;
|
|
v4_function_map_global['('] = r4_validate_group_open;
|
|
v4_function_map_global[')'] = r4_validate_group_close;
|
|
v4_function_map_slash['b'] = r4_validate_word_boundary_start;
|
|
v4_function_map_slash['B'] = r4_validate_word_boundary_end;
|
|
v4_function_map_slash['d'] = r4_validate_digit;
|
|
v4_function_map_slash['w'] = r4_validate_word;
|
|
v4_function_map_slash['D'] = r4_validate_not_digit;
|
|
v4_function_map_slash['W'] = r4_validate_not_word;
|
|
v4_function_map_slash['s'] = r4_validate_whitespace;
|
|
v4_function_map_slash['S'] = r4_validate_not_whitespace;
|
|
v4_function_map_block['\\'] = r4_validate_slash;
|
|
|
|
v4_function_map_block['{'] = r4_validate_range;
|
|
}
|
|
|
|
void r4_init(r4_t *r4) {
|
|
v4_init_function_maps();
|
|
if (r4 == NULL)
|
|
return;
|
|
r4->debug = _r4_debug;
|
|
r4->valid = true;
|
|
r4->validation_count = 0;
|
|
r4->match_count = 0;
|
|
r4->start = 0;
|
|
r4->end = 0;
|
|
r4->length = 0;
|
|
r4->matches = NULL;
|
|
}
|
|
|
|
static bool r4_looks_behind(char c) { return strchr("?*+{", c) != NULL; }
|
|
|
|
r4_t *r4_new() {
|
|
r4_t *r4 = (r4_t *)malloc(sizeof(r4_t));
|
|
|
|
r4_init(r4);
|
|
|
|
return r4;
|
|
}
|
|
|
|
static bool r4_pipe_next(r4_t *r4) {
|
|
char *expr = r4->expr;
|
|
while (*expr) {
|
|
if (*expr == '|') {
|
|
r4->expr = expr + 1;
|
|
r4->valid = true;
|
|
return true;
|
|
}
|
|
expr++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool r4_backtrack(r4_t *r4) {
|
|
if (_r4_debug)
|
|
printf("\033[36mDEBUG: backtrack start (%d)\n", r4->backtracking);
|
|
r4->backtracking++;
|
|
char *str = r4->str;
|
|
char *expr = r4->expr;
|
|
bool result = r4_validate(r4);
|
|
r4->backtracking--;
|
|
if (result == false) {
|
|
r4->expr = expr;
|
|
r4->str = str;
|
|
}
|
|
if (_r4_debug)
|
|
printf("DEBUG: backtrack end (%d) result: %d %s\n", r4->backtracking,
|
|
result, r4->backtracking == 0 ? "\033[0m" : "");
|
|
return result;
|
|
}
|
|
|
|
static bool r4_validate(r4_t *r4) {
|
|
DEBUG_VALIDATE_FUNCTION
|
|
r4->validation_count++;
|
|
char c_val = *r4->expr;
|
|
if (c_val == 0) {
|
|
return r4->valid;
|
|
}
|
|
if (!r4_looks_behind(c_val)) {
|
|
r4->expr_previous = r4->expr;
|
|
} else if (r4->expr == r4->_expr) {
|
|
// Regex may not start with a look behind ufnction
|
|
return false;
|
|
}
|
|
|
|
if (!r4->valid && !r4_looks_behind(*r4->expr)) {
|
|
if (!r4_pipe_next(r4)) {
|
|
return false;
|
|
}
|
|
}
|
|
r4_function f;
|
|
if (r4->in_block) {
|
|
f = v4_function_map_block[(int)c_val];
|
|
} else {
|
|
f = v4_function_map_global[(int)c_val];
|
|
}
|
|
|
|
r4->valid = f(r4);
|
|
return r4->valid;
|
|
}
|
|
|
|
char *r4_get_match(r4_t *r) {
|
|
char *match = (char *)malloc(r->length + 1);
|
|
strncpy(match, r->_str + r->start, r->length);
|
|
match[r->length] = 0;
|
|
return match;
|
|
}
|
|
|
|
static bool r4_search(r4_t *r) {
|
|
bool valid = true;
|
|
char *str_next = r->str;
|
|
while (*r->str) {
|
|
if (!(valid = r4_validate(r))) {
|
|
// Move next until we find a match
|
|
if (!r->backtracking) {
|
|
r->start++;
|
|
}
|
|
str_next++;
|
|
r->str = str_next;
|
|
r->expr = r->_expr;
|
|
r->valid = true;
|
|
} else {
|
|
/// HIGH DOUBT
|
|
if (!r->backtracking) {
|
|
// r->start = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
r->valid = valid;
|
|
if (r->valid) {
|
|
r->end = strlen(r->_str) - strlen(r->str);
|
|
r->length = r->end - r->start;
|
|
r->match = r4_get_match(r);
|
|
}
|
|
return r->valid;
|
|
}
|
|
|
|
r4_t *r4(const char *str, const char *expr) {
|
|
r4_t *r = r4_new();
|
|
r->_str = (char *)str;
|
|
r->_expr = (char *)expr;
|
|
r->match = NULL;
|
|
r->str = r->_str;
|
|
r->expr = r->_expr;
|
|
r->str_previous = r->_str;
|
|
r->expr_previous = r->expr;
|
|
r->in_block = false;
|
|
r->is_greedy = true;
|
|
r->in_group = 0;
|
|
r->loop_count = 0;
|
|
r->backtracking = 0;
|
|
r->in_range = false;
|
|
r4_search(r);
|
|
return r;
|
|
}
|
|
|
|
r4_t *r4_next(r4_t *r, char *expr) {
|
|
if (expr) {
|
|
r->_expr = expr;
|
|
}
|
|
r->backtracking = 0;
|
|
r->expr = r->_expr;
|
|
r->is_greedy = true;
|
|
r->in_block = false;
|
|
r->in_range = false;
|
|
r->in_group = false;
|
|
r4_free_matches(r);
|
|
r4_search(r);
|
|
return r;
|
|
}
|
|
|
|
bool r4_match(char *str, char *expr) {
|
|
r4_t *r = r4(str, expr);
|
|
bool result = r->valid;
|
|
r4_free(r);
|
|
return result;
|
|
}
|
|
#endif |