From 0d7ef8130a1f79377d2a3b7125692f6fa50bfadd Mon Sep 17 00:00:00 2001 From: Gerben Aaltink Date: Tue, 3 Sep 2024 15:28:05 +0200 Subject: [PATCH] Repair --- Makefile | 12 +- rlib.h | 2221 +++++++++++++--- rrex.h | 20 - rrex2.c | 5 +- rrex3 | Bin 96096 -> 84304 bytes rrex3.c | 97 +- rrex3.h | 496 ++-- rrex3all.c | 7135 ++++++++++++++++++++++++++++++---------------------- 8 files changed, 6306 insertions(+), 3680 deletions(-) diff --git a/Makefile b/Makefile index 615e00d..6154e38 100644 --- a/Makefile +++ b/Makefile @@ -47,13 +47,21 @@ coverage: build_and_run_rrex3: build_rrex3 run_rrex3 build_rrex3: - gcc rrex3.c -o rrex3 -Wall -Wextra -O3 + gcc rrex3.c -o rrex3 -Wall -Wextra -O2 rmerge rrex3.c > rrex3all.c - gcc -E rrex3.c -o rrex3alle.c -Wall -Wextra -O3 + gcc -E rrex3.c -o rrex3alle.c -Wall -Wextra -O2 run_rrex3: ./rrex3 +build_and_run_re: build_re run_re + +build_re: + gcc re.c -o re -Wall -Wextra -O2 + +run_re: + ./re "/home/retoor/projects/rlib" "int.*\b(.*) \b" + coverage_rrex3: @rm -f *.gcda 2>/dev/null @rm -f *.gcno 2>/dev/null diff --git a/rlib.h b/rlib.h index 46e2312..a87e40a 100644 --- a/rlib.h +++ b/rlib.h @@ -1,107 +1,31 @@ -/* - RETOOR -*/ -// Found (local) include: rmath.h -// Found (local) include: rmalloc.h -// Found (local) include: rtime.h -// Found (local) include: arena.h -// Found (local) include: rmalloc.h -// Found (local) include: rio.h -// Found (local) include: rprint.h -// Found (local) include: rtime.h -// Found (local) include: rstring.h -// Found (local) include: rmath.h -// Found (local) include: rterminal.h -// Found (local) include: rtest.h -// Found (local) include: rmalloc.h -// Found (local) include: rprint.h -// Found (local) include: rtest.h -// Found (local) include: rtree.h -// Found (local) include: rmalloc.h -// Found (local) include: rlexer.h -// Found (local) include: rstring.h -// Found (local) include: rbench.h -// Found (local) include: rprint.h -// Found (local) include: rtime.h -// Found (local) include: rstring.h -// Found (local) include: rterminal.h +// RETOOR - Sep 3 2024 +// MIT License +// =========== + +// Copyright (c) 2024 Retoor + +// 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 RLIB_H #define RLIB_H // BEGIN OF RLIB -#ifndef RMATH_H -#define RMATH_H -#include - -#ifndef ceil -double ceil(double x) { - if (x == (double)(long long)x) { - return x; - } else if (x > 0.0) { - return (double)(long long)x + 1.0; - } else { - return (double)(long long)x; - } -} -#endif - -#ifndef floor -double floor(double x) { - if (x >= 0.0) { - return (double)(long long)x; - } else { - double result = (double)(long long)x; - return (result == x) ? result : result - 1.0; - } -} -#endif - -#ifndef modf -double modf(double x, double *iptr) { - double int_part = (x >= 0.0) ? floor(x) : ceil(x); - *iptr = int_part; - return x - int_part; -} -#endif -#endif -#ifndef RMALLOC_H -#define RMALLOC_H -#include -#include -#include - -unsigned int rmalloc_count = 0; -unsigned int rmalloc_alloc_count = 0; -unsigned int rmalloc_free_count = 0; - -void *rmalloc(size_t size) { - rmalloc_count++; - rmalloc_alloc_count++; - return malloc(size); -} -void *rrealloc(void *obj, size_t size) { return realloc(obj, size); } -void *rfree(void *obj) { - rmalloc_count--; - rmalloc_free_count++; - free(obj); - return NULL; -} - -char *rmalloc_stats() { - static char res[100] = {0}; - sprintf(res, "Memory usage: %d allocated, %d freed, %d in use.", - rmalloc_alloc_count, rmalloc_free_count, rmalloc_count); - return res; -} - -char *rstrdup(char *str) { - - char *res = (char *)strdup(str); - rmalloc_alloc_count++; - rmalloc_count++; - return res; -} - -#endif +#ifndef RPRINT_H +#define RPRINT_H #ifndef RLIB_TIME #define RLIB_TIME @@ -171,10 +95,21 @@ char *msecs_str(long long ms) { return result; } -void nsleep(long nanoseconds) { - // long nanoseconds = (long)(1000000000 * s); - +void nsleep(nsecs_t nanoseconds) { long seconds = 0; + int factor = 0; + while (nanoseconds > 1000000000) { + factor++; + nanoseconds = nanoseconds / 10; + } + if (factor) { + seconds = 1; + factor--; + while (factor) { + seconds = seconds * 10; + factor--; + } + } struct timespec req = {seconds, nanoseconds}; struct timespec rem; @@ -239,86 +174,6 @@ char *format_time(int64_t nanoseconds) { } #endif -#ifndef RARENA_H -#define RARENA_H - -#include -#include -#include - -typedef struct arena_t { - unsigned char *memory; - unsigned int pointer; - unsigned int size; -} arena_t; - -arena_t *arena_construct() { - arena_t *arena = (arena_t *)rmalloc(sizeof(arena_t)); - arena->memory = NULL; - arena->pointer = 0; - arena->size = 0; - return arena; -} - -arena_t *arena_new(size_t size) { - arena_t *arena = arena_construct(); - arena->memory = (unsigned char *)rmalloc(size); - arena->size = size; - return arena; -} - -void *arena_alloc(arena_t *arena, size_t size) { - if (arena->pointer + size > arena->size) { - return NULL; - } - void *p = arena->memory + arena->pointer; - arena->pointer += size; - return p; -} - -void arena_free(arena_t *arena) { - // Just constructed and unused arena memory is NULL so no free needed - if (arena->memory) { - rfree(arena->memory); - } - rfree(arena); -} - -void arena_reset(arena_t *arena) { arena->pointer = 0; } -#endif -#ifndef RLIB_RIO -#define RLIB_RIO -#include -#include -#include -#include - -bool rfile_exists(char *path) { - struct stat s; - return !stat(path, &s); -} - -size_t rfile_size(char *path) { - struct stat s; - stat(path, &s); - return s.st_size; -} - -size_t rfile_readb(char *path, void *data, size_t size) { - FILE *fd = fopen(path, "rb"); - if (!fd) { - return 0; - } - __attribute__((unused)) size_t bytes_read = - fread(data, size, sizeof(char), fd); - - fclose(fd); - return size; -} - -#endif -#ifndef RPRINT_H -#define RPRINT_H #include #include #include @@ -350,7 +205,7 @@ void rclear() { printf("\033[2J"); } void rprintpf(FILE *f, const char *prefix, const char *format, va_list args) { char *pprefix = (char *)prefix; char *pformat = (char *)format; - bool reset_color = true; + bool reset_color = false; bool press_any_key = false; char new_format[4096]; bool enable_color = rprint_is_color_enabled(); @@ -361,21 +216,25 @@ void rprintpf(FILE *f, const char *prefix, const char *format, va_list args) { if (enable_color && pprefix[0]) { strcat(new_format, pprefix); new_format_length += strlen(pprefix); + reset_color = true; } while (true) { if (pformat[0] == '\\' && pformat[1] == 'i') { strcat(new_format, "\e[3m"); new_format_length += strlen("\e[3m"); + reset_color = true; pformat++; pformat++; } else if (pformat[0] == '\\' && pformat[1] == 'u') { strcat(new_format, "\e[4m"); new_format_length += strlen("\e[4m"); + reset_color = true; pformat++; pformat++; } else if (pformat[0] == '\\' && pformat[1] == 'b') { strcat(new_format, "\e[1m"); new_format_length += strlen("\e[1m"); + reset_color = true; pformat++; pformat++; } else if (pformat[0] == '\\' && pformat[1] == 'C') { @@ -435,7 +294,7 @@ void rprintpf(FILE *f, const char *prefix, const char *format, va_list args) { pformat++; } } - if (enable_color && reset_color && pprefix[0]) { + if (reset_color) { strcat(new_format, "\e[0m"); new_format_length += strlen("\e[0m"); } @@ -470,6 +329,7 @@ void rprint(char *format, ...) { rprintpf(stdout, "", format, args); va_end(args); } +#define printf rprint // Print line void rprintlf(FILE *f, char *format, ...) { @@ -481,7 +341,7 @@ void rprintlf(FILE *f, char *format, ...) { void rprintl(char *format, ...) { va_list args; va_start(args, format); - rprintlf(stdout, format, args); + rprintpf(stdout, "\\l", format, args); va_end(args); } @@ -495,7 +355,7 @@ void rprintkf(FILE *f, char *format, ...) { void rprintk(char *format, ...) { va_list args; va_start(args, format); - rprintkf(stdout, format, args); + rprintpf(stdout, "\e[30m", format, args); va_end(args); } @@ -509,7 +369,7 @@ void rprintrf(FILE *f, char *format, ...) { void rprintr(char *format, ...) { va_list args; va_start(args, format); - rprintrf(stdout, format, args); + rprintpf(stdout, "\e[31m", format, args); va_end(args); } @@ -523,7 +383,7 @@ void rprintgf(FILE *f, char *format, ...) { void rprintg(char *format, ...) { va_list args; va_start(args, format); - rprintgf(stdout, format, args); + rprintpf(stdout, "\e[32m", format, args); va_end(args); } @@ -537,7 +397,7 @@ void rprintyf(FILE *f, char *format, ...) { void rprinty(char *format, ...) { va_list args; va_start(args, format); - rprintyf(stdout, format, args); + rprintpf(stdout, "\e[33m", format, args); va_end(args); } @@ -549,54 +409,1444 @@ void rprintbf(FILE *f, char *format, ...) { va_end(args); } -void rprintb(char *format, ...) { - va_list args; - va_start(args, format); - rprintbf(stdout, format, args); - va_end(args); -} +void rprintb(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[34m", format, args); + va_end(args); +} + +// Magenta +void rprintmf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[35m", format, args); + va_end(args); +} +void rprintm(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[35m", format, args); + va_end(args); +} + +// Cyan +void rprintcf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[36m", format, args); + va_end(args); +} +void rprintc(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[36m", format, args); + va_end(args); +} + +// White +void rprintwf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[37m", format, args); + va_end(args); +} +void rprintw(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[37m", format, args); + va_end(args); +} +#endif +#ifndef RMATH_H +#define RMATH_H +#include + +#ifndef ceil +double ceil(double x) { + if (x == (double)(long long)x) { + return x; + } else if (x > 0.0) { + return (double)(long long)x + 1.0; + } else { + return (double)(long long)x; + } +} +#endif + +#ifndef floor +double floor(double x) { + if (x >= 0.0) { + return (double)(long long)x; + } else { + double result = (double)(long long)x; + return (result == x) ? result : result - 1.0; + } +} +#endif + +#ifndef modf +double modf(double x, double *iptr) { + double int_part = (x >= 0.0) ? floor(x) : ceil(x); + *iptr = int_part; + return x - int_part; +} +#endif +#endif +#ifndef RMALLOC_H +#define RMALLOC_H +#include +#include +#include + +unsigned long long rmalloc_count = 0; +unsigned long long rmalloc_alloc_count = 0; +unsigned long long int rmalloc_free_count = 0; + +void *rmalloc(size_t size) { + rmalloc_count++; + rmalloc_alloc_count++; + return malloc(size); +} +void *rrealloc(void *obj, size_t size) { + if (obj == NULL) { + rmalloc_count++; + rmalloc_alloc_count++; + } + return realloc(obj, size); +} +void *rfree(void *obj) { + rmalloc_count--; + rmalloc_free_count++; + free(obj); + return NULL; +} + +#define malloc rmalloc +#define realloc rrealloc +#define free rfree + +char *rmalloc_stats() { + static char res[100] = {0}; + sprintf(res, "Memory usage: %lld allocated, %lld freed, %lld in use.", + rmalloc_alloc_count, rmalloc_free_count, rmalloc_count); + return res; +} + +char *rstrdup(char *str) { + + char *res = (char *)strdup(str); + rmalloc_alloc_count++; + rmalloc_count++; + return res; +} + +#endif + +#ifndef RTEST_H +#define RTEST_H +#include +#include +#include +#define debug(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__); + +char *rcurrent_banner; +int rassert_count = 0; +unsigned short rtest_is_first = 1; +unsigned int rtest_fail_count = 0; + +int rtest_end(char *content) { + // Returns application exit code. 0 == success + printf("%s", content); + printf("\n@assertions: %d\n", rassert_count); + printf("@memory: %s\n", rmalloc_stats()); + + if (rmalloc_count != 0) { + printf("MEMORY ERROR\n"); + return rtest_fail_count > 0; + } + return rtest_fail_count > 0; +} + +void rtest_test_banner(char *content, char *file) { + if (rtest_is_first == 1) { + char delimiter[] = "."; + char *d = delimiter; + char f[2048]; + strcpy(f, file); + printf("%s tests", strtok(f, d)); + rtest_is_first = 0; + setvbuf(stdout, NULL, _IONBF, 0); + } + printf("\n - %s ", content); +} + +bool rtest_test_true_silent(char *expr, int res, int line) { + rassert_count++; + if (res) { + return true; + } + rprintrf(stderr, "\nERROR on line %d: %s", line, expr); + rtest_fail_count++; + return false; +} + +bool rtest_test_true(char *expr, int res, int line) { + rassert_count++; + if (res) { + fprintf(stdout, "."); + return true; + } + rprintrf(stderr, "\nERROR on line %d: %s", line, expr); + rtest_fail_count++; + return false; +} +bool rtest_test_false_silent(char *expr, int res, int line) { + return rtest_test_true_silent(expr, !res, line); +} +bool rtest_test_false(char *expr, int res, int line) { + return rtest_test_true(expr, !res, line); +} +void rtest_test_skip(char *expr, int line) { + rprintgf(stderr, "\n @skip(%s) on line %d\n", expr, line); +} +bool rtest_test_assert(char *expr, int res, int line) { + if (rtest_test_true(expr, res, line)) { + return true; + } + rtest_end(""); + exit(40); +} + +#define rtest_banner(content) \ + rcurrent_banner = content; \ + rtest_test_banner(content, __FILE__); +#define rtest_true(expr) rtest_test_true(#expr, expr, __LINE__); +#define rtest_assert(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true(#expr, __valid, __LINE__); \ + }; \ + ; + +#define rassert(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true(#expr, __valid, __LINE__); \ + }; \ + ; +#define rtest_asserts(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true_silent(#expr, __valid, __LINE__); \ + }; +#define rasserts(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true_silent(#expr, __valid, __LINE__); \ + }; +#define rtest_false(expr) \ + rprintf(" [%s]\t%s\t\n", expr == 0 ? "OK" : "NOK", #expr); \ + assert_count++; \ + assert(#expr); +#define rtest_skip(expr) rtest_test_skip(#expr, __LINE__); + +FILE *rtest_create_file(char *path, char *content) { + FILE *fd = fopen(path, "wb"); + + char c; + int index = 0; + + while ((c = content[index]) != 0) { + fputc(c, fd); + index++; + } + fclose(fd); + fd = fopen(path, "rb"); + return fd; +} + +void rtest_delete_file(char *path) { unlink(path); } +#endif +#ifndef RREX3_H +#define RREX3_H +#include +#include +#include +#include +#include +#include +#include +#ifndef RREX3_DEBUG +#define RREX3_DEBUG 0 +#endif + +struct rrex3_t; + +typedef void (*rrex3_function)(struct rrex3_t *); + +typedef struct rrex3_t { + void (*functions[254])(struct rrex3_t *); + void (*slash_functions[254])(struct rrex3_t *); + bool valid; + int match_count; + int match_capacity; + char **matches; + bool exit; + char *__expr; + char *__str; + char *_expr; + char *_str; + char *expr; + char *str; + char *compiled; + bool inside_brackets; + bool inside_parentheses; + bool pattern_error; + bool match_from_start; + char bytecode; + rrex3_function function; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } previous; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } failed; +} rrex3_t; + +static bool isdigitrange(char *s) { + if (!isdigit(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isdigit(*(s + 2)); +} + +static bool isalpharange(char *s) { + if (!isalpha(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isalpha(*(s + 2)); +} + +void rrex3_free_matches(rrex3_t *rrex3) { + if (!rrex3->matches) + return; + for (int i = 0; i < rrex3->match_count; i++) { + free(rrex3->matches[i]); + } + free(rrex3->matches); + rrex3->matches = NULL; + rrex3->match_count = 0; + rrex3->match_capacity = 0; +} + +void rrex3_free(rrex3_t *rrex3) { + if (!rrex3) + return; + if (rrex3->compiled) { + free(rrex3->compiled); + rrex3->compiled = NULL; + } + rrex3_free_matches(rrex3); + free(rrex3); + rrex3 = NULL; +} +static bool rrex3_move(rrex3_t *, bool); +static void rrex3_set_previous(rrex3_t *); +inline static void rrex3_cmp_asterisk(rrex3_t *); +void rrex3_cmp_literal_range(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Range check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char start = *rrex3->expr; + rrex3->expr++; + rrex3->expr++; + char end = *rrex3->expr; + if (*rrex3->str >= start && *rrex3->str <= end) { + rrex3->str++; + rrex3->valid = true; + } else { + rrex3->valid = false; + } + rrex3->expr++; +} + +bool rrex3_is_function(char chr) { + if (chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || + chr == '*') + return true; + return false; +} + +inline static void rrex3_cmp_literal(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + if (*rrex3->expr == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK"); + exit(1); + } + if (rrex3->valid == false) { + rrex3->expr++; + return; + } + if (rrex3->inside_brackets) { + if (isalpharange(rrex3->expr) || isdigitrange(rrex3->expr)) { + rrex3_cmp_literal_range(rrex3); + return; + } + } +#if RREX3_DEBUG == 1 + printf("Literal check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + if (*rrex3->expr == *rrex3->str) { + rrex3->expr++; + rrex3->str++; + rrex3->valid = true; + // if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == + // rrex3_cmp_literal && !rrex3->inside_brackets && + //! rrex3_is_function(*rrex3->expr)){ rrex3_cmp_literal(rrex3); + // if(rrex3->valid == false){ + // rrex3->expr--; + // rrex3->valid = true; + // } + // } + return; + } + rrex3->expr++; + rrex3->valid = false; +} + +inline static void rrex3_cmp_dot(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Dot check (any char): %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + rrex3->expr++; + if (!rrex3->valid) { + return; + } + if (*rrex3->str && *rrex3->str != '\n') { + rrex3->str++; + if (*rrex3->expr && *rrex3->expr == '.') { + rrex3_cmp_dot(rrex3); + return; + } /*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == + '+')){ char * next = strchr(rrex3->str,*(rrex3->expr + 1)); char * + space = strchr(rrex3->str,'\n'); if(next && (!space || space > next)){ + rrex3->str = next; + } + }*/ + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_question_mark(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Question mark check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + if (rrex3->valid == false) + rrex3->valid = true; + rrex3->expr++; +} + +inline static void rrex3_cmp_whitespace(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char c = *rrex3->expr; + rrex3->valid = c == ' ' || c == '\n' || c == '\t'; + if (rrex3->valid) { + rrex3->str++; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_whitespace_upper(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Non whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char c = *rrex3->expr; + rrex3->valid = !(c == ' ' || c == '\n' || c == '\t'); + if (rrex3->valid) { + rrex3->str++; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_plus(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Plus check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + if (rrex3->valid) { + rrex3->str--; + } else { + return; + } + char *original_expr = rrex3->expr; + char *next = original_expr + 1; + char *loop_expr = rrex3->previous.expr - 1; + if (*loop_expr == '+') { + rrex3->valid = false; + rrex3->pattern_error = true; + rrex3->expr++; + return; + } + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *next_next = NULL; + char *next_str = rrex3->str; + while (*rrex3->str) { + // Check if next matches + char *original_str = rrex3->str; + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + success_next = true; + next_next = rrex3->expr; + next_str = rrex3->str; + success_next_once = true; + } else { + success_next = false; + } + if (success_next_once && !success_next) { + break; + } + // Check if current matches + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!*rrex3->str || !rrex3_move(rrex3, false)) { + success_current = false; + } else { + success_current = true; + if (!success_next) { + next_next = rrex3->expr + 1; // +1 is the * itself + next_str = rrex3->str; + } + } + if (success_next && !success_current) { + break; + } + } + if (!next_next) + rrex3->expr = next; + else { + rrex3->expr = next_next; + } + rrex3->str = next_str; + rrex3->valid = true; +} + +inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintg("Asterisk start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + if (!rrex3->valid) { + rrex3->valid = true; + rrex3->expr++; + return; + } + if (*rrex3->previous.expr == '*') { + // Support for ** + rrex3->valid = false; + // rrex3->pattern_error = true; + rrex3->expr++; + return; + } + rrex3->str = rrex3->previous.str; + ; + char *next = rrex3->expr + 1; + char *next_original = NULL; + if (*next == '*') { + next++; + } + if (*next == ')' && *(next + 1)) { + next_original = next; + next++; + } + char *loop_expr = rrex3->previous.expr; + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *right_next = NULL; + char *right_str = rrex3->str; + while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { + // Remember original_str because it's modified + // by checking right and should be restored + // for checking left so they're matching the + // same value. + char *original_str = rrex3->str; + // Check if right matches. + // if(*next != ')'){ + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + // Match rright. + success_next = true; + if (!next_original) { + right_next = rrex3->expr; + } else { + right_next = next_original; + break; + } + right_str = rrex3->str; + success_next_once = true; + } else { + // No match Right. + success_next = false; + } + //} + if (success_next_once && !success_next) { + // Matched previous time but now doesn't. + break; + } + // Check if left matches. + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!rrex3_move(rrex3, false)) { + // No match left. + success_current = false; + } else { + // Match left. + success_current = true; + // NOT SURE< WITHOUT DOET HETZELFDE: + // original_str = rrex3->str; + if (!success_next) { + right_str = rrex3->str; + if (*rrex3->expr != ')') { + right_next = rrex3->expr + 1; // +1 is the * itself + + } else { + + // break; + } + } + } + + if ((success_next && !success_current) || + (!success_next && !success_current)) { + break; + } + } + rrex3->expr = right_next; + rrex3->str = right_str; + rrex3->valid = true; +#if RREX3_DEBUG == 1 + rprintg("Asterisk end check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif +} + +inline static void rrex3_cmp_roof(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); +#if RREX3_DEBUG == 1 + printf("expr, *rrex3->str, rrex3->valid); +#endif + rrex3->valid = rrex3->str == rrex3->_str; + rrex3->match_from_start = true; + rrex3->expr++; +} +inline static void rrex3_cmp_dollar(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + +#if RREX3_DEBUG == 1 + printf("Dollar check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (*rrex3->str || !rrex3->valid) { + rrex3->valid = false; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_w(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} +inline static void rrex3_cmp_w_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_d(rrex3_t *rrex3) { + + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} +inline static void rrex3_cmp_d_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_slash(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; + + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->slash_functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); +} + +inline static int collect_digits(rrex3_t *rrex3) { + char output[20]; + unsigned int digit_count = 0; + while (isdigit(*rrex3->expr)) { + + output[digit_count] = *rrex3->expr; + rrex3->expr++; + digit_count++; + } + output[digit_count] = 0; + return atoi(output); +} + +inline static void rrex3_cmp_range(rrex3_t *rrex3) { + char *loop_code = rrex3->previous.expr; + char *expr_original = rrex3->expr; + rrex3->expr++; + int range_start = collect_digits(rrex3) - 1; + int range_end = 0; + if (*rrex3->expr == ',') { + rrex3->expr++; + range_end = collect_digits(rrex3); + } + rrex3->expr++; + int times_valid = 0; + while (*rrex3->str) { + rrex3->expr = loop_code; + rrex3_move(rrex3, false); + if (rrex3->valid == false) { + break; + } else { + times_valid++; + } + if (range_end) { + if (times_valid >= range_start && times_valid == range_end - 1) { + rrex3->valid = true; + } else { + rrex3->valid = false; + } + break; + } else if (range_start) { + if (times_valid == range_start) { + rrex3->valid = true; + break; + } + } + } + rrex3->valid = times_valid >= range_start; + if (rrex3->valid && range_end) { + rrex3->valid = times_valid <= range_end; + } + rrex3->expr = strchr(expr_original, '}') + 1; +} + +inline static void rrex3_cmp_word_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + bool valid = false; + if (isalpha(*rrex3->str)) { + if (rrex3->_str != rrex3->str) { + if (!isalpha(*(rrex3->str - 1))) { + valid = true; + } + } else { + valid = true; + } + } else if (isalpha(isalpha(*rrex3->str) && !isalpha(*rrex3->str + 1))) { + valid = true; + } + rrex3->expr++; + rrex3->valid = valid; +} +inline static void rrex3_cmp_word_not_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3_cmp_word_start_or_end(rrex3); + rrex3->valid = !rrex3->valid; +} + +inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets start: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + char *original_expr = rrex3->expr; + rrex3->expr++; + rrex3->inside_brackets = true; + bool valid_once = false; + bool reversed = false; + if (*rrex3->expr == '^') { + reversed = true; + rrex3->expr++; + } + bool valid = false; + while (*rrex3->expr != ']' && *rrex3->expr != 0) { + rrex3->valid = true; + valid = rrex3_move(rrex3, false); + if (reversed) { + valid = !valid; + } + if (valid) { + valid_once = true; + if (!reversed) { + valid_once = true; + break; + } + } else { + if (reversed) { + valid_once = false; + break; + } + } + } + if (valid_once && reversed) { + rrex3->str++; + } + while (*rrex3->expr != ']' && *rrex3->expr != 0) + rrex3->expr++; + if (*rrex3->expr != 0) + rrex3->expr++; + + rrex3->valid = valid_once; + rrex3->inside_brackets = false; + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif +} + +inline static void rrex3_cmp_pipe(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + +#if RREX3_DEBUG == 1 + printf("Pipe check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (rrex3->valid == true) { + rrex3->exit = true; + } else { + rrex3->valid = true; + } + rrex3->expr++; +} +inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, + *rrex3->str, rrex3->valid); +#endif + if (!rrex3->valid) { + rrex3->expr++; + return; + } + rrex3_set_previous(rrex3); + if (rrex3->match_count == rrex3->match_capacity) { + + rrex3->match_capacity++; + rrex3->matches = (char **)realloc( + rrex3->matches, rrex3->match_capacity * sizeof(char *)); + } + rrex3->matches[rrex3->match_count] = (char *)malloc(strlen(rrex3->str) + 1); + strcpy(rrex3->matches[rrex3->match_count], rrex3->str); + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->expr++; + rrex3->inside_parentheses = true; + while (*rrex3->expr != ')' && !rrex3->exit) { + rrex3_move(rrex3, false); + } + while (*rrex3->expr != ')') { + rrex3->expr++; + } + rrex3->expr++; + rrex3->inside_parentheses = false; + + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; + if (rrex3->valid == false) { + rrex3->str = original_str; + free(rrex3->matches[rrex3->match_count]); + } else { + rrex3->matches[rrex3->match_count] + [strlen(rrex3->matches[rrex3->match_count]) - + strlen(rrex3->str)] = 0; + rrex3->match_count++; + } +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif +} + +inline static void rrex3_reset(rrex3_t *rrex3) { + rrex3_free_matches(rrex3); + rrex3->valid = true; + rrex3->pattern_error = false; + rrex3->inside_brackets = false; + rrex3->inside_parentheses = false; + rrex3->exit = false; + rrex3->previous.expr = NULL; + rrex3->previous.str = NULL; + rrex3->previous.bytecode = 0; + rrex3->failed.expr = NULL; + rrex3->failed.str = NULL; + rrex3->failed.bytecode = 0; + rrex3->match_from_start = false; +} + +void rrex3_init(rrex3_t *rrex3) { + for (__uint8_t i = 0; i < 254; i++) { + rrex3->functions[i] = rrex3_cmp_literal; + rrex3->slash_functions[i] = rrex3_cmp_literal; + } + rrex3->functions['?'] = rrex3_cmp_question_mark; + rrex3->functions['^'] = rrex3_cmp_roof; + rrex3->functions['$'] = rrex3_cmp_dollar; + rrex3->functions['.'] = rrex3_cmp_dot; + rrex3->functions['*'] = rrex3_cmp_asterisk; + rrex3->functions['+'] = rrex3_cmp_plus; + rrex3->functions['|'] = rrex3_cmp_pipe; + rrex3->functions['\\'] = rrex3_cmp_slash; + rrex3->functions['{'] = rrex3_cmp_range; + rrex3->functions['['] = rrex3_cmp_brackets; + rrex3->functions['('] = rrex3_cmp_parentheses; + rrex3->slash_functions['w'] = rrex3_cmp_w; + rrex3->slash_functions['W'] = rrex3_cmp_w_upper; + rrex3->slash_functions['d'] = rrex3_cmp_d; + rrex3->slash_functions['D'] = rrex3_cmp_d_upper; + rrex3->slash_functions['s'] = rrex3_cmp_whitespace; + rrex3->slash_functions['S'] = rrex3_cmp_whitespace_upper; + rrex3->slash_functions['b'] = rrex3_cmp_word_start_or_end; + rrex3->slash_functions['B'] = rrex3_cmp_word_not_start_or_end; + rrex3->match_count = 0; + rrex3->match_capacity = 0; + rrex3->matches = NULL; + rrex3->compiled = NULL; + + rrex3_reset(rrex3); +} + +rrex3_t *rrex3_new() { + rrex3_t *rrex3 = (rrex3_t *)malloc(sizeof(rrex3_t)); + + rrex3_init(rrex3); + + return rrex3; +} + +rrex3_t *rrex3_compile(rrex3_t *rrex, char *expr) { + + rrex3_t *rrex3 = rrex ? rrex : rrex3_new(); + + char *compiled = (char *)malloc(strlen(expr) + 1); + unsigned int count = 0; + while (*expr) { + if (*expr == '[' && *(expr + 2) == ']') { + *compiled = *(expr + 1); + expr++; + expr++; + } else if (*expr == '[' && *(expr + 1) == '0' && *(expr + 2) == '-' && + *(expr + 3) == '9' && *(expr + 4) == ']') { + *compiled = '\\'; + compiled++; + *compiled = 'd'; + count++; + expr++; + expr++; + expr++; + expr++; + } else { + *compiled = *expr; + } + if (*compiled == '[') { + // in_brackets = true; + + } else if (*compiled == ']') { + // in_brackets = false; + } + expr++; + compiled++; + count++; + } + *compiled = 0; + compiled -= count; + rrex3->compiled = compiled; + return rrex3; +} + +inline static void rrex3_set_previous(rrex3_t *rrex3) { + rrex3->previous.function = rrex3->function; + rrex3->previous.expr = rrex3->expr; + rrex3->previous.str = rrex3->str; + rrex3->previous.bytecode = *rrex3->expr; +} + +static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); + if (!*rrex3->expr && !*rrex3->str) { + + rrex3->exit = true; + return rrex3->valid; + } + if (rrex3->pattern_error) { + rrex3->valid = false; + return rrex3->valid; + } + if (resume_on_fail && !rrex3->valid && *rrex3->expr) { + // rrex3_set_previous(rrex3); + rrex3->failed.bytecode = rrex3->bytecode; + rrex3->failed.function = rrex3->function; + rrex3->failed.expr = original_expr; + rrex3->failed.str = original_str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); + + if (!rrex3->valid && !rrex3->pattern_error) { + + if (*rrex3->str) { + char *pipe_position = strstr(rrex3->expr, "|"); + if (pipe_position != NULL) { + rrex3->expr = pipe_position + 1; + rrex3->str = rrex3->_str; + rrex3->valid = true; + return true; + } + } + if (rrex3->match_from_start) { + rrex3->valid = false; + return rrex3->valid; + } + if (!*rrex3->str++) { + rrex3->valid = false; + return rrex3->valid; + } + rrex3->expr = rrex3->_expr; + if (rrex3->str) + rrex3->valid = true; + } + } + return rrex3->valid; +} + +rrex3_t *rrex3(rrex3_t *rrex3, char *str, char *expr) { +#if RREX3_DEBUG == 1 + printf("Regex check: %s:%s:%d\n", expr, str, 1); +#endif + bool self_initialized = false; + if (rrex3 == NULL) { + self_initialized = true; + rrex3 = rrex3_new(); + } else { + rrex3_reset(rrex3); + } + + rrex3->_str = str; + rrex3->_expr = rrex3->compiled ? rrex3->compiled : expr; + rrex3->str = rrex3->_str; + rrex3->expr = rrex3->_expr; + while (*rrex3->expr && !rrex3->exit) { + if (!rrex3_move(rrex3, true)) + return NULL; + } + if (rrex3->valid) { + return rrex3; + } else { + if (self_initialized) { + rrex3_free(rrex3); + } + return NULL; + } +} + +void rrex3_test() { + rrex3_t *rrex = rrex3_new(); + + assert(rrex3(rrex, "aaaaaaa", "a*a$")); + + // assert(rrex3("ababa", "a*b*a*b*a$")); + assert(rrex3(rrex, "#include\"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "#include \"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "aaaaaad", "a*d$")); + assert(rrex3(rrex, "abcdef", "abd?cdef")); + assert(!rrex3(rrex, "abcdef", "abd?def")); + assert(rrex3(rrex, "abcdef", "def")); + assert(!rrex3(rrex, "abcdef", "^def")); + assert(rrex3(rrex, "abcdef", "def$")); + assert(!rrex3(rrex, "abcdef", "^abc$")); + assert(rrex3(rrex, "aB!.#1", "......")); + assert(!rrex3(rrex, "aB!.#\n", " ......")); + assert(!rrex3(rrex, "aaaaaad", "q+d$")); + assert(rrex3(rrex, "aaaaaaa", "a+a$")); + assert(rrex3(rrex, "aaaaaad", "q*d$")); + assert(!rrex3(rrex, "aaaaaad", "^q*d$")); + + // Asterisk function + assert(rrex3(rrex, "123321", "123*321")); + assert(rrex3(rrex, "pony", "p*ony")); + assert(rrex3(rrex, "pppony", "p*ony")); + assert(rrex3(rrex, "ppony", "p*pony")); + assert(rrex3(rrex, "pppony", "pp*pony")); + assert(rrex3(rrex, "pppony", ".*pony")); + assert(rrex3(rrex, "pony", ".*ony")); + assert(rrex3(rrex, "pony", "po*ny")); + // assert(rrex3(rrex,"ppppony", "p*pppony")); + + // Plus function + assert(rrex3(rrex, "pony", "p+ony")); + assert(!rrex3(rrex, "ony", "p+ony")); + assert(rrex3(rrex, "ppony", "p+pony")); + assert(rrex3(rrex, "pppony", "pp+pony")); + assert(rrex3(rrex, "pppony", ".+pony")); + assert(rrex3(rrex, "pony", ".+ony")); + assert(rrex3(rrex, "pony", "po+ny")); + + // Slash functions + assert(rrex3(rrex, "a", "\\w")); + assert(!rrex3(rrex, "1", "\\w")); + assert(rrex3(rrex, "1", "\\W")); + assert(!rrex3(rrex, "a", "\\W")); + assert(rrex3(rrex, "a", "\\S")); + assert(!rrex3(rrex, " ", "\\s")); + assert(!rrex3(rrex, "\t", "\\s")); + assert(!rrex3(rrex, "\n", "\\s")); + assert(rrex3(rrex, "1", "\\d")); + assert(!rrex3(rrex, "a", "\\d")); + assert(rrex3(rrex, "a", "\\D")); + assert(!rrex3(rrex, "1", "\\D")); + assert(rrex3(rrex, "abc", "\\b")); + + assert(rrex3(rrex, "abc", "\\babc")); + assert(!rrex3(rrex, "abc", "a\\b")); + assert(!rrex3(rrex, "abc", "ab\\b")); + assert(!rrex3(rrex, "abc", "abc\\b")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + assert(rrex3(rrex, "abc", "ab\\B")); + assert(!rrex3(rrex, "1ab", "1\\Bab")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + + // Escaping of special characters test. + assert(rrex3(rrex, "()+*.\\", "\\(\\)\\+\\*\\.\\\\")); + + // Pipe + // assert(rrex3(rrex,"abc","abc|def")); + assert(rrex3(rrex, "abc", "def|jkl|abc")); + assert(rrex3(rrex, "abc", "abc|def")); + + assert(rrex3(rrex, "rhq", "def|rhq|rha")); + assert(rrex3(rrex, "abc", "abc|def")); + + // Repeat + assert(rrex3(rrex, "aaaaa", "a{4}")); + + assert(rrex3(rrex, "aaaa", "a{1,3}a")); + + // Range + assert(rrex3(rrex, "abc", "[abc][abc][abc]$")); + assert(rrex3(rrex, "def", "[^abc][^abc][^abc]$")); + assert(rrex3(rrex, "defabc", "[^abc][^abc][^abc]abc")); + assert(rrex3(rrex, "0-9", "0-9")); + assert(rrex3(rrex, "55-9", "[^6-9]5-9$")); + assert(rrex3(rrex, "a", "[a-z]$")); + assert(rrex3(rrex, "A", "[A-Z]$")); + assert(rrex3(rrex, "5", "[0-9]$")); + assert(!rrex3(rrex, "a", "[^a-z]$")); + assert(!rrex3(rrex, "A", "[^A-Z]$")); + assert(!rrex3(rrex, "5", "[^0-9]$")); + assert(rrex3(rrex, "123abc", "[0-9]*abc$")); + assert(rrex3(rrex, "123123", "[0-9]*$")); + + // Parentheses + + assert(rrex3(rrex, "datadata", "(data)*")); + + assert(rrex3(rrex, "datadatapony", "(data)*pony$")); + + assert(!rrex3(rrex, "datadatapony", "(d*p*ata)*pond$")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato$")); + assert(!rrex3(rrex, "datadatadato", "(d*p*a*ta)*gato$")); + + // Matches + assert(rrex3(rrex, "123", "(123)")); + assert(!strcmp(rrex->matches[0], "123")); + + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); + + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); + + assert(rrex3(rrex, "aaaabc", "(.*)c")); + + assert(rrex3(rrex, "abcde", ".....$")); + + assert(rrex3(rrex, "abcdefghijklmnopqrstuvwxyz", + "..........................$")); + // printf("(%d)\n", rrex->valid); + + assert(rrex3(rrex, " #include ", "#include.*<(.*)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + /* + assert(rrex3(rrex, " #include ", "#include.+<(.+)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.+\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + */ + // assert(rrex3(rrex,"char pony() { + // }","\\b\\w+(\\s+\\*+)?\\s+\\w+\\s*\\([^)]*\\)\s*\\{[^{}]*\\}")); + + rrex3_free(rrex); +} +#endif +#ifndef RARENA_H +#define RARENA_H + +#include +#include + +typedef struct arena_t { + unsigned char *memory; + unsigned int pointer; + unsigned int size; +} arena_t; + +arena_t *arena_construct() { + arena_t *arena = (arena_t *)rmalloc(sizeof(arena_t)); + arena->memory = NULL; + arena->pointer = 0; + arena->size = 0; + return arena; +} + +arena_t *arena_new(size_t size) { + arena_t *arena = arena_construct(); + arena->memory = (unsigned char *)rmalloc(size); + arena->size = size; + return arena; +} + +void *arena_alloc(arena_t *arena, size_t size) { + if (arena->pointer + size > arena->size) { + return NULL; + } + void *p = arena->memory + arena->pointer; + arena->pointer += size; + return p; +} + +void arena_free(arena_t *arena) { + // Just constructed and unused arena memory is NULL so no free needed + if (arena->memory) { + rfree(arena->memory); + } + rfree(arena); +} + +void arena_reset(arena_t *arena) { arena->pointer = 0; } +#endif +#ifndef RLIB_RIO +#define RLIB_RIO +#include +#include +#include +#include +#include +#include +#include +#include + +bool rfile_exists(char *path) { + struct stat s; + return !stat(path, &s); +} + +void rjoin_path(char *p1, char *p2, char *output) { + output[0] = 0; + strcpy(output, p1); + + if (output[strlen(output) - 1] != '/') { + char slash[] = "/"; + strcat(output, slash); + } + if (p2[0] == '/') { + p2++; + } + strcat(output, p2); +} + +int risprivatedir(const char *path) { + struct stat statbuf; + + if (stat(path, &statbuf) != 0) { + perror("stat"); + return -1; + } + + if (!S_ISDIR(statbuf.st_mode)) { + return -2; + } + + if ((statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == S_IRWXU) { + return 1; // Private (owner has all permissions, others have none) + } + + return 0; +} +bool risdir(const char *path) { return !risprivatedir(path); } + +void rforfile(char *path, void callback(char *)) { + if (!rfile_exists(path)) + return; + DIR *dir = opendir(path); + struct dirent *d; + while ((d = readdir(dir)) != NULL) { + if (!d) + break; + + if ((d->d_name[0] == '.' && strlen(d->d_name) == 1) || + d->d_name[1] == '.') { + continue; + } + char full_path[4096]; + rjoin_path(path, d->d_name, full_path); + + if (risdir(full_path)) { + callback(full_path); + rforfile(full_path, callback); + } else { + callback(full_path); + } + } + closedir(dir); +} + +bool rfd_wait(int fd, int ms) { + fd_set read_fds; + struct timeval timeout; -// Magenta -void rprintmf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[35m", format, args); - va_end(args); -} -void rprintm(char *format, ...) { - va_list args; - va_start(args, format); - rprintmf(stdout, format, args); - va_end(args); -} + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); -// Cyan -void rprintcf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[36m", format, args); - va_end(args); + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * ms; // 100 milliseconds timeout + + int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); + return ret > 0 && FD_ISSET(fd, &read_fds); } -void rprintc(char *format, ...) { - va_list args; - va_start(args, format); - rprintcf(stdout, format, args); - va_end(args); + +bool rfd_wait_forever(int fd) { + while ((!rfd_wait(fd, 10))) { + } + return true; } -// White -void rprintwf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[37m", format, args); - va_end(args); +size_t rfile_size(char *path) { + struct stat s; + stat(path, &s); + return s.st_size; } -void rprintw(char *format, ...) { - va_list args; - va_start(args, format); - rprintwf(stdout, format, args); - va_end(args); + +size_t rfile_readb(char *path, void *data, size_t size) { + FILE *fd = fopen(path, "r"); + if (!fd) { + return 0; + } + __attribute__((unused)) size_t bytes_read = + fread(data, size, sizeof(char), fd); + + fclose(fd); + return size; } + #endif #ifndef RSTRING_H #define RSTRING_H @@ -608,6 +1858,60 @@ void rprintw(char *format, ...) { unsigned long _r_generate_key_current = 0; +char *_rcat_int_int(int a, int b) { + static char res[20]; + res[0] = 0; + sprintf(res, "%d%d", a, b); + return res; +} +char *_rcat_int_double(int a, double b) { + static char res[20]; + res[0] = 0; + sprintf(res, "%d%f", a, b); + return res; +} + +char *_rcat_charp_int(char *a, int b) { + char res[20]; + sprintf(res, "%c", b); + return strcat(a, res); +} + +char *_rcat_charp_double(char *a, double b) { + char res[20]; + sprintf(res, "%f", b); + return strcat(a, res); +} + +char *_rcat_charp_charp(char *a, char *b) { + ; + return strcat(a, b); +} +char *_rcat_charp_char(char *a, char b) { + char extra[] = {b, 0}; + return strcat(a, extra); +} +char *_rcat_charp_bool(char *a, bool *b) { + if (b) { + return strcat(a, "true"); + } else { + return strcat(a, "false"); + } +} + +#define rcat(x, y) \ + _Generic((x), \ + int: _Generic((y), \ + int: _rcat_int_int,\ + double: _rcat_int_double,\ + char*: _rcat_charp_charp),\ + char*: _Generic((y),\ + int: _rcat_charp_int, \ + double: _rcat_charp_double,\ + char*: _rcat_charp_charp, \ + char: _rcat_charp_char, \ + bool: _rcat_charp_bool))((x),(y)) + char *rgenerate_key() { _r_generate_key_current++; static char key[100]; @@ -774,6 +2078,45 @@ int rstrip_whitespace(char *input, char *output) { } return count; } + +void rstrtocstring(const char *input, char *output) { + int index = 0; + char clean_input[strlen(input) * 2]; + char *iptr = clean_input; + rstraddslashes(input, clean_input); + output[index] = '"'; + index++; + while (*iptr) { + if (*iptr == '"') { + output[index] = '\\'; + output++; + } else if (*iptr == '\\' && *(iptr + 1) == 'n') { + output[index] = '\\'; + output++; + output[index] = 'n'; + output++; + output[index] = '"'; + output++; + output[index] = '\n'; + output++; + output[index] = '"'; + output++; + iptr++; + iptr++; + continue; + } + output[index] = *iptr; + index++; + iptr++; + } + if (output[index - 1] == '"' && output[index - 2] == '\n') { + output[index - 1] = 0; + } else if (output[index - 1] != '"') { + output[index] = '"'; + output[index + 1] = 0; + } +} + size_t rstrtokline(char *input, char *output, size_t offset, bool strip_nl) { size_t len = strlen(input); @@ -925,113 +2268,6 @@ int rstrsort(char *input, char *output) { #include #include #include -#ifndef RTEST_H -#define RTEST_H -#include -#include -#include -#include -#define debug(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__); - -char *rcurrent_banner; -int rassert_count = 0; -unsigned short rtest_is_first = 1; -unsigned int rtest_fail_count = 0; - -int rtest_end(char *content) { - // Returns application exit code. 0 == success - printf("%s", content); - printf("\n@assertions: %d\n", rassert_count); - printf("@memory: %s\n", rmalloc_stats()); - - if (rmalloc_count != 0) { - printf("MEMORY ERROR\n"); - return rtest_fail_count > 0; - } - return rtest_fail_count > 0; -} - -void rtest_test_banner(char *content, char *file) { - if (rtest_is_first == 1) { - char delimiter[] = "."; - char *d = delimiter; - char f[2048]; - strcpy(f, file); - printf("%s tests", strtok(f, d)); - rtest_is_first = 0; - setvbuf(stdout, NULL, _IONBF, 0); - } - printf("\n - %s ", content); -} - -bool rtest_test_true_silent(char *expr, int res, int line) { - rassert_count++; - if (res) { - return true; - } - rprintrf(stderr, "\nERROR on line %d: %s", line, expr); - rtest_fail_count++; - return false; -} - -bool rtest_test_true(char *expr, int res, int line) { - rassert_count++; - if (res) { - fprintf(stdout, "."); - return true; - } - rprintrf(stderr, "\nERROR on line %d: %s", line, expr); - rtest_fail_count++; - return false; -} -bool rtest_test_false_silent(char *expr, int res, int line) { - return rtest_test_true_silent(expr, !res, line); -} -bool rtest_test_false(char *expr, int res, int line) { - return rtest_test_true(expr, !res, line); -} -void rtest_test_skip(char *expr, int line) { - rprintgf(stderr, "\n @skip(%s) on line %d\n", expr, line); -} -bool rtest_test_assert(char *expr, int res, int line) { - if (rtest_test_true(expr, res, line)) { - return true; - } - rtest_end(""); - exit(40); -} - -#define rtest_banner(content) \ - rcurrent_banner = content; \ - rtest_test_banner(content, __FILE__); -#define rtest_true(expr) rtest_test_true(#expr, expr, __LINE__); -#define rtest_assert(expr) rtest_test_true(#expr, expr, __LINE__); -#define rassert(expr) rtest_test_assert(#expr, expr, __LINE__); -#define rtest_asserts(expr) rtest_test_true_silent(#expr, expr, __LINE__); -#define rasserts(expr) rtest_test_true_silent(#expr, expr, __LINE__); -#define rtest_false(expr) \ - rprintf(" [%s]\t%s\t\n", expr == 0 ? "OK" : "NOK", #expr); \ - assert_count++; \ - assert(#expr); -#define rtest_skip(expr) rtest_test_skip(#expr, __LINE__); - -FILE *rtest_create_file(char *path, char *content) { - FILE *fd = fopen(path, "wb"); - - char c; - int index = 0; - - while ((c = content[index]) != 0) { - fputc(c, fd); - index++; - } - fclose(fd); - fd = fopen(path, "rb"); - return fd; -} - -void rtest_delete_file(char *path) { unlink(path); } -#endif char *rfcaptured = NULL; @@ -1215,6 +2451,272 @@ void rlib_test_progressbar() { rassert(pbar->percentage == 1); } +#endif +#ifndef RTERM_H +#define RTERM_H +#include +#include +#include +#include +#include +#include +#include + +typedef struct winsize winsize_t; + +typedef struct rshell_keypress_t { + bool pressed; + bool ctrl; + bool shift; + bool escape; + char c; + int ms; + int fd; +} rshell_keypress_t; + +typedef struct rterm_t { + bool show_cursor; + bool show_footer; + rshell_keypress_t key; + void (*before_cursor_move)(struct rterm_t *); + void (*after_cursor_move)(struct rterm_t *); + void (*after_key_press)(struct rterm_t *); + void (*before_key_press)(struct rterm_t *); + void (*before_draw)(struct rterm_t *); + void *session; + unsigned long iterations; + void (*tick)(struct rterm_t *); + char *status_text; + winsize_t size; + struct { + int x; + int y; + int pos; + int available; + } cursor; +} rterm_t; + +typedef void (*rterm_event)(rterm_t *); + +void rterm_init(rterm_t *rterm) { + memset(rterm, 0, sizeof(rterm_t)); + rterm->show_cursor = true; + rterm->show_cursor = true; +} + +void rterm_getwinsize(winsize_t *w) { + // Get the terminal size + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, w) == -1) { + perror("ioctl"); + exit(EXIT_FAILURE); + } +} + +// Terminal setup functions +void enableRawMode(struct termios *orig_termios) { + struct termios raw = *orig_termios; + raw.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echoing + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; // Set timeout for read input + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); +} + +void disableRawMode(struct termios *orig_termios) { + tcsetattr(STDIN_FILENO, TCSAFLUSH, + orig_termios); // Restore original terminal settings +} + +void rterm_clear_screen() { + printf("\x1b[2J"); // Clear the entire screen + printf("\x1b[H"); // Move cursor to the home position (0,0) +} + +void setBackgroundColor() { + printf("\x1b[44m"); // Set background color to blue +} + +void rterm_move_cursor(int x, int y) { + + printf("\x1b[%d;%dH", y + 1, x + 1); // Move cursor to (x, y) +} + +void cursor_set(rterm_t *rt, int x, int y) { + rt->cursor.x = x; + rt->cursor.y = y; + rt->cursor.pos = y * rt->size.ws_col + x; + rterm_move_cursor(rt->cursor.x, rt->cursor.y); +} +void cursor_restore(rterm_t *rt) { + rterm_move_cursor(rt->cursor.x, rt->cursor.y); +} + +void rterm_print_status_bar(rterm_t *rt, char c, unsigned long i) { + winsize_t ws = rt->size; + rterm_move_cursor(0, ws.ws_row - 1); + + char output_str[1024]; + output_str[0] = 0; + + // strcat(output_str, "\x1b[48;5;240m"); + + for (int i = 0; i < ws.ws_col; i++) { + strcat(output_str, " "); + } + char content[500]; + content[0] = 0; + if (!rt->status_text) { + sprintf(content, "\rp:%d:%d | k:%c:%d | i:%ld ", rt->cursor.x + 1, + rt->cursor.y + 1, c == 0 ? '0' : c, c, i); + } else { + sprintf(content, "\r%s", rt->status_text); + } + strcat(output_str, content); + // strcat(output_str, "\x1b[0m"); + printf("%s", output_str); + cursor_restore(rt); +} + +void rterm_show_cursor() { + printf("\x1b[?25h"); // Show the cursor +} + +void rterm_hide_cursor() { + printf("\x1b[?25l"); // Hide the cursor +} + +rshell_keypress_t rshell_getkey() { + static rshell_keypress_t press; + press.c = 0; + press.ctrl = false; + press.shift = false; + press.escape = false; + press.pressed = rfd_wait(0, 100); + if (press.pressed) { + press.c = getchar(); + } + char ch = press.c; + if (ch == '\x1b') { + // Get detail + ch = getchar(); + + if (ch == '[') { + // non char key: + press.escape = true; + + ch = getchar(); // is a number. 1 if shift + arrow + press.c = ch; + if (ch >= '0' && ch <= '9') + ch = getchar(); + press.c = ch; + if (ch == ';') { + ch = getchar(); + press.c = ch; + if (ch == '5') { + press.ctrl = true; + press.c = getchar(); // De arrow + } + } + } else { + press.c = ch; + } + } + return press; +} + +// Main function +void rterm_loop(rterm_t *rt) { + struct termios orig_termios; + tcgetattr(STDIN_FILENO, &orig_termios); // Get current terminal attributes + enableRawMode(&orig_termios); + + int x = 0, y = 0; // Initial cursor position + char ch = 0; + ; + while (1) { + rterm_getwinsize(&rt->size); + rt->cursor.available = rt->size.ws_col * rt->size.ws_row; + if (rt->tick) { + rt->tick(rt); + } + + rterm_hide_cursor(); + // setBackgroundColor(); + rterm_clear_screen(); + if (rt->before_draw) { + rt->before_draw(rt); + } + rterm_print_status_bar(rt, ch, rt->iterations); + if (!rt->iterations || (x != rt->cursor.x || y != rt->cursor.y)) { + if (y == rt->size.ws_row) { + y--; + } + if (y < 0) { + y = 0; + } + rt->cursor.x = x; + rt->cursor.y = y; + if (rt->before_cursor_move) + rt->before_cursor_move(rt); + cursor_set(rt, rt->cursor.x, rt->cursor.y); + if (rt->after_cursor_move) + rt->after_cursor_move(rt); + x = rt->cursor.x; + y = rt->cursor.y; + } + if (rt->show_cursor) + rterm_show_cursor(); + fflush(stdout); + + rt->key = rshell_getkey(); + if (rt->key.pressed && rt->before_key_press) { + rt->before_key_press(rt); + } + rshell_keypress_t key = rt->key; + ch = key.c; + if (ch == 'q') + break; // Press 'q' to quit + + // Escape + if (key.escape) { + switch (key.c) { + case 65: // Move up + if (y > -1) + y--; + break; + case 66: // Move down + if (y < rt->size.ws_row) + y++; + break; + case 68: // Move left + if (x > 0) + x--; + if (key.ctrl) + x -= 4; + break; + case 67: // Move right + if (x < rt->size.ws_col) { + x++; + } + if (key.ctrl) { + x += 4; + } + break; + } + } + if (rt->key.pressed && rt->after_key_press) { + rt->after_key_press(rt); + } + rt->iterations++; + + // usleep (1000); + } + + // Cleanup + printf("\x1b[0m"); // Reset colors + rterm_clear_screen(); + disableRawMode(&orig_termios); +} #endif #ifndef RTREE_H #define RTREE_H @@ -1701,6 +3203,41 @@ char *rlex_format(char *content) { #include #include +#define RBENCH(times, action) \ + { \ + unsigned long utimes = (unsigned long)times; \ + nsecs_t start = nsecs(); \ + for (unsigned long i = 0; i < utimes; i++) { \ + { action; } \ + } \ + nsecs_t end = nsecs(); \ + printf("%s\n", format_time(end - start)); \ + } + +#define RBENCHP(times, action) \ + { \ + printf("\n"); \ + nsecs_t start = nsecs(); \ + unsigned int prev_percentage = 0; \ + unsigned long utimes = (unsigned long)times; \ + for (unsigned long i = 0; i < utimes; i++) { \ + unsigned int percentage = \ + ((long double)i / (long double)times) * 100; \ + int percentage_changed = percentage != prev_percentage; \ + __attribute__((unused)) int first = i == 0; \ + __attribute__((unused)) int last = i == utimes - 1; \ + { action; }; \ + if (percentage_changed) { \ + printf("\r%d%%", percentage); \ + fflush(stdout); \ + \ + prev_percentage = percentage; \ + } \ + } \ + nsecs_t end = nsecs(); \ + printf("\r%s\n", format_time(end - start)); \ + } + struct rbench_t; typedef struct rbench_function_t { @@ -1864,8 +3401,10 @@ rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, } void rbench_execute_finish(rbench_t *r) { rbench_toggle_stdout(r); - free(r->progress_bar); - r->progress_bar = NULL; + if (r->progress_bar) { + free(r->progress_bar); + r->progress_bar = NULL; + } r->current->average_execution_time = r->current->total_execution_time / r->current->times_executed; ; diff --git a/rrex.h b/rrex.h index 999de32..4bcfbd3 100644 --- a/rrex.h +++ b/rrex.h @@ -17,26 +17,6 @@ bool latleast(char *s, unsigned int l) { return false; } -bool isdigitrange(char *s) { - if (!isdigit(*s)) { - return false; - } - if (*(s + 1) != '-') { - return false; - } - return isdigit(*(s + 2)); -} - -bool isalpharange(char *s) { - if (!isalpha(*s)) { - return false; - } - if (*(s + 1) != '-') { - return false; - } - return isalpha(*(s + 2)); -} - bool long_enough(char *s, char *n) { while (++(*n)) { if (!(++(*s))) diff --git a/rrex2.c b/rrex2.c index f0f2626..678264f 100644 --- a/rrex2.c +++ b/rrex2.c @@ -118,6 +118,8 @@ bool validate_dutch_zipcode_rrex(char *s) { void benchmark_dutch_zipcode(long times, char *s) { rbench_t *r = rbench_new(); + r->show_progress = false; + r->stdout = false; r->add_function(r, "rrex", "zipcode", (void *)validate_dutch_zipcode_rrex); r->add_function(r, "rrex compiled", "zipcode", (void *)validate_dutch_zipcode_rrex_precompiled); @@ -137,6 +139,7 @@ void benchmark(long times, char *s, char *e) { rprint("Benchmark \\l string:<%s> expr:<%s>\t\n", s, e); rbench_t *r; r = rbench_new(); + r->show_progress = false; r->stdout = false; r->add_function(r, "executor", "rrex", (void *)rrex_repeat); r->add_function(r, "executor", "clib", (void *)cregex_repeat); @@ -163,7 +166,7 @@ void rrex_benchmark_tests(long times) { benchmark(times, "ce", "(a|b|c|d)e"); benchmark(times, "a", "(a)"); benchmark(times, "aa", "(a){2}"); - benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaq", "[^xyzv]+q$"); + // benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaq", "[^xyzv]+q$"); benchmark(times, "abcabcabcabcabcabc", "[acb][acb]{4}"); benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "[1A-Z0-9a12345]{33}"); diff --git a/rrex3 b/rrex3 index 38e38872b4c23b7219f8ad563e093506a9198533..f31d46f5f8fa1629df17a83a8de283db2d3ac468 100755 GIT binary patch literal 84304 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
    }7oND~eyM<7avr> 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 x{LcZ(X9cYPw*TdQH|x6u)Q= - +#include "../rlib/rlib.h" +#include -void benchmark(int times, char * str, char * expr){ +void benchmark(int times, char *str, char *expr) { - regmatch_t matches[10]; - printf("Matching \"%s\" with \"%s\".\n",str,expr); - regex_t regex; - if(regcomp(®ex,expr,REG_EXTENDED)){ - printf("Creg: error in regular expression.\n"); - exit(1); - } + regmatch_t matches[10]; + printf("Matching \"%s\" with \"%s\".\n", str, expr); + regex_t regex; + if (regcomp(®ex, expr, REG_EXTENDED)) { + printf("Creg: error in regular expression.\n"); + exit(1); + } printf("creg: "); - RBENCH(times,{ - - if(regexec(®ex,str,0,&matches,0)){ + RBENCH(times, { + if (regexec(®ex, str, 0, matches, 0)) { printf("Creg: error executing regular expression.\n"); } - }) - regfree(®ex); ; - rrex3_t * rrex = rrex3_compile(NULL,expr); - printf("Compiled!\n"); - printf("rrex3 (%s): ",rrex->compiled); + regfree(®ex); + ; + rrex3_t *rrex = rrex3_compile(NULL, expr); + printf("rrex3 (%s): ", rrex->compiled); RBENCH(times, { - rrex3(rrex, str,expr); - if(rrex){ - - }else{ + rrex3(rrex, str, expr); + if (rrex) { + + } else { printf("Rrex3: error\n"); } }); - rrex3_free(rrex); + rrex3_free(rrex); printf("\n"); } int main() { rrex3_test(); - //int times = 5000000; - int times = 100; - benchmark(times, "abcdefghijklmnopqrstuvwxyz","abcdefghijklmnopqrstuvwxyz$"); - benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaaa$"); - benchmark(times, "abcdefghijklmnopqrstuvwxyz","..........................$"); - + int times = 5000000; + // int times = 1; + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyz$"); + benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaa$"); + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "..........................$"); + // [abcm] failed - benchmark(times, "abcdefghijklmnopqrstuvwxyz",".*z"); - benchmark(times, "abcde",".*e"); - benchmark(times, "abcdef",".*f"); - - benchmark(times, "abcdefghijklmnopqrstuvwxyz","[a]b*c+d\\w[f-g][g][h-i][i][^a][abcdefgk][l][m][n][o][p][a-z][r][s][t][u][v][w].*z$"); - benchmark(times, "zzz", "[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz]$"); + benchmark(times, "abcdefghijklmnopqrstuvwxyz", ".*z"); + benchmark(times, "abcde", ".*e"); + benchmark(times, "abcdef", ".*f"); - benchmark(times, "7245 Sr","[0-9][0-9][0-9][0-9] \\w\\w$"); + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "[a]b*c+d\\w[f-g][g][h-i][i][^a][abcdefgk][l][m][n][o][p][a-z][r]" + "[s][t][u][v][w].*z$"); + benchmark(times, "zzz", + "[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz][" + "abcdefghijklmnopqrstuvwxyz]$"); - benchmark(times, "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyzesting","[z-z][e-e]"); - benchmark(times, "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyzesting","zesting"); - benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"","\"(.*)\"\"(.*)\"\"(.*)\""); + benchmark(times, "7245 Sr", "[0-9][0-9][0-9][0-9] ?\\w\\w$"); + benchmark(times, + "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmn" + "opqrstuvwxyzesting", + "[z-z][e-e]"); + benchmark(times, + "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmn" + "opqrstuvwxyzesting", + "zesting"); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\".*\"\".*\"\".*\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\".+\"\".+\"\".+\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\""); } \ No newline at end of file diff --git a/rrex3.h b/rrex3.h index cb13c7a..cdc1e64 100644 --- a/rrex3.h +++ b/rrex3.h @@ -1,23 +1,15 @@ +#ifndef RREX3_H +#define RREX3_H +#include +#include #include #include +#include #include #include - -#ifdef RLIB_H - #define malloc rmalloc - #define free rfree -#else - #include -#endif -#include #ifndef RREX3_DEBUG #define RREX3_DEBUG 0 -#endif -#ifdef RLIB_H - #define assert rassert -#else - #include -#endif +#endif struct rrex3_t; @@ -29,12 +21,12 @@ typedef struct rrex3_t { bool valid; int match_count; int match_capacity; - char ** matches; + char **matches; bool exit; - char * __expr; - char * __str; - char * _expr; - char * _str; + char *__expr; + char *__str; + char *_expr; + char *_str; char *expr; char *str; char *compiled; @@ -78,24 +70,22 @@ static bool isalpharange(char *s) { return isalpha(*(s + 2)); } -void rrex3_free_matches(rrex3_t *rrex3){ - if(!rrex3->matches) +void rrex3_free_matches(rrex3_t *rrex3) { + if (!rrex3->matches) return; - for(int i = 0; i < rrex3->match_capacity - 1; i++) -{ + for (int i = 0; i < rrex3->match_count; i++) { free(rrex3->matches[i]); - } free(rrex3->matches); - rrex3->matches = NULL; + rrex3->matches = NULL; rrex3->match_count = 0; rrex3->match_capacity = 0; } void rrex3_free(rrex3_t *rrex3) { - if(!rrex3) + if (!rrex3) return; - if(rrex3->compiled){ + if (rrex3->compiled) { free(rrex3->compiled); rrex3->compiled = NULL; } @@ -125,16 +115,17 @@ void rrex3_cmp_literal_range(rrex3_t *rrex3) { rrex3->expr++; } -bool rrex3_is_function(char chr){ - if(chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || chr == '*') +bool rrex3_is_function(char chr) { + if (chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || + chr == '*') return true; return false; } inline static void rrex3_cmp_literal(rrex3_t *rrex3) { rrex3_set_previous(rrex3); - if(*rrex3->expr == 0 && !*rrex3->str){ - rprintr("ERROR, EMPTY CHECK"); + if (*rrex3->expr == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK"); exit(1); } if (rrex3->valid == false) { @@ -155,13 +146,14 @@ inline static void rrex3_cmp_literal(rrex3_t *rrex3) { rrex3->expr++; rrex3->str++; rrex3->valid = true; - /*if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == rrex3_cmp_literal && !rrex3->inside_brackets && !rrex3_is_function(*rrex3->expr)){ - rrex3_cmp_literal(rrex3); - if(rrex3->valid == false){ - rrex3->expr--; - rrex3->valid = true; - } - }*/ + // if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == + // rrex3_cmp_literal && !rrex3->inside_brackets && + //! rrex3_is_function(*rrex3->expr)){ rrex3_cmp_literal(rrex3); + // if(rrex3->valid == false){ + // rrex3->expr--; + // rrex3->valid = true; + // } + // } return; } rrex3->expr++; @@ -178,18 +170,17 @@ inline static void rrex3_cmp_dot(rrex3_t *rrex3) { if (!rrex3->valid) { return; } - if (*rrex3->str != '\n') { + if (*rrex3->str && *rrex3->str != '\n') { rrex3->str++; - if(*rrex3->expr && *rrex3->expr == '.'){ + if (*rrex3->expr && *rrex3->expr == '.') { rrex3_cmp_dot(rrex3); return; - }/*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == '+')){ - char * next = strchr(rrex3->str,*(rrex3->expr + 1)); - char * space = strchr(rrex3->str,'\n'); - if(next && (!space || space > next)){ - rrex3->str = next; - } - }*/ + } /*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == + '+')){ char * next = strchr(rrex3->str,*(rrex3->expr + 1)); char * + space = strchr(rrex3->str,'\n'); if(next && (!space || space > next)){ + rrex3->str = next; + } + }*/ } else { rrex3->valid = false; } @@ -282,7 +273,7 @@ inline static void rrex3_cmp_plus(rrex3_t *rrex3) { rrex3->str = original_str; rrex3->expr = loop_expr; rrex3->valid = true; - if (!rrex3_move(rrex3, false)) { + if (!*rrex3->str || !rrex3_move(rrex3, false)) { success_current = false; } else { success_current = true; @@ -307,7 +298,7 @@ inline static void rrex3_cmp_plus(rrex3_t *rrex3) { inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { #if RREX3_DEBUG == 1 rprintg("Asterisk start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); + rrex3->valid); #endif if (!rrex3->valid) { rrex3->valid = true; @@ -317,20 +308,20 @@ inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { if (*rrex3->previous.expr == '*') { // Support for ** rrex3->valid = false; - //rrex3->pattern_error = true; + // rrex3->pattern_error = true; rrex3->expr++; return; } - rrex3->str = rrex3->previous.str;; + rrex3->str = rrex3->previous.str; + ; char *next = rrex3->expr + 1; char *next_original = NULL; - if(*next == '*'){ + if (*next == '*') { next++; - } - if(*next == ')' && *(next + 1)){ - next_original = next; - next++; + if (*next == ')' && *(next + 1)) { + next_original = next; + next++; } char *loop_expr = rrex3->previous.expr; bool success_next = false; @@ -338,31 +329,31 @@ inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { bool success_current = false; char *right_next = NULL; char *right_str = rrex3->str; - while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { + while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { // Remember original_str because it's modified // by checking right and should be restored // for checking left so they're matching the // same value. char *original_str = rrex3->str; // Check if right matches. - //if(*next != ')'){ - rrex3->expr = next; - rrex3->valid = true; - if (rrex3_move(rrex3, false)) { - // Match rright. - success_next = true; - if(!next_original){ + // if(*next != ')'){ + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + // Match rright. + success_next = true; + if (!next_original) { right_next = rrex3->expr; - }else{ - right_next = next_original; - break; - } - right_str = rrex3->str; - success_next_once = true; } else { - // No match Right. - success_next = false; + right_next = next_original; + break; } + right_str = rrex3->str; + success_next_once = true; + } else { + // No match Right. + success_next = false; + } //} if (success_next_once && !success_next) { // Matched previous time but now doesn't. @@ -383,13 +374,12 @@ inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { if (!success_next) { right_str = rrex3->str; if (*rrex3->expr != ')') { - right_next = rrex3->expr + 1; // +1 is the * itself - - }else{ - - //break; + right_next = rrex3->expr + 1; // +1 is the * itself + + } else { + + // break; } - } } @@ -403,7 +393,7 @@ inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { rrex3->valid = true; #if RREX3_DEBUG == 1 rprintg("Asterisk end check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); + rrex3->valid); #endif } @@ -574,7 +564,7 @@ inline static void rrex3_cmp_word_not_start_or_end(rrex3_t *rrex3) { inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { #if RREX3_DEBUG == 1 rprintb("\\l Brackets start: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); + rrex3->valid); #endif rrex3_set_previous(rrex3); char *original_expr = rrex3->expr; @@ -621,7 +611,8 @@ inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { rrex3_set_previous(rrex3); rrex3->expr = previous_expr; #if RREX3_DEBUG == 1 - rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); + rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); #endif } @@ -640,18 +631,19 @@ inline static void rrex3_cmp_pipe(rrex3_t *rrex3) { } inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { #if RREX3_DEBUG == 1 - rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); + rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, + *rrex3->str, rrex3->valid); #endif - if(!rrex3->valid){ + if (!rrex3->valid) { rrex3->expr++; return; } rrex3_set_previous(rrex3); - if(rrex3->match_count == rrex3->match_capacity){ - - rrex3->match_capacity++; - rrex3->matches = (char *)realloc(rrex3->matches,rrex3->match_capacity * sizeof(char*)); + if (rrex3->match_count == rrex3->match_capacity) { + + rrex3->match_capacity++; + rrex3->matches = (char **)realloc( + rrex3->matches, rrex3->match_capacity * sizeof(char *)); } rrex3->matches[rrex3->match_count] = (char *)malloc(strlen(rrex3->str) + 1); strcpy(rrex3->matches[rrex3->match_count], rrex3->str); @@ -661,8 +653,6 @@ inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { rrex3->inside_parentheses = true; while (*rrex3->expr != ')' && !rrex3->exit) { rrex3_move(rrex3, false); - - } while (*rrex3->expr != ')') { rrex3->expr++; @@ -675,22 +665,23 @@ inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { rrex3_set_previous(rrex3); rrex3->expr = previous_expr; if (rrex3->valid == false) { - rrex3->str = original_str; + rrex3->str = original_str; free(rrex3->matches[rrex3->match_count]); } else { - rrex3->matches[rrex3->match_count][strlen(rrex3->matches[rrex3->match_count]) - strlen(rrex3->str)] = 0; + rrex3->matches[rrex3->match_count] + [strlen(rrex3->matches[rrex3->match_count]) - + strlen(rrex3->str)] = 0; rrex3->match_count++; } #if RREX3_DEBUG == 1 rprinty("\\l Parentheses end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); + rrex3->valid); #endif } - -inline static void rrex3_reset(rrex3_t * rrex3){ - rrex3_free_matches(rrex3); - rrex3->valid = true; +inline static void rrex3_reset(rrex3_t *rrex3) { + rrex3_free_matches(rrex3); + rrex3->valid = true; rrex3->pattern_error = false; rrex3->inside_brackets = false; rrex3->inside_parentheses = false; @@ -732,47 +723,47 @@ void rrex3_init(rrex3_t *rrex3) { rrex3->match_capacity = 0; rrex3->matches = NULL; rrex3->compiled = NULL; - + rrex3_reset(rrex3); - } rrex3_t *rrex3_new() { rrex3_t *rrex3 = (rrex3_t *)malloc(sizeof(rrex3_t)); - + rrex3_init(rrex3); - + return rrex3; } -rrex3_t * rrex3_compile(rrex3_t * rrex, char * expr){ - - rrex3_t * rrex3 = rrex ? rrex : rrex3_new(); - - char * compiled = (char *)malloc(strlen(expr) + 1); +rrex3_t *rrex3_compile(rrex3_t *rrex, char *expr) { + + rrex3_t *rrex3 = rrex ? rrex : rrex3_new(); + + char *compiled = (char *)malloc(strlen(expr) + 1); unsigned int count = 0; - while(*expr){ - if(*expr == '[' && *(expr + 2) == ']' ){ + while (*expr) { + if (*expr == '[' && *(expr + 2) == ']') { *compiled = *(expr + 1); expr++; - expr++; - }else if (*expr == '[' && *(expr + 1 )== '0' && *(expr + 2) == '-' && *(expr + 3) == '9' && *(expr + 4) == ']' ){ + expr++; + } else if (*expr == '[' && *(expr + 1) == '0' && *(expr + 2) == '-' && + *(expr + 3) == '9' && *(expr + 4) == ']') { *compiled = '\\'; compiled++; - *compiled = 'd'; - count++; + *compiled = 'd'; + count++; + expr++; + expr++; expr++; expr++; - expr++; - expr++; - }else{ + } else { *compiled = *expr; } - if(*compiled == '['){ - //in_brackets = true; - - }else if(*compiled == ']'){ - //in_brackets = false; + if (*compiled == '[') { + // in_brackets = true; + + } else if (*compiled == ']') { + // in_brackets = false; } expr++; compiled++; @@ -797,16 +788,15 @@ static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { rrex3->bytecode = *rrex3->expr; rrex3->function = rrex3->functions[(int)rrex3->bytecode]; rrex3->function(rrex3); - if(!*rrex3->expr && !*rrex3->str){ - + if (!*rrex3->expr && !*rrex3->str) { + rrex3->exit = true; return rrex3->valid; } - if (rrex3->pattern_error) - { + if (rrex3->pattern_error) { rrex3->valid = false; return rrex3->valid; - } + } if (resume_on_fail && !rrex3->valid && *rrex3->expr) { // rrex3_set_previous(rrex3); rrex3->failed.bytecode = rrex3->bytecode; @@ -828,7 +818,7 @@ static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { return true; } } - if (rrex3->match_from_start) { + if (!rrex3->match_from_start) { rrex3->valid = false; return rrex3->valid; } @@ -837,25 +827,25 @@ static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { return rrex3->valid; } rrex3->expr = rrex3->_expr; - if (rrex3->str) + if (*rrex3->str) rrex3->valid = true; } } return rrex3->valid; } -rrex3_t *rrex3(rrex3_t * rrex3,char *str, char *expr) { +rrex3_t *rrex3(rrex3_t *rrex3, char *str, char *expr) { #if RREX3_DEBUG == 1 printf("Regex check: %s:%s:%d\n", expr, str, 1); #endif bool self_initialized = false; - if(rrex3 == NULL){ - self_initialized = true; + if (rrex3 == NULL) { + self_initialized = true; rrex3 = rrex3_new(); - }else{ + } else { rrex3_reset(rrex3); } - + rrex3->_str = str; rrex3->_expr = rrex3->compiled ? rrex3->compiled : expr; rrex3->str = rrex3->_str; @@ -864,154 +854,166 @@ rrex3_t *rrex3(rrex3_t * rrex3,char *str, char *expr) { if (!rrex3_move(rrex3, true)) return NULL; } - if(rrex3->valid){ + if (rrex3->valid) { return rrex3; - }else{ - if( self_initialized){ - rrex3_free(rrex3); - } + } else { + if (self_initialized) { + rrex3_free(rrex3); + } return NULL; } } -int rrex3_test(){ - rrex3_t * rrex = rrex3_new(); - - assert(rrex3(rrex,"aaaaaaa", "a*a$")); - +void rrex3_test() { + rrex3_t *rrex = rrex3_new(); + + assert(rrex3(rrex, "aaaaaaa", "a*a$")); + // assert(rrex3("ababa", "a*b*a*b*a$")); - assert(rrex3(rrex,"#include\"test.h\"a", "#include.*\".*\"a$")); - assert(rrex3(rrex,"#include \"test.h\"a", "#include.*\".*\"a$")); - assert(rrex3(rrex,"aaaaaad", "a*d$")); - assert(rrex3(rrex,"abcdef", "abd?cdef")); - assert(!rrex3(rrex,"abcdef", "abd?def")); - assert(rrex3(rrex,"abcdef", "def")); - assert(!rrex3(rrex,"abcdef", "^def")); - assert(rrex3(rrex,"abcdef", "def$")); - assert(!rrex3(rrex,"abcdef", "^abc$")); - assert(rrex3(rrex,"aB!.#1", "......")); - assert(!rrex3(rrex,"aB!.#\n", " ......")); - assert(!rrex3(rrex,"aaaaaad", "q+d$")); - assert(rrex3(rrex,"aaaaaaa", "a+a$")); - assert(rrex3(rrex,"aaaaaad", "q*d$")); - assert(!rrex3(rrex,"aaaaaad", "^q*d$")); + assert(rrex3(rrex, "#include\"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "#include \"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "aaaaaad", "a*d$")); + assert(rrex3(rrex, "abcdef", "abd?cdef")); + assert(!rrex3(rrex, "abcdef", "abd?def")); + assert(rrex3(rrex, "abcdef", "def")); + assert(!rrex3(rrex, "abcdef", "^def")); + assert(rrex3(rrex, "abcdef", "def$")); + assert(!rrex3(rrex, "abcdef", "^abc$")); + assert(rrex3(rrex, "aB!.#1", "......")); + assert(!rrex3(rrex, "aB!.#\n", " ......")); + assert(!rrex3(rrex, "aaaaaad", "q+d$")); + assert(rrex3(rrex, "aaaaaaa", "a+a$")); + assert(rrex3(rrex, "aaaaaad", "q*d$")); + assert(!rrex3(rrex, "aaaaaad", "^q*d$")); // Asterisk function - assert(rrex3(rrex,"123321", "123*321")); - assert(rrex3(rrex,"pony", "p*ony")); - assert(rrex3(rrex,"pppony", "p*ony")); - assert(rrex3(rrex,"ppony", "p*pony")); - assert(rrex3(rrex,"pppony", "pp*pony")); - assert(rrex3(rrex,"pppony", ".*pony")); - assert(rrex3(rrex,"pony", ".*ony")); - assert(rrex3(rrex,"pony", "po*ny")); + assert(rrex3(rrex, "123321", "123*321")); + assert(rrex3(rrex, "pony", "p*ony")); + assert(rrex3(rrex, "pppony", "p*ony")); + assert(rrex3(rrex, "ppony", "p*pony")); + assert(rrex3(rrex, "pppony", "pp*pony")); + assert(rrex3(rrex, "pppony", ".*pony")); + assert(rrex3(rrex, "pony", ".*ony")); + assert(rrex3(rrex, "pony", "po*ny")); // assert(rrex3(rrex,"ppppony", "p*pppony")); // Plus function - assert(rrex3(rrex,"pony", "p+ony")); - assert(!rrex3(rrex,"ony", "p+ony")); - assert(rrex3(rrex,"ppony", "p+pony")); - assert(rrex3(rrex,"pppony", "pp+pony")); - assert(rrex3(rrex,"pppony", ".+pony")); - assert(rrex3(rrex,"pony", ".+ony")); - assert(rrex3(rrex,"pony", "po+ny")); + assert(rrex3(rrex, "pony", "p+ony")); + assert(!rrex3(rrex, "ony", "p+ony")); + assert(rrex3(rrex, "ppony", "p+pony")); + assert(rrex3(rrex, "pppony", "pp+pony")); + assert(rrex3(rrex, "pppony", ".+pony")); + assert(rrex3(rrex, "pony", ".+ony")); + assert(rrex3(rrex, "pony", "po+ny")); // Slash functions - assert(rrex3(rrex,"a", "\\w")); - assert(!rrex3(rrex,"1", "\\w")); - assert(rrex3(rrex,"1", "\\W")); - assert(!rrex3(rrex,"a", "\\W")); - assert(rrex3(rrex,"a", "\\S")); - assert(!rrex3(rrex," ", "\\s")); - assert(!rrex3(rrex,"\t", "\\s")); - assert(!rrex3(rrex,"\n", "\\s")); - assert(rrex3(rrex,"1", "\\d")); - assert(!rrex3(rrex,"a", "\\d")); - assert(rrex3(rrex,"a", "\\D")); - assert(!rrex3(rrex,"1", "\\D")); - assert(rrex3(rrex,"abc", "\\b")); - - assert(rrex3(rrex,"abc", "\\babc")); - assert(!rrex3(rrex,"abc", "a\\b")); - assert(!rrex3(rrex,"abc", "ab\\b")); - assert(!rrex3(rrex,"abc", "abc\\b")); - assert(rrex3(rrex,"abc", "a\\Bbc")); - assert(rrex3(rrex,"abc", "ab\\B")); - assert(!rrex3(rrex,"1ab", "1\\Bab")); - assert(rrex3(rrex,"abc", "a\\Bbc")); + assert(rrex3(rrex, "a", "\\w")); + assert(!rrex3(rrex, "1", "\\w")); + assert(rrex3(rrex, "1", "\\W")); + assert(!rrex3(rrex, "a", "\\W")); + assert(rrex3(rrex, "a", "\\S")); + assert(!rrex3(rrex, " ", "\\s")); + assert(!rrex3(rrex, "\t", "\\s")); + assert(!rrex3(rrex, "\n", "\\s")); + assert(rrex3(rrex, "1", "\\d")); + assert(!rrex3(rrex, "a", "\\d")); + assert(rrex3(rrex, "a", "\\D")); + assert(!rrex3(rrex, "1", "\\D")); + assert(rrex3(rrex, "abc", "\\b")); + + assert(rrex3(rrex, "abc", "\\babc")); + assert(!rrex3(rrex, "abc", "a\\b")); + assert(!rrex3(rrex, "abc", "ab\\b")); + assert(!rrex3(rrex, "abc", "abc\\b")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + assert(rrex3(rrex, "abc", "ab\\B")); + assert(!rrex3(rrex, "1ab", "1\\Bab")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + + // Escaping of special characters test. + assert(rrex3(rrex, "()+*.\\", "\\(\\)\\+\\*\\.\\\\")); // Pipe // assert(rrex3(rrex,"abc","abc|def")); - assert(rrex3(rrex,"abc", "def|jkl|abc")); - assert(rrex3(rrex,"abc", "abc|def")); + assert(rrex3(rrex, "abc", "def|jkl|abc")); + assert(rrex3(rrex, "abc", "abc|def")); - assert(rrex3(rrex,"rhq", "def|rhq|rha")); - assert(rrex3(rrex,"abc", "abc|def")); + assert(rrex3(rrex, "rhq", "def|rhq|rha")); + assert(rrex3(rrex, "abc", "abc|def")); // Repeat - assert(rrex3(rrex,"aaaaa", "a{4}")); + assert(rrex3(rrex, "aaaaa", "a{4}")); - assert(rrex3(rrex,"aaaa", "a{1,3}a")); + assert(rrex3(rrex, "aaaa", "a{1,3}a")); // Range - assert(rrex3(rrex,"abc", "[abc][abc][abc]$")); - assert(rrex3(rrex,"def", "[^abc][^abc][^abc]$")); - assert(rrex3(rrex,"defabc", "[^abc][^abc][^abc]abc")); - assert(rrex3(rrex,"0-9", "0-9")); - assert(rrex3(rrex,"55-9", "[^6-9]5-9$")); - assert(rrex3(rrex,"a", "[a-z]$")); - assert(rrex3(rrex,"A", "[A-Z]$")); - assert(rrex3(rrex,"5", "[0-9]$")); - assert(!rrex3(rrex,"a", "[^a-z]$")); - assert(!rrex3(rrex,"A", "[^A-Z]$")); - assert(!rrex3(rrex,"5", "[^0-9]$")); - assert(rrex3(rrex,"123abc", "[0-9]*abc$")); - assert(rrex3(rrex,"123123", "[0-9]*$")); + assert(rrex3(rrex, "abc", "[abc][abc][abc]$")); + assert(rrex3(rrex, "def", "[^abc][^abc][^abc]$")); + assert(rrex3(rrex, "defabc", "[^abc][^abc][^abc]abc")); + assert(rrex3(rrex, "0-9", "0-9")); + assert(rrex3(rrex, "55-9", "[^6-9]5-9$")); + assert(rrex3(rrex, "a", "[a-z]$")); + assert(rrex3(rrex, "A", "[A-Z]$")); + assert(rrex3(rrex, "5", "[0-9]$")); + assert(!rrex3(rrex, "a", "[^a-z]$")); + assert(!rrex3(rrex, "A", "[^A-Z]$")); + assert(!rrex3(rrex, "5", "[^0-9]$")); + assert(rrex3(rrex, "123abc", "[0-9]*abc$")); + assert(rrex3(rrex, "123123", "[0-9]*$")); // Parentheses - - assert(rrex3(rrex,"datadata", "(data)*")); - assert(rrex3(rrex,"datadatapony", "(data)*pony$")); + assert(rrex3(rrex, "datadata", "(data)*")); - assert(!rrex3(rrex,"datadatapony", "(d*p*ata)*pond$")); - assert(rrex3(rrex,"datadatadato", "(d*p*ata)*dato")); - assert(rrex3(rrex,"datadatadato", "(d*p*ata)*dato$")); - assert(!rrex3(rrex,"datadatadato", "(d*p*a*ta)*gato$")); + assert(rrex3(rrex, "datadatapony", "(data)*pony$")); + + assert(!rrex3(rrex, "datadatapony", "(d*p*ata)*pond$")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato$")); + assert(!rrex3(rrex, "datadatadato", "(d*p*a*ta)*gato$")); // Matches - assert(rrex3(rrex,"123", "(123)")); + assert(rrex3(rrex, "123", "(123)")); assert(!strcmp(rrex->matches[0], "123")); - assert(rrex3(rrex,"123321a", "(123)([0-4][2]1)a$")); - assert(!strcmp(rrex->matches[1], "321")); + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); + + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); - assert(rrex3(rrex,"123321a", "(123)([0-4][2]1)a$")); - assert(!strcmp(rrex->matches[1],"321")); - - - assert(rrex3(rrex,"aaaabc","(.*)c")); + assert(rrex3(rrex, "aaaabc", "(.*)c")); assert(rrex3(rrex, "abcde", ".....$")); - - assert(rrex3(rrex,"abcdefghijklmnopqrstuvwxyz","..........................$")); - //printf("(%d)\n", rrex->valid); - - assert(rrex3(rrex," #include ","#include.*<(.*)>")); + + assert(rrex3(rrex, "abcdefghijklmnopqrstuvwxyz", + "..........................$")); + // printf("(%d)\n", rrex->valid); + + assert(rrex3(rrex, " #include ", "#include.*<(.*)>")); assert(!strcmp(rrex->matches[0], "stdio.h")); - assert(rrex3(rrex," #include \"stdlib.h\"","#include.\"(.*)\"")); - assert(!strcmp(rrex->matches[0], "stdlib.h")); - assert(rrex3(rrex," \"stdio.h\"\"string.h\"\"sys/time.h\"","\"(.*)\"\"(.*)\"\"(.*)\"")); - assert(!strcmp(rrex->matches[0], "stdio.h")); - assert(!strcmp(rrex->matches[1], "string.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); assert(!strcmp(rrex->matches[2], "sys/time.h")); - - - rrex3_free(rrex); + /* + assert(rrex3(rrex, " #include ", "#include.+<(.+)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.+\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + */ + // assert(rrex3(rrex,"char pony() { + // }","\\b\\w+(\\s+\\*+)?\\s+\\w+\\s*\\([^)]*\\)\s*\\{[^{}]*\\}")); - #ifdef RLIB_H - return rtest_end(""); - #else - return 0; - #endif -} \ No newline at end of file + rrex3_free(rrex); +} +#endif \ No newline at end of file diff --git a/rrex3all.c b/rrex3all.c index d294cd2..caa3a92 100644 --- a/rrex3all.c +++ b/rrex3all.c @@ -1,3551 +1,4630 @@ -// RETOOR - Sep 2 2024 -// Found (local) include: ../rlib/rlib.h -// Found (local) include: rrex3.h +// RETOOR - Sep 3 2024 #define RREX3_DEBUG 0 - -// RETOOR - Sep 2 2024 -// Found (local) include: license.h -// Found (local) include: rprint.h -// Found (local) include: rtime.h -// Found (local) include: rmath.h -// Found (local) include: rmalloc.h -// Found (local) include: rtime.h -// Found (local) include: arena.h -// Found (local) include: rmalloc.h -// Found (local) include: rio.h -// Found (local) include: rstring.h -// Found (local) include: rmath.h -// Found (local) include: rterminal.h -// Found (local) include: rtest.h -// Found (local) include: rmalloc.h -// Found (local) include: rprint.h -// Found (local) include: rterm.h -// Found (local) include: rio.h -// Found (local) include: rtest.h -// Found (local) include: rtree.h -// Found (local) include: rmalloc.h -// Found (local) include: rlexer.h -// Found (local) include: rstring.h -// Found (local) include: rbench.h -// Found (local) include: rprint.h -// Found (local) include: rtime.h -// Found (local) include: rstring.h -// Found (local) include: rterminal.h -// MIT License -// =========== - -// Copyright (c) 2024 Retoor - -// 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 RLIB_H -#define RLIB_H -// BEGIN OF RLIB -#ifndef RPRINT_H -#define RPRINT_H - -#ifndef RLIB_TIME -#define RLIB_TIME - -#include -#include +#ifndef RREX3_H +#define RREX3_H +#include +#include +#include #include +#include #include -#include -#include - -#ifndef CLOCK_MONOTONIC -#define CLOCK_MONOTONIC 1 +#include +#ifndef RREX3_DEBUG +#define RREX3_DEBUG 0 #endif -typedef unsigned long long msecs_t; -typedef uint64_t nsecs_t; - -nsecs_t nsecs() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; -} +struct rrex3_t; -msecs_t rnsecs_to_msecs(nsecs_t nsecs) { return nsecs / 1000 / 1000; } +typedef void (*rrex3_function)(struct rrex3_t *); -nsecs_t rmsecs_to_nsecs(msecs_t msecs) { return msecs * 1000 * 1000; } +typedef struct rrex3_t { + void (*functions[254])(struct rrex3_t *); + void (*slash_functions[254])(struct rrex3_t *); + bool valid; + int match_count; + int match_capacity; + char **matches; + bool exit; + char *__expr; + char *__str; + char *_expr; + char *_str; + char *expr; + char *str; + char *compiled; + bool inside_brackets; + bool inside_parentheses; + bool pattern_error; + bool match_from_start; + char bytecode; + rrex3_function function; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } previous; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } failed; +} rrex3_t; -msecs_t usecs() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (long long)(tv.tv_sec) * 1000000 + (long long)(tv.tv_usec); +static bool isdigitrange(char *s) { + if (!isdigit(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isdigit(*(s + 2)); } -msecs_t msecs() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (long long)(tv.tv_sec) * 1000 + (tv.tv_usec / 1000); +static bool isalpharange(char *s) { + if (!isalpha(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isalpha(*(s + 2)); } -char *msecs_strs(msecs_t ms) { - static char str[22]; - str[0] = 0; - sprintf(str, "%f", ms * 0.001); - for (int i = strlen(str); i > 0; i--) { - if (str[i] > '0') - break; - str[i] = 0; + +void rrex3_free_matches(rrex3_t *rrex3) { + if (!rrex3->matches) + return; + for (int i = 0; i < rrex3->match_count; i++) { + free(rrex3->matches[i]); } - return str; + free(rrex3->matches); + rrex3->matches = NULL; + rrex3->match_count = 0; + rrex3->match_capacity = 0; } -char *msecs_strms(msecs_t ms) { - static char str[22]; - str[0] = 0; - sprintf(str, "%lld", ms); - return str; + +void rrex3_free(rrex3_t *rrex3) { + if (!rrex3) + return; + if (rrex3->compiled) { + free(rrex3->compiled); + rrex3->compiled = NULL; + } + rrex3_free_matches(rrex3); + free(rrex3); + rrex3 = NULL; } -char *msecs_str(long long ms) { - static char result[30]; - result[0] = 0; - if (ms > 999) { - char *s = msecs_strs(ms); - sprintf(result, "%ss", s); +static bool rrex3_move(rrex3_t *, bool); +static void rrex3_set_previous(rrex3_t *); +inline static void rrex3_cmp_asterisk(rrex3_t *); +void rrex3_cmp_literal_range(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Range check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char start = *rrex3->expr; + rrex3->expr++; + rrex3->expr++; + char end = *rrex3->expr; + if (*rrex3->str >= start && *rrex3->str <= end) { + rrex3->str++; + rrex3->valid = true; } else { - char *s = msecs_strms(ms); - sprintf(result, "%sMs", s); + rrex3->valid = false; } - return result; + rrex3->expr++; } -void nsleep(nsecs_t nanoseconds) { - long seconds = 0; - int factor = 0; - while (nanoseconds > 1000000000) { - factor++; - nanoseconds = nanoseconds / 10; +bool rrex3_is_function(char chr) { + if (chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || + chr == '*') + return true; + return false; +} + +inline static void rrex3_cmp_literal(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + if (*rrex3->expr == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK"); + exit(1); } - if (factor) { - seconds = 1; - factor--; - while (factor) { - seconds = seconds * 10; - factor--; + if (rrex3->valid == false) { + rrex3->expr++; + return; + } + if (rrex3->inside_brackets) { + if (isalpharange(rrex3->expr) || isdigitrange(rrex3->expr)) { + rrex3_cmp_literal_range(rrex3); + return; } } +#if RREX3_DEBUG == 1 + printf("Literal check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + if (*rrex3->expr == *rrex3->str) { + rrex3->expr++; + rrex3->str++; + rrex3->valid = true; + // if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == + // rrex3_cmp_literal && !rrex3->inside_brackets && + //! rrex3_is_function(*rrex3->expr)){ rrex3_cmp_literal(rrex3); + // if(rrex3->valid == false){ + // rrex3->expr--; + // rrex3->valid = true; + // } + // } + return; + } + rrex3->expr++; + rrex3->valid = false; +} - struct timespec req = {seconds, nanoseconds}; - struct timespec rem; - - if (nanosleep(&req, &rem) == -1) { - if (errno == EINTR) { - printf("Sleep was interrupted. Remaining time: %ld.%09ld seconds\n", - rem.tv_sec, rem.tv_nsec); - } else { - perror("nanosleep"); - } +inline static void rrex3_cmp_dot(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Dot check (any char): %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + rrex3->expr++; + if (!rrex3->valid) { + return; + } + if (*rrex3->str && *rrex3->str != '\n') { + rrex3->str++; + if (*rrex3->expr && *rrex3->expr == '.') { + rrex3_cmp_dot(rrex3); + return; + } /*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == + '+')){ char * next = strchr(rrex3->str,*(rrex3->expr + 1)); char * + space = strchr(rrex3->str,'\n'); if(next && (!space || space > next)){ + rrex3->str = next; + } + }*/ } else { - // printf("Slept for %ld.%09ld seconds\n", req.tv_sec, req.tv_nsec); + rrex3->valid = false; } } -void ssleep(double s) { - long nanoseconds = (long)(1000000000 * s); +inline static void rrex3_cmp_question_mark(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Question mark check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); - long seconds = 0; + if (rrex3->valid == false) + rrex3->valid = true; + rrex3->expr++; +} - struct timespec req = {seconds, nanoseconds}; - struct timespec rem; +inline static void rrex3_cmp_whitespace(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); - if (nanosleep(&req, &rem) == -1) { - if (errno == EINTR) { - printf("Sleep was interrupted. Remaining time: %ld.%09ld seconds\n", - rem.tv_sec, rem.tv_nsec); - } else { - perror("nanosleep"); - } - } else { - // printf("Slept for %ld.%09ld seconds\n", req.tv_sec, req.tv_nsec); + char c = *rrex3->expr; + rrex3->valid = c == ' ' || c == '\n' || c == '\t'; + if (rrex3->valid) { + rrex3->str++; } + rrex3->expr++; } -void msleep(long miliseonds) { - long nanoseconds = miliseonds * 1000000; - nsleep(nanoseconds); + +inline static void rrex3_cmp_whitespace_upper(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Non whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char c = *rrex3->expr; + rrex3->valid = !(c == ' ' || c == '\n' || c == '\t'); + if (rrex3->valid) { + rrex3->str++; + } + rrex3->expr++; } -char *format_time(int64_t nanoseconds) { - static char output[1024]; - size_t output_size = sizeof(output); - output[0] = 0; - if (nanoseconds < 1000) { - // Less than 1 microsecond - snprintf(output, output_size, "%ldns", nanoseconds); - } else if (nanoseconds < 1000000) { - // Less than 1 millisecond - double us = nanoseconds / 1000.0; - snprintf(output, output_size, "%.2fµs", us); - } else if (nanoseconds < 1000000000) { - // Less than 1 second - double ms = nanoseconds / 1000000.0; - snprintf(output, output_size, "%.2fms", ms); +inline static void rrex3_cmp_plus(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Plus check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + if (rrex3->valid) { + rrex3->str--; } else { - // 1 second or more - double s = nanoseconds / 1000000000.0; - snprintf(output, output_size, "%.2fs", s); + return; } - return output; + char *original_expr = rrex3->expr; + char *next = original_expr + 1; + char *loop_expr = rrex3->previous.expr - 1; + if (*loop_expr == '+') { + rrex3->valid = false; + rrex3->pattern_error = true; + rrex3->expr++; + return; + } + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *next_next = NULL; + char *next_str = rrex3->str; + while (*rrex3->str) { + // Check if next matches + char *original_str = rrex3->str; + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + success_next = true; + next_next = rrex3->expr; + next_str = rrex3->str; + success_next_once = true; + } else { + success_next = false; + } + if (success_next_once && !success_next) { + break; + } + // Check if current matches + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!*rrex3->str || !rrex3_move(rrex3, false)) { + success_current = false; + } else { + success_current = true; + if (!success_next) { + next_next = rrex3->expr + 1; // +1 is the * itself + next_str = rrex3->str; + } + } + if (success_next && !success_current) { + break; + } + } + if (!next_next) + rrex3->expr = next; + else { + rrex3->expr = next_next; + } + rrex3->str = next_str; + rrex3->valid = true; } +inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintg("Asterisk start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); #endif -#include -#include -#include -#include -#include + if (!rrex3->valid) { + rrex3->valid = true; + rrex3->expr++; + return; + } + if (*rrex3->previous.expr == '*') { + // Support for ** + rrex3->valid = false; + // rrex3->pattern_error = true; + rrex3->expr++; + return; + } + rrex3->str = rrex3->previous.str; + ; + char *next = rrex3->expr + 1; + char *next_original = NULL; + if (*next == '*') { + next++; + } + if (*next == ')' && *(next + 1)) { + next_original = next; + next++; + } + char *loop_expr = rrex3->previous.expr; + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *right_next = NULL; + char *right_str = rrex3->str; + while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { + // Remember original_str because it's modified + // by checking right and should be restored + // for checking left so they're matching the + // same value. + char *original_str = rrex3->str; + // Check if right matches. + // if(*next != ')'){ + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + // Match rright. + success_next = true; + if (!next_original) { + right_next = rrex3->expr; + } else { + right_next = next_original; + break; + } + right_str = rrex3->str; + success_next_once = true; + } else { + // No match Right. + success_next = false; + } + //} + if (success_next_once && !success_next) { + // Matched previous time but now doesn't. + break; + } + // Check if left matches. + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!rrex3_move(rrex3, false)) { + // No match left. + success_current = false; + } else { + // Match left. + success_current = true; + // NOT SURE< WITHOUT DOET HETZELFDE: + // original_str = rrex3->str; + if (!success_next) { + right_str = rrex3->str; + if (*rrex3->expr != ')') { + right_next = rrex3->expr + 1; // +1 is the * itself -long rpline_number = 0; -nsecs_t rprtime = 0; + } else { -int8_t _env_rdisable_colors = -1; -bool _rprint_enable_colors = true; + // break; + } + } + } -bool rprint_is_color_enabled() { - if (_env_rdisable_colors == -1) { - _env_rdisable_colors = getenv("RDISABLE_COLORS") != NULL; - } - if (_env_rdisable_colors) { - _rprint_enable_colors = false; + if ((success_next && !success_current) || + (!success_next && !success_current)) { + break; + } } - return _rprint_enable_colors; + rrex3->expr = right_next; + rrex3->str = right_str; + rrex3->valid = true; +#if RREX3_DEBUG == 1 + rprintg("Asterisk end check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif } -void rprint_disable_colors() { _rprint_enable_colors = false; } -void rprint_enable_colors() { _rprint_enable_colors = true; } -void rprint_toggle_colors() { _rprint_enable_colors = !_rprint_enable_colors; } +inline static void rrex3_cmp_roof(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); +#if RREX3_DEBUG == 1 + printf("expr, *rrex3->str, rrex3->valid); +#endif + rrex3->valid = rrex3->str == rrex3->_str; + rrex3->match_from_start = true; + rrex3->expr++; +} +inline static void rrex3_cmp_dollar(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -void rclear() { printf("\033[2J"); } +#if RREX3_DEBUG == 1 + printf("Dollar check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (*rrex3->str || !rrex3->valid) { + rrex3->valid = false; + } + rrex3->expr++; +} -void rprintpf(FILE *f, const char *prefix, const char *format, va_list args) { - char *pprefix = (char *)prefix; - char *pformat = (char *)format; - bool reset_color = false; - bool press_any_key = false; - char new_format[4096]; - bool enable_color = rprint_is_color_enabled(); - memset(new_format, 0, 4096); - int new_format_length = 0; - char temp[1000]; - memset(temp, 0, 1000); - if (enable_color && pprefix[0]) { - strcat(new_format, pprefix); - new_format_length += strlen(pprefix); - reset_color = true; +inline static void rrex3_cmp_w(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; } - while (true) { - if (pformat[0] == '\\' && pformat[1] == 'i') { - strcat(new_format, "\e[3m"); - new_format_length += strlen("\e[3m"); - reset_color = true; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'u') { - strcat(new_format, "\e[4m"); - new_format_length += strlen("\e[4m"); - reset_color = true; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'b') { - strcat(new_format, "\e[1m"); - new_format_length += strlen("\e[1m"); - reset_color = true; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'C') { - press_any_key = true; - rpline_number++; - pformat++; - pformat++; - reset_color = false; - } else if (pformat[0] == '\\' && pformat[1] == 'k') { - press_any_key = true; - rpline_number++; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'c') { - rpline_number++; - strcat(new_format, "\e[2J\e[H"); - new_format_length += strlen("\e[2J\e[H"); - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'L') { - rpline_number++; - temp[0] = 0; - sprintf(temp, "%ld", rpline_number); - strcat(new_format, temp); - new_format_length += strlen(temp); - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'l') { - rpline_number++; - temp[0] = 0; - sprintf(temp, "%.5ld", rpline_number); - strcat(new_format, temp); - new_format_length += strlen(temp); - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'T') { - nsecs_t nsecs_now = nsecs(); - nsecs_t end = rprtime ? nsecs_now - rprtime : 0; - temp[0] = 0; - sprintf(temp, "%s", format_time(end)); - strcat(new_format, temp); - new_format_length += strlen(temp); - rprtime = nsecs_now; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 't') { - rprtime = nsecs(); - pformat++; - pformat++; - } else { - new_format[new_format_length] = *pformat; - new_format_length++; - if (!*pformat) - break; +} +inline static void rrex3_cmp_w_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); - // printf("%c",*pformat); - pformat++; - } - } - if (reset_color) { - strcat(new_format, "\e[0m"); - new_format_length += strlen("\e[0m"); + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; } +} - new_format[new_format_length] = 0; - vfprintf(f, new_format, args); +inline static void rrex3_cmp_d(rrex3_t *rrex3) { - fflush(stdout); - if (press_any_key) { - nsecs_t s = nsecs(); - fgetc(stdin); - rprtime += nsecs() - s; + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; } } +inline static void rrex3_cmp_d_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -void rprintp(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "", format, args); - va_end(args); + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } } -void rprintf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "", format, args); - va_end(args); -} -void rprint(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "", format, args); - va_end(args); -} -#define printf rprint +inline static void rrex3_cmp_slash(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -// Print line -void rprintlf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\\l", format, args); - va_end(args); -} -void rprintl(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\\l", format, args); - va_end(args); -} + rrex3->expr++; -// Black -void rprintkf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[30m", format, args); - va_end(args); -} -void rprintk(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[30m", format, args); - va_end(args); + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->slash_functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); } -// Red -void rprintrf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[31m", format, args); - va_end(args); -} -void rprintr(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[31m", format, args); - va_end(args); -} +inline static int collect_digits(rrex3_t *rrex3) { + char output[20]; + unsigned int digit_count = 0; + while (isdigit(*rrex3->expr)) { -// Green -void rprintgf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[32m", format, args); - va_end(args); -} -void rprintg(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[32m", format, args); - va_end(args); + output[digit_count] = *rrex3->expr; + rrex3->expr++; + digit_count++; + } + output[digit_count] = 0; + return atoi(output); } -// Yellow -void rprintyf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[33m", format, args); - va_end(args); -} -void rprinty(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[33m", format, args); - va_end(args); +inline static void rrex3_cmp_range(rrex3_t *rrex3) { + char *loop_code = rrex3->previous.expr; + char *expr_original = rrex3->expr; + rrex3->expr++; + int range_start = collect_digits(rrex3) - 1; + int range_end = 0; + if (*rrex3->expr == ',') { + rrex3->expr++; + range_end = collect_digits(rrex3); + } + rrex3->expr++; + int times_valid = 0; + while (*rrex3->str) { + rrex3->expr = loop_code; + rrex3_move(rrex3, false); + if (rrex3->valid == false) { + break; + } else { + times_valid++; + } + if (range_end) { + if (times_valid >= range_start && times_valid == range_end - 1) { + rrex3->valid = true; + } else { + rrex3->valid = false; + } + break; + } else if (range_start) { + if (times_valid == range_start) { + rrex3->valid = true; + break; + } + } + } + rrex3->valid = times_valid >= range_start; + if (rrex3->valid && range_end) { + rrex3->valid = times_valid <= range_end; + } + rrex3->expr = strchr(expr_original, '}') + 1; } -// Blue -void rprintbf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[34m", format, args); - va_end(args); +inline static void rrex3_cmp_word_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + bool valid = false; + if (isalpha(*rrex3->str)) { + if (rrex3->_str != rrex3->str) { + if (!isalpha(*(rrex3->str - 1))) { + valid = true; + } + } else { + valid = true; + } + } else if (isalpha(isalpha(*rrex3->str) && !isalpha(*rrex3->str + 1))) { + valid = true; + } + rrex3->expr++; + rrex3->valid = valid; } +inline static void rrex3_cmp_word_not_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -void rprintb(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[34m", format, args); - va_end(args); + rrex3_cmp_word_start_or_end(rrex3); + rrex3->valid = !rrex3->valid; } -// Magenta -void rprintmf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[35m", format, args); - va_end(args); -} -void rprintm(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[35m", format, args); - va_end(args); -} +inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets start: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + char *original_expr = rrex3->expr; + rrex3->expr++; + rrex3->inside_brackets = true; + bool valid_once = false; + bool reversed = false; + if (*rrex3->expr == '^') { + reversed = true; + rrex3->expr++; + } + bool valid = false; + while (*rrex3->expr != ']' && *rrex3->expr != 0) { + rrex3->valid = true; + valid = rrex3_move(rrex3, false); + if (reversed) { + valid = !valid; + } + if (valid) { + valid_once = true; + if (!reversed) { + valid_once = true; + break; + } + } else { + if (reversed) { + valid_once = false; + break; + } + } + } + if (valid_once && reversed) { + rrex3->str++; + } + while (*rrex3->expr != ']' && *rrex3->expr != 0) + rrex3->expr++; + if (*rrex3->expr != 0) + rrex3->expr++; -// Cyan -void rprintcf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[36m", format, args); - va_end(args); -} -void rprintc(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[36m", format, args); - va_end(args); + rrex3->valid = valid_once; + rrex3->inside_brackets = false; + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif } -// White -void rprintwf(FILE *f, char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(f, "\e[37m", format, args); - va_end(args); -} -void rprintw(char *format, ...) { - va_list args; - va_start(args, format); - rprintpf(stdout, "\e[37m", format, args); - va_end(args); -} -#endif -#ifndef RMATH_H -#define RMATH_H -#include +inline static void rrex3_cmp_pipe(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -#ifndef ceil -double ceil(double x) { - if (x == (double)(long long)x) { - return x; - } else if (x > 0.0) { - return (double)(long long)x + 1.0; +#if RREX3_DEBUG == 1 + printf("Pipe check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (rrex3->valid == true) { + rrex3->exit = true; } else { - return (double)(long long)x; + rrex3->valid = true; } + rrex3->expr++; } +inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, + *rrex3->str, rrex3->valid); #endif + if (!rrex3->valid) { + rrex3->expr++; + return; + } + rrex3_set_previous(rrex3); + if (rrex3->match_count == rrex3->match_capacity) { -#ifndef floor -double floor(double x) { - if (x >= 0.0) { - return (double)(long long)x; + rrex3->match_capacity++; + rrex3->matches = (char **)realloc( + rrex3->matches, rrex3->match_capacity * sizeof(char *)); + } + rrex3->matches[rrex3->match_count] = (char *)malloc(strlen(rrex3->str) + 1); + strcpy(rrex3->matches[rrex3->match_count], rrex3->str); + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->expr++; + rrex3->inside_parentheses = true; + while (*rrex3->expr != ')' && !rrex3->exit) { + rrex3_move(rrex3, false); + } + while (*rrex3->expr != ')') { + rrex3->expr++; + } + rrex3->expr++; + rrex3->inside_parentheses = false; + + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; + if (rrex3->valid == false) { + rrex3->str = original_str; + free(rrex3->matches[rrex3->match_count]); } else { - double result = (double)(long long)x; - return (result == x) ? result : result - 1.0; + rrex3->matches[rrex3->match_count] + [strlen(rrex3->matches[rrex3->match_count]) - + strlen(rrex3->str)] = 0; + rrex3->match_count++; } -} +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); #endif +} -#ifndef modf -double modf(double x, double *iptr) { - double int_part = (x >= 0.0) ? floor(x) : ceil(x); - *iptr = int_part; - return x - int_part; +inline static void rrex3_reset(rrex3_t *rrex3) { + rrex3_free_matches(rrex3); + rrex3->valid = true; + rrex3->pattern_error = false; + rrex3->inside_brackets = false; + rrex3->inside_parentheses = false; + rrex3->exit = false; + rrex3->previous.expr = NULL; + rrex3->previous.str = NULL; + rrex3->previous.bytecode = 0; + rrex3->failed.expr = NULL; + rrex3->failed.str = NULL; + rrex3->failed.bytecode = 0; + rrex3->match_from_start = false; } -#endif -#endif -#ifndef RMALLOC_H -#define RMALLOC_H -#include -#include -#include -unsigned long long rmalloc_count = 0; -unsigned long long rmalloc_alloc_count = 0; -unsigned long long int rmalloc_free_count = 0; +void rrex3_init(rrex3_t *rrex3) { + for (__uint8_t i = 0; i < 254; i++) { + rrex3->functions[i] = rrex3_cmp_literal; + rrex3->slash_functions[i] = rrex3_cmp_literal; + } + rrex3->functions['?'] = rrex3_cmp_question_mark; + rrex3->functions['^'] = rrex3_cmp_roof; + rrex3->functions['$'] = rrex3_cmp_dollar; + rrex3->functions['.'] = rrex3_cmp_dot; + rrex3->functions['*'] = rrex3_cmp_asterisk; + rrex3->functions['+'] = rrex3_cmp_plus; + rrex3->functions['|'] = rrex3_cmp_pipe; + rrex3->functions['\\'] = rrex3_cmp_slash; + rrex3->functions['{'] = rrex3_cmp_range; + rrex3->functions['['] = rrex3_cmp_brackets; + rrex3->functions['('] = rrex3_cmp_parentheses; + rrex3->slash_functions['w'] = rrex3_cmp_w; + rrex3->slash_functions['W'] = rrex3_cmp_w_upper; + rrex3->slash_functions['d'] = rrex3_cmp_d; + rrex3->slash_functions['D'] = rrex3_cmp_d_upper; + rrex3->slash_functions['s'] = rrex3_cmp_whitespace; + rrex3->slash_functions['S'] = rrex3_cmp_whitespace_upper; + rrex3->slash_functions['b'] = rrex3_cmp_word_start_or_end; + rrex3->slash_functions['B'] = rrex3_cmp_word_not_start_or_end; + rrex3->match_count = 0; + rrex3->match_capacity = 0; + rrex3->matches = NULL; + rrex3->compiled = NULL; -void *rmalloc(size_t size) { - rmalloc_count++; - rmalloc_alloc_count++; - return malloc(size); -} -void *rrealloc(void *obj, size_t size) { return realloc(obj, size); } -void *rfree(void *obj) { - rmalloc_count--; - rmalloc_free_count++; - free(obj); - return NULL; + rrex3_reset(rrex3); } -char *rmalloc_stats() { - static char res[100] = {0}; - sprintf(res, "Memory usage: %lld allocated, %lld freed, %lld in use.", - rmalloc_alloc_count, rmalloc_free_count, rmalloc_count); - return res; -} +rrex3_t *rrex3_new() { + rrex3_t *rrex3 = (rrex3_t *)malloc(sizeof(rrex3_t)); -char *rstrdup(char *str) { + rrex3_init(rrex3); - char *res = (char *)strdup(str); - rmalloc_alloc_count++; - rmalloc_count++; - return res; + return rrex3; } -#endif -#ifndef RARENA_H -#define RARENA_H +rrex3_t *rrex3_compile(rrex3_t *rrex, char *expr) { -#include -#include + rrex3_t *rrex3 = rrex ? rrex : rrex3_new(); -typedef struct arena_t { - unsigned char *memory; - unsigned int pointer; - unsigned int size; -} arena_t; + char *compiled = (char *)malloc(strlen(expr) + 1); + unsigned int count = 0; + while (*expr) { + if (*expr == '[' && *(expr + 2) == ']') { + *compiled = *(expr + 1); + expr++; + expr++; + } else if (*expr == '[' && *(expr + 1) == '0' && *(expr + 2) == '-' && + *(expr + 3) == '9' && *(expr + 4) == ']') { + *compiled = '\\'; + compiled++; + *compiled = 'd'; + count++; + expr++; + expr++; + expr++; + expr++; + } else { + *compiled = *expr; + } + if (*compiled == '[') { + // in_brackets = true; -arena_t *arena_construct() { - arena_t *arena = (arena_t *)rmalloc(sizeof(arena_t)); - arena->memory = NULL; - arena->pointer = 0; - arena->size = 0; - return arena; + } else if (*compiled == ']') { + // in_brackets = false; + } + expr++; + compiled++; + count++; + } + *compiled = 0; + compiled -= count; + rrex3->compiled = compiled; + return rrex3; } -arena_t *arena_new(size_t size) { - arena_t *arena = arena_construct(); - arena->memory = (unsigned char *)rmalloc(size); - arena->size = size; - return arena; +inline static void rrex3_set_previous(rrex3_t *rrex3) { + rrex3->previous.function = rrex3->function; + rrex3->previous.expr = rrex3->expr; + rrex3->previous.str = rrex3->str; + rrex3->previous.bytecode = *rrex3->expr; } -void *arena_alloc(arena_t *arena, size_t size) { - if (arena->pointer + size > arena->size) { - return NULL; +static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); + if (!*rrex3->expr && !*rrex3->str) { + + rrex3->exit = true; + return rrex3->valid; } - void *p = arena->memory + arena->pointer; - arena->pointer += size; - return p; -} + if (rrex3->pattern_error) { + rrex3->valid = false; + return rrex3->valid; + } + if (resume_on_fail && !rrex3->valid && *rrex3->expr) { + // rrex3_set_previous(rrex3); + rrex3->failed.bytecode = rrex3->bytecode; + rrex3->failed.function = rrex3->function; + rrex3->failed.expr = original_expr; + rrex3->failed.str = original_str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); -void arena_free(arena_t *arena) { - // Just constructed and unused arena memory is NULL so no free needed - if (arena->memory) { - rfree(arena->memory); + if (!rrex3->valid && !rrex3->pattern_error) { + + if (*rrex3->str) { + char *pipe_position = strstr(rrex3->expr, "|"); + if (pipe_position != NULL) { + rrex3->expr = pipe_position + 1; + rrex3->str = rrex3->_str; + rrex3->valid = true; + return true; + } + } + if (rrex3->match_from_start) { + rrex3->valid = false; + return rrex3->valid; + } + if (!*rrex3->str++) { + rrex3->valid = false; + return rrex3->valid; + } + rrex3->expr = rrex3->_expr; + if (rrex3->str) + rrex3->valid = true; + } } - rfree(arena); + return rrex3->valid; } -void arena_reset(arena_t *arena) { arena->pointer = 0; } +rrex3_t *rrex3(rrex3_t *rrex3, char *str, char *expr) { +#if RREX3_DEBUG == 1 + printf("Regex check: %s:%s:%d\n", expr, str, 1); #endif -#ifndef RLIB_RIO -#define RLIB_RIO -#include -#include -#include -#include -#include + bool self_initialized = false; + if (rrex3 == NULL) { + self_initialized = true; + rrex3 = rrex3_new(); + } else { + rrex3_reset(rrex3); + } -bool rfd_wait(int fd, int ms) { - fd_set read_fds; - struct timeval timeout; + rrex3->_str = str; + rrex3->_expr = rrex3->compiled ? rrex3->compiled : expr; + rrex3->str = rrex3->_str; + rrex3->expr = rrex3->_expr; + while (*rrex3->expr && !rrex3->exit) { + if (!rrex3_move(rrex3, true)) + return NULL; + } + if (rrex3->valid) { + return rrex3; + } else { + if (self_initialized) { + rrex3_free(rrex3); + } + return NULL; + } +} - FD_ZERO(&read_fds); - FD_SET(fd, &read_fds); +void rrex3_test() { + rrex3_t *rrex = rrex3_new(); - timeout.tv_sec = 0; - timeout.tv_usec = 1000 * ms; // 100 milliseconds timeout + assert(rrex3(rrex, "aaaaaaa", "a*a$")); - int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); - return ret > 0 && FD_ISSET(fd, &read_fds); -} + // assert(rrex3("ababa", "a*b*a*b*a$")); + assert(rrex3(rrex, "#include\"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "#include \"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "aaaaaad", "a*d$")); + assert(rrex3(rrex, "abcdef", "abd?cdef")); + assert(!rrex3(rrex, "abcdef", "abd?def")); + assert(rrex3(rrex, "abcdef", "def")); + assert(!rrex3(rrex, "abcdef", "^def")); + assert(rrex3(rrex, "abcdef", "def$")); + assert(!rrex3(rrex, "abcdef", "^abc$")); + assert(rrex3(rrex, "aB!.#1", "......")); + assert(!rrex3(rrex, "aB!.#\n", " ......")); + assert(!rrex3(rrex, "aaaaaad", "q+d$")); + assert(rrex3(rrex, "aaaaaaa", "a+a$")); + assert(rrex3(rrex, "aaaaaad", "q*d$")); + assert(!rrex3(rrex, "aaaaaad", "^q*d$")); -bool rfd_wait_forever(int fd) { - while ((!rfd_wait(fd, 10))) { - } - return true; -} + // Asterisk function + assert(rrex3(rrex, "123321", "123*321")); + assert(rrex3(rrex, "pony", "p*ony")); + assert(rrex3(rrex, "pppony", "p*ony")); + assert(rrex3(rrex, "ppony", "p*pony")); + assert(rrex3(rrex, "pppony", "pp*pony")); + assert(rrex3(rrex, "pppony", ".*pony")); + assert(rrex3(rrex, "pony", ".*ony")); + assert(rrex3(rrex, "pony", "po*ny")); + // assert(rrex3(rrex,"ppppony", "p*pppony")); -bool rfile_exists(char *path) { - struct stat s; - return !stat(path, &s); -} + // Plus function + assert(rrex3(rrex, "pony", "p+ony")); + assert(!rrex3(rrex, "ony", "p+ony")); + assert(rrex3(rrex, "ppony", "p+pony")); + assert(rrex3(rrex, "pppony", "pp+pony")); + assert(rrex3(rrex, "pppony", ".+pony")); + assert(rrex3(rrex, "pony", ".+ony")); + assert(rrex3(rrex, "pony", "po+ny")); -size_t rfile_size(char *path) { - struct stat s; - stat(path, &s); - return s.st_size; -} + // Slash functions + assert(rrex3(rrex, "a", "\\w")); + assert(!rrex3(rrex, "1", "\\w")); + assert(rrex3(rrex, "1", "\\W")); + assert(!rrex3(rrex, "a", "\\W")); + assert(rrex3(rrex, "a", "\\S")); + assert(!rrex3(rrex, " ", "\\s")); + assert(!rrex3(rrex, "\t", "\\s")); + assert(!rrex3(rrex, "\n", "\\s")); + assert(rrex3(rrex, "1", "\\d")); + assert(!rrex3(rrex, "a", "\\d")); + assert(rrex3(rrex, "a", "\\D")); + assert(!rrex3(rrex, "1", "\\D")); + assert(rrex3(rrex, "abc", "\\b")); + + assert(rrex3(rrex, "abc", "\\babc")); + assert(!rrex3(rrex, "abc", "a\\b")); + assert(!rrex3(rrex, "abc", "ab\\b")); + assert(!rrex3(rrex, "abc", "abc\\b")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + assert(rrex3(rrex, "abc", "ab\\B")); + assert(!rrex3(rrex, "1ab", "1\\Bab")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + + // Escaping of special characters test. + assert(rrex3(rrex, "()+*.\\", "\\(\\)\\+\\*\\.\\\\")); -size_t rfile_readb(char *path, void *data, size_t size) { - FILE *fd = fopen(path, "rb"); - if (!fd) { - return 0; - } - __attribute__((unused)) size_t bytes_read = - fread(data, size, sizeof(char), fd); + // Pipe + // assert(rrex3(rrex,"abc","abc|def")); + assert(rrex3(rrex, "abc", "def|jkl|abc")); + assert(rrex3(rrex, "abc", "abc|def")); - fclose(fd); - return size; -} + assert(rrex3(rrex, "rhq", "def|rhq|rha")); + assert(rrex3(rrex, "abc", "abc|def")); -#endif -#ifndef RSTRING_H -#define RSTRING_H -#include -#include -#include -#include -#include + // Repeat + assert(rrex3(rrex, "aaaaa", "a{4}")); -unsigned long _r_generate_key_current = 0; + assert(rrex3(rrex, "aaaa", "a{1,3}a")); -char *_rcat_int_int(int a, int b) { - static char res[20]; - res[0] = 0; - sprintf(res, "%d%d", a, b); - return res; -} -char *_rcat_int_double(int a, double b) { - static char res[20]; - res[0] = 0; - sprintf(res, "%d%f", a, b); - return res; -} + // Range + assert(rrex3(rrex, "abc", "[abc][abc][abc]$")); + assert(rrex3(rrex, "def", "[^abc][^abc][^abc]$")); + assert(rrex3(rrex, "defabc", "[^abc][^abc][^abc]abc")); + assert(rrex3(rrex, "0-9", "0-9")); + assert(rrex3(rrex, "55-9", "[^6-9]5-9$")); + assert(rrex3(rrex, "a", "[a-z]$")); + assert(rrex3(rrex, "A", "[A-Z]$")); + assert(rrex3(rrex, "5", "[0-9]$")); + assert(!rrex3(rrex, "a", "[^a-z]$")); + assert(!rrex3(rrex, "A", "[^A-Z]$")); + assert(!rrex3(rrex, "5", "[^0-9]$")); + assert(rrex3(rrex, "123abc", "[0-9]*abc$")); + assert(rrex3(rrex, "123123", "[0-9]*$")); -char *_rcat_charp_int(char *a, int b) { - char res[20]; - sprintf(res, "%c", b); - return strcat(a, res); -} + // Parentheses -char *_rcat_charp_double(char *a, double b) { - char res[20]; - sprintf(res, "%f", b); - return strcat(a, res); -} + assert(rrex3(rrex, "datadata", "(data)*")); -char *_rcat_charp_charp(char *a, char *b) { - ; - return strcat(a, b); -} -char *_rcat_charp_char(char *a, char b) { - char extra[] = {b, 0}; - return strcat(a, extra); -} -char *_rcat_charp_bool(char *a, bool *b) { - if (b) { - return strcat(a, "true"); - } else { - return strcat(a, "false"); - } -} + assert(rrex3(rrex, "datadatapony", "(data)*pony$")); -#define rcat(x, y) \ - _Generic((x), \ - int: _Generic((y), \ - int: _rcat_int_int,\ - double: _rcat_int_double,\ - char*: _rcat_charp_charp),\ - char*: _Generic((y),\ - int: _rcat_charp_int, \ - double: _rcat_charp_double,\ - char*: _rcat_charp_charp, \ - char: _rcat_charp_char, \ - bool: _rcat_charp_bool))((x),(y)) + assert(!rrex3(rrex, "datadatapony", "(d*p*ata)*pond$")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato$")); + assert(!rrex3(rrex, "datadatadato", "(d*p*a*ta)*gato$")); -char *rgenerate_key() { - _r_generate_key_current++; - static char key[100]; - key[0] = 0; - sprintf(key, "%ld", _r_generate_key_current); - return key; -} + // Matches + assert(rrex3(rrex, "123", "(123)")); + assert(!strcmp(rrex->matches[0], "123")); -char *rformat_number(long lnumber) { - static char formatted[1024]; + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); - char number[1024]; - sprintf(number, "%ld", lnumber); + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); - int len = strlen(number); - int commas_needed = (len - 1) / 3; - int new_len = len + commas_needed; + assert(rrex3(rrex, "aaaabc", "(.*)c")); - formatted[new_len] = '\0'; + assert(rrex3(rrex, "abcde", ".....$")); - int i = len - 1; - int j = new_len - 1; - int count = 0; + assert(rrex3(rrex, "abcdefghijklmnopqrstuvwxyz", + "..........................$")); + // printf("(%d)\n", rrex->valid); - while (i >= 0) { - if (count == 3) { - formatted[j--] = '.'; - count = 0; - } - formatted[j--] = number[i--]; - count++; - } - return formatted; -} + assert(rrex3(rrex, " #include ", "#include.*<(.*)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + /* + assert(rrex3(rrex, " #include ", "#include.+<(.+)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.+\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); -bool rstrextractdouble(char *str, double *d1) { - for (size_t i = 0; i < strlen(str); i++) { - if (isdigit(str[i])) { - str += i; - sscanf(str, "%lf", d1); - return true; - } - } - return false; -} + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + */ + // assert(rrex3(rrex,"char pony() { + // }","\\b\\w+(\\s+\\*+)?\\s+\\w+\\s*\\([^)]*\\)\s*\\{[^{}]*\\}")); -void rstrstripslashes(const char *content, char *result) { - size_t content_length = strlen((char *)content); - unsigned int index = 0; - for (unsigned int i = 0; i < content_length; i++) { - char c = content[i]; - if (c == '\\') { - i++; - c = content[i]; - if (c == 'r') { - c = '\r'; - } else if (c == 't') { - c = '\t'; - } else if (c == 'b') { - c = '\b'; - } else if (c == 'n') { - c = '\n'; - } else if (c == 'f') { - c = '\f'; - } else if (c == '\\') { - // No need tbh - c = '\\'; - } - } - result[index] = c; - index++; - } - result[index] = 0; + rrex3_free(rrex); } +#endif +// RETOOR - Sep 3 2024 +// MIT License +// =========== -int rstrstartswith(const char *s1, const char *s2) { - if (s1 == NULL) - return s2 == NULL; - if (s1 == s2 || s2 == NULL || *s2 == 0) - return true; - size_t len_s2 = strlen(s2); - size_t len_s1 = strlen(s1); - if (len_s2 > len_s1) - return false; - return !strncmp(s1, s2, len_s2); -} +// Copyright (c) 2024 Retoor -bool rstrendswith(const char *s1, const char *s2) { - if (s1 == NULL) - return s2 == NULL; - if (s1 == s2 || s2 == NULL || *s2 == 0) - return true; - size_t len_s2 = strlen(s2); - size_t len_s1 = strlen(s1); - if (len_s2 > len_s1) { - return false; - } - s1 += len_s1 - len_s2; - return !strncmp(s1, s2, len_s2); -} +// 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: -void rstraddslashes(const char *content, char *result) { - size_t content_length = strlen((char *)content); - unsigned int index = 0; - for (unsigned int i = 0; i < content_length; i++) { - if (content[i] == '\r') { - result[index] = '\\'; - index++; - result[index] = 'r'; - index++; - continue; - } else if (content[i] == '\t') { - result[index] = '\\'; - index++; - result[index] = 't'; - index++; - continue; - } else if (content[i] == '\n') { - result[index] = '\\'; - index++; - result[index] = 'n'; - index++; - continue; - } else if (content[i] == '\\') { - result[index] = '\\'; - index++; - result[index] = '\\'; - index++; - continue; - } else if (content[i] == '\b') { - result[index] = '\\'; - index++; - result[index] = 'b'; - index++; - continue; - } else if (content[i] == '\f') { - result[index] = '\\'; - index++; - result[index] = 'f'; - index++; - continue; - } - result[index] = content[i]; - index++; - } - result[index] = 0; -} +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. -int rstrip_whitespace(char *input, char *output) { - output[0] = 0; - int count = 0; - size_t len = strlen(input); - for (size_t i = 0; i < len; i++) { - if (input[i] == '\t' || input[i] == ' ') { - continue; - } - count = i; - size_t j; - for (j = 0; j < len - count; j++) { - output[j] = input[j + count]; - } - output[j] = '\0'; - break; - } - return count; -} -size_t rstrtokline(char *input, char *output, size_t offset, bool strip_nl) { +// 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 RLIB_H +#define RLIB_H +// BEGIN OF RLIB +#ifndef RPRINT_H +#define RPRINT_H - size_t len = strlen(input); - output[0] = 0; - size_t new_offset = 0; - size_t j; - size_t index = 0; +#ifndef RLIB_TIME +#define RLIB_TIME - for (j = offset; j < len + offset; j++) { - if (input[j] == 0) { - index++; - break; - } - index = j - offset; - output[index] = input[j]; +#include +#include +#include +#include +#include +#include - if (output[index] == '\n') { - index++; - break; - } - } - output[index] = 0; +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 1 +#endif - new_offset = index + offset; +typedef unsigned long long msecs_t; +typedef uint64_t nsecs_t; - if (strip_nl) { - if (output[index - 1] == '\n') { - output[index - 1] = 0; - } - } - return new_offset; +nsecs_t nsecs() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; } -void rstrjoin(char **lines, size_t count, char *glue, char *output) { - output[0] = 0; - for (size_t i = 0; i < count; i++) { - strcat(output, lines[i]); - if (i != count - 1) - strcat(output, glue); - } +msecs_t rnsecs_to_msecs(nsecs_t nsecs) { return nsecs / 1000 / 1000; } + +nsecs_t rmsecs_to_nsecs(msecs_t msecs) { return msecs * 1000 * 1000; } + +msecs_t usecs() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (long long)(tv.tv_sec) * 1000000 + (long long)(tv.tv_usec); } -int rstrsplit(char *input, char **lines) { - int index = 0; - size_t offset = 0; - char line[1024]; - while ((offset = rstrtokline(input, line, offset, false)) && *line) { - if (!*line) { +msecs_t msecs() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (long long)(tv.tv_sec) * 1000 + (tv.tv_usec / 1000); +} +char *msecs_strs(msecs_t ms) { + static char str[22]; + str[0] = 0; + sprintf(str, "%f", ms * 0.001); + for (int i = strlen(str); i > 0; i--) { + if (str[i] > '0') break; - } - lines[index] = (char *)malloc(strlen(line) + 1); - strcpy(lines[index], line); - index++; + str[i] = 0; } - return index; + return str; } - -bool rstartswithnumber(char *str) { return isdigit(str[0]); } - -void rstrmove2(char *str, unsigned int start, size_t length, - unsigned int new_pos) { - size_t str_len = strlen(str); - char new_str[str_len + 1]; - memset(new_str, 0, str_len); - if (start < new_pos) { - strncat(new_str, str + length, str_len - length - start); - new_str[new_pos] = 0; - strncat(new_str, str + start, length); - strcat(new_str, str + strlen(new_str)); - memset(str, 0, str_len); - strcpy(str, new_str); +char *msecs_strms(msecs_t ms) { + static char str[22]; + str[0] = 0; + sprintf(str, "%lld", ms); + return str; +} +char *msecs_str(long long ms) { + static char result[30]; + result[0] = 0; + if (ms > 999) { + char *s = msecs_strs(ms); + sprintf(result, "%ss", s); } else { - strncat(new_str, str + start, length); - strncat(new_str, str, start); - strncat(new_str, str + start + length, str_len - start); - memset(str, 0, str_len); - strcpy(str, new_str); + char *s = msecs_strms(ms); + sprintf(result, "%sMs", s); } - new_str[str_len] = 0; + return result; } -void rstrmove(char *str, unsigned int start, size_t length, - unsigned int new_pos) { - size_t str_len = strlen(str); - if (start >= str_len || new_pos >= str_len || start + length > str_len) { - return; +void nsleep(nsecs_t nanoseconds) { + long seconds = 0; + int factor = 0; + while (nanoseconds > 1000000000) { + factor++; + nanoseconds = nanoseconds / 10; } - char temp[length + 1]; - strncpy(temp, str + start, length); - temp[length] = 0; - if (start < new_pos) { - memmove(str + start, str + start + length, new_pos - start); - strncpy(str + new_pos - length + 1, temp, length); + if (factor) { + seconds = 1; + factor--; + while (factor) { + seconds = seconds * 10; + factor--; + } + } + + struct timespec req = {seconds, nanoseconds}; + struct timespec rem; + + if (nanosleep(&req, &rem) == -1) { + if (errno == EINTR) { + printf("Sleep was interrupted. Remaining time: %ld.%09ld seconds\n", + rem.tv_sec, rem.tv_nsec); + } else { + perror("nanosleep"); + } } else { - memmove(str + new_pos + length, str + new_pos, start - new_pos); - strncpy(str + new_pos, temp, length); + // printf("Slept for %ld.%09ld seconds\n", req.tv_sec, req.tv_nsec); } } -int cmp_line(const void *left, const void *right) { - char *l = *(char **)left; - char *r = *(char **)right; +void ssleep(double s) { + long nanoseconds = (long)(1000000000 * s); - char lstripped[strlen(l) + 1]; - rstrip_whitespace(l, lstripped); - char rstripped[strlen(r) + 1]; - rstrip_whitespace(r, rstripped); + long seconds = 0; - double d1, d2; - bool found_d1 = rstrextractdouble(lstripped, &d1); - bool found_d2 = rstrextractdouble(rstripped, &d2); + struct timespec req = {seconds, nanoseconds}; + struct timespec rem; - if (found_d1 && found_d2) { - double frac_part1; - double int_part1; - frac_part1 = modf(d1, &int_part1); - double frac_part2; - double int_part2; - frac_part2 = modf(d2, &int_part2); - if (d1 == d2) { - return strcmp(lstripped, rstripped); - } else if (frac_part1 && frac_part2) { - return d1 > d2; - } else if (frac_part1 && !frac_part2) { - return 1; - } else if (frac_part2 && !frac_part1) { - return -1; - } else if (!frac_part1 && !frac_part2) { - return d1 > d2; + if (nanosleep(&req, &rem) == -1) { + if (errno == EINTR) { + printf("Sleep was interrupted. Remaining time: %ld.%09ld seconds\n", + rem.tv_sec, rem.tv_nsec); + } else { + perror("nanosleep"); } + } else { + // printf("Slept for %ld.%09ld seconds\n", req.tv_sec, req.tv_nsec); } - return 0; +} +void msleep(long miliseonds) { + long nanoseconds = miliseonds * 1000000; + nsleep(nanoseconds); } -int rstrsort(char *input, char *output) { - char **lines = (char **)malloc(strlen(input) * 10); - int line_count = rstrsplit(input, lines); - qsort(lines, line_count, sizeof(char *), cmp_line); - rstrjoin(lines, line_count, "", output); - free(lines); - return line_count; +char *format_time(int64_t nanoseconds) { + static char output[1024]; + size_t output_size = sizeof(output); + output[0] = 0; + if (nanoseconds < 1000) { + // Less than 1 microsecond + snprintf(output, output_size, "%ldns", nanoseconds); + } else if (nanoseconds < 1000000) { + // Less than 1 millisecond + double us = nanoseconds / 1000.0; + snprintf(output, output_size, "%.2fµs", us); + } else if (nanoseconds < 1000000000) { + // Less than 1 second + double ms = nanoseconds / 1000000.0; + snprintf(output, output_size, "%.2fms", ms); + } else { + // 1 second or more + double s = nanoseconds / 1000000000.0; + snprintf(output, output_size, "%.2fs", s); + } + return output; } #endif -#ifndef RLIB_TERMINAL_H -#define RLIB_TERMINAL_H - +#include #include #include #include -#include -#ifndef RTEST_H -#define RTEST_H -#include -#include #include -#define debug(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__); - -char *rcurrent_banner; -int rassert_count = 0; -unsigned short rtest_is_first = 1; -unsigned int rtest_fail_count = 0; -int rtest_end(char *content) { - // Returns application exit code. 0 == success - printf("%s", content); - printf("\n@assertions: %d\n", rassert_count); - printf("@memory: %s\n", rmalloc_stats()); +long rpline_number = 0; +nsecs_t rprtime = 0; - if (rmalloc_count != 0) { - printf("MEMORY ERROR\n"); - return rtest_fail_count > 0; - } - return rtest_fail_count > 0; -} +int8_t _env_rdisable_colors = -1; +bool _rprint_enable_colors = true; -void rtest_test_banner(char *content, char *file) { - if (rtest_is_first == 1) { - char delimiter[] = "."; - char *d = delimiter; - char f[2048]; - strcpy(f, file); - printf("%s tests", strtok(f, d)); - rtest_is_first = 0; - setvbuf(stdout, NULL, _IONBF, 0); +bool rprint_is_color_enabled() { + if (_env_rdisable_colors == -1) { + _env_rdisable_colors = getenv("RDISABLE_COLORS") != NULL; } - printf("\n - %s ", content); -} - -bool rtest_test_true_silent(char *expr, int res, int line) { - rassert_count++; - if (res) { - return true; + if (_env_rdisable_colors) { + _rprint_enable_colors = false; } - rprintrf(stderr, "\nERROR on line %d: %s", line, expr); - rtest_fail_count++; - return false; + return _rprint_enable_colors; } -bool rtest_test_true(char *expr, int res, int line) { - rassert_count++; - if (res) { - fprintf(stdout, "."); - return true; - } - rprintrf(stderr, "\nERROR on line %d: %s", line, expr); - rtest_fail_count++; - return false; -} -bool rtest_test_false_silent(char *expr, int res, int line) { - return rtest_test_true_silent(expr, !res, line); -} -bool rtest_test_false(char *expr, int res, int line) { - return rtest_test_true(expr, !res, line); -} -void rtest_test_skip(char *expr, int line) { - rprintgf(stderr, "\n @skip(%s) on line %d\n", expr, line); -} -bool rtest_test_assert(char *expr, int res, int line) { - if (rtest_test_true(expr, res, line)) { - return true; - } - rtest_end(""); - exit(40); -} +void rprint_disable_colors() { _rprint_enable_colors = false; } +void rprint_enable_colors() { _rprint_enable_colors = true; } +void rprint_toggle_colors() { _rprint_enable_colors = !_rprint_enable_colors; } -#define rtest_banner(content) \ - rcurrent_banner = content; \ - rtest_test_banner(content, __FILE__); -#define rtest_true(expr) rtest_test_true(#expr, expr, __LINE__); -#define rtest_assert(expr) \ - { \ - int __valid = expr ? 1 : 0; \ - rtest_test_true(#expr, __valid, __LINE__); \ - }; \ - ; +void rclear() { printf("\033[2J"); } -#define rassert(expr) \ - { \ - int __valid = expr ? 1 : 0; \ - rtest_test_true(#expr, __valid, __LINE__); \ - }; \ - ; -#define rtest_asserts(expr) \ - { \ - int __valid = expr ? 1 : 0; \ - rtest_test_true_silent(#expr, __valid, __LINE__); \ - }; -#define rasserts(expr) \ - { \ - int __valid = expr ? 1 : 0; \ - rtest_test_true_silent(#expr, __valid, __LINE__); \ - }; -#define rtest_false(expr) \ - rprintf(" [%s]\t%s\t\n", expr == 0 ? "OK" : "NOK", #expr); \ - assert_count++; \ - assert(#expr); -#define rtest_skip(expr) rtest_test_skip(#expr, __LINE__); +void rprintpf(FILE *f, const char *prefix, const char *format, va_list args) { + char *pprefix = (char *)prefix; + char *pformat = (char *)format; + bool reset_color = false; + bool press_any_key = false; + char new_format[4096]; + bool enable_color = rprint_is_color_enabled(); + memset(new_format, 0, 4096); + int new_format_length = 0; + char temp[1000]; + memset(temp, 0, 1000); + if (enable_color && pprefix[0]) { + strcat(new_format, pprefix); + new_format_length += strlen(pprefix); + reset_color = true; + } + while (true) { + if (pformat[0] == '\\' && pformat[1] == 'i') { + strcat(new_format, "\e[3m"); + new_format_length += strlen("\e[3m"); + reset_color = true; + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'u') { + strcat(new_format, "\e[4m"); + new_format_length += strlen("\e[4m"); + reset_color = true; + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'b') { + strcat(new_format, "\e[1m"); + new_format_length += strlen("\e[1m"); + reset_color = true; + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'C') { + press_any_key = true; + rpline_number++; + pformat++; + pformat++; + reset_color = false; + } else if (pformat[0] == '\\' && pformat[1] == 'k') { + press_any_key = true; + rpline_number++; + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'c') { + rpline_number++; + strcat(new_format, "\e[2J\e[H"); + new_format_length += strlen("\e[2J\e[H"); + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'L') { + rpline_number++; + temp[0] = 0; + sprintf(temp, "%ld", rpline_number); + strcat(new_format, temp); + new_format_length += strlen(temp); + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'l') { + rpline_number++; + temp[0] = 0; + sprintf(temp, "%.5ld", rpline_number); + strcat(new_format, temp); + new_format_length += strlen(temp); + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 'T') { + nsecs_t nsecs_now = nsecs(); + nsecs_t end = rprtime ? nsecs_now - rprtime : 0; + temp[0] = 0; + sprintf(temp, "%s", format_time(end)); + strcat(new_format, temp); + new_format_length += strlen(temp); + rprtime = nsecs_now; + pformat++; + pformat++; + } else if (pformat[0] == '\\' && pformat[1] == 't') { + rprtime = nsecs(); + pformat++; + pformat++; + } else { + new_format[new_format_length] = *pformat; + new_format_length++; + if (!*pformat) + break; + + // printf("%c",*pformat); + pformat++; + } + } + if (reset_color) { + strcat(new_format, "\e[0m"); + new_format_length += strlen("\e[0m"); + } + + new_format[new_format_length] = 0; + vfprintf(f, new_format, args); + + fflush(stdout); + if (press_any_key) { + nsecs_t s = nsecs(); + fgetc(stdin); + rprtime += nsecs() - s; + } +} + +void rprintp(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "", format, args); + va_end(args); +} + +void rprintf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "", format, args); + va_end(args); +} +void rprint(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "", format, args); + va_end(args); +} +#define printf rprint + +// Print line +void rprintlf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\\l", format, args); + va_end(args); +} +void rprintl(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\\l", format, args); + va_end(args); +} + +// Black +void rprintkf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[30m", format, args); + va_end(args); +} +void rprintk(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[30m", format, args); + va_end(args); +} + +// Red +void rprintrf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[31m", format, args); + va_end(args); +} +void rprintr(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[31m", format, args); + va_end(args); +} + +// Green +void rprintgf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[32m", format, args); + va_end(args); +} +void rprintg(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[32m", format, args); + va_end(args); +} + +// Yellow +void rprintyf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[33m", format, args); + va_end(args); +} +void rprinty(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[33m", format, args); + va_end(args); +} + +// Blue +void rprintbf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[34m", format, args); + va_end(args); +} + +void rprintb(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[34m", format, args); + va_end(args); +} + +// Magenta +void rprintmf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[35m", format, args); + va_end(args); +} +void rprintm(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[35m", format, args); + va_end(args); +} + +// Cyan +void rprintcf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[36m", format, args); + va_end(args); +} +void rprintc(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[36m", format, args); + va_end(args); +} + +// White +void rprintwf(FILE *f, char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[37m", format, args); + va_end(args); +} +void rprintw(char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[37m", format, args); + va_end(args); +} +#endif +#ifndef RMATH_H +#define RMATH_H +#include + +#ifndef ceil +double ceil(double x) { + if (x == (double)(long long)x) { + return x; + } else if (x > 0.0) { + return (double)(long long)x + 1.0; + } else { + return (double)(long long)x; + } +} +#endif + +#ifndef floor +double floor(double x) { + if (x >= 0.0) { + return (double)(long long)x; + } else { + double result = (double)(long long)x; + return (result == x) ? result : result - 1.0; + } +} +#endif + +#ifndef modf +double modf(double x, double *iptr) { + double int_part = (x >= 0.0) ? floor(x) : ceil(x); + *iptr = int_part; + return x - int_part; +} +#endif +#endif +#ifndef RMALLOC_H +#define RMALLOC_H +#include +#include +#include + +unsigned long long rmalloc_count = 0; +unsigned long long rmalloc_alloc_count = 0; +unsigned long long int rmalloc_free_count = 0; + +void *rmalloc(size_t size) { + rmalloc_count++; + rmalloc_alloc_count++; + return malloc(size); +} +void *rrealloc(void *obj, size_t size) { + if (obj == NULL) { + rmalloc_count++; + rmalloc_alloc_count++; + } + return realloc(obj, size); +} +void *rfree(void *obj) { + rmalloc_count--; + rmalloc_free_count++; + free(obj); + return NULL; +} + +#define malloc rmalloc +#define realloc rrealloc +#define free rfree + +char *rmalloc_stats() { + static char res[100] = {0}; + sprintf(res, "Memory usage: %lld allocated, %lld freed, %lld in use.", + rmalloc_alloc_count, rmalloc_free_count, rmalloc_count); + return res; +} + +char *rstrdup(char *str) { + + char *res = (char *)strdup(str); + rmalloc_alloc_count++; + rmalloc_count++; + return res; +} + +#endif + +#ifndef RTEST_H +#define RTEST_H +#include +#include +#include +#define debug(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__); + +char *rcurrent_banner; +int rassert_count = 0; +unsigned short rtest_is_first = 1; +unsigned int rtest_fail_count = 0; + +int rtest_end(char *content) { + // Returns application exit code. 0 == success + printf("%s", content); + printf("\n@assertions: %d\n", rassert_count); + printf("@memory: %s\n", rmalloc_stats()); + + if (rmalloc_count != 0) { + printf("MEMORY ERROR\n"); + return rtest_fail_count > 0; + } + return rtest_fail_count > 0; +} + +void rtest_test_banner(char *content, char *file) { + if (rtest_is_first == 1) { + char delimiter[] = "."; + char *d = delimiter; + char f[2048]; + strcpy(f, file); + printf("%s tests", strtok(f, d)); + rtest_is_first = 0; + setvbuf(stdout, NULL, _IONBF, 0); + } + printf("\n - %s ", content); +} + +bool rtest_test_true_silent(char *expr, int res, int line) { + rassert_count++; + if (res) { + return true; + } + rprintrf(stderr, "\nERROR on line %d: %s", line, expr); + rtest_fail_count++; + return false; +} + +bool rtest_test_true(char *expr, int res, int line) { + rassert_count++; + if (res) { + fprintf(stdout, "."); + return true; + } + rprintrf(stderr, "\nERROR on line %d: %s", line, expr); + rtest_fail_count++; + return false; +} +bool rtest_test_false_silent(char *expr, int res, int line) { + return rtest_test_true_silent(expr, !res, line); +} +bool rtest_test_false(char *expr, int res, int line) { + return rtest_test_true(expr, !res, line); +} +void rtest_test_skip(char *expr, int line) { + rprintgf(stderr, "\n @skip(%s) on line %d\n", expr, line); +} +bool rtest_test_assert(char *expr, int res, int line) { + if (rtest_test_true(expr, res, line)) { + return true; + } + rtest_end(""); + exit(40); +} + +#define rtest_banner(content) \ + rcurrent_banner = content; \ + rtest_test_banner(content, __FILE__); +#define rtest_true(expr) rtest_test_true(#expr, expr, __LINE__); +#define rtest_assert(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true(#expr, __valid, __LINE__); \ + }; \ + ; + +#define rassert(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true(#expr, __valid, __LINE__); \ + }; \ + ; +#define rtest_asserts(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true_silent(#expr, __valid, __LINE__); \ + }; +#define rasserts(expr) \ + { \ + int __valid = expr ? 1 : 0; \ + rtest_test_true_silent(#expr, __valid, __LINE__); \ + }; +#define rtest_false(expr) \ + rprintf(" [%s]\t%s\t\n", expr == 0 ? "OK" : "NOK", #expr); \ + assert_count++; \ + assert(#expr); +#define rtest_skip(expr) rtest_test_skip(#expr, __LINE__); + +FILE *rtest_create_file(char *path, char *content) { + FILE *fd = fopen(path, "wb"); + + char c; + int index = 0; + + while ((c = content[index]) != 0) { + fputc(c, fd); + index++; + } + fclose(fd); + fd = fopen(path, "rb"); + return fd; +} + +void rtest_delete_file(char *path) { unlink(path); } +#endif +#ifndef RREX3_H +#define RREX3_H +#include +#include +#include +#include +#include +#include +#include +#ifndef RREX3_DEBUG +#define RREX3_DEBUG 0 +#endif + +struct rrex3_t; + +typedef void (*rrex3_function)(struct rrex3_t *); + +typedef struct rrex3_t { + void (*functions[254])(struct rrex3_t *); + void (*slash_functions[254])(struct rrex3_t *); + bool valid; + int match_count; + int match_capacity; + char **matches; + bool exit; + char *__expr; + char *__str; + char *_expr; + char *_str; + char *expr; + char *str; + char *compiled; + bool inside_brackets; + bool inside_parentheses; + bool pattern_error; + bool match_from_start; + char bytecode; + rrex3_function function; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } previous; + struct { + void (*function)(struct rrex3_t *); + char *expr; + char *str; + char bytecode; + } failed; +} rrex3_t; + +static bool isdigitrange(char *s) { + if (!isdigit(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isdigit(*(s + 2)); +} + +static bool isalpharange(char *s) { + if (!isalpha(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isalpha(*(s + 2)); +} + +void rrex3_free_matches(rrex3_t *rrex3) { + if (!rrex3->matches) + return; + for (int i = 0; i < rrex3->match_count; i++) { + free(rrex3->matches[i]); + } + free(rrex3->matches); + rrex3->matches = NULL; + rrex3->match_count = 0; + rrex3->match_capacity = 0; +} + +void rrex3_free(rrex3_t *rrex3) { + if (!rrex3) + return; + if (rrex3->compiled) { + free(rrex3->compiled); + rrex3->compiled = NULL; + } + rrex3_free_matches(rrex3); + free(rrex3); + rrex3 = NULL; +} +static bool rrex3_move(rrex3_t *, bool); +static void rrex3_set_previous(rrex3_t *); +inline static void rrex3_cmp_asterisk(rrex3_t *); +void rrex3_cmp_literal_range(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Range check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char start = *rrex3->expr; + rrex3->expr++; + rrex3->expr++; + char end = *rrex3->expr; + if (*rrex3->str >= start && *rrex3->str <= end) { + rrex3->str++; + rrex3->valid = true; + } else { + rrex3->valid = false; + } + rrex3->expr++; +} + +bool rrex3_is_function(char chr) { + if (chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || + chr == '*') + return true; + return false; +} + +inline static void rrex3_cmp_literal(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + if (*rrex3->expr == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK"); + exit(1); + } + if (rrex3->valid == false) { + rrex3->expr++; + return; + } + if (rrex3->inside_brackets) { + if (isalpharange(rrex3->expr) || isdigitrange(rrex3->expr)) { + rrex3_cmp_literal_range(rrex3); + return; + } + } +#if RREX3_DEBUG == 1 + printf("Literal check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + if (*rrex3->expr == *rrex3->str) { + rrex3->expr++; + rrex3->str++; + rrex3->valid = true; + // if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == + // rrex3_cmp_literal && !rrex3->inside_brackets && + //! rrex3_is_function(*rrex3->expr)){ rrex3_cmp_literal(rrex3); + // if(rrex3->valid == false){ + // rrex3->expr--; + // rrex3->valid = true; + // } + // } + return; + } + rrex3->expr++; + rrex3->valid = false; +} + +inline static void rrex3_cmp_dot(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Dot check (any char): %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + rrex3->expr++; + if (!rrex3->valid) { + return; + } + if (*rrex3->str && *rrex3->str != '\n') { + rrex3->str++; + if (*rrex3->expr && *rrex3->expr == '.') { + rrex3_cmp_dot(rrex3); + return; + } /*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == + '+')){ char * next = strchr(rrex3->str,*(rrex3->expr + 1)); char * + space = strchr(rrex3->str,'\n'); if(next && (!space || space > next)){ + rrex3->str = next; + } + }*/ + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_question_mark(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Question mark check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + if (rrex3->valid == false) + rrex3->valid = true; + rrex3->expr++; +} + +inline static void rrex3_cmp_whitespace(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char c = *rrex3->expr; + rrex3->valid = c == ' ' || c == '\n' || c == '\t'; + if (rrex3->valid) { + rrex3->str++; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_whitespace_upper(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Non whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + char c = *rrex3->expr; + rrex3->valid = !(c == ' ' || c == '\n' || c == '\t'); + if (rrex3->valid) { + rrex3->str++; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_plus(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + printf("Plus check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + rrex3_set_previous(rrex3); + + if (rrex3->valid) { + rrex3->str--; + } else { + return; + } + char *original_expr = rrex3->expr; + char *next = original_expr + 1; + char *loop_expr = rrex3->previous.expr - 1; + if (*loop_expr == '+') { + rrex3->valid = false; + rrex3->pattern_error = true; + rrex3->expr++; + return; + } + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *next_next = NULL; + char *next_str = rrex3->str; + while (*rrex3->str) { + // Check if next matches + char *original_str = rrex3->str; + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + success_next = true; + next_next = rrex3->expr; + next_str = rrex3->str; + success_next_once = true; + } else { + success_next = false; + } + if (success_next_once && !success_next) { + break; + } + // Check if current matches + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!*rrex3->str || !rrex3_move(rrex3, false)) { + success_current = false; + } else { + success_current = true; + if (!success_next) { + next_next = rrex3->expr + 1; // +1 is the * itself + next_str = rrex3->str; + } + } + if (success_next && !success_current) { + break; + } + } + if (!next_next) + rrex3->expr = next; + else { + rrex3->expr = next_next; + } + rrex3->str = next_str; + rrex3->valid = true; +} + +inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintg("Asterisk start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + if (!rrex3->valid) { + rrex3->valid = true; + rrex3->expr++; + return; + } + if (*rrex3->previous.expr == '*') { + // Support for ** + rrex3->valid = false; + // rrex3->pattern_error = true; + rrex3->expr++; + return; + } + rrex3->str = rrex3->previous.str; + ; + char *next = rrex3->expr + 1; + char *next_original = NULL; + if (*next == '*') { + next++; + } + if (*next == ')' && *(next + 1)) { + next_original = next; + next++; + } + char *loop_expr = rrex3->previous.expr; + bool success_next = false; + bool success_next_once = false; + bool success_current = false; + char *right_next = NULL; + char *right_str = rrex3->str; + while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { + // Remember original_str because it's modified + // by checking right and should be restored + // for checking left so they're matching the + // same value. + char *original_str = rrex3->str; + // Check if right matches. + // if(*next != ')'){ + rrex3->expr = next; + rrex3->valid = true; + if (rrex3_move(rrex3, false)) { + // Match rright. + success_next = true; + if (!next_original) { + right_next = rrex3->expr; + } else { + right_next = next_original; + break; + } + right_str = rrex3->str; + success_next_once = true; + } else { + // No match Right. + success_next = false; + } + //} + if (success_next_once && !success_next) { + // Matched previous time but now doesn't. + break; + } + // Check if left matches. + rrex3->str = original_str; + rrex3->expr = loop_expr; + rrex3->valid = true; + if (!rrex3_move(rrex3, false)) { + // No match left. + success_current = false; + } else { + // Match left. + success_current = true; + // NOT SURE< WITHOUT DOET HETZELFDE: + // original_str = rrex3->str; + if (!success_next) { + right_str = rrex3->str; + if (*rrex3->expr != ')') { + right_next = rrex3->expr + 1; // +1 is the * itself -FILE *rtest_create_file(char *path, char *content) { - FILE *fd = fopen(path, "wb"); + } else { - char c; - int index = 0; + // break; + } + } + } - while ((c = content[index]) != 0) { - fputc(c, fd); - index++; + if ((success_next && !success_current) || + (!success_next && !success_current)) { + break; + } + } + rrex3->expr = right_next; + rrex3->str = right_str; + rrex3->valid = true; +#if RREX3_DEBUG == 1 + rprintg("Asterisk end check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif +} + +inline static void rrex3_cmp_roof(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); +#if RREX3_DEBUG == 1 + printf("expr, *rrex3->str, rrex3->valid); +#endif + rrex3->valid = rrex3->str == rrex3->_str; + rrex3->match_from_start = true; + rrex3->expr++; +} +inline static void rrex3_cmp_dollar(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + +#if RREX3_DEBUG == 1 + printf("Dollar check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (*rrex3->str || !rrex3->valid) { + rrex3->valid = false; + } + rrex3->expr++; +} + +inline static void rrex3_cmp_w(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} +inline static void rrex3_cmp_w_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isalpha(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_d(rrex3_t *rrex3) { + + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} +inline static void rrex3_cmp_d_upper(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; +#if RREX3_DEBUG == 1 + printf("!Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (!isdigit(*rrex3->str)) { + rrex3->str++; + } else { + rrex3->valid = false; + } +} + +inline static void rrex3_cmp_slash(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3->expr++; + + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->slash_functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); +} + +inline static int collect_digits(rrex3_t *rrex3) { + char output[20]; + unsigned int digit_count = 0; + while (isdigit(*rrex3->expr)) { + + output[digit_count] = *rrex3->expr; + rrex3->expr++; + digit_count++; + } + output[digit_count] = 0; + return atoi(output); +} + +inline static void rrex3_cmp_range(rrex3_t *rrex3) { + char *loop_code = rrex3->previous.expr; + char *expr_original = rrex3->expr; + rrex3->expr++; + int range_start = collect_digits(rrex3) - 1; + int range_end = 0; + if (*rrex3->expr == ',') { + rrex3->expr++; + range_end = collect_digits(rrex3); + } + rrex3->expr++; + int times_valid = 0; + while (*rrex3->str) { + rrex3->expr = loop_code; + rrex3_move(rrex3, false); + if (rrex3->valid == false) { + break; + } else { + times_valid++; + } + if (range_end) { + if (times_valid >= range_start && times_valid == range_end - 1) { + rrex3->valid = true; + } else { + rrex3->valid = false; + } + break; + } else if (range_start) { + if (times_valid == range_start) { + rrex3->valid = true; + break; + } + } + } + rrex3->valid = times_valid >= range_start; + if (rrex3->valid && range_end) { + rrex3->valid = times_valid <= range_end; + } + rrex3->expr = strchr(expr_original, '}') + 1; +} + +inline static void rrex3_cmp_word_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + bool valid = false; + if (isalpha(*rrex3->str)) { + if (rrex3->_str != rrex3->str) { + if (!isalpha(*(rrex3->str - 1))) { + valid = true; + } + } else { + valid = true; + } + } else if (isalpha(isalpha(*rrex3->str) && !isalpha(*rrex3->str + 1))) { + valid = true; + } + rrex3->expr++; + rrex3->valid = valid; +} +inline static void rrex3_cmp_word_not_start_or_end(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); + + rrex3_cmp_word_start_or_end(rrex3); + rrex3->valid = !rrex3->valid; +} + +inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets start: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif + rrex3_set_previous(rrex3); + char *original_expr = rrex3->expr; + rrex3->expr++; + rrex3->inside_brackets = true; + bool valid_once = false; + bool reversed = false; + if (*rrex3->expr == '^') { + reversed = true; + rrex3->expr++; } - fclose(fd); - fd = fopen(path, "rb"); - return fd; -} + bool valid = false; + while (*rrex3->expr != ']' && *rrex3->expr != 0) { + rrex3->valid = true; + valid = rrex3_move(rrex3, false); + if (reversed) { + valid = !valid; + } + if (valid) { + valid_once = true; + if (!reversed) { + valid_once = true; + break; + } + } else { + if (reversed) { + valid_once = false; + break; + } + } + } + if (valid_once && reversed) { + rrex3->str++; + } + while (*rrex3->expr != ']' && *rrex3->expr != 0) + rrex3->expr++; + if (*rrex3->expr != 0) + rrex3->expr++; -void rtest_delete_file(char *path) { unlink(path); } + rrex3->valid = valid_once; + rrex3->inside_brackets = false; + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; +#if RREX3_DEBUG == 1 + rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); #endif - -char *rfcaptured = NULL; - -void rfcapture(FILE *f, char *buff, size_t size) { - rfcaptured = buff; - setvbuf(f, rfcaptured, _IOFBF, size); } -void rfstopcapture(FILE *f) { setvbuf(f, 0, _IOFBF, 0); } -bool _r_disable_stdout_toggle = false; - -FILE *_r_original_stdout = NULL; +inline static void rrex3_cmp_pipe(rrex3_t *rrex3) { + rrex3_set_previous(rrex3); -bool rr_enable_stdout() { - if (_r_disable_stdout_toggle) - return false; - if (!_r_original_stdout) { - stdout = fopen("/dev/null", "rb"); - return false; - } - if (_r_original_stdout && _r_original_stdout != stdout) { - fclose(stdout); +#if RREX3_DEBUG == 1 + printf("Pipe check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +#endif + if (rrex3->valid == true) { + rrex3->exit = true; + } else { + rrex3->valid = true; } - stdout = _r_original_stdout; - return true; + rrex3->expr++; } -bool rr_disable_stdout() { - if (_r_disable_stdout_toggle) { - return false; +inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, + *rrex3->str, rrex3->valid); +#endif + if (!rrex3->valid) { + rrex3->expr++; + return; } - if (_r_original_stdout == NULL) { - _r_original_stdout = stdout; + rrex3_set_previous(rrex3); + if (rrex3->match_count == rrex3->match_capacity) { + + rrex3->match_capacity++; + rrex3->matches = (char **)realloc( + rrex3->matches, rrex3->match_capacity * sizeof(char *)); } - if (stdout == _r_original_stdout) { - stdout = fopen("/dev/null", "rb"); - return true; + rrex3->matches[rrex3->match_count] = (char *)malloc(strlen(rrex3->str) + 1); + strcpy(rrex3->matches[rrex3->match_count], rrex3->str); + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->expr++; + rrex3->inside_parentheses = true; + while (*rrex3->expr != ')' && !rrex3->exit) { + rrex3_move(rrex3, false); } - return false; -} -bool rr_toggle_stdout() { - if (!_r_original_stdout) { - rr_disable_stdout(); - return true; - } else if (stdout != _r_original_stdout) { - rr_enable_stdout(); - return true; + while (*rrex3->expr != ')') { + rrex3->expr++; + } + rrex3->expr++; + rrex3->inside_parentheses = false; + + char *previous_expr = rrex3->expr; + rrex3->expr = original_expr; + rrex3_set_previous(rrex3); + rrex3->expr = previous_expr; + if (rrex3->valid == false) { + rrex3->str = original_str; + free(rrex3->matches[rrex3->match_count]); } else { - rr_disable_stdout(); - return true; + rrex3->matches[rrex3->match_count] + [strlen(rrex3->matches[rrex3->match_count]) - + strlen(rrex3->str)] = 0; + rrex3->match_count++; + } +#if RREX3_DEBUG == 1 + rprinty("\\l Parentheses end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, + rrex3->valid); +#endif +} + +inline static void rrex3_reset(rrex3_t *rrex3) { + rrex3_free_matches(rrex3); + rrex3->valid = true; + rrex3->pattern_error = false; + rrex3->inside_brackets = false; + rrex3->inside_parentheses = false; + rrex3->exit = false; + rrex3->previous.expr = NULL; + rrex3->previous.str = NULL; + rrex3->previous.bytecode = 0; + rrex3->failed.expr = NULL; + rrex3->failed.str = NULL; + rrex3->failed.bytecode = 0; + rrex3->match_from_start = false; +} + +void rrex3_init(rrex3_t *rrex3) { + for (__uint8_t i = 0; i < 254; i++) { + rrex3->functions[i] = rrex3_cmp_literal; + rrex3->slash_functions[i] = rrex3_cmp_literal; } + rrex3->functions['?'] = rrex3_cmp_question_mark; + rrex3->functions['^'] = rrex3_cmp_roof; + rrex3->functions['$'] = rrex3_cmp_dollar; + rrex3->functions['.'] = rrex3_cmp_dot; + rrex3->functions['*'] = rrex3_cmp_asterisk; + rrex3->functions['+'] = rrex3_cmp_plus; + rrex3->functions['|'] = rrex3_cmp_pipe; + rrex3->functions['\\'] = rrex3_cmp_slash; + rrex3->functions['{'] = rrex3_cmp_range; + rrex3->functions['['] = rrex3_cmp_brackets; + rrex3->functions['('] = rrex3_cmp_parentheses; + rrex3->slash_functions['w'] = rrex3_cmp_w; + rrex3->slash_functions['W'] = rrex3_cmp_w_upper; + rrex3->slash_functions['d'] = rrex3_cmp_d; + rrex3->slash_functions['D'] = rrex3_cmp_d_upper; + rrex3->slash_functions['s'] = rrex3_cmp_whitespace; + rrex3->slash_functions['S'] = rrex3_cmp_whitespace_upper; + rrex3->slash_functions['b'] = rrex3_cmp_word_start_or_end; + rrex3->slash_functions['B'] = rrex3_cmp_word_not_start_or_end; + rrex3->match_count = 0; + rrex3->match_capacity = 0; + rrex3->matches = NULL; + rrex3->compiled = NULL; + + rrex3_reset(rrex3); } -typedef struct rprogressbar_t { - unsigned long current_value; - unsigned long min_value; - unsigned long max_value; - unsigned int length; - bool changed; - double percentage; - unsigned int width; - unsigned long draws; - FILE *fout; -} rprogressbar_t; +rrex3_t *rrex3_new() { + rrex3_t *rrex3 = (rrex3_t *)malloc(sizeof(rrex3_t)); -rprogressbar_t *rprogressbar_new(long min_value, long max_value, - unsigned int width, FILE *fout) { - rprogressbar_t *pbar = (rprogressbar_t *)malloc(sizeof(rprogressbar_t)); - pbar->min_value = min_value; - pbar->max_value = max_value; - pbar->current_value = min_value; - pbar->width = width; - pbar->draws = 0; - pbar->length = 0; - pbar->changed = false; - pbar->fout = fout ? fout : stdout; - return pbar; + rrex3_init(rrex3); + + return rrex3; } -void rprogressbar_free(rprogressbar_t *pbar) { free(pbar); } +rrex3_t *rrex3_compile(rrex3_t *rrex, char *expr) { -void rprogressbar_draw(rprogressbar_t *pbar) { - if (!pbar->changed) { - return; - } else { - pbar->changed = false; - } - pbar->draws++; - char draws_text[22]; - draws_text[0] = 0; - sprintf(draws_text, "%ld", pbar->draws); - char *draws_textp = draws_text; - // bool draws_text_len = strlen(draws_text); - char bar_begin_char = ' '; - char bar_progress_char = ' '; - char bar_empty_char = ' '; - char bar_end_char = ' '; - char content[4096] = {0}; - char bar_content[1024]; - char buff[2048] = {0}; - bar_content[0] = '\r'; - bar_content[1] = bar_begin_char; - unsigned int index = 2; - for (unsigned long i = 0; i < pbar->length; i++) { - if (*draws_textp) { - bar_content[index] = *draws_textp; - draws_textp++; + rrex3_t *rrex3 = rrex ? rrex : rrex3_new(); + + char *compiled = (char *)malloc(strlen(expr) + 1); + unsigned int count = 0; + while (*expr) { + if (*expr == '[' && *(expr + 2) == ']') { + *compiled = *(expr + 1); + expr++; + expr++; + } else if (*expr == '[' && *(expr + 1) == '0' && *(expr + 2) == '-' && + *(expr + 3) == '9' && *(expr + 4) == ']') { + *compiled = '\\'; + compiled++; + *compiled = 'd'; + count++; + expr++; + expr++; + expr++; + expr++; } else { - bar_content[index] = bar_progress_char; + *compiled = *expr; } - index++; + if (*compiled == '[') { + // in_brackets = true; + + } else if (*compiled == ']') { + // in_brackets = false; + } + expr++; + compiled++; + count++; } - char infix[] = "\033[0m"; - for (unsigned long i = 0; i < strlen(infix); i++) { - bar_content[index] = infix[i]; - index++; + *compiled = 0; + compiled -= count; + rrex3->compiled = compiled; + return rrex3; +} + +inline static void rrex3_set_previous(rrex3_t *rrex3) { + rrex3->previous.function = rrex3->function; + rrex3->previous.expr = rrex3->expr; + rrex3->previous.str = rrex3->str; + rrex3->previous.bytecode = *rrex3->expr; +} + +static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { + char *original_expr = rrex3->expr; + char *original_str = rrex3->str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); + if (!*rrex3->expr && !*rrex3->str) { + + rrex3->exit = true; + return rrex3->valid; } - for (unsigned long i = 0; i < pbar->width - pbar->length; i++) { - bar_content[index] = bar_empty_char; - index++; + if (rrex3->pattern_error) { + rrex3->valid = false; + return rrex3->valid; } - bar_content[index] = bar_end_char; - bar_content[index + 1] = '\0'; - sprintf(buff, "\033[43m%s\033[0m \033[33m%.2f%%\033[0m ", bar_content, - pbar->percentage * 100); - strcat(content, buff); - if (pbar->width == pbar->length) { - strcat(content, "\r"); - for (unsigned long i = 0; i < pbar->width + 10; i++) { - strcat(content, " "); + if (resume_on_fail && !rrex3->valid && *rrex3->expr) { + // rrex3_set_previous(rrex3); + rrex3->failed.bytecode = rrex3->bytecode; + rrex3->failed.function = rrex3->function; + rrex3->failed.expr = original_expr; + rrex3->failed.str = original_str; + rrex3->bytecode = *rrex3->expr; + rrex3->function = rrex3->functions[(int)rrex3->bytecode]; + rrex3->function(rrex3); + + if (!rrex3->valid && !rrex3->pattern_error) { + + if (*rrex3->str) { + char *pipe_position = strstr(rrex3->expr, "|"); + if (pipe_position != NULL) { + rrex3->expr = pipe_position + 1; + rrex3->str = rrex3->_str; + rrex3->valid = true; + return true; + } + } + if (rrex3->match_from_start) { + rrex3->valid = false; + return rrex3->valid; + } + if (!*rrex3->str++) { + rrex3->valid = false; + return rrex3->valid; + } + rrex3->expr = rrex3->_expr; + if (rrex3->str) + rrex3->valid = true; } - strcat(content, "\r"); } - fprintf(pbar->fout, "%s", content); - fflush(pbar->fout); + return rrex3->valid; } -bool rprogressbar_update(rprogressbar_t *pbar, unsigned long value) { - if (value == pbar->current_value) { - return false; +rrex3_t *rrex3(rrex3_t *rrex3, char *str, char *expr) { +#if RREX3_DEBUG == 1 + printf("Regex check: %s:%s:%d\n", expr, str, 1); +#endif + bool self_initialized = false; + if (rrex3 == NULL) { + self_initialized = true; + rrex3 = rrex3_new(); + } else { + rrex3_reset(rrex3); } - pbar->current_value = value; - pbar->percentage = (double)pbar->current_value / - (double)(pbar->max_value - pbar->min_value); - unsigned long new_length = (unsigned long)(pbar->percentage * pbar->width); - pbar->changed = new_length != pbar->length; - if (pbar->changed) { - pbar->length = new_length; - rprogressbar_draw(pbar); - return true; + + rrex3->_str = str; + rrex3->_expr = rrex3->compiled ? rrex3->compiled : expr; + rrex3->str = rrex3->_str; + rrex3->expr = rrex3->_expr; + while (*rrex3->expr && !rrex3->exit) { + if (!rrex3_move(rrex3, true)) + return NULL; + } + if (rrex3->valid) { + return rrex3; + } else { + if (self_initialized) { + rrex3_free(rrex3); + } + return NULL; } - return false; } -size_t rreadline(char *data, size_t len, bool strip_ln) { - __attribute__((unused)) char *unused = fgets(data, len, stdin); - size_t length = strlen(data); - if (length && strip_ln) - data[length - 1] = 0; - return length; -} +void rrex3_test() { + rrex3_t *rrex = rrex3_new(); -void rlib_test_progressbar() { - rtest_banner("Progress bar"); - rprogressbar_t *pbar = rprogressbar_new(0, 1000, 10, stderr); - rprogressbar_draw(pbar); - // No draws executed, nothing to show - rassert(pbar->draws == 0); - rprogressbar_update(pbar, 500); - rassert(pbar->percentage == 0.5); - rprogressbar_update(pbar, 500); - rprogressbar_update(pbar, 501); - rprogressbar_update(pbar, 502); - // Should only have drawn one time since value did change, but percentage - // did not - rassert(pbar->draws == 1); - // Changed is false because update function calls draw - rassert(pbar->changed == false); - rprogressbar_update(pbar, 777); - rassert(pbar->percentage == 0.777); - rprogressbar_update(pbar, 1000); - rassert(pbar->percentage == 1); -} + assert(rrex3(rrex, "aaaaaaa", "a*a$")); -#endif -#ifndef RTERM_H -#define RTERM_H -#include -#include -#include -#include -#include -#include -#include + // assert(rrex3("ababa", "a*b*a*b*a$")); + assert(rrex3(rrex, "#include\"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "#include \"test.h\"a", "#include.*\".*\"a$")); + assert(rrex3(rrex, "aaaaaad", "a*d$")); + assert(rrex3(rrex, "abcdef", "abd?cdef")); + assert(!rrex3(rrex, "abcdef", "abd?def")); + assert(rrex3(rrex, "abcdef", "def")); + assert(!rrex3(rrex, "abcdef", "^def")); + assert(rrex3(rrex, "abcdef", "def$")); + assert(!rrex3(rrex, "abcdef", "^abc$")); + assert(rrex3(rrex, "aB!.#1", "......")); + assert(!rrex3(rrex, "aB!.#\n", " ......")); + assert(!rrex3(rrex, "aaaaaad", "q+d$")); + assert(rrex3(rrex, "aaaaaaa", "a+a$")); + assert(rrex3(rrex, "aaaaaad", "q*d$")); + assert(!rrex3(rrex, "aaaaaad", "^q*d$")); -typedef struct winsize winsize_t; + // Asterisk function + assert(rrex3(rrex, "123321", "123*321")); + assert(rrex3(rrex, "pony", "p*ony")); + assert(rrex3(rrex, "pppony", "p*ony")); + assert(rrex3(rrex, "ppony", "p*pony")); + assert(rrex3(rrex, "pppony", "pp*pony")); + assert(rrex3(rrex, "pppony", ".*pony")); + assert(rrex3(rrex, "pony", ".*ony")); + assert(rrex3(rrex, "pony", "po*ny")); + // assert(rrex3(rrex,"ppppony", "p*pppony")); -typedef struct rshell_keypress_t { - bool pressed; - bool ctrl; - bool shift; - bool escape; - char c; - int ms; - int fd; -} rshell_keypress_t; + // Plus function + assert(rrex3(rrex, "pony", "p+ony")); + assert(!rrex3(rrex, "ony", "p+ony")); + assert(rrex3(rrex, "ppony", "p+pony")); + assert(rrex3(rrex, "pppony", "pp+pony")); + assert(rrex3(rrex, "pppony", ".+pony")); + assert(rrex3(rrex, "pony", ".+ony")); + assert(rrex3(rrex, "pony", "po+ny")); -typedef struct rterm_t { - bool show_cursor; - bool show_footer; - rshell_keypress_t key; - void (*before_cursor_move)(struct rterm_t *); - void (*after_cursor_move)(struct rterm_t *); - void (*after_key_press)(struct rterm_t *); - void (*before_key_press)(struct rterm_t *); - void (*before_draw)(struct rterm_t *); - void *session; - unsigned long iterations; - void (*tick)(struct rterm_t *); - char *status_text; - winsize_t size; - struct { - int x; - int y; - int pos; - int available; - } cursor; -} rterm_t; + // Slash functions + assert(rrex3(rrex, "a", "\\w")); + assert(!rrex3(rrex, "1", "\\w")); + assert(rrex3(rrex, "1", "\\W")); + assert(!rrex3(rrex, "a", "\\W")); + assert(rrex3(rrex, "a", "\\S")); + assert(!rrex3(rrex, " ", "\\s")); + assert(!rrex3(rrex, "\t", "\\s")); + assert(!rrex3(rrex, "\n", "\\s")); + assert(rrex3(rrex, "1", "\\d")); + assert(!rrex3(rrex, "a", "\\d")); + assert(rrex3(rrex, "a", "\\D")); + assert(!rrex3(rrex, "1", "\\D")); + assert(rrex3(rrex, "abc", "\\b")); + + assert(rrex3(rrex, "abc", "\\babc")); + assert(!rrex3(rrex, "abc", "a\\b")); + assert(!rrex3(rrex, "abc", "ab\\b")); + assert(!rrex3(rrex, "abc", "abc\\b")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + assert(rrex3(rrex, "abc", "ab\\B")); + assert(!rrex3(rrex, "1ab", "1\\Bab")); + assert(rrex3(rrex, "abc", "a\\Bbc")); + + // Escaping of special characters test. + assert(rrex3(rrex, "()+*.\\", "\\(\\)\\+\\*\\.\\\\")); -typedef void (*rterm_event)(rterm_t *); + // Pipe + // assert(rrex3(rrex,"abc","abc|def")); + assert(rrex3(rrex, "abc", "def|jkl|abc")); + assert(rrex3(rrex, "abc", "abc|def")); -void rterm_init(rterm_t *rterm) { - memset(rterm, 0, sizeof(rterm_t)); - rterm->show_cursor = true; - rterm->show_cursor = true; -} + assert(rrex3(rrex, "rhq", "def|rhq|rha")); + assert(rrex3(rrex, "abc", "abc|def")); -void rterm_getwinsize(winsize_t *w) { - // Get the terminal size - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, w) == -1) { - perror("ioctl"); - exit(EXIT_FAILURE); - } -} + // Repeat + assert(rrex3(rrex, "aaaaa", "a{4}")); -// Terminal setup functions -void enableRawMode(struct termios *orig_termios) { - struct termios raw = *orig_termios; - raw.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echoing - raw.c_cc[VMIN] = 0; - raw.c_cc[VTIME] = 1; // Set timeout for read input + assert(rrex3(rrex, "aaaa", "a{1,3}a")); - tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); -} + // Range + assert(rrex3(rrex, "abc", "[abc][abc][abc]$")); + assert(rrex3(rrex, "def", "[^abc][^abc][^abc]$")); + assert(rrex3(rrex, "defabc", "[^abc][^abc][^abc]abc")); + assert(rrex3(rrex, "0-9", "0-9")); + assert(rrex3(rrex, "55-9", "[^6-9]5-9$")); + assert(rrex3(rrex, "a", "[a-z]$")); + assert(rrex3(rrex, "A", "[A-Z]$")); + assert(rrex3(rrex, "5", "[0-9]$")); + assert(!rrex3(rrex, "a", "[^a-z]$")); + assert(!rrex3(rrex, "A", "[^A-Z]$")); + assert(!rrex3(rrex, "5", "[^0-9]$")); + assert(rrex3(rrex, "123abc", "[0-9]*abc$")); + assert(rrex3(rrex, "123123", "[0-9]*$")); -void disableRawMode(struct termios *orig_termios) { - tcsetattr(STDIN_FILENO, TCSAFLUSH, - orig_termios); // Restore original terminal settings + // Parentheses + + assert(rrex3(rrex, "datadata", "(data)*")); + + assert(rrex3(rrex, "datadatapony", "(data)*pony$")); + + assert(!rrex3(rrex, "datadatapony", "(d*p*ata)*pond$")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato")); + assert(rrex3(rrex, "datadatadato", "(d*p*ata)*dato$")); + assert(!rrex3(rrex, "datadatadato", "(d*p*a*ta)*gato$")); + + // Matches + assert(rrex3(rrex, "123", "(123)")); + assert(!strcmp(rrex->matches[0], "123")); + + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); + + assert(rrex3(rrex, "123321a", "(123)([0-4][2]1)a$")); + assert(!strcmp(rrex->matches[1], "321")); + + assert(rrex3(rrex, "aaaabc", "(.*)c")); + + assert(rrex3(rrex, "abcde", ".....$")); + + assert(rrex3(rrex, "abcdefghijklmnopqrstuvwxyz", + "..........................$")); + // printf("(%d)\n", rrex->valid); + + assert(rrex3(rrex, " #include ", "#include.*<(.*)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + /* + assert(rrex3(rrex, " #include ", "#include.+<(.+)>")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(rrex3(rrex, " #include \"stdlib.h\"", "#include.+\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdlib.h")); + + assert(rrex3(rrex, " \"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\"")); + assert(!strcmp(rrex->matches[0], "stdio.h")); + assert(!strcmp(rrex->matches[1], "string.h")); + assert(!strcmp(rrex->matches[2], "sys/time.h")); + */ + // assert(rrex3(rrex,"char pony() { + // }","\\b\\w+(\\s+\\*+)?\\s+\\w+\\s*\\([^)]*\\)\s*\\{[^{}]*\\}")); + + rrex3_free(rrex); } +#endif +#ifndef RARENA_H +#define RARENA_H -void rterm_clear_screen() { - printf("\x1b[2J"); // Clear the entire screen - printf("\x1b[H"); // Move cursor to the home position (0,0) +#include +#include + +typedef struct arena_t { + unsigned char *memory; + unsigned int pointer; + unsigned int size; +} arena_t; + +arena_t *arena_construct() { + arena_t *arena = (arena_t *)rmalloc(sizeof(arena_t)); + arena->memory = NULL; + arena->pointer = 0; + arena->size = 0; + return arena; } -void setBackgroundColor() { - printf("\x1b[44m"); // Set background color to blue +arena_t *arena_new(size_t size) { + arena_t *arena = arena_construct(); + arena->memory = (unsigned char *)rmalloc(size); + arena->size = size; + return arena; } -void rterm_move_cursor(int x, int y) { - - printf("\x1b[%d;%dH", y + 1, x + 1); // Move cursor to (x, y) +void *arena_alloc(arena_t *arena, size_t size) { + if (arena->pointer + size > arena->size) { + return NULL; + } + void *p = arena->memory + arena->pointer; + arena->pointer += size; + return p; } -void cursor_set(rterm_t *rt, int x, int y) { - rt->cursor.x = x; - rt->cursor.y = y; - rt->cursor.pos = y * rt->size.ws_col + x; - rterm_move_cursor(rt->cursor.x, rt->cursor.y); -} -void cursor_restore(rterm_t *rt) { - rterm_move_cursor(rt->cursor.x, rt->cursor.y); +void arena_free(arena_t *arena) { + // Just constructed and unused arena memory is NULL so no free needed + if (arena->memory) { + rfree(arena->memory); + } + rfree(arena); } -void rterm_print_status_bar(rterm_t *rt, char c, unsigned long i) { - winsize_t ws = rt->size; - rterm_move_cursor(0, ws.ws_row - 1); +void arena_reset(arena_t *arena) { arena->pointer = 0; } +#endif +#ifndef RLIB_RIO +#define RLIB_RIO +#include +#include +#include +#include +#include +#include +#include +#include - char output_str[1024]; - output_str[0] = 0; +bool rfile_exists(char *path) { + struct stat s; + return !stat(path, &s); +} - // strcat(output_str, "\x1b[48;5;240m"); +void rjoin_path(char *p1, char *p2, char *output) { + output[0] = 0; + strcpy(output, p1); - for (int i = 0; i < ws.ws_col; i++) { - strcat(output_str, " "); + if (output[strlen(output) - 1] != '/') { + char slash[] = "/"; + strcat(output, slash); } - char content[500]; - content[0] = 0; - if (!rt->status_text) { - sprintf(content, "\rp:%d:%d | k:%c:%d | i:%ld ", rt->cursor.x + 1, - rt->cursor.y + 1, c == 0 ? '0' : c, c, i); - } else { - sprintf(content, "\r%s", rt->status_text); + if (p2[0] == '/') { + p2++; } - strcat(output_str, content); - // strcat(output_str, "\x1b[0m"); - printf("%s", output_str); - cursor_restore(rt); -} - -void rterm_show_cursor() { - printf("\x1b[?25h"); // Show the cursor + strcat(output, p2); } -void rterm_hide_cursor() { - printf("\x1b[?25l"); // Hide the cursor -} +int risprivatedir(const char *path) { + struct stat statbuf; -rshell_keypress_t rshell_getkey() { - static rshell_keypress_t press; - press.c = 0; - press.ctrl = false; - press.shift = false; - press.escape = false; - press.pressed = rfd_wait(0, 100); - if (press.pressed) { - press.c = getchar(); + if (stat(path, &statbuf) != 0) { + perror("stat"); + return -1; } - char ch = press.c; - if (ch == '\x1b') { - // Get detail - ch = getchar(); - - if (ch == '[') { - // non char key: - press.escape = true; - ch = getchar(); // is a number. 1 if shift + arrow - press.c = ch; - if (ch >= '0' && ch <= '9') - ch = getchar(); - press.c = ch; - if (ch == ';') { - ch = getchar(); - press.c = ch; - if (ch == '5') { - press.ctrl = true; - press.c = getchar(); // De arrow - } - } - } else { - press.c = ch; - } + if (!S_ISDIR(statbuf.st_mode)) { + return -2; } - return press; -} -// Main function -void rterm_loop(rterm_t *rt) { - struct termios orig_termios; - tcgetattr(STDIN_FILENO, &orig_termios); // Get current terminal attributes - enableRawMode(&orig_termios); + if ((statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == S_IRWXU) { + return 1; // Private (owner has all permissions, others have none) + } - int x = 0, y = 0; // Initial cursor position - char ch = 0; - ; - while (1) { - rterm_getwinsize(&rt->size); - rt->cursor.available = rt->size.ws_col * rt->size.ws_row; - if (rt->tick) { - rt->tick(rt); - } + return 0; +} +bool risdir(const char *path) { return !risprivatedir(path); } - rterm_hide_cursor(); - // setBackgroundColor(); - rterm_clear_screen(); - if (rt->before_draw) { - rt->before_draw(rt); - } - rterm_print_status_bar(rt, ch, rt->iterations); - if (!rt->iterations || (x != rt->cursor.x || y != rt->cursor.y)) { - if (y == rt->size.ws_row) { - y--; - } - if (y < 0) { - y = 0; - } - rt->cursor.x = x; - rt->cursor.y = y; - if (rt->before_cursor_move) - rt->before_cursor_move(rt); - cursor_set(rt, rt->cursor.x, rt->cursor.y); - if (rt->after_cursor_move) - rt->after_cursor_move(rt); - x = rt->cursor.x; - y = rt->cursor.y; - } - if (rt->show_cursor) - rterm_show_cursor(); - fflush(stdout); +void rforfile(char *path, void callback(char *)) { + if (!rfile_exists(path)) + return; + DIR *dir = opendir(path); + struct dirent *d; + while ((d = readdir(dir)) != NULL) { + if (!d) + break; - rt->key = rshell_getkey(); - if (rt->key.pressed && rt->before_key_press) { - rt->before_key_press(rt); + if ((d->d_name[0] == '.' && strlen(d->d_name) == 1) || + d->d_name[1] == '.') { + continue; } - rshell_keypress_t key = rt->key; - ch = key.c; - if (ch == 'q') - break; // Press 'q' to quit + char full_path[4096]; + rjoin_path(path, d->d_name, full_path); - // Escape - if (key.escape) { - switch (key.c) { - case 65: // Move up - if (y > -1) - y--; - break; - case 66: // Move down - if (y < rt->size.ws_row) - y++; - break; - case 68: // Move left - if (x > 0) - x--; - if (key.ctrl) - x -= 4; - break; - case 67: // Move right - if (x < rt->size.ws_col) { - x++; - } - if (key.ctrl) { - x += 4; - } - break; - } - } - if (rt->key.pressed && rt->after_key_press) { - rt->after_key_press(rt); + if (risdir(full_path)) { + callback(full_path); + rforfile(full_path, callback); + } else { + callback(full_path); } - rt->iterations++; - - // usleep (1000); } - - // Cleanup - printf("\x1b[0m"); // Reset colors - rterm_clear_screen(); - disableRawMode(&orig_termios); + closedir(dir); } -#endif -#ifndef RTREE_H -#define RTREE_H -#include -#include -#include - -typedef struct rtree_t { - struct rtree_t *next; - struct rtree_t *children; - char c; - void *data; -} rtree_t; -rtree_t *rtree_new() { - rtree_t *b = (rtree_t *)rmalloc(sizeof(rtree_t)); - b->next = NULL; - b->children = NULL; - b->c = 0; - b->data = NULL; - return b; -} +bool rfd_wait(int fd, int ms) { + fd_set read_fds; + struct timeval timeout; -rtree_t *rtree_set(rtree_t *b, char *c, void *data) { - while (b) { - if (b->c == 0) { - b->c = *c; - c++; - if (*c == 0) { - b->data = data; - // printf("SET1 %c\n", b->c); - return b; - } - } else if (b->c == *c) { - c++; - if (*c == 0) { - b->data = data; - return b; - } - if (b->children) { - b = b->children; - } else { - b->children = rtree_new(); - b = b->children; - } - } else if (b->next) { - b = b->next; - } else { - b->next = rtree_new(); - b = b->next; - b->c = *c; - c++; - if (*c == 0) { - b->data = data; - return b; - } else { - b->children = rtree_new(); - b = b->children; - } - } - } - return NULL; + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * ms; // 100 milliseconds timeout + + int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); + return ret > 0 && FD_ISSET(fd, &read_fds); } -rtree_t *rtree_find(rtree_t *b, char *c) { - while (b) { - if (b->c == *c) { - c++; - if (*c == 0) { - return b; - } - b = b->children; - continue; - } - b = b->next; +bool rfd_wait_forever(int fd) { + while ((!rfd_wait(fd, 10))) { } - return NULL; + return true; } -void rtree_free(rtree_t *b) { - if (!b) - return; - rtree_free(b->children); - rtree_free(b->next); - rfree(b); +size_t rfile_size(char *path) { + struct stat s; + stat(path, &s); + return s.st_size; } -void *rtree_get(rtree_t *b, char *c) { - rtree_t *t = rtree_find(b, c); - if (t) { - return t->data; +size_t rfile_readb(char *path, void *data, size_t size) { + FILE *fd = fopen(path, "r"); + if (!fd) { + return 0; } - return NULL; + __attribute__((unused)) size_t bytes_read = + fread(data, size, sizeof(char), fd); + + fclose(fd); + return size; } + #endif -#ifndef RLEXER_H -#define RLEXER_H +#ifndef RSTRING_H +#define RSTRING_H #include #include #include #include #include -#include - -#define RTOKEN_VALUE_SIZE 1024 - -typedef enum rtoken_type_t { - RT_UNKNOWN = 0, - RT_SYMBOL, - RT_NUMBER, - RT_STRING, - RT_PUNCT, - RT_OPERATOR, - RT_EOF = 10, - RT_BRACE_OPEN, - RT_CURLY_BRACE_OPEN, - RT_BRACKET_OPEN, - RT_BRACE_CLOSE, - RT_CURLY_BRACE_CLOSE, - RT_BRACKET_CLOSE -} rtoken_type_t; - -typedef struct rtoken_t { - rtoken_type_t type; - char value[RTOKEN_VALUE_SIZE]; - unsigned int line; - unsigned int col; -} rtoken_t; -static char *_content; -static unsigned int _content_ptr; -static unsigned int _content_line; -static unsigned int _content_col; +unsigned long _r_generate_key_current = 0; -static int isgroupingchar(char c) { - return (c == '{' || c == '}' || c == '(' || c == ')' || c == '[' || - c == ']' || c == '"' || c == '\''); +char *_rcat_int_int(int a, int b) { + static char res[20]; + res[0] = 0; + sprintf(res, "%d%d", a, b); + return res; +} +char *_rcat_int_double(int a, double b) { + static char res[20]; + res[0] = 0; + sprintf(res, "%d%f", a, b); + return res; } -static int isoperator(char c) { - return (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || - c == '>' || c == '<' || c == '|' || c == '&'); +char *_rcat_charp_int(char *a, int b) { + char res[20]; + sprintf(res, "%c", b); + return strcat(a, res); } -static rtoken_t rtoken_new() { - rtoken_t token; - memset(&token, 0, sizeof(token)); - token.type = RT_UNKNOWN; - return token; +char *_rcat_charp_double(char *a, double b) { + char res[20]; + sprintf(res, "%f", b); + return strcat(a, res); } -rtoken_t rlex_number() { - rtoken_t token = rtoken_new(); - token.col = _content_col; - token.line = _content_line; - bool first_char = true; - int dot_count = 0; - char c; - while (isdigit(c = _content[_content_ptr]) || - (first_char && _content[_content_ptr] == '-') || - (dot_count == 0 && _content[_content_ptr] == '.')) { - if (c == '.') - dot_count++; - first_char = false; - char chars[] = {c, 0}; - strcat(token.value, chars); - _content_ptr++; - _content_col++; +char *_rcat_charp_charp(char *a, char *b) { + ; + return strcat(a, b); +} +char *_rcat_charp_char(char *a, char b) { + char extra[] = {b, 0}; + return strcat(a, extra); +} +char *_rcat_charp_bool(char *a, bool *b) { + if (b) { + return strcat(a, "true"); + } else { + return strcat(a, "false"); } - token.type = RT_NUMBER; - return token; } -static rtoken_t rlex_symbol() { - rtoken_t token = rtoken_new(); +#define rcat(x, y) \ + _Generic((x), \ + int: _Generic((y), \ + int: _rcat_int_int,\ + double: _rcat_int_double,\ + char*: _rcat_charp_charp),\ + char*: _Generic((y),\ + int: _rcat_charp_int, \ + double: _rcat_charp_double,\ + char*: _rcat_charp_charp, \ + char: _rcat_charp_char, \ + bool: _rcat_charp_bool))((x),(y)) - token.col = _content_col; - token.line = _content_line; - char c; - while (isalpha(_content[_content_ptr]) || _content[_content_ptr] == '_') { - c = _content[_content_ptr]; - char chars[] = {c, 0}; - strcat(token.value, chars); - _content_ptr++; - _content_col++; - } - token.type = RT_SYMBOL; - return token; +char *rgenerate_key() { + _r_generate_key_current++; + static char key[100]; + key[0] = 0; + sprintf(key, "%ld", _r_generate_key_current); + return key; } -static rtoken_t rlex_operator() { +char *rformat_number(long lnumber) { + static char formatted[1024]; - rtoken_t token = rtoken_new(); + char number[1024]; + sprintf(number, "%ld", lnumber); - token.col = _content_col; - token.line = _content_line; - char c; - bool is_first = true; - while (isoperator(_content[_content_ptr])) { - if (!is_first) { - if (_content[_content_ptr - 1] == '=' && - _content[_content_ptr] == '-') { - break; - } - } - c = _content[_content_ptr]; - char chars[] = {c, 0}; - strcat(token.value, chars); - _content_ptr++; - _content_col++; - is_first = false; - } - token.type = RT_OPERATOR; - return token; -} + int len = strlen(number); + int commas_needed = (len - 1) / 3; + int new_len = len + commas_needed; -static rtoken_t rlex_punct() { + formatted[new_len] = '\0'; - rtoken_t token = rtoken_new(); + int i = len - 1; + int j = new_len - 1; + int count = 0; - token.col = _content_col; - token.line = _content_line; - char c; - bool is_first = true; - while (ispunct(_content[_content_ptr])) { - if (!is_first) { - if (_content[_content_ptr] == '"') { - break; - } - if (_content[_content_ptr] == '\'') { - break; - } - if (isgroupingchar(_content[_content_ptr])) { - break; - } - if (isoperator(_content[_content_ptr])) { - break; - } + while (i >= 0) { + if (count == 3) { + formatted[j--] = '.'; + count = 0; } - c = _content[_content_ptr]; - char chars[] = {c, 0}; - strcat(token.value, chars); - _content_ptr++; - _content_col++; - is_first = false; + formatted[j--] = number[i--]; + count++; } - token.type = RT_PUNCT; - return token; + return formatted; } -static rtoken_t rlex_string() { - rtoken_t token = rtoken_new(); - char c; - token.col = _content_col; - token.line = _content_line; - char str_chr = _content[_content_ptr]; - _content_ptr++; - while (_content[_content_ptr] != str_chr) { - c = _content[_content_ptr]; +bool rstrextractdouble(char *str, double *d1) { + for (size_t i = 0; i < strlen(str); i++) { + if (isdigit(str[i])) { + str += i; + sscanf(str, "%lf", d1); + return true; + } + } + return false; +} + +void rstrstripslashes(const char *content, char *result) { + size_t content_length = strlen((char *)content); + unsigned int index = 0; + for (unsigned int i = 0; i < content_length; i++) { + char c = content[i]; if (c == '\\') { - _content_ptr++; - c = _content[_content_ptr]; - if (c == 'n') { - c = '\n'; - } else if (c == 'r') { + i++; + c = content[i]; + if (c == 'r') { c = '\r'; } else if (c == 't') { c = '\t'; - } else if (c == str_chr) { - c = str_chr; + } else if (c == 'b') { + c = '\b'; + } else if (c == 'n') { + c = '\n'; + } else if (c == 'f') { + c = '\f'; + } else if (c == '\\') { + // No need tbh + c = '\\'; } - - _content_col++; } - char chars[] = {c, 0}; - strcat(token.value, chars); - _content_ptr++; - _content_col++; + result[index] = c; + index++; } - _content_ptr++; - token.type = RT_STRING; - return token; + result[index] = 0; } -void rlex(char *content) { - _content = content; - _content_ptr = 0; - _content_col = 1; - _content_line = 1; +int rstrstartswith(const char *s1, const char *s2) { + if (s1 == NULL) + return s2 == NULL; + if (s1 == s2 || s2 == NULL || *s2 == 0) + return true; + size_t len_s2 = strlen(s2); + size_t len_s1 = strlen(s1); + if (len_s2 > len_s1) + return false; + return !strncmp(s1, s2, len_s2); } -static void rlex_repeat_str(char *dest, char *src, unsigned int times) { - for (size_t i = 0; i < times; i++) { - strcat(dest, src); +bool rstrendswith(const char *s1, const char *s2) { + if (s1 == NULL) + return s2 == NULL; + if (s1 == s2 || s2 == NULL || *s2 == 0) + return true; + size_t len_s2 = strlen(s2); + size_t len_s1 = strlen(s1); + if (len_s2 > len_s1) { + return false; } + s1 += len_s1 - len_s2; + return !strncmp(s1, s2, len_s2); } -rtoken_t rtoken_create(rtoken_type_t type, char *value) { - rtoken_t token = rtoken_new(); - token.type = type; - token.col = _content_col; - token.line = _content_line; - strcpy(token.value, value); - return token; +void rstraddslashes(const char *content, char *result) { + size_t content_length = strlen((char *)content); + unsigned int index = 0; + for (unsigned int i = 0; i < content_length; i++) { + if (content[i] == '\r') { + result[index] = '\\'; + index++; + result[index] = 'r'; + index++; + continue; + } else if (content[i] == '\t') { + result[index] = '\\'; + index++; + result[index] = 't'; + index++; + continue; + } else if (content[i] == '\n') { + result[index] = '\\'; + index++; + result[index] = 'n'; + index++; + continue; + } else if (content[i] == '\\') { + result[index] = '\\'; + index++; + result[index] = '\\'; + index++; + continue; + } else if (content[i] == '\b') { + result[index] = '\\'; + index++; + result[index] = 'b'; + index++; + continue; + } else if (content[i] == '\f') { + result[index] = '\\'; + index++; + result[index] = 'f'; + index++; + continue; + } + result[index] = content[i]; + index++; + } + result[index] = 0; } -rtoken_t rlex_next() { - while (true) { +int rstrip_whitespace(char *input, char *output) { + output[0] = 0; + int count = 0; + size_t len = strlen(input); + for (size_t i = 0; i < len; i++) { + if (input[i] == '\t' || input[i] == ' ') { + continue; + } + count = i; + size_t j; + for (j = 0; j < len - count; j++) { + output[j] = input[j + count]; + } + output[j] = '\0'; + break; + } + return count; +} +size_t rstrtokline(char *input, char *output, size_t offset, bool strip_nl) { - _content_col++; + size_t len = strlen(input); + output[0] = 0; + size_t new_offset = 0; + size_t j; + size_t index = 0; - if (_content[_content_ptr] == 0) { - return rtoken_create(RT_EOF, "eof"); - } else if (_content[_content_ptr] == '\n') { - _content_line++; - _content_col = 1; - _content_ptr++; - } else if (isspace(_content[_content_ptr])) { - _content_ptr++; - } else if (isdigit(_content[_content_ptr]) || - (_content[_content_ptr] == '-' && - isdigit(_content[_content_ptr + 1]))) { - return rlex_number(); - } else if (isalpha(_content[_content_ptr]) || - _content[_content_ptr] == '_') { - return rlex_symbol(); - } else if (_content[_content_ptr] == '"' || - _content[_content_ptr] == '\'') { - return rlex_string(); - } else if (isoperator(_content[_content_ptr])) { - return rlex_operator(); - } else if (ispunct(_content[_content_ptr])) { - if (_content[_content_ptr] == '{') { + for (j = offset; j < len + offset; j++) { + if (input[j] == 0) { + index++; + break; + } + index = j - offset; + output[index] = input[j]; - _content_ptr++; - return rtoken_create(RT_CURLY_BRACE_OPEN, "{"); - } - if (_content[_content_ptr] == '}') { + if (output[index] == '\n') { + index++; + break; + } + } + output[index] = 0; - _content_ptr++; - return rtoken_create(RT_CURLY_BRACE_CLOSE, "}"); - } - if (_content[_content_ptr] == '(') { + new_offset = index + offset; - _content_ptr++; - return rtoken_create(RT_BRACE_OPEN, "("); - } - if (_content[_content_ptr] == ')') { + if (strip_nl) { + if (output[index - 1] == '\n') { + output[index - 1] = 0; + } + } + return new_offset; +} - _content_ptr++; - return rtoken_create(RT_BRACE_CLOSE, ")"); - } - if (_content[_content_ptr] == '[') { +void rstrjoin(char **lines, size_t count, char *glue, char *output) { + output[0] = 0; + for (size_t i = 0; i < count; i++) { + strcat(output, lines[i]); + if (i != count - 1) + strcat(output, glue); + } +} - _content_ptr++; - return rtoken_create(RT_BRACKET_OPEN, "["); - } - if (_content[_content_ptr] == ']') { +int rstrsplit(char *input, char **lines) { + int index = 0; + size_t offset = 0; + char line[1024]; + while ((offset = rstrtokline(input, line, offset, false)) && *line) { + if (!*line) { + break; + } + lines[index] = (char *)malloc(strlen(line) + 1); + strcpy(lines[index], line); + index++; + } + return index; +} + +bool rstartswithnumber(char *str) { return isdigit(str[0]); } + +void rstrmove2(char *str, unsigned int start, size_t length, + unsigned int new_pos) { + size_t str_len = strlen(str); + char new_str[str_len + 1]; + memset(new_str, 0, str_len); + if (start < new_pos) { + strncat(new_str, str + length, str_len - length - start); + new_str[new_pos] = 0; + strncat(new_str, str + start, length); + strcat(new_str, str + strlen(new_str)); + memset(str, 0, str_len); + strcpy(str, new_str); + } else { + strncat(new_str, str + start, length); + strncat(new_str, str, start); + strncat(new_str, str + start + length, str_len - start); + memset(str, 0, str_len); + strcpy(str, new_str); + } + new_str[str_len] = 0; +} - _content_ptr++; - return rtoken_create(RT_BRACKET_CLOSE, "]"); - } - return rlex_punct(); - } +void rstrmove(char *str, unsigned int start, size_t length, + unsigned int new_pos) { + size_t str_len = strlen(str); + if (start >= str_len || new_pos >= str_len || start + length > str_len) { + return; + } + char temp[length + 1]; + strncpy(temp, str + start, length); + temp[length] = 0; + if (start < new_pos) { + memmove(str + start, str + start + length, new_pos - start); + strncpy(str + new_pos - length + 1, temp, length); + } else { + memmove(str + new_pos + length, str + new_pos, start - new_pos); + strncpy(str + new_pos, temp, length); } } -char *rlex_format(char *content) { - rlex(content); - char *result = (char *)malloc(strlen(content) + 4096); - result[0] = 0; - unsigned int tab_index = 0; - char *tab_chars = " "; - unsigned int col = 0; - rtoken_t token_previous; - token_previous.value[0] = 0; - token_previous.type = RT_UNKNOWN; - while (true) { - rtoken_t token = rlex_next(); - if (token.type == RT_EOF) { - break; - } +int cmp_line(const void *left, const void *right) { + char *l = *(char **)left; + char *r = *(char **)right; - // col = strlen(token.value); + char lstripped[strlen(l) + 1]; + rstrip_whitespace(l, lstripped); + char rstripped[strlen(r) + 1]; + rstrip_whitespace(r, rstripped); - if (col == 0) { - rlex_repeat_str(result, tab_chars, tab_index); - // col = strlen(token.value);// strlen(tab_chars) * tab_index; - } + double d1, d2; + bool found_d1 = rstrextractdouble(lstripped, &d1); + bool found_d2 = rstrextractdouble(rstripped, &d2); - if (token.type == RT_STRING) { - strcat(result, "\""); + if (found_d1 && found_d2) { + double frac_part1; + double int_part1; + frac_part1 = modf(d1, &int_part1); + double frac_part2; + double int_part2; + frac_part2 = modf(d2, &int_part2); + if (d1 == d2) { + return strcmp(lstripped, rstripped); + } else if (frac_part1 && frac_part2) { + return d1 > d2; + } else if (frac_part1 && !frac_part2) { + return 1; + } else if (frac_part2 && !frac_part1) { + return -1; + } else if (!frac_part1 && !frac_part2) { + return d1 > d2; + } + } + return 0; +} - char string_with_slashes[strlen(token.value) * 2 + 1]; - rstraddslashes(token.value, string_with_slashes); - strcat(result, string_with_slashes); +int rstrsort(char *input, char *output) { + char **lines = (char **)malloc(strlen(input) * 10); + int line_count = rstrsplit(input, lines); + qsort(lines, line_count, sizeof(char *), cmp_line); + rstrjoin(lines, line_count, "", output); + free(lines); + return line_count; +} - strcat(result, "\""); - // col+= strlen(token.value) + 2; - // printf("\n"); - // printf("<<<%s>>>\n",token.value); +#endif +#ifndef RLIB_TERMINAL_H +#define RLIB_TERMINAL_H - memcpy(&token_previous, &token, sizeof(token)); - continue; - } - if (!(strcmp(token.value, "{"))) { - if (col != 0) { - strcat(result, "\n"); - rlex_repeat_str(result, " ", tab_index); - } - strcat(result, token.value); +#include +#include +#include +#include - tab_index++; +char *rfcaptured = NULL; - strcat(result, "\n"); +void rfcapture(FILE *f, char *buff, size_t size) { + rfcaptured = buff; + setvbuf(f, rfcaptured, _IOFBF, size); +} +void rfstopcapture(FILE *f) { setvbuf(f, 0, _IOFBF, 0); } - col = 0; +bool _r_disable_stdout_toggle = false; - memcpy(&token_previous, &token, sizeof(token)); - continue; - } else if (!(strcmp(token.value, "}"))) { - unsigned int tab_indexed = 0; - if (tab_index) - tab_index--; - strcat(result, "\n"); +FILE *_r_original_stdout = NULL; - rlex_repeat_str(result, tab_chars, tab_index); - tab_indexed++; +bool rr_enable_stdout() { + if (_r_disable_stdout_toggle) + return false; + if (!_r_original_stdout) { + stdout = fopen("/dev/null", "rb"); + return false; + } + if (_r_original_stdout && _r_original_stdout != stdout) { + fclose(stdout); + } + stdout = _r_original_stdout; + return true; +} +bool rr_disable_stdout() { + if (_r_disable_stdout_toggle) { + return false; + } + if (_r_original_stdout == NULL) { + _r_original_stdout = stdout; + } + if (stdout == _r_original_stdout) { + stdout = fopen("/dev/null", "rb"); + return true; + } + return false; +} +bool rr_toggle_stdout() { + if (!_r_original_stdout) { + rr_disable_stdout(); + return true; + } else if (stdout != _r_original_stdout) { + rr_enable_stdout(); + return true; + } else { + rr_disable_stdout(); + return true; + } +} - strcat(result, token.value); - strcat(result, "\n"); - col = 0; +typedef struct rprogressbar_t { + unsigned long current_value; + unsigned long min_value; + unsigned long max_value; + unsigned int length; + bool changed; + double percentage; + unsigned int width; + unsigned long draws; + FILE *fout; +} rprogressbar_t; - memcpy(&token_previous, &token, sizeof(token)); - continue; - } - if ((token_previous.type == RT_SYMBOL && token.type == RT_NUMBER) || - (token_previous.type == RT_NUMBER && token.type == RT_SYMBOL) || - (token_previous.type == RT_PUNCT && token.type == RT_SYMBOL) || - (token_previous.type == RT_BRACE_CLOSE && - token.type == RT_SYMBOL) || - (token_previous.type == RT_SYMBOL && token.type == RT_SYMBOL)) { - if (token_previous.value[0] != ',' && - token_previous.value[0] != '.') { - if (token.type != RT_OPERATOR && token.value[0] != '.') { - strcat(result, "\n"); - rlex_repeat_str(result, tab_chars, tab_index); - } - } - } +rprogressbar_t *rprogressbar_new(long min_value, long max_value, + unsigned int width, FILE *fout) { + rprogressbar_t *pbar = (rprogressbar_t *)malloc(sizeof(rprogressbar_t)); + pbar->min_value = min_value; + pbar->max_value = max_value; + pbar->current_value = min_value; + pbar->width = width; + pbar->draws = 0; + pbar->length = 0; + pbar->changed = false; + pbar->fout = fout ? fout : stdout; + return pbar; +} - if (token.type == RT_OPERATOR) { - strcat(result, " "); - } - if (token.type == RT_STRING) { - strcat(result, "\""); - } - strcat(result, token.value); - if (token.type == RT_STRING) { - strcat(result, "\""); - } +void rprogressbar_free(rprogressbar_t *pbar) { free(pbar); } - if (token.type == RT_OPERATOR) { - strcat(result, " "); +void rprogressbar_draw(rprogressbar_t *pbar) { + if (!pbar->changed) { + return; + } else { + pbar->changed = false; + } + pbar->draws++; + char draws_text[22]; + draws_text[0] = 0; + sprintf(draws_text, "%ld", pbar->draws); + char *draws_textp = draws_text; + // bool draws_text_len = strlen(draws_text); + char bar_begin_char = ' '; + char bar_progress_char = ' '; + char bar_empty_char = ' '; + char bar_end_char = ' '; + char content[4096] = {0}; + char bar_content[1024]; + char buff[2048] = {0}; + bar_content[0] = '\r'; + bar_content[1] = bar_begin_char; + unsigned int index = 2; + for (unsigned long i = 0; i < pbar->length; i++) { + if (*draws_textp) { + bar_content[index] = *draws_textp; + draws_textp++; + } else { + bar_content[index] = bar_progress_char; } - if (!strcmp(token.value, ",")) { - strcat(result, " "); + index++; + } + char infix[] = "\033[0m"; + for (unsigned long i = 0; i < strlen(infix); i++) { + bar_content[index] = infix[i]; + index++; + } + for (unsigned long i = 0; i < pbar->width - pbar->length; i++) { + bar_content[index] = bar_empty_char; + index++; + } + bar_content[index] = bar_end_char; + bar_content[index + 1] = '\0'; + sprintf(buff, "\033[43m%s\033[0m \033[33m%.2f%%\033[0m ", bar_content, + pbar->percentage * 100); + strcat(content, buff); + if (pbar->width == pbar->length) { + strcat(content, "\r"); + for (unsigned long i = 0; i < pbar->width + 10; i++) { + strcat(content, " "); } - col += strlen(token.value); - memcpy(&token_previous, &token, sizeof(token)); + strcat(content, "\r"); } - return result; + fprintf(pbar->fout, "%s", content); + fflush(pbar->fout); } -#endif -#ifndef RBENCH_H -#define RBENCH_H - -#include -#include -#include -#include -#include -#include -#include -#include -#define RBENCH(times, action) \ - { \ - unsigned long utimes = (unsigned long)times; \ - nsecs_t start = nsecs(); \ - for (unsigned long i = 0; i < utimes; i++) { \ - { action; } \ - } \ - nsecs_t end = nsecs(); \ - printf("%s\n", format_time(end - start)); \ +bool rprogressbar_update(rprogressbar_t *pbar, unsigned long value) { + if (value == pbar->current_value) { + return false; } - -#define RBENCHP(times, action) \ - { \ - printf("\n"); \ - nsecs_t start = nsecs(); \ - unsigned int prev_percentage = 0; \ - unsigned long utimes = (unsigned long)times; \ - for (unsigned long i = 0; i < utimes; i++) { \ - unsigned int percentage = \ - ((long double)i / (long double)times) * 100; \ - int percentage_changed = percentage != prev_percentage; \ - __attribute__((unused)) int first = i == 0; \ - __attribute__((unused)) int last = i == utimes - 1; \ - { action; }; \ - if (percentage_changed) { \ - printf("\r%d%%", percentage); \ - fflush(stdout); \ - \ - prev_percentage = percentage; \ - } \ - } \ - nsecs_t end = nsecs(); \ - printf("\r%s\n", format_time(end - start)); \ + pbar->current_value = value; + pbar->percentage = (double)pbar->current_value / + (double)(pbar->max_value - pbar->min_value); + unsigned long new_length = (unsigned long)(pbar->percentage * pbar->width); + pbar->changed = new_length != pbar->length; + if (pbar->changed) { + pbar->length = new_length; + rprogressbar_draw(pbar); + return true; } + return false; +} -struct rbench_t; - -typedef struct rbench_function_t { -#ifdef __cplusplus - void (*call)(); -#else - void(*call); -#endif - char name[256]; - char group[256]; - void *arg; - void *data; - bool first; - bool last; - int argc; - unsigned long times_executed; +size_t rreadline(char *data, size_t len, bool strip_ln) { + __attribute__((unused)) char *unused = fgets(data, len, stdin); + size_t length = strlen(data); + if (length && strip_ln) + data[length - 1] = 0; + return length; +} - nsecs_t average_execution_time; - nsecs_t total_execution_time; -} rbench_function_t; +void rlib_test_progressbar() { + rtest_banner("Progress bar"); + rprogressbar_t *pbar = rprogressbar_new(0, 1000, 10, stderr); + rprogressbar_draw(pbar); + // No draws executed, nothing to show + rassert(pbar->draws == 0); + rprogressbar_update(pbar, 500); + rassert(pbar->percentage == 0.5); + rprogressbar_update(pbar, 500); + rprogressbar_update(pbar, 501); + rprogressbar_update(pbar, 502); + // Should only have drawn one time since value did change, but percentage + // did not + rassert(pbar->draws == 1); + // Changed is false because update function calls draw + rassert(pbar->changed == false); + rprogressbar_update(pbar, 777); + rassert(pbar->percentage == 0.777); + rprogressbar_update(pbar, 1000); + rassert(pbar->percentage == 1); +} -typedef struct rbench_t { - unsigned int function_count; - rbench_function_t functions[100]; - rbench_function_t *current; - rprogressbar_t *progress_bar; - bool show_progress; - int winner; - bool stdout; - unsigned long times; - bool silent; - nsecs_t execution_time; -#ifdef __cplusplus - void (*add_function)(struct rbench_t *r, const char *name, - const char *group, void (*)()); -#else - void (*add_function)(struct rbench_t *r, const char *name, - const char *group, void *); #endif - void (*rbench_reset)(struct rbench_t *r); - struct rbench_t *(*execute)(struct rbench_t *r, long times); - struct rbench_t *(*execute1)(struct rbench_t *r, long times, void *arg1); - struct rbench_t *(*execute2)(struct rbench_t *r, long times, void *arg1, - void *arg2); - struct rbench_t *(*execute3)(struct rbench_t *r, long times, void *arg1, - void *arg2, void *arg3); +#ifndef RTERM_H +#define RTERM_H +#include +#include +#include +#include +#include +#include +#include -} rbench_t; +typedef struct winsize winsize_t; -FILE *_rbench_stdout = NULL; -FILE *_rbench_stdnull = NULL; +typedef struct rshell_keypress_t { + bool pressed; + bool ctrl; + bool shift; + bool escape; + char c; + int ms; + int fd; +} rshell_keypress_t; -void rbench_toggle_stdout(rbench_t *r) { - if (!r->stdout) { - if (_rbench_stdout == NULL) { - _rbench_stdout = stdout; - } - if (_rbench_stdnull == NULL) { - _rbench_stdnull = fopen("/dev/null", "wb"); - } - if (stdout == _rbench_stdout) { - stdout = _rbench_stdnull; - } else { - stdout = _rbench_stdout; - } - } -} -void rbench_restore_stdout(rbench_t *r) { - if (r->stdout) - return; - if (_rbench_stdout) { - stdout = _rbench_stdout; - } - if (_rbench_stdnull) { - fclose(_rbench_stdnull); - _rbench_stdnull = NULL; - } -} +typedef struct rterm_t { + bool show_cursor; + bool show_footer; + rshell_keypress_t key; + void (*before_cursor_move)(struct rterm_t *); + void (*after_cursor_move)(struct rterm_t *); + void (*after_key_press)(struct rterm_t *); + void (*before_key_press)(struct rterm_t *); + void (*before_draw)(struct rterm_t *); + void *session; + unsigned long iterations; + void (*tick)(struct rterm_t *); + char *status_text; + winsize_t size; + struct { + int x; + int y; + int pos; + int available; + } cursor; +} rterm_t; -rbench_t *rbench_new(); +typedef void (*rterm_event)(rterm_t *); -rbench_t *_rbench = NULL; -rbench_function_t *rbf; -rbench_t *rbench() { - if (_rbench == NULL) { - _rbench = rbench_new(); - } - return _rbench; +void rterm_init(rterm_t *rterm) { + memset(rterm, 0, sizeof(rterm_t)); + rterm->show_cursor = true; + rterm->show_cursor = true; } -typedef void *(*rbench_call)(); -typedef void *(*rbench_call1)(void *); -typedef void *(*rbench_call2)(void *, void *); -typedef void *(*rbench_call3)(void *, void *, void *); - -#ifdef __cplusplus -void rbench_add_function(rbench_t *rp, const char *name, const char *group, - void (*call)()) { -#else -void rbench_add_function(rbench_t *rp, const char *name, const char *group, - void *call) { -#endif - rbench_function_t *f = &rp->functions[rp->function_count]; - rp->function_count++; - f->average_execution_time = 0; - f->total_execution_time = 0; - f->times_executed = 0; - f->call = call; - strcpy(f->name, name); - strcpy(f->group, group); +void rterm_getwinsize(winsize_t *w) { + // Get the terminal size + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, w) == -1) { + perror("ioctl"); + exit(EXIT_FAILURE); + } } -void rbench_reset_function(rbench_function_t *f) { - f->average_execution_time = 0; - f->times_executed = 0; - f->total_execution_time = 0; +// Terminal setup functions +void enableRawMode(struct termios *orig_termios) { + struct termios raw = *orig_termios; + raw.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echoing + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 1; // Set timeout for read input + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); } -void rbench_reset(rbench_t *rp) { - for (unsigned int i = 0; i < rp->function_count; i++) { - rbench_reset_function(&rp->functions[i]); - } +void disableRawMode(struct termios *orig_termios) { + tcsetattr(STDIN_FILENO, TCSAFLUSH, + orig_termios); // Restore original terminal settings } -int rbench_get_winner_index(rbench_t *r) { - int winner = 0; - nsecs_t time = 0; - for (unsigned int i = 0; i < r->function_count; i++) { - if (time == 0 || r->functions[i].total_execution_time < time) { - winner = i; - time = r->functions[i].total_execution_time; - } - } - return winner; + +void rterm_clear_screen() { + printf("\x1b[2J"); // Clear the entire screen + printf("\x1b[H"); // Move cursor to the home position (0,0) } -bool rbench_was_last_function(rbench_t *r) { - for (unsigned int i = 0; i < r->function_count; i++) { - if (i == r->function_count - 1 && r->current == &r->functions[i]) - return true; - } - return false; + +void setBackgroundColor() { + printf("\x1b[44m"); // Set background color to blue } -rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, - int argc) { - rbench_toggle_stdout(r); - if (findex == 0) { - r->execution_time = 0; - } - rbench_function_t *rf = &r->functions[findex]; - rf->argc = argc; - rbf = rf; - r->current = rf; - if (r->show_progress) - r->progress_bar = rprogressbar_new(0, times, 20, stderr); - r->times = times; - // printf(" %s:%s gets executed for %ld times with %d - // arguments.\n",rf->group, rf->name, times,argc); - rbench_reset_function(rf); +void rterm_move_cursor(int x, int y) { - return rf; + printf("\x1b[%d;%dH", y + 1, x + 1); // Move cursor to (x, y) } -void rbench_execute_finish(rbench_t *r) { - rbench_toggle_stdout(r); - free(r->progress_bar); - r->progress_bar = NULL; - r->current->average_execution_time = - r->current->total_execution_time / r->current->times_executed; - ; - // printf(" %s:%s finished executing in - // %s\n",r->current->group,r->current->name, - // format_time(r->current->total_execution_time)); - // rbench_show_results_function(r->current); - if (rbench_was_last_function(r)) { - rbench_restore_stdout(r); - unsigned int winner_index = rbench_get_winner_index(r); - r->winner = winner_index + 1; - if (!r->silent) - rprintgf(stderr, "Benchmark results:\n"); - nsecs_t total_time = 0; - for (unsigned int i = 0; i < r->function_count; i++) { - rbf = &r->functions[i]; - total_time += rbf->total_execution_time; - bool is_winner = winner_index == i; - if (is_winner) { - if (!r->silent) - rprintyf(stderr, " > %s:%s:%s\n", - format_time(rbf->total_execution_time), rbf->group, - rbf->name); - } else { - if (!r->silent) - rprintbf(stderr, " %s:%s:%s\n", - format_time(rbf->total_execution_time), rbf->group, - rbf->name); - } - } - if (!r->silent) - rprintgf(stderr, "Total execution time: %s\n", - format_time(total_time)); - } - rbench_restore_stdout(r); - rbf = NULL; - r->current = NULL; +void cursor_set(rterm_t *rt, int x, int y) { + rt->cursor.x = x; + rt->cursor.y = y; + rt->cursor.pos = y * rt->size.ws_col + x; + rterm_move_cursor(rt->cursor.x, rt->cursor.y); +} +void cursor_restore(rterm_t *rt) { + rterm_move_cursor(rt->cursor.x, rt->cursor.y); } -struct rbench_t *rbench_execute(rbench_t *r, long times) { - for (unsigned int i = 0; i < r->function_count; i++) { +void rterm_print_status_bar(rterm_t *rt, char c, unsigned long i) { + winsize_t ws = rt->size; + rterm_move_cursor(0, ws.ws_row - 1); - rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); - rbench_call c = (rbench_call)f->call; - nsecs_t start = nsecs(); - f->first = true; - c(); - f->first = false; - f->last = false; - f->times_executed++; - for (int j = 1; j < times; j++) { - c(); - f->times_executed++; - f->last = f->times_executed == r->times - 1; - if (r->progress_bar) { - rprogressbar_update(r->progress_bar, f->times_executed); - } - } - f->total_execution_time = nsecs() - start; - r->execution_time += f->total_execution_time; - rbench_execute_finish(r); - } - return r; -} + char output_str[1024]; + output_str[0] = 0; -struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { + // strcat(output_str, "\x1b[48;5;240m"); - for (unsigned int i = 0; i < r->function_count; i++) { - rbench_function_t *f = rbench_execute_prepare(r, i, times, 1); - rbench_call1 c = (rbench_call1)f->call; - nsecs_t start = nsecs(); - f->first = true; - c(arg1); - f->first = false; - f->last = false; - f->times_executed++; - for (int j = 1; j < times; j++) { - c(arg1); - f->times_executed++; - f->last = f->times_executed == r->times - 1; - if (r->progress_bar) { - rprogressbar_update(r->progress_bar, f->times_executed); - } - } - f->total_execution_time = nsecs() - start; - r->execution_time += f->total_execution_time; - rbench_execute_finish(r); + for (int i = 0; i < ws.ws_col; i++) { + strcat(output_str, " "); } - return r; + char content[500]; + content[0] = 0; + if (!rt->status_text) { + sprintf(content, "\rp:%d:%d | k:%c:%d | i:%ld ", rt->cursor.x + 1, + rt->cursor.y + 1, c == 0 ? '0' : c, c, i); + } else { + sprintf(content, "\r%s", rt->status_text); + } + strcat(output_str, content); + // strcat(output_str, "\x1b[0m"); + printf("%s", output_str); + cursor_restore(rt); } -struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, - void *arg2) { +void rterm_show_cursor() { + printf("\x1b[?25h"); // Show the cursor +} - for (unsigned int i = 0; i < r->function_count; i++) { - rbench_function_t *f = rbench_execute_prepare(r, i, times, 2); - rbench_call2 c = (rbench_call2)f->call; - nsecs_t start = nsecs(); - f->first = true; - c(arg1, arg2); - f->first = false; - f->last = false; - f->times_executed++; - for (int j = 1; j < times; j++) { - c(arg1, arg2); - f->times_executed++; - f->last = f->times_executed == r->times - 1; - if (r->progress_bar) { - rprogressbar_update(r->progress_bar, f->times_executed); - } - } - f->total_execution_time = nsecs() - start; - r->execution_time += f->total_execution_time; - rbench_execute_finish(r); - } - return r; +void rterm_hide_cursor() { + printf("\x1b[?25l"); // Hide the cursor } -struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, - void *arg2, void *arg3) { +rshell_keypress_t rshell_getkey() { + static rshell_keypress_t press; + press.c = 0; + press.ctrl = false; + press.shift = false; + press.escape = false; + press.pressed = rfd_wait(0, 100); + if (press.pressed) { + press.c = getchar(); + } + char ch = press.c; + if (ch == '\x1b') { + // Get detail + ch = getchar(); - for (unsigned int i = 0; i < r->function_count; i++) { - rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); + if (ch == '[') { + // non char key: + press.escape = true; - rbench_call3 c = (rbench_call3)f->call; - nsecs_t start = nsecs(); - f->first = true; - c(arg1, arg2, arg3); - f->first = false; - f->last = false; - f->times_executed++; - for (int j = 1; j < times; j++) { - c(arg1, arg2, arg3); - f->times_executed++; - f->last = f->times_executed == r->times - 1; - if (r->progress_bar) { - rprogressbar_update(r->progress_bar, f->times_executed); + ch = getchar(); // is a number. 1 if shift + arrow + press.c = ch; + if (ch >= '0' && ch <= '9') + ch = getchar(); + press.c = ch; + if (ch == ';') { + ch = getchar(); + press.c = ch; + if (ch == '5') { + press.ctrl = true; + press.c = getchar(); // De arrow + } } + } else { + press.c = ch; } - f->total_execution_time = nsecs() - start; - rbench_execute_finish(r); } - return r; -} - -rbench_t *rbench_new() { - - rbench_t *r = (rbench_t *)malloc(sizeof(rbench_t)); - memset(r, 0, sizeof(rbench_t)); - r->add_function = rbench_add_function; - r->rbench_reset = rbench_reset; - r->execute1 = rbench_execute1; - r->execute2 = rbench_execute2; - r->execute3 = rbench_execute3; - r->execute = rbench_execute; - r->stdout = true; - r->silent = false; - r->winner = 0; - r->show_progress = true; - return r; + return press; } -void rbench_free(rbench_t *r) { free(r); } -#endif -// END OF RLIB -#endif - -#include -#include -#include -#include +// Main function +void rterm_loop(rterm_t *rt) { + struct termios orig_termios; + tcgetattr(STDIN_FILENO, &orig_termios); // Get current terminal attributes + enableRawMode(&orig_termios); -#ifdef RLIB_H - #define malloc rmalloc - #define free rfree -#else - #include -#endif -#include -#ifndef RREX3_DEBUG -#define RREX3_DEBUG 0 -#endif -#ifdef RLIB_H - #define assert rassert -#else - #include -#endif + int x = 0, y = 0; // Initial cursor position + char ch = 0; + ; + while (1) { + rterm_getwinsize(&rt->size); + rt->cursor.available = rt->size.ws_col * rt->size.ws_row; + if (rt->tick) { + rt->tick(rt); + } -struct rrex3_t; + rterm_hide_cursor(); + // setBackgroundColor(); + rterm_clear_screen(); + if (rt->before_draw) { + rt->before_draw(rt); + } + rterm_print_status_bar(rt, ch, rt->iterations); + if (!rt->iterations || (x != rt->cursor.x || y != rt->cursor.y)) { + if (y == rt->size.ws_row) { + y--; + } + if (y < 0) { + y = 0; + } + rt->cursor.x = x; + rt->cursor.y = y; + if (rt->before_cursor_move) + rt->before_cursor_move(rt); + cursor_set(rt, rt->cursor.x, rt->cursor.y); + if (rt->after_cursor_move) + rt->after_cursor_move(rt); + x = rt->cursor.x; + y = rt->cursor.y; + } + if (rt->show_cursor) + rterm_show_cursor(); + fflush(stdout); -typedef void (*rrex3_function)(struct rrex3_t *); + rt->key = rshell_getkey(); + if (rt->key.pressed && rt->before_key_press) { + rt->before_key_press(rt); + } + rshell_keypress_t key = rt->key; + ch = key.c; + if (ch == 'q') + break; // Press 'q' to quit -typedef struct rrex3_t { - void (*functions[254])(struct rrex3_t *); - void (*slash_functions[254])(struct rrex3_t *); - bool valid; - int match_count; - int match_capacity; - char ** matches; - bool exit; - char * __expr; - char * __str; - char * _expr; - char * _str; - char *expr; - char *str; - char *compiled; - bool inside_brackets; - bool inside_parentheses; - bool pattern_error; - bool match_from_start; - char bytecode; - rrex3_function function; - struct { - void (*function)(struct rrex3_t *); - char *expr; - char *str; - char bytecode; - } previous; - struct { - void (*function)(struct rrex3_t *); - char *expr; - char *str; - char bytecode; - } failed; -} rrex3_t; + // Escape + if (key.escape) { + switch (key.c) { + case 65: // Move up + if (y > -1) + y--; + break; + case 66: // Move down + if (y < rt->size.ws_row) + y++; + break; + case 68: // Move left + if (x > 0) + x--; + if (key.ctrl) + x -= 4; + break; + case 67: // Move right + if (x < rt->size.ws_col) { + x++; + } + if (key.ctrl) { + x += 4; + } + break; + } + } + if (rt->key.pressed && rt->after_key_press) { + rt->after_key_press(rt); + } + rt->iterations++; -static bool isdigitrange(char *s) { - if (!isdigit(*s)) { - return false; - } - if (*(s + 1) != '-') { - return false; + // usleep (1000); } - return isdigit(*(s + 2)); -} -static bool isalpharange(char *s) { - if (!isalpha(*s)) { - return false; - } - if (*(s + 1) != '-') { - return false; - } - return isalpha(*(s + 2)); + // Cleanup + printf("\x1b[0m"); // Reset colors + rterm_clear_screen(); + disableRawMode(&orig_termios); } +#endif +#ifndef RTREE_H +#define RTREE_H +#include +#include +#include -void rrex3_free_matches(rrex3_t *rrex3){ - if(!rrex3->matches) - return; - for(int i = 0; i < rrex3->match_capacity - 1; i++) -{ - free(rrex3->matches[i]); - - } - free(rrex3->matches); - rrex3->matches = NULL; - rrex3->match_count = 0; - rrex3->match_capacity = 0; -} +typedef struct rtree_t { + struct rtree_t *next; + struct rtree_t *children; + char c; + void *data; +} rtree_t; -void rrex3_free(rrex3_t *rrex3) { - if(!rrex3) - return; - if(rrex3->compiled){ - free(rrex3->compiled); - rrex3->compiled = NULL; - } - rrex3_free_matches(rrex3); - free(rrex3); - rrex3 = NULL; +rtree_t *rtree_new() { + rtree_t *b = (rtree_t *)rmalloc(sizeof(rtree_t)); + b->next = NULL; + b->children = NULL; + b->c = 0; + b->data = NULL; + return b; } -static bool rrex3_move(rrex3_t *, bool); -static void rrex3_set_previous(rrex3_t *); -inline static void rrex3_cmp_asterisk(rrex3_t *); -void rrex3_cmp_literal_range(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Range check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - rrex3_set_previous(rrex3); - char start = *rrex3->expr; - rrex3->expr++; - rrex3->expr++; - char end = *rrex3->expr; - if (*rrex3->str >= start && *rrex3->str <= end) { - rrex3->str++; - rrex3->valid = true; - } else { - rrex3->valid = false; +rtree_t *rtree_set(rtree_t *b, char *c, void *data) { + while (b) { + if (b->c == 0) { + b->c = *c; + c++; + if (*c == 0) { + b->data = data; + // printf("SET1 %c\n", b->c); + return b; + } + } else if (b->c == *c) { + c++; + if (*c == 0) { + b->data = data; + return b; + } + if (b->children) { + b = b->children; + } else { + b->children = rtree_new(); + b = b->children; + } + } else if (b->next) { + b = b->next; + } else { + b->next = rtree_new(); + b = b->next; + b->c = *c; + c++; + if (*c == 0) { + b->data = data; + return b; + } else { + b->children = rtree_new(); + b = b->children; + } + } } - rrex3->expr++; -} - -bool rrex3_is_function(char chr){ - if(chr == ']' || chr == ')' || chr == '\\' || chr == '?' || chr == '+' || chr == '*') - return true; - return false; + return NULL; } -inline static void rrex3_cmp_literal(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); - if(*rrex3->expr == 0 && !*rrex3->str){ - rprintr("ERROR, EMPTY CHECK"); - exit(1); - } - if (rrex3->valid == false) { - rrex3->expr++; - return; - } - if (rrex3->inside_brackets) { - if (isalpharange(rrex3->expr) || isdigitrange(rrex3->expr)) { - rrex3_cmp_literal_range(rrex3); - return; - } - } -#if RREX3_DEBUG == 1 - printf("Literal check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - if (*rrex3->expr == *rrex3->str) { - rrex3->expr++; - rrex3->str++; - rrex3->valid = true; - /*if(*rrex3->expr &&rrex3->functions[(int)*rrex3->expr] == rrex3_cmp_literal && !rrex3->inside_brackets && !rrex3_is_function(*rrex3->expr)){ - rrex3_cmp_literal(rrex3); - if(rrex3->valid == false){ - rrex3->expr--; - rrex3->valid = true; +rtree_t *rtree_find(rtree_t *b, char *c) { + while (b) { + if (b->c == *c) { + c++; + if (*c == 0) { + return b; } - }*/ - return; + b = b->children; + continue; + } + b = b->next; } - rrex3->expr++; - rrex3->valid = false; + return NULL; } -inline static void rrex3_cmp_dot(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Dot check (any char): %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - rrex3_set_previous(rrex3); - rrex3->expr++; - if (!rrex3->valid) { +void rtree_free(rtree_t *b) { + if (!b) return; - } - if (*rrex3->str != '\n') { - rrex3->str++; - if(*rrex3->expr && *rrex3->expr == '.'){ - rrex3_cmp_dot(rrex3); - return; - }/*else if(*rrex3->expr && (*rrex3->expr == '*' || *rrex3->expr == '+')){ - char * next = strchr(rrex3->str,*(rrex3->expr + 1)); - char * space = strchr(rrex3->str,'\n'); - if(next && (!space || space > next)){ - rrex3->str = next; - } - }*/ - } else { - rrex3->valid = false; - } + rtree_free(b->children); + rtree_free(b->next); + rfree(b); } -inline static void rrex3_cmp_question_mark(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Question mark check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); +void *rtree_get(rtree_t *b, char *c) { + rtree_t *t = rtree_find(b, c); + if (t) { + return t->data; + } + return NULL; +} #endif - rrex3_set_previous(rrex3); +#ifndef RLEXER_H +#define RLEXER_H +#include +#include +#include +#include +#include +#include - if (rrex3->valid == false) - rrex3->valid = true; - rrex3->expr++; +#define RTOKEN_VALUE_SIZE 1024 + +typedef enum rtoken_type_t { + RT_UNKNOWN = 0, + RT_SYMBOL, + RT_NUMBER, + RT_STRING, + RT_PUNCT, + RT_OPERATOR, + RT_EOF = 10, + RT_BRACE_OPEN, + RT_CURLY_BRACE_OPEN, + RT_BRACKET_OPEN, + RT_BRACE_CLOSE, + RT_CURLY_BRACE_CLOSE, + RT_BRACKET_CLOSE +} rtoken_type_t; + +typedef struct rtoken_t { + rtoken_type_t type; + char value[RTOKEN_VALUE_SIZE]; + unsigned int line; + unsigned int col; +} rtoken_t; + +static char *_content; +static unsigned int _content_ptr; +static unsigned int _content_line; +static unsigned int _content_col; + +static int isgroupingchar(char c) { + return (c == '{' || c == '}' || c == '(' || c == ')' || c == '[' || + c == ']' || c == '"' || c == '\''); } -inline static void rrex3_cmp_whitespace(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - rrex3_set_previous(rrex3); +static int isoperator(char c) { + return (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || + c == '>' || c == '<' || c == '|' || c == '&'); +} - char c = *rrex3->expr; - rrex3->valid = c == ' ' || c == '\n' || c == '\t'; - if (rrex3->valid) { - rrex3->str++; +static rtoken_t rtoken_new() { + rtoken_t token; + memset(&token, 0, sizeof(token)); + token.type = RT_UNKNOWN; + return token; +} + +rtoken_t rlex_number() { + rtoken_t token = rtoken_new(); + token.col = _content_col; + token.line = _content_line; + bool first_char = true; + int dot_count = 0; + char c; + while (isdigit(c = _content[_content_ptr]) || + (first_char && _content[_content_ptr] == '-') || + (dot_count == 0 && _content[_content_ptr] == '.')) { + if (c == '.') + dot_count++; + first_char = false; + char chars[] = {c, 0}; + strcat(token.value, chars); + _content_ptr++; + _content_col++; } - rrex3->expr++; + token.type = RT_NUMBER; + return token; } -inline static void rrex3_cmp_whitespace_upper(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Non whitespace check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - rrex3_set_previous(rrex3); +static rtoken_t rlex_symbol() { + rtoken_t token = rtoken_new(); - char c = *rrex3->expr; - rrex3->valid = !(c == ' ' || c == '\n' || c == '\t'); - if (rrex3->valid) { - rrex3->str++; + token.col = _content_col; + token.line = _content_line; + char c; + while (isalpha(_content[_content_ptr]) || _content[_content_ptr] == '_') { + c = _content[_content_ptr]; + char chars[] = {c, 0}; + strcat(token.value, chars); + _content_ptr++; + _content_col++; } - rrex3->expr++; + token.type = RT_SYMBOL; + return token; } -inline static void rrex3_cmp_plus(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - printf("Plus check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - rrex3_set_previous(rrex3); +static rtoken_t rlex_operator() { - if (rrex3->valid) { - rrex3->str--; - } else { - return; - } - char *original_expr = rrex3->expr; - char *next = original_expr + 1; - char *loop_expr = rrex3->previous.expr - 1; - if (*loop_expr == '+') { - rrex3->valid = false; - rrex3->pattern_error = true; - rrex3->expr++; - return; - } - bool success_next = false; - bool success_next_once = false; - bool success_current = false; - char *next_next = NULL; - char *next_str = rrex3->str; - while (*rrex3->str) { - // Check if next matches - char *original_str = rrex3->str; - rrex3->expr = next; - rrex3->valid = true; - if (rrex3_move(rrex3, false)) { - success_next = true; - next_next = rrex3->expr; - next_str = rrex3->str; - success_next_once = true; - } else { - success_next = false; - } - if (success_next_once && !success_next) { - break; - } - // Check if current matches - rrex3->str = original_str; - rrex3->expr = loop_expr; - rrex3->valid = true; - if (!rrex3_move(rrex3, false)) { - success_current = false; - } else { - success_current = true; - if (!success_next) { - next_next = rrex3->expr + 1; // +1 is the * itself - next_str = rrex3->str; + rtoken_t token = rtoken_new(); + + token.col = _content_col; + token.line = _content_line; + char c; + bool is_first = true; + while (isoperator(_content[_content_ptr])) { + if (!is_first) { + if (_content[_content_ptr - 1] == '=' && + _content[_content_ptr] == '-') { + break; } } - if (success_next && !success_current) { - break; - } - } - if (!next_next) - rrex3->expr = next; - else { - rrex3->expr = next_next; + c = _content[_content_ptr]; + char chars[] = {c, 0}; + strcat(token.value, chars); + _content_ptr++; + _content_col++; + is_first = false; } - rrex3->str = next_str; - rrex3->valid = true; + token.type = RT_OPERATOR; + return token; } -inline static void rrex3_cmp_asterisk(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - rprintg("Asterisk start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - if (!rrex3->valid) { - rrex3->valid = true; - rrex3->expr++; - return; - } - if (*rrex3->previous.expr == '*') { - // Support for ** - rrex3->valid = false; - //rrex3->pattern_error = true; - rrex3->expr++; - return; - } - rrex3->str = rrex3->previous.str;; - char *next = rrex3->expr + 1; - char *next_original = NULL; - if(*next == '*'){ - next++; - - } - if(*next == ')' && *(next + 1)){ - next_original = next; - next++; - } - char *loop_expr = rrex3->previous.expr; - bool success_next = false; - bool success_next_once = false; - bool success_current = false; - char *right_next = NULL; - char *right_str = rrex3->str; - while (*rrex3->str && *rrex3->expr && *rrex3->expr != ')') { - // Remember original_str because it's modified - // by checking right and should be restored - // for checking left so they're matching the - // same value. - char *original_str = rrex3->str; - // Check if right matches. - //if(*next != ')'){ - rrex3->expr = next; - rrex3->valid = true; - if (rrex3_move(rrex3, false)) { - // Match rright. - success_next = true; - if(!next_original){ - right_next = rrex3->expr; - }else{ - right_next = next_original; - break; - } - right_str = rrex3->str; - success_next_once = true; - } else { - // No match Right. - success_next = false; +static rtoken_t rlex_punct() { + + rtoken_t token = rtoken_new(); + + token.col = _content_col; + token.line = _content_line; + char c; + bool is_first = true; + while (ispunct(_content[_content_ptr])) { + if (!is_first) { + if (_content[_content_ptr] == '"') { + break; } - //} - if (success_next_once && !success_next) { - // Matched previous time but now doesn't. - break; - } - // Check if left matches. - rrex3->str = original_str; - rrex3->expr = loop_expr; - rrex3->valid = true; - if (!rrex3_move(rrex3, false)) { - // No match left. - success_current = false; - } else { - // Match left. - success_current = true; - // NOT SURE< WITHOUT DOET HETZELFDE: - // original_str = rrex3->str; - if (!success_next) { - right_str = rrex3->str; - if (*rrex3->expr != ')') { - right_next = rrex3->expr + 1; // +1 is the * itself - - }else{ - - //break; - } - + if (_content[_content_ptr] == '\'') { + break; + } + if (isgroupingchar(_content[_content_ptr])) { + break; + } + if (isoperator(_content[_content_ptr])) { + break; } } + c = _content[_content_ptr]; + char chars[] = {c, 0}; + strcat(token.value, chars); + _content_ptr++; + _content_col++; + is_first = false; + } + token.type = RT_PUNCT; + return token; +} - if ((success_next && !success_current) || - (!success_next && !success_current)) { - break; +static rtoken_t rlex_string() { + rtoken_t token = rtoken_new(); + char c; + token.col = _content_col; + token.line = _content_line; + char str_chr = _content[_content_ptr]; + _content_ptr++; + while (_content[_content_ptr] != str_chr) { + c = _content[_content_ptr]; + if (c == '\\') { + _content_ptr++; + c = _content[_content_ptr]; + if (c == 'n') { + c = '\n'; + } else if (c == 'r') { + c = '\r'; + } else if (c == 't') { + c = '\t'; + } else if (c == str_chr) { + c = str_chr; + } + + _content_col++; } + char chars[] = {c, 0}; + strcat(token.value, chars); + _content_ptr++; + _content_col++; } - rrex3->expr = right_next; - rrex3->str = right_str; - rrex3->valid = true; -#if RREX3_DEBUG == 1 - rprintg("Asterisk end check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif + _content_ptr++; + token.type = RT_STRING; + return token; } -inline static void rrex3_cmp_roof(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); -#if RREX3_DEBUG == 1 - printf("expr, *rrex3->str, rrex3->valid); -#endif - rrex3->valid = rrex3->str == rrex3->_str; - rrex3->match_from_start = true; - rrex3->expr++; +void rlex(char *content) { + _content = content; + _content_ptr = 0; + _content_col = 1; + _content_line = 1; } -inline static void rrex3_cmp_dollar(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); -#if RREX3_DEBUG == 1 - printf("Dollar check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - if (*rrex3->str || !rrex3->valid) { - rrex3->valid = false; +static void rlex_repeat_str(char *dest, char *src, unsigned int times) { + for (size_t i = 0; i < times; i++) { + strcat(dest, src); } - rrex3->expr++; } -inline static void rrex3_cmp_w(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); +rtoken_t rtoken_create(rtoken_type_t type, char *value) { + rtoken_t token = rtoken_new(); + token.type = type; + token.col = _content_col; + token.line = _content_line; + strcpy(token.value, value); + return token; +} - rrex3->expr++; -#if RREX3_DEBUG == 1 - printf("Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - if (isalpha(*rrex3->str)) { - rrex3->str++; - } else { - rrex3->valid = false; +rtoken_t rlex_next() { + while (true) { + + _content_col++; + + if (_content[_content_ptr] == 0) { + return rtoken_create(RT_EOF, "eof"); + } else if (_content[_content_ptr] == '\n') { + _content_line++; + _content_col = 1; + _content_ptr++; + } else if (isspace(_content[_content_ptr])) { + _content_ptr++; + } else if (isdigit(_content[_content_ptr]) || + (_content[_content_ptr] == '-' && + isdigit(_content[_content_ptr + 1]))) { + return rlex_number(); + } else if (isalpha(_content[_content_ptr]) || + _content[_content_ptr] == '_') { + return rlex_symbol(); + } else if (_content[_content_ptr] == '"' || + _content[_content_ptr] == '\'') { + return rlex_string(); + } else if (isoperator(_content[_content_ptr])) { + return rlex_operator(); + } else if (ispunct(_content[_content_ptr])) { + if (_content[_content_ptr] == '{') { + + _content_ptr++; + return rtoken_create(RT_CURLY_BRACE_OPEN, "{"); + } + if (_content[_content_ptr] == '}') { + + _content_ptr++; + return rtoken_create(RT_CURLY_BRACE_CLOSE, "}"); + } + if (_content[_content_ptr] == '(') { + + _content_ptr++; + return rtoken_create(RT_BRACE_OPEN, "("); + } + if (_content[_content_ptr] == ')') { + + _content_ptr++; + return rtoken_create(RT_BRACE_CLOSE, ")"); + } + if (_content[_content_ptr] == '[') { + + _content_ptr++; + return rtoken_create(RT_BRACKET_OPEN, "["); + } + if (_content[_content_ptr] == ']') { + + _content_ptr++; + return rtoken_create(RT_BRACKET_CLOSE, "]"); + } + return rlex_punct(); + } } } -inline static void rrex3_cmp_w_upper(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); - rrex3->expr++; -#if RREX3_DEBUG == 1 - printf("!Word check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - if (!isalpha(*rrex3->str)) { - rrex3->str++; - } else { - rrex3->valid = false; - } -} +char *rlex_format(char *content) { + rlex(content); + char *result = (char *)malloc(strlen(content) + 4096); + result[0] = 0; + unsigned int tab_index = 0; + char *tab_chars = " "; + unsigned int col = 0; + rtoken_t token_previous; + token_previous.value[0] = 0; + token_previous.type = RT_UNKNOWN; + while (true) { + rtoken_t token = rlex_next(); + if (token.type == RT_EOF) { + break; + } + + // col = strlen(token.value); + + if (col == 0) { + rlex_repeat_str(result, tab_chars, tab_index); + // col = strlen(token.value);// strlen(tab_chars) * tab_index; + } -inline static void rrex3_cmp_d(rrex3_t *rrex3) { + if (token.type == RT_STRING) { + strcat(result, "\""); - rrex3_set_previous(rrex3); + char string_with_slashes[strlen(token.value) * 2 + 1]; + rstraddslashes(token.value, string_with_slashes); + strcat(result, string_with_slashes); - rrex3->expr++; -#if RREX3_DEBUG == 1 - printf("Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - if (isdigit(*rrex3->str)) { - rrex3->str++; - } else { - rrex3->valid = false; - } -} -inline static void rrex3_cmp_d_upper(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); + strcat(result, "\""); + // col+= strlen(token.value) + 2; + // printf("\n"); + // printf("<<<%s>>>\n",token.value); - rrex3->expr++; -#if RREX3_DEBUG == 1 - printf("!Digit check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); -#endif - if (!isdigit(*rrex3->str)) { - rrex3->str++; - } else { - rrex3->valid = false; - } -} + memcpy(&token_previous, &token, sizeof(token)); + continue; + } + if (!(strcmp(token.value, "{"))) { + if (col != 0) { + strcat(result, "\n"); + rlex_repeat_str(result, " ", tab_index); + } + strcat(result, token.value); -inline static void rrex3_cmp_slash(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); + tab_index++; - rrex3->expr++; + strcat(result, "\n"); - rrex3->bytecode = *rrex3->expr; - rrex3->function = rrex3->slash_functions[(int)rrex3->bytecode]; - rrex3->function(rrex3); -} + col = 0; -inline static int collect_digits(rrex3_t *rrex3) { - char output[20]; - unsigned int digit_count = 0; - while (isdigit(*rrex3->expr)) { + memcpy(&token_previous, &token, sizeof(token)); + continue; + } else if (!(strcmp(token.value, "}"))) { + unsigned int tab_indexed = 0; + if (tab_index) + tab_index--; + strcat(result, "\n"); - output[digit_count] = *rrex3->expr; - rrex3->expr++; - digit_count++; - } - output[digit_count] = 0; - return atoi(output); -} + rlex_repeat_str(result, tab_chars, tab_index); + tab_indexed++; -inline static void rrex3_cmp_range(rrex3_t *rrex3) { - char *loop_code = rrex3->previous.expr; - char *expr_original = rrex3->expr; - rrex3->expr++; - int range_start = collect_digits(rrex3) - 1; - int range_end = 0; - if (*rrex3->expr == ',') { - rrex3->expr++; - range_end = collect_digits(rrex3); - } - rrex3->expr++; - int times_valid = 0; - while (*rrex3->str) { - rrex3->expr = loop_code; - rrex3_move(rrex3, false); - if (rrex3->valid == false) { - break; - } else { - times_valid++; + strcat(result, token.value); + strcat(result, "\n"); + col = 0; + + memcpy(&token_previous, &token, sizeof(token)); + continue; } - if (range_end) { - if (times_valid >= range_start && times_valid == range_end - 1) { - rrex3->valid = true; - } else { - rrex3->valid = false; - } - break; - } else if (range_start) { - if (times_valid == range_start) { - rrex3->valid = true; - break; + if ((token_previous.type == RT_SYMBOL && token.type == RT_NUMBER) || + (token_previous.type == RT_NUMBER && token.type == RT_SYMBOL) || + (token_previous.type == RT_PUNCT && token.type == RT_SYMBOL) || + (token_previous.type == RT_BRACE_CLOSE && + token.type == RT_SYMBOL) || + (token_previous.type == RT_SYMBOL && token.type == RT_SYMBOL)) { + if (token_previous.value[0] != ',' && + token_previous.value[0] != '.') { + if (token.type != RT_OPERATOR && token.value[0] != '.') { + strcat(result, "\n"); + rlex_repeat_str(result, tab_chars, tab_index); + } } } - } - rrex3->valid = times_valid >= range_start; - if (rrex3->valid && range_end) { - rrex3->valid = times_valid <= range_end; - } - rrex3->expr = strchr(expr_original, '}') + 1; -} -inline static void rrex3_cmp_word_start_or_end(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); - bool valid = false; - if (isalpha(*rrex3->str)) { - if (rrex3->_str != rrex3->str) { - if (!isalpha(*(rrex3->str - 1))) { - valid = true; - } - } else { - valid = true; + if (token.type == RT_OPERATOR) { + strcat(result, " "); } - } else if (isalpha(isalpha(*rrex3->str) && !isalpha(*rrex3->str + 1))) { - valid = true; + if (token.type == RT_STRING) { + strcat(result, "\""); + } + strcat(result, token.value); + if (token.type == RT_STRING) { + strcat(result, "\""); + } + + if (token.type == RT_OPERATOR) { + strcat(result, " "); + } + if (!strcmp(token.value, ",")) { + strcat(result, " "); + } + col += strlen(token.value); + memcpy(&token_previous, &token, sizeof(token)); } - rrex3->expr++; - rrex3->valid = valid; + return result; } -inline static void rrex3_cmp_word_not_start_or_end(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); +#endif +#ifndef RBENCH_H +#define RBENCH_H - rrex3_cmp_word_start_or_end(rrex3); - rrex3->valid = !rrex3->valid; -} +#include +#include +#include +#include +#include +#include +#include +#include -inline static void rrex3_cmp_brackets(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - rprintb("\\l Brackets start: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - rrex3_set_previous(rrex3); - char *original_expr = rrex3->expr; - rrex3->expr++; - rrex3->inside_brackets = true; - bool valid_once = false; - bool reversed = false; - if (*rrex3->expr == '^') { - reversed = true; - rrex3->expr++; - } - bool valid = false; - while (*rrex3->expr != ']' && *rrex3->expr != 0) { - rrex3->valid = true; - valid = rrex3_move(rrex3, false); - if (reversed) { - valid = !valid; - } - if (valid) { - valid_once = true; - if (!reversed) { - valid_once = true; - break; - } - } else { - if (reversed) { - valid_once = false; - break; - } - } +#define RBENCH(times, action) \ + { \ + unsigned long utimes = (unsigned long)times; \ + nsecs_t start = nsecs(); \ + for (unsigned long i = 0; i < utimes; i++) { \ + { action; } \ + } \ + nsecs_t end = nsecs(); \ + printf("%s\n", format_time(end - start)); \ } - if (valid_once && reversed) { - rrex3->str++; + +#define RBENCHP(times, action) \ + { \ + printf("\n"); \ + nsecs_t start = nsecs(); \ + unsigned int prev_percentage = 0; \ + unsigned long utimes = (unsigned long)times; \ + for (unsigned long i = 0; i < utimes; i++) { \ + unsigned int percentage = \ + ((long double)i / (long double)times) * 100; \ + int percentage_changed = percentage != prev_percentage; \ + __attribute__((unused)) int first = i == 0; \ + __attribute__((unused)) int last = i == utimes - 1; \ + { action; }; \ + if (percentage_changed) { \ + printf("\r%d%%", percentage); \ + fflush(stdout); \ + \ + prev_percentage = percentage; \ + } \ + } \ + nsecs_t end = nsecs(); \ + printf("\r%s\n", format_time(end - start)); \ } - while (*rrex3->expr != ']' && *rrex3->expr != 0) - rrex3->expr++; - if (*rrex3->expr != 0) - rrex3->expr++; - rrex3->valid = valid_once; - rrex3->inside_brackets = false; - char *previous_expr = rrex3->expr; - rrex3->expr = original_expr; - rrex3_set_previous(rrex3); - rrex3->expr = previous_expr; -#if RREX3_DEBUG == 1 - rprintb("\\l Brackets end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +struct rbench_t; + +typedef struct rbench_function_t { +#ifdef __cplusplus + void (*call)(); +#else + void(*call); #endif -} + char name[256]; + char group[256]; + void *arg; + void *data; + bool first; + bool last; + int argc; + unsigned long times_executed; -inline static void rrex3_cmp_pipe(rrex3_t *rrex3) { - rrex3_set_previous(rrex3); + nsecs_t average_execution_time; + nsecs_t total_execution_time; +} rbench_function_t; -#if RREX3_DEBUG == 1 - printf("Pipe check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); +typedef struct rbench_t { + unsigned int function_count; + rbench_function_t functions[100]; + rbench_function_t *current; + rprogressbar_t *progress_bar; + bool show_progress; + int winner; + bool stdout; + unsigned long times; + bool silent; + nsecs_t execution_time; +#ifdef __cplusplus + void (*add_function)(struct rbench_t *r, const char *name, + const char *group, void (*)()); +#else + void (*add_function)(struct rbench_t *r, const char *name, + const char *group, void *); #endif - if (rrex3->valid == true) { - rrex3->exit = true; - } else { - rrex3->valid = true; + void (*rbench_reset)(struct rbench_t *r); + struct rbench_t *(*execute)(struct rbench_t *r, long times); + struct rbench_t *(*execute1)(struct rbench_t *r, long times, void *arg1); + struct rbench_t *(*execute2)(struct rbench_t *r, long times, void *arg1, + void *arg2); + struct rbench_t *(*execute3)(struct rbench_t *r, long times, void *arg1, + void *arg2, void *arg3); + +} rbench_t; + +FILE *_rbench_stdout = NULL; +FILE *_rbench_stdnull = NULL; + +void rbench_toggle_stdout(rbench_t *r) { + if (!r->stdout) { + if (_rbench_stdout == NULL) { + _rbench_stdout = stdout; + } + if (_rbench_stdnull == NULL) { + _rbench_stdnull = fopen("/dev/null", "wb"); + } + if (stdout == _rbench_stdout) { + stdout = _rbench_stdnull; + } else { + stdout = _rbench_stdout; + } } - rrex3->expr++; } -inline static void rrex3_cmp_parentheses(rrex3_t *rrex3) { -#if RREX3_DEBUG == 1 - rprinty("\\l Parentheses start check: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif - if(!rrex3->valid){ - rrex3->expr++; +void rbench_restore_stdout(rbench_t *r) { + if (r->stdout) return; + if (_rbench_stdout) { + stdout = _rbench_stdout; } - rrex3_set_previous(rrex3); - if(rrex3->match_count == rrex3->match_capacity){ - - rrex3->match_capacity++; - rrex3->matches = (char *)realloc(rrex3->matches,rrex3->match_capacity * sizeof(char*)); - } - rrex3->matches[rrex3->match_count] = (char *)malloc(strlen(rrex3->str) + 1); - strcpy(rrex3->matches[rrex3->match_count], rrex3->str); - char *original_expr = rrex3->expr; - char *original_str = rrex3->str; - rrex3->expr++; - rrex3->inside_parentheses = true; - while (*rrex3->expr != ')' && !rrex3->exit) { - rrex3_move(rrex3, false); - - - } - while (*rrex3->expr != ')') { - rrex3->expr++; + if (_rbench_stdnull) { + fclose(_rbench_stdnull); + _rbench_stdnull = NULL; } - rrex3->expr++; - rrex3->inside_parentheses = false; +} - char *previous_expr = rrex3->expr; - rrex3->expr = original_expr; - rrex3_set_previous(rrex3); - rrex3->expr = previous_expr; - if (rrex3->valid == false) { - rrex3->str = original_str; - free(rrex3->matches[rrex3->match_count]); - } else { - rrex3->matches[rrex3->match_count][strlen(rrex3->matches[rrex3->match_count]) - strlen(rrex3->str)] = 0; - rrex3->match_count++; +rbench_t *rbench_new(); + +rbench_t *_rbench = NULL; +rbench_function_t *rbf; +rbench_t *rbench() { + if (_rbench == NULL) { + _rbench = rbench_new(); } -#if RREX3_DEBUG == 1 - rprinty("\\l Parentheses end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, - rrex3->valid); -#endif + return _rbench; } +typedef void *(*rbench_call)(); +typedef void *(*rbench_call1)(void *); +typedef void *(*rbench_call2)(void *, void *); +typedef void *(*rbench_call3)(void *, void *, void *); -inline static void rrex3_reset(rrex3_t * rrex3){ - rrex3_free_matches(rrex3); - rrex3->valid = true; - rrex3->pattern_error = false; - rrex3->inside_brackets = false; - rrex3->inside_parentheses = false; - rrex3->exit = false; - rrex3->previous.expr = NULL; - rrex3->previous.str = NULL; - rrex3->previous.bytecode = 0; - rrex3->failed.expr = NULL; - rrex3->failed.str = NULL; - rrex3->failed.bytecode = 0; - rrex3->match_from_start = false; +#ifdef __cplusplus +void rbench_add_function(rbench_t *rp, const char *name, const char *group, + void (*call)()) { +#else +void rbench_add_function(rbench_t *rp, const char *name, const char *group, + void *call) { +#endif + rbench_function_t *f = &rp->functions[rp->function_count]; + rp->function_count++; + f->average_execution_time = 0; + f->total_execution_time = 0; + f->times_executed = 0; + f->call = call; + strcpy(f->name, name); + strcpy(f->group, group); } -void rrex3_init(rrex3_t *rrex3) { - for (__uint8_t i = 0; i < 254; i++) { - rrex3->functions[i] = rrex3_cmp_literal; - rrex3->slash_functions[i] = rrex3_cmp_literal; +void rbench_reset_function(rbench_function_t *f) { + f->average_execution_time = 0; + f->times_executed = 0; + f->total_execution_time = 0; +} + +void rbench_reset(rbench_t *rp) { + for (unsigned int i = 0; i < rp->function_count; i++) { + rbench_reset_function(&rp->functions[i]); } - rrex3->functions['?'] = rrex3_cmp_question_mark; - rrex3->functions['^'] = rrex3_cmp_roof; - rrex3->functions['$'] = rrex3_cmp_dollar; - rrex3->functions['.'] = rrex3_cmp_dot; - rrex3->functions['*'] = rrex3_cmp_asterisk; - rrex3->functions['+'] = rrex3_cmp_plus; - rrex3->functions['|'] = rrex3_cmp_pipe; - rrex3->functions['\\'] = rrex3_cmp_slash; - rrex3->functions['{'] = rrex3_cmp_range; - rrex3->functions['['] = rrex3_cmp_brackets; - rrex3->functions['('] = rrex3_cmp_parentheses; - rrex3->slash_functions['w'] = rrex3_cmp_w; - rrex3->slash_functions['W'] = rrex3_cmp_w_upper; - rrex3->slash_functions['d'] = rrex3_cmp_d; - rrex3->slash_functions['D'] = rrex3_cmp_d_upper; - rrex3->slash_functions['s'] = rrex3_cmp_whitespace; - rrex3->slash_functions['S'] = rrex3_cmp_whitespace_upper; - rrex3->slash_functions['b'] = rrex3_cmp_word_start_or_end; - rrex3->slash_functions['B'] = rrex3_cmp_word_not_start_or_end; - rrex3->match_count = 0; - rrex3->match_capacity = 0; - rrex3->matches = NULL; - rrex3->compiled = NULL; - - rrex3_reset(rrex3); - +} +int rbench_get_winner_index(rbench_t *r) { + int winner = 0; + nsecs_t time = 0; + for (unsigned int i = 0; i < r->function_count; i++) { + if (time == 0 || r->functions[i].total_execution_time < time) { + winner = i; + time = r->functions[i].total_execution_time; + } + } + return winner; +} +bool rbench_was_last_function(rbench_t *r) { + for (unsigned int i = 0; i < r->function_count; i++) { + if (i == r->function_count - 1 && r->current == &r->functions[i]) + return true; + } + return false; } -rrex3_t *rrex3_new() { - rrex3_t *rrex3 = (rrex3_t *)malloc(sizeof(rrex3_t)); - - rrex3_init(rrex3); - - return rrex3; +rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, + int argc) { + rbench_toggle_stdout(r); + if (findex == 0) { + r->execution_time = 0; + } + rbench_function_t *rf = &r->functions[findex]; + rf->argc = argc; + rbf = rf; + r->current = rf; + if (r->show_progress) + r->progress_bar = rprogressbar_new(0, times, 20, stderr); + r->times = times; + // printf(" %s:%s gets executed for %ld times with %d + // arguments.\n",rf->group, rf->name, times,argc); + rbench_reset_function(rf); + + return rf; } +void rbench_execute_finish(rbench_t *r) { + rbench_toggle_stdout(r); + free(r->progress_bar); + r->progress_bar = NULL; + r->current->average_execution_time = + r->current->total_execution_time / r->current->times_executed; + ; + // printf(" %s:%s finished executing in + // %s\n",r->current->group,r->current->name, + // format_time(r->current->total_execution_time)); + // rbench_show_results_function(r->current); + if (rbench_was_last_function(r)) { + rbench_restore_stdout(r); + unsigned int winner_index = rbench_get_winner_index(r); + r->winner = winner_index + 1; + if (!r->silent) + rprintgf(stderr, "Benchmark results:\n"); + nsecs_t total_time = 0; -rrex3_t * rrex3_compile(rrex3_t * rrex, char * expr){ - - rrex3_t * rrex3 = rrex ? rrex : rrex3_new(); - - char * compiled = (char *)malloc(strlen(expr) + 1); - unsigned int count = 0; - while(*expr){ - if(*expr == '[' && *(expr + 2) == ']' ){ - *compiled = *(expr + 1); - expr++; - expr++; - }else if (*expr == '[' && *(expr + 1 )== '0' && *(expr + 2) == '-' && *(expr + 3) == '9' && *(expr + 4) == ']' ){ - *compiled = '\\'; - compiled++; - *compiled = 'd'; - count++; - expr++; - expr++; - expr++; - expr++; - }else{ - *compiled = *expr; - } - if(*compiled == '['){ - //in_brackets = true; - - }else if(*compiled == ']'){ - //in_brackets = false; + for (unsigned int i = 0; i < r->function_count; i++) { + rbf = &r->functions[i]; + total_time += rbf->total_execution_time; + bool is_winner = winner_index == i; + if (is_winner) { + if (!r->silent) + rprintyf(stderr, " > %s:%s:%s\n", + format_time(rbf->total_execution_time), rbf->group, + rbf->name); + } else { + if (!r->silent) + rprintbf(stderr, " %s:%s:%s\n", + format_time(rbf->total_execution_time), rbf->group, + rbf->name); + } } - expr++; - compiled++; - count++; + if (!r->silent) + rprintgf(stderr, "Total execution time: %s\n", + format_time(total_time)); } - *compiled = 0; - compiled -= count; - rrex3->compiled = compiled; - return rrex3; + rbench_restore_stdout(r); + rbf = NULL; + r->current = NULL; } +struct rbench_t *rbench_execute(rbench_t *r, long times) { -inline static void rrex3_set_previous(rrex3_t *rrex3) { - rrex3->previous.function = rrex3->function; - rrex3->previous.expr = rrex3->expr; - rrex3->previous.str = rrex3->str; - rrex3->previous.bytecode = *rrex3->expr; -} + for (unsigned int i = 0; i < r->function_count; i++) { -static bool rrex3_move(rrex3_t *rrex3, bool resume_on_fail) { - char *original_expr = rrex3->expr; - char *original_str = rrex3->str; - rrex3->bytecode = *rrex3->expr; - rrex3->function = rrex3->functions[(int)rrex3->bytecode]; - rrex3->function(rrex3); - if(!*rrex3->expr && !*rrex3->str){ - - rrex3->exit = true; - return rrex3->valid; + rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); + rbench_call c = (rbench_call)f->call; + nsecs_t start = nsecs(); + f->first = true; + c(); + f->first = false; + f->last = false; + f->times_executed++; + for (int j = 1; j < times; j++) { + c(); + f->times_executed++; + f->last = f->times_executed == r->times - 1; + if (r->progress_bar) { + rprogressbar_update(r->progress_bar, f->times_executed); + } + } + f->total_execution_time = nsecs() - start; + r->execution_time += f->total_execution_time; + rbench_execute_finish(r); } - if (rrex3->pattern_error) - { - rrex3->valid = false; - return rrex3->valid; - } - if (resume_on_fail && !rrex3->valid && *rrex3->expr) { - // rrex3_set_previous(rrex3); - rrex3->failed.bytecode = rrex3->bytecode; - rrex3->failed.function = rrex3->function; - rrex3->failed.expr = original_expr; - rrex3->failed.str = original_str; - rrex3->bytecode = *rrex3->expr; - rrex3->function = rrex3->functions[(int)rrex3->bytecode]; - rrex3->function(rrex3); + return r; +} - if (!rrex3->valid && !rrex3->pattern_error) { +struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { - if (*rrex3->str) { - char *pipe_position = strstr(rrex3->expr, "|"); - if (pipe_position != NULL) { - rrex3->expr = pipe_position + 1; - rrex3->str = rrex3->_str; - rrex3->valid = true; - return true; - } - } - if (rrex3->match_from_start) { - rrex3->valid = false; - return rrex3->valid; - } - if (!*rrex3->str++) { - rrex3->valid = false; - return rrex3->valid; + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 1); + rbench_call1 c = (rbench_call1)f->call; + nsecs_t start = nsecs(); + f->first = true; + c(arg1); + f->first = false; + f->last = false; + f->times_executed++; + for (int j = 1; j < times; j++) { + c(arg1); + f->times_executed++; + f->last = f->times_executed == r->times - 1; + if (r->progress_bar) { + rprogressbar_update(r->progress_bar, f->times_executed); } - rrex3->expr = rrex3->_expr; - if (rrex3->str) - rrex3->valid = true; } + f->total_execution_time = nsecs() - start; + r->execution_time += f->total_execution_time; + rbench_execute_finish(r); } - return rrex3->valid; + return r; } -rrex3_t *rrex3(rrex3_t * rrex3,char *str, char *expr) { -#if RREX3_DEBUG == 1 - printf("Regex check: %s:%s:%d\n", expr, str, 1); -#endif - bool self_initialized = false; - if(rrex3 == NULL){ - self_initialized = true; - rrex3 = rrex3_new(); - }else{ - rrex3_reset(rrex3); - } - - rrex3->_str = str; - rrex3->_expr = rrex3->compiled ? rrex3->compiled : expr; - rrex3->str = rrex3->_str; - rrex3->expr = rrex3->_expr; - while (*rrex3->expr && !rrex3->exit) { - if (!rrex3_move(rrex3, true)) - return NULL; - } - if(rrex3->valid){ - return rrex3; - }else{ - if( self_initialized){ - rrex3_free(rrex3); - } - return NULL; +struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, + void *arg2) { + + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 2); + rbench_call2 c = (rbench_call2)f->call; + nsecs_t start = nsecs(); + f->first = true; + c(arg1, arg2); + f->first = false; + f->last = false; + f->times_executed++; + for (int j = 1; j < times; j++) { + c(arg1, arg2); + f->times_executed++; + f->last = f->times_executed == r->times - 1; + if (r->progress_bar) { + rprogressbar_update(r->progress_bar, f->times_executed); + } + } + f->total_execution_time = nsecs() - start; + r->execution_time += f->total_execution_time; + rbench_execute_finish(r); } + return r; } -int rrex3_test(){ - rrex3_t * rrex = rrex3_new(); - - assert(rrex3(rrex,"aaaaaaa", "a*a$")); - - // assert(rrex3("ababa", "a*b*a*b*a$")); - assert(rrex3(rrex,"#include\"test.h\"a", "#include.*\".*\"a$")); - assert(rrex3(rrex,"#include \"test.h\"a", "#include.*\".*\"a$")); - assert(rrex3(rrex,"aaaaaad", "a*d$")); - assert(rrex3(rrex,"abcdef", "abd?cdef")); - assert(!rrex3(rrex,"abcdef", "abd?def")); - assert(rrex3(rrex,"abcdef", "def")); - assert(!rrex3(rrex,"abcdef", "^def")); - assert(rrex3(rrex,"abcdef", "def$")); - assert(!rrex3(rrex,"abcdef", "^abc$")); - assert(rrex3(rrex,"aB!.#1", "......")); - assert(!rrex3(rrex,"aB!.#\n", " ......")); - assert(!rrex3(rrex,"aaaaaad", "q+d$")); - assert(rrex3(rrex,"aaaaaaa", "a+a$")); - assert(rrex3(rrex,"aaaaaad", "q*d$")); - assert(!rrex3(rrex,"aaaaaad", "^q*d$")); - - // Asterisk function - assert(rrex3(rrex,"123321", "123*321")); - assert(rrex3(rrex,"pony", "p*ony")); - assert(rrex3(rrex,"pppony", "p*ony")); - assert(rrex3(rrex,"ppony", "p*pony")); - assert(rrex3(rrex,"pppony", "pp*pony")); - assert(rrex3(rrex,"pppony", ".*pony")); - assert(rrex3(rrex,"pony", ".*ony")); - assert(rrex3(rrex,"pony", "po*ny")); - // assert(rrex3(rrex,"ppppony", "p*pppony")); - - // Plus function - assert(rrex3(rrex,"pony", "p+ony")); - assert(!rrex3(rrex,"ony", "p+ony")); - assert(rrex3(rrex,"ppony", "p+pony")); - assert(rrex3(rrex,"pppony", "pp+pony")); - assert(rrex3(rrex,"pppony", ".+pony")); - assert(rrex3(rrex,"pony", ".+ony")); - assert(rrex3(rrex,"pony", "po+ny")); - - // Slash functions - assert(rrex3(rrex,"a", "\\w")); - assert(!rrex3(rrex,"1", "\\w")); - assert(rrex3(rrex,"1", "\\W")); - assert(!rrex3(rrex,"a", "\\W")); - assert(rrex3(rrex,"a", "\\S")); - assert(!rrex3(rrex," ", "\\s")); - assert(!rrex3(rrex,"\t", "\\s")); - assert(!rrex3(rrex,"\n", "\\s")); - assert(rrex3(rrex,"1", "\\d")); - assert(!rrex3(rrex,"a", "\\d")); - assert(rrex3(rrex,"a", "\\D")); - assert(!rrex3(rrex,"1", "\\D")); - assert(rrex3(rrex,"abc", "\\b")); - - assert(rrex3(rrex,"abc", "\\babc")); - assert(!rrex3(rrex,"abc", "a\\b")); - assert(!rrex3(rrex,"abc", "ab\\b")); - assert(!rrex3(rrex,"abc", "abc\\b")); - assert(rrex3(rrex,"abc", "a\\Bbc")); - assert(rrex3(rrex,"abc", "ab\\B")); - assert(!rrex3(rrex,"1ab", "1\\Bab")); - assert(rrex3(rrex,"abc", "a\\Bbc")); - - // Pipe - // assert(rrex3(rrex,"abc","abc|def")); - assert(rrex3(rrex,"abc", "def|jkl|abc")); - assert(rrex3(rrex,"abc", "abc|def")); - - assert(rrex3(rrex,"rhq", "def|rhq|rha")); - assert(rrex3(rrex,"abc", "abc|def")); - - // Repeat - assert(rrex3(rrex,"aaaaa", "a{4}")); - - assert(rrex3(rrex,"aaaa", "a{1,3}a")); - - // Range - assert(rrex3(rrex,"abc", "[abc][abc][abc]$")); - assert(rrex3(rrex,"def", "[^abc][^abc][^abc]$")); - assert(rrex3(rrex,"defabc", "[^abc][^abc][^abc]abc")); - assert(rrex3(rrex,"0-9", "0-9")); - assert(rrex3(rrex,"55-9", "[^6-9]5-9$")); - assert(rrex3(rrex,"a", "[a-z]$")); - assert(rrex3(rrex,"A", "[A-Z]$")); - assert(rrex3(rrex,"5", "[0-9]$")); - assert(!rrex3(rrex,"a", "[^a-z]$")); - assert(!rrex3(rrex,"A", "[^A-Z]$")); - assert(!rrex3(rrex,"5", "[^0-9]$")); - assert(rrex3(rrex,"123abc", "[0-9]*abc$")); - assert(rrex3(rrex,"123123", "[0-9]*$")); - - // Parentheses - - assert(rrex3(rrex,"datadata", "(data)*")); - - assert(rrex3(rrex,"datadatapony", "(data)*pony$")); - - assert(!rrex3(rrex,"datadatapony", "(d*p*ata)*pond$")); - assert(rrex3(rrex,"datadatadato", "(d*p*ata)*dato")); - assert(rrex3(rrex,"datadatadato", "(d*p*ata)*dato$")); - assert(!rrex3(rrex,"datadatadato", "(d*p*a*ta)*gato$")); - - // Matches - assert(rrex3(rrex,"123", "(123)")); - assert(!strcmp(rrex->matches[0], "123")); +struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, + void *arg2, void *arg3) { - assert(rrex3(rrex,"123321a", "(123)([0-4][2]1)a$")); - assert(!strcmp(rrex->matches[1], "321")); + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); - assert(rrex3(rrex,"123321a", "(123)([0-4][2]1)a$")); - assert(!strcmp(rrex->matches[1],"321")); - - - assert(rrex3(rrex,"aaaabc","(.*)c")); + rbench_call3 c = (rbench_call3)f->call; + nsecs_t start = nsecs(); + f->first = true; + c(arg1, arg2, arg3); + f->first = false; + f->last = false; + f->times_executed++; + for (int j = 1; j < times; j++) { + c(arg1, arg2, arg3); + f->times_executed++; + f->last = f->times_executed == r->times - 1; + if (r->progress_bar) { + rprogressbar_update(r->progress_bar, f->times_executed); + } + } + f->total_execution_time = nsecs() - start; + rbench_execute_finish(r); + } + return r; +} - assert(rrex3(rrex, "abcde", ".....$")); - - assert(rrex3(rrex,"abcdefghijklmnopqrstuvwxyz","..........................$")); - //printf("(%d)\n", rrex->valid); - - assert(rrex3(rrex," #include ","#include.*<(.*)>")); - assert(!strcmp(rrex->matches[0], "stdio.h")); - assert(rrex3(rrex," #include \"stdlib.h\"","#include.\"(.*)\"")); - assert(!strcmp(rrex->matches[0], "stdlib.h")); - assert(rrex3(rrex," \"stdio.h\"\"string.h\"\"sys/time.h\"","\"(.*)\"\"(.*)\"\"(.*)\"")); - assert(!strcmp(rrex->matches[0], "stdio.h")); - assert(!strcmp(rrex->matches[1], "string.h")); - assert(!strcmp(rrex->matches[2], "sys/time.h")); - - - rrex3_free(rrex); +rbench_t *rbench_new() { - #ifdef RLIB_H - return rtest_end(""); - #else - return 0; - #endif + rbench_t *r = (rbench_t *)malloc(sizeof(rbench_t)); + memset(r, 0, sizeof(rbench_t)); + r->add_function = rbench_add_function; + r->rbench_reset = rbench_reset; + r->execute1 = rbench_execute1; + r->execute2 = rbench_execute2; + r->execute3 = rbench_execute3; + r->execute = rbench_execute; + r->stdout = true; + r->silent = false; + r->winner = 0; + r->show_progress = true; + return r; } -#include +void rbench_free(rbench_t *r) { free(r); } +#endif +// END OF RLIB +#endif +#include -void benchmark(int times, char * str, char * expr){ +void benchmark(int times, char *str, char *expr) { - regmatch_t matches[10]; - printf("Matching \"%s\" with \"%s\".\n",str,expr); - regex_t regex; - if(regcomp(®ex,expr,REG_EXTENDED)){ - printf("Creg: error in regular expression.\n"); - exit(1); - } + regmatch_t matches[10]; + printf("Matching \"%s\" with \"%s\".\n", str, expr); + regex_t regex; + if (regcomp(®ex, expr, REG_EXTENDED)) { + printf("Creg: error in regular expression.\n"); + exit(1); + } printf("creg: "); - RBENCH(times,{ - - if(regexec(®ex,str,0,&matches,0)){ + RBENCH(times, { + if (regexec(®ex, str, 0, matches, 0)) { printf("Creg: error executing regular expression.\n"); } - }) - regfree(®ex); ; - rrex3_t * rrex = rrex3_compile(NULL,expr); - printf("Compiled!\n"); - printf("rrex3 (%s): ",rrex->compiled); + regfree(®ex); + ; + rrex3_t *rrex = rrex3_compile(NULL, expr); + printf("rrex3 (%s): ", rrex->compiled); RBENCH(times, { - rrex3(rrex, str,expr); - if(rrex){ - - }else{ + rrex3(rrex, str, expr); + if (rrex) { + + } else { printf("Rrex3: error\n"); } }); - rrex3_free(rrex); + rrex3_free(rrex); printf("\n"); } int main() { rrex3_test(); - //int times = 5000000; - int times = 100; - benchmark(times, "abcdefghijklmnopqrstuvwxyz","abcdefghijklmnopqrstuvwxyz$"); - benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaaa$"); - benchmark(times, "abcdefghijklmnopqrstuvwxyz","..........................$"); - - // [abcm] failed - benchmark(times, "abcdefghijklmnopqrstuvwxyz",".*z"); - benchmark(times, "abcde",".*e"); - benchmark(times, "abcdef",".*f"); - - benchmark(times, "abcdefghijklmnopqrstuvwxyz","[a]b*c+d\\w[f-g][g][h-i][i][^a][abcdefgk][l][m][n][o][p][a-z][r][s][t][u][v][w].*z$"); - benchmark(times, "zzz", "[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz]$"); - - benchmark(times, "7245 Sr","[0-9][0-9][0-9][0-9] \\w\\w$"); - - benchmark(times, "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyzesting","[z-z][e-e]"); - benchmark(times, "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyzesting","zesting"); - benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"","\"(.*)\"\"(.*)\"\"(.*)\""); + int times = 5000000; + // int times = 1; + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyz$"); + benchmark(times, "aaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaa$"); + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "..........................$"); + // [abcm] failed + benchmark(times, "abcdefghijklmnopqrstuvwxyz", ".*z"); + benchmark(times, "abcde", ".*e"); + benchmark(times, "abcdef", ".*f"); + + benchmark(times, "abcdefghijklmnopqrstuvwxyz", + "[a]b*c+d\\w[f-g][g][h-i][i][^a][abcdefgk][l][m][n][o][p][a-z][r]" + "[s][t][u][v][w].*z$"); + benchmark(times, "zzz", + "[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz][" + "abcdefghijklmnopqrstuvwxyz]$"); + + benchmark(times, "7245 Sr", "[0-9][0-9][0-9][0-9] ?\\w\\w$"); + + benchmark(times, + "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmn" + "opqrstuvwxyzesting", + "[z-z][e-e]"); + benchmark(times, + "abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmn" + "opqrstuvwxyzesting", + "zesting"); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\".*\"\".*\"\".*\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.*)\"\"(.*)\"\"(.*)\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\".+\"\".+\"\".+\""); + benchmark(times, "\"stdio.h\"\"string.h\"\"sys/time.h\"", + "\"(.+)\"\"(.+)\"\"(.+)\""); } -