From aa1ceb3a0a8f632720655c3f2dba727cc1810c01 Mon Sep 17 00:00:00 2001 From: retoor <retoor@molodetz.nl> Date: Thu, 20 Mar 2025 04:16:06 +0100 Subject: [PATCH] Refactor codebase: 25 files modified with 2672 insertions and 2220 deletions --- .backup.1._rlib.h | 45 + .backup.1.arena.c | 35 + .backup.1.arena.h | 47 + .backup.1.license.h | 22 + .backup.1.main.h | 51 + .backup.1.nsock.c | 11 + .backup.1.nsock.h | 420 ++ .backup.1.r.c | 20 + .backup.1.rargs.h | 58 + .backup.1.rautocomplete.c | 32 + .backup.1.rautocomplete.h | 63 + .backup.1.rbench.c | 388 ++ .backup.1.rbench.h | 370 ++ .backup.1.rbuffer.c | 39 + .backup.1.rbuffer.h | 174 + .backup.1.rcase.c | 3 + .backup.1.rcase.h | 164 + .backup.1.rcat.c | 3 + .backup.1.rcat.h | 29 + .backup.1.rcov.c | 3 + .backup.1.rcov.h | 77 + .backup.1.reditor.c | 162 + .backup.1.remo.c | 7 + .backup.1.remo.h | 247 ++ .backup.1.rfalloc.c | 113 + .backup.1.rhashtable.c | 12 + .backup.1.rhashtable.h | 67 + .backup.1.rhttp.c | 72 + .backup.1.rhttp.h | 653 +++ .backup.1.rhttpc.c | 11 + .backup.1.ricli.c | 336 ++ .backup.1.rinterp.c | 40 + .backup.1.rio.c | 9 + .backup.1.rio.h | 117 + .backup.1.rjson.c | 19 + .backup.1.rjson.h | 130 + .backup.1.rkeytable.c | 12 + .backup.1.rkeytable.h | 68 + .backup.1.rlexer.c | 189 + .backup.1.rlexer.h | 370 ++ .backup.1.rlib.c | 3 + .backup.1.rlib.h | 8451 +++++++++++++++++++++++++++++++++++++ .backup.1.rlibrlibso.c | 8451 +++++++++++++++++++++++++++++++++++++ .backup.1.rlibso.c | 18 + .backup.1.rliza.c | 156 + .backup.1.rliza.h | 775 ++++ .backup.1.rmalloc.c | 44 + .backup.1.rmalloc.h | 145 + .backup.1.rmath.h | 35 + .backup.1.rmerge.c | 3 + .backup.1.rmerge.h | 178 + .backup.1.rnet.c | 42 + .backup.1.rnet.h | 480 +++ .backup.1.rprint.c | 47 + .backup.1.rprint.h | 287 ++ .backup.1.rrex3.c | 10 + .backup.1.rrex4.c | 158 + .backup.1.rstring.c | 179 + .backup.1.rstring_list.c | 27 + .backup.1.rtemp.c | 38 + .backup.1.rterm.c | 34 + .backup.1.rterminal.c | 4 + .backup.1.rtime.c | 19 + .backup.1.rtree.c | 67 + .backup.1.rtypes.c | 14 + .r_history | 8 + _rlib.h | 23 +- arena.h | 12 +- license.h | 14 +- main.h | 25 +- nsock.h | 50 +- rargs.h | 31 +- rautocomplete.h | 41 +- rbench.h | 122 +- rbuffer.h | 73 +- rcase.h | 101 +- rcat.h | 14 +- rcov.h | 32 +- remo.h | 377 +- rhashtable.h | 55 +- rhttp.h | 67 +- rio.h | 52 +- rjson.h | 36 +- rlib.h | 1622 +++---- rlibrlibso.c | 1622 +++---- rliza.h | 44 +- rmalloc.h | 52 +- rmath.h | 26 + rmerge.h | 83 +- rnet.h | 198 +- rprint.h | 120 +- 91 files changed, 27033 insertions(+), 2220 deletions(-) create mode 100644 .backup.1._rlib.h create mode 100644 .backup.1.arena.c create mode 100644 .backup.1.arena.h create mode 100644 .backup.1.license.h create mode 100644 .backup.1.main.h create mode 100644 .backup.1.nsock.c create mode 100644 .backup.1.nsock.h create mode 100644 .backup.1.r.c create mode 100644 .backup.1.rargs.h create mode 100644 .backup.1.rautocomplete.c create mode 100644 .backup.1.rautocomplete.h create mode 100644 .backup.1.rbench.c create mode 100644 .backup.1.rbench.h create mode 100644 .backup.1.rbuffer.c create mode 100644 .backup.1.rbuffer.h create mode 100644 .backup.1.rcase.c create mode 100644 .backup.1.rcase.h create mode 100644 .backup.1.rcat.c create mode 100644 .backup.1.rcat.h create mode 100644 .backup.1.rcov.c create mode 100644 .backup.1.rcov.h create mode 100644 .backup.1.reditor.c create mode 100644 .backup.1.remo.c create mode 100644 .backup.1.remo.h create mode 100644 .backup.1.rfalloc.c create mode 100644 .backup.1.rhashtable.c create mode 100644 .backup.1.rhashtable.h create mode 100644 .backup.1.rhttp.c create mode 100644 .backup.1.rhttp.h create mode 100644 .backup.1.rhttpc.c create mode 100644 .backup.1.ricli.c create mode 100644 .backup.1.rinterp.c create mode 100644 .backup.1.rio.c create mode 100644 .backup.1.rio.h create mode 100644 .backup.1.rjson.c create mode 100644 .backup.1.rjson.h create mode 100644 .backup.1.rkeytable.c create mode 100644 .backup.1.rkeytable.h create mode 100644 .backup.1.rlexer.c create mode 100644 .backup.1.rlexer.h create mode 100644 .backup.1.rlib.c create mode 100644 .backup.1.rlib.h create mode 100644 .backup.1.rlibrlibso.c create mode 100644 .backup.1.rlibso.c create mode 100644 .backup.1.rliza.c create mode 100644 .backup.1.rliza.h create mode 100644 .backup.1.rmalloc.c create mode 100644 .backup.1.rmalloc.h create mode 100644 .backup.1.rmath.h create mode 100644 .backup.1.rmerge.c create mode 100644 .backup.1.rmerge.h create mode 100644 .backup.1.rnet.c create mode 100644 .backup.1.rnet.h create mode 100644 .backup.1.rprint.c create mode 100644 .backup.1.rprint.h create mode 100644 .backup.1.rrex3.c create mode 100644 .backup.1.rrex4.c create mode 100644 .backup.1.rstring.c create mode 100644 .backup.1.rstring_list.c create mode 100644 .backup.1.rtemp.c create mode 100644 .backup.1.rterm.c create mode 100644 .backup.1.rterminal.c create mode 100644 .backup.1.rtime.c create mode 100644 .backup.1.rtree.c create mode 100644 .backup.1.rtypes.c create mode 100644 .r_history diff --git a/.backup.1._rlib.h b/.backup.1._rlib.h new file mode 100644 index 0000000..7dec69c --- /dev/null +++ b/.backup.1._rlib.h @@ -0,0 +1,45 @@ +#include "license.h" +#ifndef RLIB_H +#define RLIB_H +// BEGIN OF RLIB + +/* + * Line below will be filtered by rmerge +<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after +tag" /> +*/ +#include "rtypes.h" +#include "nsock.h" +#include "rmalloc.h" +#include "uuid.h" +#include "rnet.h" +#include "rargs.h" +#include "rcat.h" +#include "rliza.h" +#include "rcov.h" +#include "rtemp.h" +#include "rhttp.h" +#include "rjson.h" +#include "rstring_list.h" +#include "rautocomplete.h" +#include "rrex4.h" +#include "rprint.h" +#include "rmath.h" +#include "rtest.h" +#include "rkeytable.h" +#include "rhashtable.h" +#include "rstring_list.h" +#include "rrex3.h" +#include "rtime.h" +#include "arena.h" +#include "rio.h" +#include "rstring.h" +#include "rcase.h" +#include "rterminal.h" +#include "rterm.h" +#include "rtree.h" +#include "rlexer.h" +#include "rbench.h" +#include "main.h" +// END OF RLIB +#endif diff --git a/.backup.1.arena.c b/.backup.1.arena.c new file mode 100644 index 0000000..12d7d8f --- /dev/null +++ b/.backup.1.arena.c @@ -0,0 +1,35 @@ +#include "arena.h" +#include "rtest.h" +#include <stdio.h> +#include <string.h> + +int main() { + rtest_banner("testing arena"); + arena_t *arena = arena_construct(); + // Test initial data + rtest_banner("Initial values"); + rtest_assert(arena->memory == NULL); + rtest_assert(arena->size == 0); + rtest_assert(arena->pointer == 0); + arena_free(arena); + // New instance test + rtest_banner("New instance defaults"); + arena = arena_new(1024); + rtest_assert(arena->memory != NULL); + rtest_assert(arena->size == 1024); + rtest_assert(arena->pointer == 0); + arena_free(arena); + // Allocate test + rtest_banner("Allocate"); + arena = arena_new(1024); + int *int_one = (int *)arena_alloc(arena, sizeof(int)); + *int_one = 10; + rtest_assert(*int_one == 10); + rtest_assert(arena->pointer == sizeof(int)); + int *int_two = (int *)arena_alloc(arena, sizeof(int)); + *int_two = 20; + rtest_assert(*int_two == 20); + rtest_assert(arena->pointer == sizeof(int) * 2); + arena_free(arena); + return rtest_end(""); +} \ No newline at end of file diff --git a/.backup.1.arena.h b/.backup.1.arena.h new file mode 100644 index 0000000..64bec59 --- /dev/null +++ b/.backup.1.arena.h @@ -0,0 +1,47 @@ +#ifndef RARENA_H +#define RARENA_H + +#include "rmalloc.h" +#include <stdlib.h> +#include <string.h> + +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 \ No newline at end of file diff --git a/.backup.1.license.h b/.backup.1.license.h new file mode 100644 index 0000000..40a1554 --- /dev/null +++ b/.backup.1.license.h @@ -0,0 +1,22 @@ +// 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. \ No newline at end of file diff --git a/.backup.1.main.h b/.backup.1.main.h new file mode 100644 index 0000000..40d1545 --- /dev/null +++ b/.backup.1.main.h @@ -0,0 +1,51 @@ +#ifndef RLIB_MAIN +#define RLIB_MAIN +#include "rhttp.h" +#include "rmerge.h" +#include "rcov.h" +#include "rcase.h" + +void forward_argument(int *argcc, char *argv[]) { + int argc = *argcc; + for (int i = 0; i < argc; i++) { + argv[i] = argv[i + 1]; + } + argc--; + *argcc = argc; +} + +int rlib_main(int argc, char *argv[]) { + + if (argc == 1) { + printf("rlib\n\n"); + printf("options:\n"); + printf(" httpd - a http file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts c source files to one file \n" + " with local includes by giving main file as argument.\n"); + printf(" rcov - coverage tool theat cleans up after himself. Based on " + "lcov.\n"); + printf(" rcase - tool to swap input file automatically between" + " camel case and snake case.\n"); + return 0; + } + + forward_argument(&argc, argv); + + if (!strcmp(argv[0], "httpd")) { + + return rhttp_main(argc, argv); + } + if (!strcmp(argv[0], "rmerge")) { + return rmerge_main(argc, argv); + } + if (!strcmp(argv[0], "rcov")) { + return rcov_main(argc, argv); + } + if (!strcmp(argv[0], "rcase")) { + return rcase_main(argc, argv); + } + + return 0; +} + +#endif diff --git a/.backup.1.nsock.c b/.backup.1.nsock.c new file mode 100644 index 0000000..1fa4f0b --- /dev/null +++ b/.backup.1.nsock.c @@ -0,0 +1,11 @@ +#include "nsock.h" + +void on_connect(int fd) { printf("connect\n"); } +void on_data(int fd) { printf("data\n"); } +void on_close(int fd) { printf("close\n"); } + +int main() { + + nsock(9999, on_connect, on_data, on_close); + return 0; +} \ No newline at end of file diff --git a/.backup.1.nsock.h b/.backup.1.nsock.h new file mode 100644 index 0000000..55cc84f --- /dev/null +++ b/.backup.1.nsock.h @@ -0,0 +1,420 @@ +#ifndef NSOCK_H +#define NSOCK_H +#include <unistd.h> +#include "rmalloc.h" +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <unistd.h> +#include "rio.h" + +int *nsock_socks = NULL; +int *nsock_readable = NULL; +void **nsock_data = NULL; +int nsock_server_fd = 0; +int nsock_max_socket_fd = 0; + +typedef enum nsock_type_t { NSOCK_NONE = 0, NSOCK_SERVER, NSOCK_CLIENT, NSOCK_UPSTREAM } nsock_type_t; + +typedef struct nsock_it { + int fd; + int *upstreams; + bool connected; + bool downstream; + unsigned int upstream_count; + nsock_type_t type; +} nsock_t; + +nsock_t **nsocks = NULL; +int nsocks_count = 0; + +void (*nsock_on_connect)(int fd) = NULL; +void (*nsock_on_data)(int fd) = NULL; +void (*nsock_on_close)(int fd) = NULL; +void nsock_on_before_data(int fd); + +nsock_t *nsock_get(int fd) { + if (nsock_socks[fd] == 0) { + return NULL; + } + if (fd >= nsocks_count || nsocks[fd] == NULL) { + if (fd >= nsocks_count) { + nsocks_count = fd + 1; + nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); + nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + } + nsocks[fd]->upstreams = NULL; + nsocks[fd]->fd = fd; + nsocks[fd]->connected = false; + nsocks[fd]->downstream = false; + nsocks[fd]->upstream_count = 0; + nsocks[fd]->type = NSOCK_CLIENT; + return nsocks[fd]; + } + return nsocks[fd]; +} + +void nsock_close(int fd) { + if (nsock_on_close) + nsock_on_close(fd); + nsock_t *sock = nsock_get(fd); + if (sock && sock->connected) { + sock->connected = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + nsock_t *upstream = nsock_get(sock->upstreams[i]); + if (upstream->connected) + nsock_close(sock->upstreams[i]); + sock->upstreams[i] = 0; + } + if (sock->upstream_count) { + free(sock->upstreams); + } + sock->upstream_count = 0; + } + nsock_socks[fd] = 0; + close(fd); +} + +nsock_t *nsock_create(int fd, nsock_type_t type) { + if (fd <= 0) + return NULL; + nsock_socks[fd] = fd; + nsock_t *sock = nsock_get(fd); + sock->connected = true; + sock->downstream = false; + sock->type = type; + return sock; +} + +int *nsock_init(int socket_count) { + if (nsock_socks) { + return nsock_socks; + } + nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + if (nsock_data) { + free(nsock_data); + nsock_data = NULL; + } + nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_socks[socket_count] = -1; + return nsock_socks; +} + +void nsock_free() { + if (nsock_socks) + free(nsock_socks); + if (nsock_readable) + free(nsock_readable); + nsock_server_fd = 0; + nsock_max_socket_fd = 0; + if (nsock_data) { + exit(1); + } +} + +void nsock_add_upstream(int source, int target, bool downstream) { + if (!nsock_socks[target]) + return; + if (!nsock_socks[source]) + return; + nsock_t *sock = nsock_get(source); + nsock_t *sock_target = nsock_get(target); + sock_target->type = NSOCK_UPSTREAM; + sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->downstream = downstream; + sock->upstreams[sock->upstream_count] = target; + sock->upstream_count++; +} + +void *nsock_get_data(int socket) { return nsock_data[socket]; } +void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } + +int nsock_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = 0; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return 0; + } + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + break; + } + if (p == NULL) { + freeaddrinfo(res); + return 0; + } + freeaddrinfo(res); + if (socket_fd) { + if (nsock_socks == NULL) { + nsock_init(2048); + } + nsock_socks[socket_fd] = socket_fd; + nsock_t *sock = nsock_create(socket_fd, NSOCK_CLIENT); + sock->connected = true; + } + return socket_fd; +} + +void nsock_listen(int port) { + int server_fd; + struct sockaddr_in address; + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed"); + exit(EXIT_FAILURE); + } + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("setsockopt failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + if (listen(server_fd, 8096) < 0) { + perror("Listen failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + nsock_server_fd = server_fd; +} + +int *nsock_select(suseconds_t timeout) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout; + int server_fd = nsock_server_fd; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(server_fd, &rfds); + int *socks = nsock_socks; + fd_set efds; + FD_ZERO(&efds); + nsock_max_socket_fd = server_fd; + for (int i = 0; socks[i] != -1; i++) { + if (i == server_fd) + continue; + ; + if (!socks[i]) + continue; + if (socks[i] > nsock_max_socket_fd) { + nsock_max_socket_fd = socks[i]; + } + FD_SET(socks[i], &rfds); + FD_SET(socks[i], &efds); + } + int activity = select(nsock_max_socket_fd + 1, &rfds, NULL, &efds, timeout == 0 ? NULL : &tv); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } else if (activity == 0) { + return NULL; + } + if (FD_ISSET(server_fd, &rfds)) { + struct sockaddr_in address; + int addrlen = sizeof(address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + int new_socket = 0; + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed"); + } else { + nsock_socks[new_socket] = new_socket; + nsock_create(new_socket, NSOCK_CLIENT); + if (nsock_on_connect) + nsock_on_connect(new_socket); + if (new_socket > nsock_max_socket_fd) + nsock_max_socket_fd = new_socket; + } + } + if (nsock_readable) { + free(nsock_readable); + } + nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable[nsock_max_socket_fd + 1] = -1; + nsock_readable[0] = 0; + int readable_count = 0; + for (int i = 0; i < nsock_max_socket_fd + 1; i++) { + nsock_t *sock = nsock_get(i); + if (!sock) + continue; + if (FD_ISSET(i, &efds)) { + nsock_close(nsock_socks[i]); + nsock_socks[i] = 0; + nsock_readable[i] = 0; + } else if (FD_ISSET(i, &rfds) && i != server_fd) { + nsock_readable[i] = i; + readable_count++; + nsock_on_before_data(i); + } else { + nsock_readable[i] = 0; + sock->connected = false; + } + } + return nsock_readable; +} + +unsigned char *nsock_read(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = read(fd, buffer, length); + if (bytes_read <= 0) { + nsock_close(fd); + return NULL; + } + buffer[bytes_read] = 0; + return buffer; +} + +unsigned char *nsock_read_all(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = 0; + while (bytes_read < length) { + int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); + if (bytes_chunk <= 0) { + nsock_close(fd); + return NULL; + } + bytes_read += bytes_chunk; + } + buffer[bytes_read] = 0; + return buffer; +} + +int nsock_write_all(int fd, unsigned char *data, int length) { + if (!nsock_socks[fd]) + return 0; + int bytes_written = 0; + while (bytes_written < length) { + int bytes_chunk = write(fd, data + bytes_written, length - bytes_written); + if (bytes_chunk <= 0) { + nsock_close(fd); + return 0; + } + bytes_written += bytes_chunk; + } + return bytes_written; +} + +int nsock_execute_upstream(int source, size_t buffer_size) { + int result = 0; + nsock_t *sock = nsock_get(source); + unsigned char data[buffer_size]; + memset(data, 0, buffer_size); + int bytes_read = read(source, data, buffer_size); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + bool downstreamed = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + if (!nsock_socks[sock->upstreams[i]]) + continue; + int bytes_sent = nsock_write_all(sock->upstreams[i], data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + continue; + } + if (sock->downstream && downstreamed == false) { + downstreamed = true; + unsigned char data[4096]; + memset(data, 0, 4096); + int bytes_read = read(sock->upstreams[i], data, 4096); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + int bytes_sent = nsock_write_all(sock->fd, data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + return 0; + } + } + result++; + } + return result; +} + +void nsock_on_before_data(int fd) { + if (!nsock_socks[fd]) + return; + nsock_t *sock = nsock_get(fd); + if (sock->upstream_count) { + int upstreamed_to_count = nsock_execute_upstream(fd, 4096); + if (!upstreamed_to_count) { + nsock_close(fd); + } + return; + } else if (sock->type == NSOCK_UPSTREAM) { + while (rfd_wait(sock->fd, 0)) { + unsigned char *data = nsock_read(fd, 4096); + (void)data; + } + } + if (nsock_on_data) + nsock_on_data(fd); +} + +void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void (*on_close)(int fd)) { + nsock_init(2048); + nsock_listen(port); + nsock_on_connect = on_connect; + nsock_on_data = on_data; + nsock_on_close = on_close; + int serve_in_terminal = nsock_on_connect == NULL && nsock_on_data == NULL && nsock_on_close == NULL; + while (1) { + int *readable = nsock_select(0); + if (!serve_in_terminal) + continue; + if (!readable) + continue; + for (int i = 0; readable[i] != -1; i++) { + if (!readable[i]) + continue; + char buffer[1024] = {0}; + int bytes_read = read(readable[i], buffer, 1); + buffer[bytes_read] = 0; + if (bytes_read <= 0) { + nsock_close(readable[i]); + continue; + } + if (write(readable[i], buffer, bytes_read) <= 0) { + nsock_close(readable[i]); + continue; + } + } + } +} +#endif diff --git a/.backup.1.r.c b/.backup.1.r.c new file mode 100644 index 0000000..95cb412 --- /dev/null +++ b/.backup.1.r.c @@ -0,0 +1,20 @@ +#include "rlib.h" + +void dummy_function() { + for (long i = 0; i < 100000; i++) { + long a = i * 2; + } +} + +int main() { + rbench_t *r = rbench_new(); + r->add_function(r, "function", "dummy_function", dummy_function); + r->execute(r, 10000); + + rbench_free(r); + + for (int i = 0; i < 10000; i++) { + + // rprintr("\\l\\T message\n"); + } +} \ No newline at end of file diff --git a/.backup.1.rargs.h b/.backup.1.rargs.h new file mode 100644 index 0000000..3050042 --- /dev/null +++ b/.backup.1.rargs.h @@ -0,0 +1,58 @@ +#include <stdio.h> +#ifndef RLIB_RARGS_H +#define RLIB_RARGS_H +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> + +bool rargs_isset(int argc, char *argv[], char *key) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + return true; + } + } + return false; +} + +char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return argv[i + 1]; + } + } + } + return (char *)def; +} + +int rargs_get_option_int(int argc, char *argv[], char *key, int def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return atoi(argv[i + 1]); + } + } + } + return def; +} + +bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + if (!strcmp(argv[i + 1], "false")) + return false; + if (!strcmp(argv[i + 1], "0")) + return false; + return true; + } + } + } + + return def; +} +#endif \ No newline at end of file diff --git a/.backup.1.rautocomplete.c b/.backup.1.rautocomplete.c new file mode 100644 index 0000000..6ae4c61 --- /dev/null +++ b/.backup.1.rautocomplete.c @@ -0,0 +1,32 @@ +#include "rautocomplete.h" + +int main() { + + rautocomplete_t *ac = rautocomplete_new(); + rstring_list_add(ac, "first"); + rstring_list_add(ac, "test2"); + rstring_list_add(ac, "test3"); + rstring_list_add(ac, "test4"); + rstring_list_add(ac, "test5"); + rstring_list_add(ac, "test6"); + rstring_list_add(ac, "test7"); + rstring_list_add(ac, "test8"); + rstring_list_add(ac, "test9"); + rstring_list_add(ac, "test10"); + rstring_list_add(ac, "test11"); + rstring_list_add(ac, "test12"); + rstring_list_add(ac, "test13"); + rstring_list_add(ac, "test14"); + rstring_list_add(ac, "test15"); + rstring_list_add(ac, "test16"); + rstring_list_add(ac, "test17"); + rstring_list_add(ac, "test18"); + rstring_list_add(ac, "test19"); + rstring_list_add(ac, "test20"); + printf(r4_escape("test")); + char *str = rautocomplete_find(ac, "firsta"); + if (str) + printf("%s\n", str); + rautocomplete_free(ac); + return 0; +} \ No newline at end of file diff --git a/.backup.1.rautocomplete.h b/.backup.1.rautocomplete.h new file mode 100644 index 0000000..0579e71 --- /dev/null +++ b/.backup.1.rautocomplete.h @@ -0,0 +1,63 @@ +#ifndef RAUTOCOMPLETE_H +#define RAUTOCOMPLETE_H +#define R4_DEBUG +#include "rrex4.h" +#include "rstring_list.h" +#define rautocomplete_new rstring_list_new +#define rautocomplete_free rstring_list_free +#define rautocomplete_add rstring_list_add +#define rautocomplete_find rstring_list_find +#define rautocomplete_t rstring_list_t +#define rautocomplete_contains rstring_list_contains + +char *r4_escape(char *content) { + size_t size = strlen(content) * 2 + 1; + char *escaped = (char *)calloc(size, sizeof(char)); + char *espr = escaped; + char *to_escape = "?*+()[]{}^$\\"; + *espr = '('; + espr++; + while (*content) { + if (strchr(to_escape, *content)) { + *espr = '\\'; + espr++; + } + *espr = *content; + espr++; + content++; + } + *espr = '.'; + espr++; + *espr = '+'; + espr++; + *espr = ')'; + espr++; + *espr = 0; + return escaped; +} + +char *rautocomplete_find(rstring_list_t *list, char *expr) { + if (!list->count) + return NULL; + if (!expr || !strlen(expr)) + return NULL; + + char *escaped = r4_escape(expr); + + for (unsigned int i = list->count - 1; i == 0; i--) { + char *match; + r4_t *r = r4(list->strings[i], escaped); + if (r->valid && r->match_count == 1) { + match = strdup(r->matches[0]); + } + r4_free(r); + if (match) { + + free(escaped); + return match; + } + } + free(escaped); + return NULL; +} +#endif \ No newline at end of file diff --git a/.backup.1.rbench.c b/.backup.1.rbench.c new file mode 100644 index 0000000..ced4a0a --- /dev/null +++ b/.backup.1.rbench.c @@ -0,0 +1,388 @@ +#include "rbench.h" +#include "rtest.h" +#include "rtree.h" +#include "rhashtable.h" +#include <math.h> +#include <string.h> +#include "rtime.h" + +char *format_number_retoor(long lnumber) { + static char formatted[1024]; + char number[1024]; + number[0] = 0; + sprintf(number, "%ld", lnumber); + size_t len = strlen(number); + int comma_count = len / 3; + int count = 0; + int offset = 0; + int i; + formatted[comma_count + len] = 0; + for (i = len + comma_count; i > 0; i--) { + formatted[i - offset] = number[i - comma_count]; + if (count == 3) { + count = 0; + offset++; + if (i > 1) { + formatted[i - offset] = '.'; + } + } + count++; + } + return formatted; +} +char *format_number_yurii(long long num) { + static char buf[1024]; + char *buff = buf; + int isneg = num < 0; + if (isneg) + num = -num; + long long rev = num; + size_t count; + for (count = 0; num; count++, num /= 10) + rev = rev * 10 + num % 10; + count += (count - 1) / 3; + + if (isneg) + *buff++ = '-'; + for (size_t i = 0; i < count; i++) { + if ((count - i) % 4 == 0) { + *buff++ = '.'; + } else { + *buff++ = (rev % 10 + '0'); + rev /= 10; + } + } + *buff = '\0'; + return buf; +} + +char *format_number_gpt(long lnumber) { + static char formatted[1024]; + + char number[1024]; + sprintf(number, "%ld", lnumber); + + int len = strlen(number); + int commas_needed = (len - 1) / 3; // Determine how many dots are needed + int new_len = len + commas_needed; // New length with dots included + + formatted[new_len] = '\0'; // Null-terminate the formatted string + + int i = len - 1; // Index for original number + int j = new_len - 1; // Index for formatted number + int count = 0; // Counter for placing dots + + while (i >= 0) { + if (count == 3) { + formatted[j--] = '.'; // Insert dot after every 3 digits + count = 0; // Reset the counter + } + formatted[j--] = number[i--]; // Copy digit from the original number + count++; + } + return formatted; +} + +int rstrcmp(char *l, char *r) { + while (*l && *l == *r) { + l++; + r++; + } + return *l - *r; +} +int strcmp_gpt(const char *str1, const char *str2) { + while (*str1 && (*str1 == *str2)) { + str1++; + str2++; + } + + return *(unsigned char *)str1 - *(unsigned char *)str2; +} +int strcmp_clib(p1, p2) const char *p1; +const char *p2; +{ + register const unsigned char *s1 = (const unsigned char *)p1; + register const unsigned char *s2 = (const unsigned char *)p2; + unsigned c1, c2; + + do { + c1 = (unsigned char)*s1++; + c2 = (unsigned char)*s2++; + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + +void bench_rstrcmp(void *arg1, void *arg2) { __attribute__((unused)) int res = rstrcmp(arg1, arg2); } +void bench_cstrcmp(void *arg1, void *arg2) { __attribute__((unused)) int res = strcmp(arg1, arg2); } + +bool bench_starts_with_r(const char *s1, const char *s2) { return rstrstartswith(s1, s2); } +bool bench_ends_with_r(const char *s1, const char *s2) { return rstrendswith(s1, s2); } + +bool bench_starts_with_gpt(const char *str, const char *prefix) { + while (*prefix) { + if (*str != *prefix) { + return false; // Mismatch found + } + str++; + prefix++; + } + return true; // All characters matched +} + +int bench_starts_with_yurii(const char *str, const char *start) { + if (str == NULL) + return start == NULL; + if (str == start || start == NULL || *start == '\0') + return 1; + + return strncmp(str, start, strlen(start)) == 0; +} + +bool bench_ends_with_gpt(const char *str, const char *suffix) { + size_t str_len = strlen(str); + size_t suffix_len = strlen(suffix); + + // If the suffix is longer than the string, it can't be a suffix + if (suffix_len > str_len) { + return false; + } + + // Start comparing from the end of both strings + const char *str_end = str + str_len - suffix_len; + while (*suffix) { + if (*str_end != *suffix) { + return false; // Mismatch found + } + str_end++; + suffix++; + } + + return true; // All characters matched +} + +int bench_ends_with_yurii(const char *str, const char *end) { + size_t end_len; + + if (str == NULL) + return end == NULL; + if (str == end || end == NULL || *end == '\0') + return 1; + + end_len = strlen(end); + return strncmp(str + (strlen(str) - end_len), end, end_len) == 0; +} + +void plus(int v1, int v2) { __attribute__((unused)) int v3 = v1 + v2; } +void min(int v1, int v2) { __attribute__((unused)) int v3 = v2 - v1; } + +void bench_rstrmove_r() { + char to_move_1[] = "abc?defgaa"; + rstrmove2(to_move_1, 3, 5, 0); + rasserts(!strcmp(to_move_1, "?defgabcaa")); + char to_move_2[] = "?defgabcaa"; + rstrmove2(to_move_2, 0, 5, 3); + rasserts(!strcmp(to_move_2, "abc?defgaa")); + char to_move_3[] = "?defgabcaa"; + rstrmove2(to_move_3, 0, 5, 6); + rasserts(!strcmp(to_move_3, "abcaa?defg")); +} + +void bench_rstrmove_gpt() { + char to_move_1[] = "abc?defgaa"; + rstrmove(to_move_1, 3, 5, 0); + rasserts(!strcmp(to_move_1, "?defgabcaa")); + char to_move_2[] = "?defgabcaa"; + rstrmove(to_move_2, 0, 5, 2); + // printf("BECAME: %s\n",to_move_2); + // Goes wrong! + // rasserts(!strcmp(to_move_2, "ab?defgcaa")); + char to_move_3[] = "?defgabcaa"; + rstrmove(to_move_3, 0, 5, 7); + rasserts(!strcmp(to_move_3, "abc?defgaa")); +} + +void rbench_table_rtree() { + rtree_t *tree = (rtree_t *)rbf->data; + if (rbf->first) { + tree = rtree_new(); + rbf->data = (void *)tree; + } + for (int i = 0; i < 1; i++) { + char *key = rgenerate_key(); + rtree_set(tree, key, key); + rasserts(!strcmp(rtree_get(tree, key), key)); + } + if (rbf->last) + rtree_free(rbf->data); +} + +void rbench_table_rhashtable() { + for (int i = 0; i < 1; i++) { + char *key = rgenerate_key(); + rset(key, key); + rasserts(!strcmp(rget(key), key)); + } +} + +nsecs_t total_execution_time = 0; +long total_times = 0; +bool show_progress = 1; +void bench_format_number(long times, long number) { + rbench_t *r; + rprint("\\T B\\l Times: %ld\n", times); + r = rbench_new(); + r->show_progress = show_progress; + r->add_function(r, "number_format", "retoor", format_number_retoor); + r->add_function(r, "number_format", "yurii", format_number_yurii); + r->add_function(r, "number_format", "gpt", format_number_gpt); + r->execute1(r, times, (void *)number); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +void bench_table(long times) { + rbench_t *r; + rprint("\\T B\\l Times: %ld\n", times); + r = rbench_new(); + r->show_progress = show_progress; + r->add_function(r, "rtree", "retoor", rbench_table_rtree); + r->add_function(r, "hashtable", "k*r", rbench_table_rhashtable); + r->execute(r, times); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +void bench_rstrmove(long times) { + rbench_t *r; + rprint("\\T B\\l Times: %ld\n", times); + r = rbench_new(); + r->show_progress = show_progress; + r->add_function(r, "rstrmove2", "retoor", bench_rstrmove_r); + r->add_function(r, "rstrmove", "gpt", bench_rstrmove_gpt); + r->execute(r, times); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} +void bench_math(long times) { + rbench_t *r = rbench_new(); + r->show_progress = show_progress; + rprint("\\T B\\l Times: %ld\n", times); + r->add_function(r, "plus", "math", plus); + r->add_function(r, "min", "math", min); + r->execute2(r, times, (void *)5, (void *)5); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} +void bench_strcmp(long times) { + rbench_t *r = rbench_new(); + r->stdout = false; + r->show_progress = show_progress; + rprint("\\T B\\l Times: %ld\n", times); + r->add_function(r, "strcmp_clib", "scmp", strcmp_clib); + r->add_function(r, "strcmp", "scmp", strcmp); + r->add_function(r, "rstrcmp", "scmp", rstrcmp); + r->add_function(r, "strcmp_gpt", "scmp", strcmp_gpt); + r->execute2(r, times, "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +void printf_strcat() { + char buffer[1000] = {0}; + for (int i = 0; i < 1000; i++) { + strcat(buffer, "a"); + } + printf("%s", buffer); +} +void printf_raw() { + for (int i = 0; i < 1000; i++) { + printf("%s", "a"); + } +} + +void bench_sprintf(long times) { + rbench_t *r = rbench_new(); + r->stdout = false; + r->show_progress = show_progress; + rprint("\\T B\\l Times: %ld\n", times); + r->add_function(r, "strcat", "buffered", printf_strcat); + r->add_function(r, "printf", "raw", printf_raw); + r->execute(r, times); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +void bench_startswith(long times) { + rbench_t *r = rbench_new(); + r->stdout = false; + r->show_progress = show_progress; + rprint("\\T B\\l Times: %ld\n", times); + r->add_function(r, "startswith", "retoor", bench_starts_with_r); + r->add_function(r, "startswith", "gpt", bench_starts_with_gpt); + r->add_function(r, "startswith", "yurii", bench_starts_with_yurii); + r->execute2(r, times, "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnop"); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +void bench_endswith(long times) { + rbench_t *r = rbench_new(); + r->stdout = false; + r->show_progress = show_progress; + rprint("\\T B\\l Times: %ld\n", times); + r->add_function(r, "endswith", "retoor", bench_ends_with_r); + r->add_function(r, "endswith", "gpt", bench_ends_with_gpt); + r->add_function(r, "endswith", "yurii", bench_ends_with_yurii); + r->execute2(r, times, "abcdefghijklmnopqrstuvwxyzdef", "qrstuvwxyzdef"); + total_execution_time += r->execution_time; + total_times += times * 2; + rbench_free(r); +} + +#define ifwhile(cond, action) \ + { \ + bool _did_doit = false; \ + while (cond) { \ + _did_doit = true; \ + { action } \ + } \ + if (_did_doit) + +#define endifwhile } + +int main() { + show_progress = true; + long times = 900000000; + + printf("With %% progress times:\n"); + BENCH(times, { bench_starts_with_yurii("abcdefghijklmnopqrstuvw", "abcdef"); }); + BENCH(times, { bench_ends_with_yurii("abcdefghijklmnopqrstuvw", "uvw"); }); + + printf("Without %% progress times:\n"); + BENCH(times * 1000, { bench_starts_with_yurii("abcdefghijklmnopqrstuvw", "abcdef"); }); + BENCH(times * 1000, { bench_ends_with_yurii("abcdefghijklmnopqrstuvw", "uvw"); }); + + bench_table(times / 10000); + bench_sprintf(times / 10000); + bench_format_number(times / 100, 123456789); + bench_rstrmove(times / 100); + bench_math(times); + bench_strcmp(times / 100); + + bench_startswith(times / 10); + bench_endswith(times / 10); + printf("\nTotal execution time:%s\n", format_time(total_execution_time)); + printf("Total times: %s\n", rformat_number(total_times)); + + return 0; +} \ No newline at end of file diff --git a/.backup.1.rbench.h b/.backup.1.rbench.h new file mode 100644 index 0000000..ea6a2d6 --- /dev/null +++ b/.backup.1.rbench.h @@ -0,0 +1,370 @@ +#ifndef RBENCH_H +#define RBENCH_H + +#include "rprint.h" +#include "rtime.h" +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> + +#include "rstring.h" +#include "rterminal.h" + +#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 { +#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; + + nsecs_t average_execution_time; + nsecs_t total_execution_time; +} rbench_function_t; + +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); + +} 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; + } + } +} +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; + } +} + +rbench_t *rbench_new(); + +rbench_t *_rbench = NULL; +rbench_function_t *rbf; +rbench_t *rbench() { + if (_rbench == NULL) { + _rbench = rbench_new(); + } + return _rbench; +} + +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 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]); + } +} +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; +} + +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); + 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; + ; + // 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; +} +struct rbench_t *rbench_execute(rbench_t *r, long times) { + + for (unsigned int i = 0; i < r->function_count; i++) { + + 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; +} + +struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { + + 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); + } + return r; +} + +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; +} + +struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { + + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); + + 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; +} + +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; +} +void rbench_free(rbench_t *r) { free(r); } + +#endif \ No newline at end of file diff --git a/.backup.1.rbuffer.c b/.backup.1.rbuffer.c new file mode 100644 index 0000000..f8df937 --- /dev/null +++ b/.backup.1.rbuffer.c @@ -0,0 +1,39 @@ +#include "rtest.h" +#include "rbuffer.h" + +int main() { + rtest_banner("rbuffer"); + unsigned char *content = (unsigned char *)"[ {\n\t \"\r1\t3\n4truefalsetrue \" }, ]"; + char *ignore = "\r| |\n|\t|\f|\v"; + rbuffer_t *buffer = rbuffer_new(content, ustrlen(content)); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '['); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '{'); + rbuffer_reset(buffer); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '['); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '{'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '"'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '1'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '3'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '4'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == 't'); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == 'f'); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == 't'); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + rbuffer_pop(buffer); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == '"'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b|}", ignore) == '}'); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b", ignore) == ','); + assert(*rbuffer_consume(buffer, "{|[|,|\"|\\d|\\b|]", ignore) == ']'); + unsigned char *str = rbuffer_to_string(buffer); + printf(">%s<\n", str); + free(str); + return rtest_end(""); +} \ No newline at end of file diff --git a/.backup.1.rbuffer.h b/.backup.1.rbuffer.h new file mode 100644 index 0000000..decdd9c --- /dev/null +++ b/.backup.1.rbuffer.h @@ -0,0 +1,174 @@ +#ifndef RBUFFER_H +#define RBUFFER_H +#include "rmalloc.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <assert.h> +typedef struct rbuffer_t { + unsigned char *data; + unsigned char *_data; + size_t size; + size_t pos; + bool eof; +} rbuffer_t; + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size); +void rbuffer_free(rbuffer_t *rfb); +void rbuffer_reset(rbuffer_t *rfb); +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +unsigned char rbuffer_pop(rbuffer_t *rfb); +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); + +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size) { + if (rfb->_data) { + free(rfb->_data); + rfb->_data = NULL; + rfb->data = NULL; + rfb->eof = true; + } + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->data = rfb->_data; + rfb->eof = false; + } + rfb->size = size; + rfb->pos = 0; +} + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { + rbuffer_t *rfb = (rbuffer_t *)malloc(sizeof(rbuffer_t)); + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->eof = false; + } else { + rfb->_data = NULL; + rfb->eof = true; + } + rfb->size = size; + rfb->pos = 0; + rfb->data = rfb->_data; + return rfb; +} +void rbuffer_free(rbuffer_t *rfb) { + if (rfb->_data) + free(rfb->_data); + free(rfb); +} + +size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { + if (rfb->pos < rfb->size) { + rfb->_data[rfb->pos++] = c; + return 1; + } + rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); + rfb->_data[rfb->pos++] = c; + rfb->size++; + return rfb->pos; +} +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { + unsigned char *data_ptr = (unsigned char *)data; + for (size_t i = 0; i < size; i++) { + rbuffer_push(rfb, data_ptr[i]); + } +} + +unsigned char rbuffer_peek(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos != rfb->size) { + result = rfb->_data[rfb->pos]; + return result; + } + rfb->eof = true; + return EOF; +} +unsigned char rbuffer_pop(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos <= rfb->size) { + result = rfb->_data[rfb->pos]; + rfb->pos++; + rfb->data++; + if (rfb->pos == rfb->size) { + rfb->eof = true; + } + return result; + } + rfb->eof = true; + return result; +} +void rbuffer_reset(rbuffer_t *rfb) { + rfb->data = rfb->_data; + rfb->pos = 0; +} + +unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { + return strncmp((char *)s1, (char *)s2, n); + while (n && *s1 == *s2) { + n--; + s1++; + s2++; + } + return *s1 != *s2; +} +size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +unsigned char *rbuffer_to_string(rbuffer_t *rfb) { + unsigned char *result = rfb->_data; + rfb->_data = NULL; + rfb->data = NULL; + rbuffer_free(rfb); + return result; +} + +unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { + char *option = NULL; + char options_cpy[1024] = {0}; + strcpy(options_cpy, options); + char *memory = options_cpy; + while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { + + size_t option_length = strlen(option); + if (option_length > rfb->size - rfb->pos) { + continue; + } + if (!strcmp(option, "\\d") && *rfb->data >= '0' && *rfb->data <= '9') { + return rfb->data; + } + if (rfb->size - rfb->pos >= 5 && !strcmp(option, "\\b") && + ((!ustrncmp(rfb->data, (unsigned char *)"true", 4) || !ustrncmp(rfb->data, (unsigned char *)"false", 5)))) { + return rfb->data; + } + if (!ustrncmp(rfb->data, (unsigned char *)option, option_length)) { + return rfb->data; + } + } + return NULL; +} + +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { + while (rfb->pos < rfb->size) { + if (rbuffer_match_option(rfb, options) != NULL) { + return rfb->data; + } + if (rbuffer_match_option(rfb, ignore)) { + printf("SKIP:%s\n", rfb->data); + rbuffer_pop(rfb); + continue; + } + break; + } + return NULL; +} +unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { + unsigned char *result = NULL; + if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { + rbuffer_pop(rfb); + } + return result; +} +#endif \ No newline at end of file diff --git a/.backup.1.rcase.c b/.backup.1.rcase.c new file mode 100644 index 0000000..ac872be --- /dev/null +++ b/.backup.1.rcase.c @@ -0,0 +1,3 @@ +#include "rcase.h" + +int main(int argc, char *argv[]) { return rcase_main(argc, argv); } \ No newline at end of file diff --git a/.backup.1.rcase.h b/.backup.1.rcase.h new file mode 100644 index 0000000..4c32f3c --- /dev/null +++ b/.backup.1.rcase.h @@ -0,0 +1,164 @@ +#ifndef RCASE_H +#define RCASE_H +#include "rio.h" +#include "rmalloc.h" +#include "rprint.h" +#include "rstring.h" +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#define RCAMEL_CASE 1 +#define RSNAKE_CASE 2 +#define RINVALID_CASE 0 +#define RCONST_TEST_T 4; + +int rdetermine_case(const char *str) { + int length = strlen(str); + + char p = 0; + while (*str) { + if (p == '_' && islower(*str)) + return RSNAKE_CASE; + if (p != '_' && !isupper(p) && isupper(*str)) + return RCAMEL_CASE; + p = *str; + str++; + } + return RINVALID_CASE; + + if (length == 0) { + return RINVALID_CASE; + } + if (strchr(str, '_')) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + return RINVALID_CASE; + } + for (int i = 0; i < length; i++) { + if (!islower(str[i]) && str[i] != '_') { + return RINVALID_CASE; + } + } + return RSNAKE_CASE; + } else { + + if (!islower(str[0])) { + return RINVALID_CASE; + } + for (int i = 1; i < length; i++) { + if (str[i] == '_') { + return RINVALID_CASE; + } + if (isupper(str[i]) && isupper(str[i - 1])) { + return RINVALID_CASE; + } + } + return RCAMEL_CASE; + } +} + +char *rsnake_to_camel(const char *snake_case) { + int length = strlen(snake_case); + char *camel_case = (char *)malloc(length + 1); + int j = 0; + int toUpper = 0; + + for (int i = 0; i < length; i++) { + if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { + toUpper = 1; + if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + + toUpper = 0; + } + } + if (snake_case[i] == '_' && snake_case[i + 1] != 't') { + toUpper = 1; + if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + toUpper = 0; + } + } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { + toUpper = 1; + } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { + toUpper = 1; + camel_case[j++] = '_'; + j++; + } else { + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; + } else { + camel_case[j++] = snake_case[i]; + } + } + } + + camel_case[j] = '\0'; + return camel_case; +} +char *rcamel_to_snake(const char *camelCase) { + int length = strlen(camelCase); + char *snake_case = (char *)malloc(2 * length + 1); + int j = 0; + + for (int i = 0; i < length; i++) { + if (isupper(camelCase[i])) { + if (i != 0) { + snake_case[j++] = '_'; + } + snake_case[j++] = tolower(camelCase[i]); + } else { + snake_case[j++] = camelCase[i]; + } + } + + snake_case[j] = '\0'; + return snake_case; +} + +char *rflip_case(char *content) { + if (rdetermine_case(content) == RSNAKE_CASE) { + return rcamel_to_snake(content); + } else if (rdetermine_case(content) == RCAMEL_CASE) { + return rsnake_to_camel(content); + } else { + rprintr("Could not determine case\n"); + return NULL; + } +} + +char *rflip_case_file(char *filepath) { + size_t file_size = rfile_size(filepath); + if (file_size == 0) { + return NULL; + } + char *content = (char *)malloc(file_size); + char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { + result = rflip_case(content); + if (result) { + free(content); + return result; + } else { + return content; + } + } + return result; +} + +int rcase_main(int argc, char *argv[]) { + if (argc < 2) { + printf("usage: rcase <file>\n"); + return 1; + } + for (int i = 1; i < argc; i++) { + char *result = rflip_case_file(argv[i]); + if (result) { + printf("%s\n", result); + free(result); + } + } + return 0; +} +#endif diff --git a/.backup.1.rcat.c b/.backup.1.rcat.c new file mode 100644 index 0000000..3d4c90b --- /dev/null +++ b/.backup.1.rcat.c @@ -0,0 +1,3 @@ +#include "rcat.h" + +int main(int argc, char *argv[]) { return rcat_main(argc, argv); } diff --git a/.backup.1.rcat.h b/.backup.1.rcat.h new file mode 100644 index 0000000..ce780f0 --- /dev/null +++ b/.backup.1.rcat.h @@ -0,0 +1,29 @@ +#ifndef RCAT_H +#define RCAT_H +#include <stdio.h> +#include <stdlib.h> + +void rcat(char *filename) { + FILE *f = fopen(filename, "rb"); + if (!f) { + printf("rcat: couldn't open \"%s\" for read.\n", filename); + return; + } + unsigned char c; + while ((c = fgetc(f)) && !feof(f)) { + printf("%c", c); + } + fclose(f); + fflush(stdout); +} + +int rcat_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [filename]\n"); + return 1; + } + rcat(argv[1]); + return 0; +} + +#endif diff --git a/.backup.1.rcov.c b/.backup.1.rcov.c new file mode 100644 index 0000000..b2db4ed --- /dev/null +++ b/.backup.1.rcov.c @@ -0,0 +1,3 @@ +#include "rcov.h" + +int main(int argc, char *argv[]) { return rcov_main(argc, argv); } diff --git a/.backup.1.rcov.h b/.backup.1.rcov.h new file mode 100644 index 0000000..42779bc --- /dev/null +++ b/.backup.1.rcov.h @@ -0,0 +1,77 @@ +#ifndef RCOV_H +#define RCOV_H +#include "rtypes.h" +#include "rtemp.h" +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "rbench.h" +bool check_lcov() { + char buffer[1024 * 64]; + FILE *fp; + fp = popen("lcov --help", "r"); + if (fp == NULL) { + return false; + } + if (fgets(buffer, sizeof(buffer), fp) == NULL) { + return false; + } + pclose(fp); + return strstr(buffer, "lcov: not found") ? false : true; +} + +int rcov_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [source.c]\n"); + return 1; + } + char argstr[4096] = {0}; + for (int i = 2; i < argc; i++) { + strcat(argstr, argv[i]); + strcat(argstr, " "); + } + if (!check_lcov()) { + + printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); + return 1; + } + char *source_file = argv[1]; + char *commands[] = {"rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", + "gcc -pg -fprofile-arcs -ftest-coverage -g -o %s_coverage.o %s", + "./%s_coverage.o", + "lcov --capture --directory . --output-file %s.coverage.info", + "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", + "rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", + + "gprof %s_coverage.o gmon.out > output.rcov_analysis", + + "rm -f gmon.out", + "cat output.rcov_analysis", + "rm output.rcov_analysis", + "rm -f %s_coverage.o", + + "google-chrome /tmp/%s.coverage/index.html"}; + uint command_count = sizeof(commands) / sizeof(commands[0]); + RBENCH(1,{ + for (uint i = 0; i < command_count; i++) { + char *formatted_command = sbuf(""); + sprintf(formatted_command, commands[i], source_file, source_file); + // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { + strcat(formatted_command, " "); + strcat(formatted_command, argstr); + } + + if (system(formatted_command)) { + printf("`%s` returned non-zero code.\n", formatted_command); + } + }); + } + return 0; +} +#endif diff --git a/.backup.1.reditor.c b/.backup.1.reditor.c new file mode 100644 index 0000000..1e17271 --- /dev/null +++ b/.backup.1.reditor.c @@ -0,0 +1,162 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> +#include <string.h> + +void rget_terminal_size(int *x, int *y) { + struct winsize w; + + // Get terminal size + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + + // Print terminal size + // printf("Rows: %d, Columns: %d\n", w.ws_row, w.ws_col); + + // You can use this width in your program logic + int terminal_width = w.ws_col; + *x = w.ws_col; + *y = w.ws_row; + + // printf("Setting content width to half the terminal width:\n"); + + // Example content that fits within half the terminal width + // printf("%.*s\n", terminal_width / 2, "This text is formatted to half + // the terminal width."); +} + +struct termios rorig_termios; + +// Restore original terminal settings +void reset_terminal_mode() { tcsetattr(STDIN_FILENO, TCSANOW, &rorig_termios); } + +void set_raw_mode() { + struct termios new_termios; + tcgetattr(STDIN_FILENO, &rorig_termios); // Get current terminal settings + atexit(reset_terminal_mode); // Ensure original settings are restored on exit + + new_termios = rorig_termios; + new_termios.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echoing + new_termios.c_cc[VMIN] = 1; // Minimum number of characters for noncanonical read + new_termios.c_cc[VTIME] = 0; // Timeout in deciseconds for noncanonical read + + tcsetattr(STDIN_FILENO, TCSANOW, &new_termios); // Apply new settings +} + +unsigned int read_key() { + int nread; + char c; + if ((nread = read(STDIN_FILENO, &c, 1)) == -1) + return -1; + return c; +} + +void rrclear() { + printf("\033[2J"); // Clear screen +} + +void rset_cursor_position(int x, int y) { + // rrclear(); + printf("\033[%d;%dH", y, x); +} + +void get_cursor_position(int *cols, int *rows) { + char buf[32]; + unsigned int i = 0; + + // Request cursor position + printf("\033[6n"); + + // Read the response: ESC [ rows ; cols R + while (i < sizeof(buf) - 1) { + if (read(STDIN_FILENO, buf + i, 1) != 1) + break; + if (buf[i] == 'R') + break; + i++; + } + buf[i] = '\0'; + + // Parse the response + if (buf[0] == '\033' && buf[1] == '[') { + sscanf(buf + 2, "%d;%d", rows, cols); + } +} + +void run() { + int c; + int x = 3; + int y = 3; // Initial y position + int file_index = 0; + set_raw_mode(); + printf("\033[2J"); // Clear screen + rset_cursor_position(x, y); + char screen_data[1024]; + + int width, height; + rget_terminal_size(&width, &height); + + screen_data[0] = 0; + for (int i = 0; i < width * height; i++) { // screen_data[i] = '\0'; + // screen_data[i] = 0; + } + memset(&screen_data, 0, 2048); + // printf(screen_data); + + while (1) { + c = read_key(); + if (c == '\033') { // If the first character is ESC + + if (read_key() == '[') { // If the second character is '[' + rrclear(); + c = read_key(); + if (c == 'A') { + if (y) { + y--; + } + rset_cursor_position(x, y); + } else if (c == 'B') { + if (y) { + y++; + } + rset_cursor_position(x, y); + } else if (c == 'C') { + + x++; + + rset_cursor_position(x, y); + + } else if (c == 'D') { + x--; + + rset_cursor_position(x, y); + } + printf(screen_data); + } + } else if (c == 'q') { + break; // Press 'q' to quit + } else { + for (int i = 0; i < file_index; i++) { + if (screen_data[i] == '\0') { + screen_data[i] = ' '; + } + } + screen_data[file_index] = c; + // file_index++; + get_cursor_position(&x, &y); + file_index = x * y; + x++; + // putc(c, stdout); + // rrclear(); + rset_cursor_position(1, 1); + // ss x++; + printf(screen_data); + rset_cursor_position(x, y); + + fflush(stdout); + } + } +} + +int main() { run(); } diff --git a/.backup.1.remo.c b/.backup.1.remo.c new file mode 100644 index 0000000..8ff3ae3 --- /dev/null +++ b/.backup.1.remo.c @@ -0,0 +1,7 @@ +#include "remo.h" + +int main() { + remo_print(); + printf("<%s>", remo_get("zany")); + return 0; +} \ No newline at end of file diff --git a/.backup.1.remo.h b/.backup.1.remo.h new file mode 100644 index 0000000..7219f11 --- /dev/null +++ b/.backup.1.remo.h @@ -0,0 +1,247 @@ +#ifndef REMO_H +#define REMO_H +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdbool.h> + +typedef struct { + const char *str; + const char *description; +} remo_t; + +remo_t remo[] = { + {"\U0001F600", "Grinning Face"}, // 😀 + {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 + {"\U0001F602", "Face with Tears of Joy"}, // 😂 + {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 + {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 + {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 + {"\U0001F609", "Winking Face"}, // 😉 + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 + {"\U0001F618", "Face Blowing a Kiss"}, // 😘 + {"\U0001F617", "Kissing Face"}, // 😗 + {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 + {"\U0001F642", "Slightly Smiling Face"}, // 🙂 + {"\U0001F643", "Upside-Down Face"}, // 🙃 + {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 + {"\U0001F60B", "Face Savoring Food"}, // 😋 + {"\U0001F61B", "Face with Tongue"}, // 😛 + {"\U0001F61C", "Winking Face with Tongue"}, // 😜 + {"\U0001F92A", "Zany Face"}, // 🤪 + {"\U0001F929", "Star-Struck"}, // 🤩 + {"\U0001F631", "Face Screaming in Fear"}, // 😱 + {"\U0001F62D", "Loudly Crying Face"}, // 😭 + {"\U0001F624", "Face with Steam From Nose"}, // 😤 + {"\U0001F620", "Angry Face"}, // 😠 + {"\U0001F621", "Pouting Face"}, // 😡 + {"\U0001F47B", "Ghost"}, // 👻 + {"\U0001F480", "Skull"}, // 💀 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + {"\U0001F47D", "Alien"}, // 👽 + // Geometric Shapes + {"\U000025A0", "Black Square"}, // ■ + {"\U000025B2", "Upward Triangle"}, // ▲ + {"\U000025CF", "Black Circle"}, // ● + {"\U000025CB", "White Circle"}, // ○ + {"\U00002B1B", "Large Black Square"}, // ⬛ + {"\U00002B1C", "Large White Square"}, // ⬜ + + // Mathematical Symbols + {"\U00002200", "For All"}, // ∀ + {"\U00002203", "Exists"}, // ∃ + {"\U00002205", "Empty Set"}, // ∅ + {"\U00002207", "Nabla"}, // ∇ + {"\U0000220F", "N-Ary Product"}, // ∏ + {"\U00002212", "Minus Sign"}, // − + {"\U0000221E", "Infinity"}, // ∞ + + // Arrows + {"\U00002190", "Left Arrow"}, // ← + {"\U00002191", "Up Arrow"}, // ↑ + {"\U00002192", "Right Arrow"}, // → + {"\U00002193", "Down Arrow"}, // ↓ + {"\U00002195", "Up Down Arrow"}, // ↕ + {"\U00002197", "Up Right Arrow"}, // ↗ + {"\U00002198", "Down Right Arrow"}, // ↘ + {"\U000027A1", "Black Right Arrow"}, // ➡️ + + // Dingbats + {"\U00002714", "Check Mark"}, // ✔️ + {"\U00002716", "Heavy Multiplication X"}, // ✖️ + {"\U00002728", "Sparkles"}, // ✨ + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002795", "Heavy Plus Sign"}, // ➕ + + // Miscellaneous Symbols + {"\U00002600", "Sun"}, // ☀️ + {"\U00002614", "Umbrella with Rain Drops"}, // ☔ + {"\U00002620", "Skull and Crossbones"}, // ☠️ + {"\U000026A0", "Warning Sign"}, // ⚠️ + {"\U000026BD", "Soccer Ball"}, // ⚽ + {"\U000026C4", "Snowman"}, // ⛄ + + // Stars and Asterisks + {"\U00002733", "Eight Pointed Black Star"}, // ✳️ + {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U00002728", "Sparkles"}, // ✨ + // Animals and Nature + {"\U0001F98A", "Fox"}, // 🦊 + {"\U0001F415", "Dog"}, // 🐕 + {"\U0001F431", "Cat Face"}, // 🐱 + {"\U0001F435", "Monkey Face"}, // 🐵 + {"\U0001F408", "Black Cat"}, // 🐈 + {"\U0001F98C", "Deer"}, // 🦌 + {"\U0001F344", "Mushroom"}, // 🍄 + {"\U0001F333", "Tree"}, // 🌳 + + // Weather and Space Symbols + {"\U0001F308", "Rainbow"}, // 🌈 + {"\U0001F320", "Shooting Star"}, // 🌠 + {"\U00002600", "Sun"}, // ☀️ + {"\U00002601", "Cloud"}, // ☁️ + {"\U000026A1", "High Voltage"}, // ⚡ + {"\U0001F525", "Fire"}, // 🔥 + {"\U000026C4", "Snowman"}, // ⛄ + {"\U0001F30A", "Water Wave"}, // 🌊 + + // Transport and Map Symbols + {"\U0001F68C", "Bus"}, // 🚌 + {"\U0001F697", "Car"}, // 🚗 + {"\U0001F6B2", "Bicycle"}, // 🚲 + {"\U0001F6A2", "Ship"}, // 🚢 + {"\U0001F681", "Helicopter"}, // 🚁 + {"\U0001F680", "Rocket"}, // 🚀 + {"\U0001F6EB", "Airplane"}, // 🛫 + + // Currency Symbols + {"\U00000024", "Dollar Sign"}, // $ + {"\U000000A3", "Pound Sign"}, // £ + {"\U000000A5", "Yen Sign"}, // ¥ + {"\U000020AC", "Euro Sign"}, // € + {"\U0001F4B5", "Dollar Banknote"}, // 💵 + {"\U0001F4B4", "Yen Banknote"}, // 💴 + + // Card Suits + {"\U00002660", "Black Spade Suit"}, // ♠️ + {"\U00002663", "Black Club Suit"}, // ♣️ + {"\U00002665", "Black Heart Suit"}, // ♥️ + {"\U00002666", "Black Diamond Suit"}, // ♦️ + {"\U0001F0CF", "Joker Card"}, // 🃏 + + // Office Supplies and Objects + {"\U0001F4DA", "Books"}, // 📚 + {"\U0001F4D7", "Green Book"}, // 📗 + {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 + {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 + {"\U0001F4B0", "Money Bag"}, // 💰 + {"\U0001F4B8", "Money with Wings"}, // 💸 + {"\U0001F4E6", "Package"}, // 📦 + + // Miscellaneous Symbols + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U00002714", "Check Mark"}, // ✔️ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002705", "Check Mark Button"}, // ✅ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U0001F4A1", "Light Bulb"}, // 💡 + {"\U0001F4A3", "Bomb"}, // 💣 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + // Musical Symbols + {"\U0001F3B5", "Musical Note"}, // 🎵 + {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 + {"\U0001F3BC", "Musical Score"}, // 🎼 + {"\U0001F399", "Studio Microphone"}, // 🎙️ + {"\U0001F3A4", "Microphone"}, // 🎤 + + // Food and Drink + {"\U0001F35F", "Cheese Wedge"}, // 🧀 + {"\U0001F355", "Slice of Pizza"}, // 🍕 + {"\U0001F32D", "Taco"}, // 🌮 + {"\U0001F37D", "Beer Mug"}, // 🍻 + {"\U0001F96B", "Cup with Straw"}, // 🥤 + {"\U0001F32E", "Hot Pepper"}, // 🌶️ + {"\U0001F95A", "Potato"}, // 🥔 + + // Zodiac Signs + {"\U00002600", "Aries"}, // ♈ + {"\U00002601", "Taurus"}, // ♉ + {"\U00002602", "Gemini"}, // ♊ + {"\U00002603", "Cancer"}, // ♋ + {"\U00002604", "Leo"}, // ♌ + {"\U00002605", "Virgo"}, // ♍ + {"\U00002606", "Libra"}, // ♎ + {"\U00002607", "Scorpio"}, // ♏ + {"\U00002608", "Sagittarius"}, // ♐ + {"\U00002609", "Capricorn"}, // ♑ + {"\U0000260A", "Aquarius"}, // ♒ + {"\U0000260B", "Pisces"}, // ♓ + + // Miscellaneous Shapes + {"\U0001F4C8", "Chart Increasing"}, // 📈 + {"\U0001F4C9", "Chart Decreasing"}, // 📉 + {"\U0001F4CA", "Bar Chart"}, // 📊 + {"\U0001F7E6", "Orange Circle"}, // 🟠 + {"\U0001F7E7", "Yellow Circle"}, // 🟡 + {"\U0001F7E8", "Green Circle"}, // 🟢 + {"\U0001F7E9", "Blue Circle"}, // 🔵 + {"\U0001F7EA", "Purple Circle"}, // 🟣 + + // Flags + {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 + + // Additional Miscellaneous Symbols + {"\U0001F4A5", "Collision"}, // 💥 + {"\U0001F4A6", "Sweat Droplets"}, // 💦 + {"\U0001F4A8", "Dashing Away"}, // 💨 + {"\U0001F50B", "Battery"}, // 🔋 + {"\U0001F4BB", "Laptop Computer"}, // 💻 + {"\U0001F4DE", "Telephone"}, // 📞 + {"\U0001F4E7", "Incoming Envelope"}, // 📧 +}; +size_t remo_count = sizeof(remo) / sizeof(remo[0]); + +void rstrtolower(const char *input, char *output) { + while (*input) { + *output = tolower(*input); + input++; + output++; + } + *output = 0; +} +bool rstrinstr(const char *haystack, const char *needle) { + char lower1[strlen(haystack) + 1]; + char lower2[strlen(needle) + 1]; + rstrtolower(haystack, lower1); + rstrtolower(needle, lower2); + return strstr(lower1, lower2) ? true : false; +} + +void remo_print() { + + for (size_t i = 0; i < remo_count; i++) { + printf("%s - %s\n", remo[i].str, remo[i].description); + } +} + +const char *remo_get(char *name) { + for (size_t i = 0; i < remo_count; i++) { + if (rstrinstr(remo[i].description, name)) { + return remo[i].str; + } + } + return NULL; +} + +#endif \ No newline at end of file diff --git a/.backup.1.rfalloc.c b/.backup.1.rfalloc.c new file mode 100644 index 0000000..40f1f5b --- /dev/null +++ b/.backup.1.rfalloc.c @@ -0,0 +1,113 @@ +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +// r file memory +typedef struct rfm_t { + char path[4096]; + void *data; + size_t size; + long ptr; + FILE *f; + int fd; +} rfm_t; + +rfm_t rfm; +bool _initialized = false; + +void rfm_destroy(rfm_t *r) { + if (munmap(r->data, r->size) == -1) { + perror("munmap"); + exit(EXIT_FAILURE); + } + close(rfm.fd); +} + +void *falloc(size_t s) { + rfm_t *rr = &rfm; + + printf("hier\n"); + char *data = (char *)rr->data + rfm.ptr; + // data+= rfm.ptr; + rfm.ptr += s; + return data; +} + +void *finit(char *path, size_t size) { + + printf("HIERR\n"); + if (!_initialized) { + rfm.ptr = 0; + _initialized = true; + rfm.size = size; + + printf("HIERR\n"); + memset(&rfm, 0, sizeof(rfm_t)); + rfm.size = size; + rfm.ptr = 0; + + printf("HIERR\n"); + // rfm.fd = open(path, O_RDWR); + // ftruncate(rfm.fd, size); + + if (path) { + printf("HIERR\n"); + rfm.path[0] = 0; + strcpy(rfm.path, path); + // creat(path,F_) + rfm.fd = open(path, O_RDWR); + printf("OPEN %s\n", path); + } + if (!path) { + rfm.f = tmpfile(); + rfm.fd = fileno(rfm.f); + } + // if (ftruncate(rfm.fd, size) == -1) + // { + // perror("ftruncate"); + // exit(EXIT_FAILURE); + // } + // rfensurefile(path,1024*1024); + rfm.data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, rfm.fd, 0); + printf("HIERR\n"); + } + /* + if (rfm.data == MAP_FAILED) + { + perror("mmap"); + exit(EXIT_FAILURE); + } + char *data = (char *)rfm.data; + printf(data); + if (munmap(rfm.data, size) == -1) + { + perror("munmap"); + exit(EXIT_FAILURE); + } + fclose(rfm.f); + */ +} +int main() { + // Step 1: Create a temporary file + finit("tast.dat", 1024 * 1024 * 100); + printf("gaa\n"); + char *data = (char *)falloc(10); + strcpy(data, "ab"); + char *data2 = (char *)falloc(30); + strcpy(data2, "ff\n"); + + // for(int i = 0; i < 333333; i++) + // strcat(data,"ggggggggggggggggg"); + + printf("%s\n", data); + + // printf("%s\n",data);; + + // strcpy(data2,"aaaa"); + + return 0; +} \ No newline at end of file diff --git a/.backup.1.rhashtable.c b/.backup.1.rhashtable.c new file mode 100644 index 0000000..55dda76 --- /dev/null +++ b/.backup.1.rhashtable.c @@ -0,0 +1,12 @@ +#include "rhashtable.h" +#include "rtest.h" +#include "rstring.h" + +int main() { + + for (int i = 0; i < 1000; i++) { + char *key = rgenerate_key(); + rset(key, "tast"); + rasserts(!strcmp(rget(key), "tast")); + } +} \ No newline at end of file diff --git a/.backup.1.rhashtable.h b/.backup.1.rhashtable.h new file mode 100644 index 0000000..193b31d --- /dev/null +++ b/.backup.1.rhashtable.h @@ -0,0 +1,67 @@ +#ifndef RHASHTABLE_H +#define RHASHTABLE_H +/* + ORIGINAL SOURCE IS FROM K&R + */ + +#include "rmalloc.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HASHSIZE 101 + +// Structure for the table entries +typedef struct rnlist { + struct rnlist *next; + char *name; + char *defn; +} rnlist; + +// Hash table array +static rnlist *rhashtab[HASHSIZE]; + +// Hash function +unsigned rhash(char *s) { + unsigned hashval; + for (hashval = 0; *s != '\0'; s++) + hashval = *s + 31 * hashval; + return hashval % HASHSIZE; +} + +rnlist *rlget(char *s) { + rnlist *np; + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +// Lookup function +char *rget(char *s) { + rnlist *np = rlget(s); + return np ? np->defn : NULL; +} + +// Install function (adds a name and definition to the table) +struct rnlist *rset(char *name, char *defn) { + struct rnlist *np = NULL; + unsigned hashval; + + if ((rlget(name)) == NULL) { // Not found + np = (struct rnlist *)malloc(sizeof(*np)); + if (np == NULL || (np->name = strdup(name)) == NULL) + return NULL; + hashval = rhash(name); + np->next = rhashtab[hashval]; + rhashtab[hashval] = np; + } else { + if (np->defn) + free((void *)np->defn); + np->defn = NULL; + } + if ((np->defn = strdup(defn)) == NULL) + return NULL; + return np; +} +#endif diff --git a/.backup.1.rhttp.c b/.backup.1.rhttp.c new file mode 100644 index 0000000..158a5bd --- /dev/null +++ b/.backup.1.rhttp.c @@ -0,0 +1,72 @@ +#include "rmalloc.h" +#include "rhttp.h" +#include "rtest.h" +#include <pthread.h> + +int request_handler(rhttp_request_t *r) { + rhttp_send_drain(r->c, + "HTTP/1.1 200 OK\r\n" + "Content-Length: 3\r\n" + "Connection: close\r\n\r\n" + "Ok!", + 0); + close(r->c); + return 1; +} + +rhttp_request_handler_t handler = request_handler; + +void *rhttp_serve_thread(void *port_arg) { + int port = *(int *)port_arg; + rhttp_serve(rhttp_opt_host, port, 1024, rhttp_opt_request_logging, rhttp_opt_debug, handler, NULL); + return NULL; +} + +int main(int argc, char *argv[]) { + bool do_test = true; + int port = 9876; + + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--serve")) { + printf("rhttp serve mode\n"); + printf("Handlers available:\n"); + printf(" - rhttp_root (/)\n"); + printf(" - rhttp_counter (/counter*)\n"); + printf(" - rhttp_404 (/*)\n"); + do_test = false; + } + if (!strcmp(argv[i], "--quiet")) { + rhttp_opt_info = false; + rhttp_opt_warn = false; + rhttp_opt_request_logging = false; + rhttp_opt_debug = false; + printf("Quiet mode enabled\n"); + } + if (atoi(argv[i])) { + port = atoi(argv[i]); + } + } + if (do_test) { + rtest_banner("rhttp"); + } else { + printf("Serving on %s:%d\n", rhttp_opt_host, port); + handler = rhttp_default_request_handler; + } + + pthread_t st; + pthread_create(&st, 0, rhttp_serve_thread, (void *)&port); + + char *response = rhttp_client_get("127.0.0.1", port, "/"); + + if (do_test) { + rassert(!strcmp(response, "Ok!")); + pthread_cancel(st); + // cleanup + } else { + pthread_join(st, NULL); + } + // rhttp_main(argc, argv); + if (do_test) + return rtest_end(""); + return 0; +} diff --git a/.backup.1.rhttp.h b/.backup.1.rhttp.h new file mode 100644 index 0000000..98d750c --- /dev/null +++ b/.backup.1.rhttp.h @@ -0,0 +1,653 @@ +#ifndef RHTTP_H +#define RHTTP_H +#include "rio.h" +#include "rmalloc.h" +#include "rstring.h" +#include "rtemp.h" +#include "rtime.h" +#include <arpa/inet.h> +#include <pthread.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#define BUFF_SIZE 8096 +#define RHTTP_MAX_CONNECTIONS 100 + +int rhttp_opt_error = 1; +int rhttp_opt_warn = 1; +int rhttp_opt_info = 1; +int rhttp_opt_port = 8080; +int rhttp_opt_debug = 0; +int rhttp_opt_request_logging = 0; +int rhttp_sock = 0; +int rhttp_opt_buffered = 0; +int rhttp_c = 0; +int rhttp_c_mutex_initialized = 0; +pthread_mutex_t rhttp_c_mutex; +char rhttp_opt_host[1024] = "0.0.0.0"; +unsigned int rhttp_connections_handled = 0; + +typedef struct rhttp_header_t { + char *name; + char *value; + struct rhttp_header_t *next; +} rhttp_header_t; + +typedef struct rhttp_request_t { + int c; + int closed; + bool keep_alive; + nsecs_t start; + char *raw; + char *line; + char *body; + char *method; + char *path; + char *version; + void *context; + unsigned int bytes_received; + rhttp_header_t *headers; +} rhttp_request_t; + +char *rhttp_current_timestamp() { + time_t current_time; + time(¤t_time); + struct tm *local_time = localtime(¤t_time); + static char time_string[100]; + time_string[0] = 0; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); + + return time_string; +} + +void rhttp_logs(const char *prefix, const char *level, const char *format, va_list args) { + char buf[strlen(format) + BUFSIZ + 1]; + buf[0] = 0; + sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); + vfprintf(stdout, buf, args); +} +void rhttp_log_info(const char *format, ...) { + if (!rhttp_opt_info) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[32m", "INFO ", format, args); + va_end(args); +} +void rhttp_log_debug(const char *format, ...) { + if (!rhttp_opt_debug) + return; + va_list args; + va_start(args, format); + if (rhttp_opt_debug) + rhttp_logs("\e[33m", "DEBUG", format, args); + + va_end(args); +} +void rhttp_log_warn(const char *format, ...) { + if (!rhttp_opt_warn) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[34m", "WARN ", format, args); + + va_end(args); +} +void rhttp_log_error(const char *format, ...) { + if (!rhttp_opt_error) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[35m", "ERROR", format, args); + + va_end(args); +} + +void http_request_init(rhttp_request_t *r) { + r->raw = NULL; + r->line = NULL; + r->body = NULL; + r->method = NULL; + r->path = NULL; + r->version = NULL; + r->start = 0; + r->headers = NULL; + r->bytes_received = 0; + r->closed = 0; +} + +void rhttp_free_header(rhttp_header_t *h) { + if (!h) + return; + rhttp_header_t *next = h->next; + free(h->name); + free(h->value); + free(h); + if (next) + rhttp_free_header(next); +} +void rhttp_rhttp_free_headers(rhttp_request_t *r) { + if (!r->headers) + return; + rhttp_free_header(r->headers); + r->headers = NULL; +} + +rhttp_header_t *rhttp_parse_headers(rhttp_request_t *s) { + int first = 1; + char *body = strdup(s->body); + char *body_original = body; + while (body && *body) { + char *line = __strtok_r(first ? body : NULL, "\r\n", &body); + if (!line) + break; + rhttp_header_t *h = (rhttp_header_t *)malloc(sizeof(rhttp_header_t)); + h->name = NULL; + h->value = NULL; + h->next = NULL; + char *name = __strtok_r(line, ": ", &line); + first = 0; + if (!name) { + rhttp_free_header(h); + break; + } + h->name = strdup(name); + char *value = __strtok_r(NULL, "\r\n", &line); + if (!value) { + rhttp_free_header(h); + break; + } + h->value = value ? strdup(value + 1) : strdup(""); + h->next = s->headers; + s->headers = h; + } + free(body_original); + return s->headers; +} + +void rhttp_free_request(rhttp_request_t *r) { + if (r->raw) { + free(r->raw); + free(r->body); + free(r->method); + free(r->path); + free(r->version); + rhttp_rhttp_free_headers(r); + } + free(r); +} + +long rhttp_header_get_long(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return strtol(h->value, NULL, 10); + h = h->next; + } + return -1; +} +char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return h->value && *h->value ? h->value : NULL; + h = h->next; + } + return NULL; +} + +void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } +void rhttp_print_headers(rhttp_header_t *h) { + while (h) { + rhttp_print_header(h); + h = h->next; + } +} +void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } +void rhttp_print_request(rhttp_request_t *r) { + rhttp_print_request_line(r); + if (rhttp_opt_debug) + rhttp_print_headers(r->headers); +} +void rhttp_close(rhttp_request_t *r) { + if (!r) + return; + if (!r->closed) + close(r->c); + rhttp_free_request(r); +} +rhttp_request_t *rhttp_parse_request(int s) { + rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); + http_request_init(request); + char buf[BUFF_SIZE] = {0}; + request->c = s; + int breceived = 0; + while (!rstrendswith(buf, "\r\n\r\n")) { + int chunk_size = read(s, buf + breceived, 1); + if (chunk_size <= 0) { + close(request->c); + request->closed = 1; + return request; + } + breceived += chunk_size; + } + if (breceived <= 0) { + close(request->c); + request->closed = 1; + return request; + } + buf[breceived] = '\0'; + char *original_buf = buf; + + char *b = original_buf; + request->raw = strdup(b); + b = original_buf; + char *line = strtok(b, "\r\n"); + b = original_buf; + char *body = b + strlen(line) + 2; + request->body = strdup(body); + b = original_buf; + char *method = strtok(b, " "); + char *path = strtok(NULL, " "); + char *version = strtok(NULL, " "); + request->bytes_received = breceived; + request->line = line; + request->start = nsecs(); + request->method = strdup(method); + request->path = strdup(path); + request->version = strdup(version); + request->headers = NULL; + request->keep_alive = false; + if (rhttp_parse_headers(request)) { + char *keep_alive_string = rhttp_header_get_string(request, "Connection"); + if (keep_alive_string && !strcmp(keep_alive_string, "keep-alive")) { + request->keep_alive = 1; + } + } + return request; +} + +void rhttp_close_server() { + close(rhttp_sock); + close(rhttp_c); + printf("Connections handled: %d\n", rhttp_connections_handled); + printf("Gracefully closed\n"); + exit(0); +} + +size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { + if (to_send_len == 0 && *(unsigned char *)tsend) { + to_send_len = strlen(tsend); + } + unsigned char *to_send = (unsigned char *)malloc(to_send_len); + unsigned char *to_send_original = to_send; + + memcpy(to_send, tsend, to_send_len); + // to_send[to_send_len] = '\0'; + long bytes_sent = 0; + long bytes_sent_total = 0; + while (1) { + bytes_sent = send(s, to_send + bytes_sent_total, to_send_len - bytes_sent_total, 0); + if (bytes_sent <= 0) { + bytes_sent_total = 0; + break; + } + bytes_sent_total += bytes_sent; + + if (bytes_sent_total == (long)to_send_len) { + break; + } else if (!bytes_sent) { + bytes_sent_total = 0; + // error + break; + } else { + rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); + } + } + + free(to_send_original); + return bytes_sent_total; +} + +typedef int (*rhttp_request_handler_t)(rhttp_request_t *r); + +void rhttp_serve(const char *host, int port, int backlog, int request_logging, int request_debug, rhttp_request_handler_t handler, + void *context) { + signal(SIGPIPE, SIG_IGN); + rhttp_sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(host ? host : "0.0.0.0"); + rhttp_opt_debug = request_debug; + rhttp_opt_request_logging = request_logging; + int opt = 1; + setsockopt(rhttp_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (bind(rhttp_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + printf("Binding error\n"); + exit(1); + } + listen(rhttp_sock, backlog); + while (1) { + struct sockaddr_in client_addr; + int addrlen = sizeof(client_addr); + + rhttp_c = accept(rhttp_sock, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen); + + rhttp_connections_handled++; + while (true) { + rhttp_request_t *r = rhttp_parse_request(rhttp_c); + r->context = context; + if (!r->closed) { + if (!handler(r) && !r->closed) { + rhttp_close(r); + } + } + if (!r->keep_alive && !r->closed) { + rhttp_close(r); + } else if (r->keep_alive && !r->closed) { + } + if (r->closed) { + break; + } + rhttp_free_request(r); + } + } +} + +unsigned int rhttp_calculate_number_char_count(unsigned int number) { + unsigned int width = 1; + unsigned int tcounter = number; + while (tcounter / 10 >= 1) { + tcounter = tcounter / 10; + width++; + } + return width; +} + +int rhttp_file_response(rhttp_request_t *r, char *path) { + if (!*path) + return 0; + FILE *f = fopen(path, "rb"); + if (f == NULL) + return 0; + size_t file_size = rfile_size(path); + char response[1024] = {0}; + char content_type_header[100] = {0}; + char *ext = strstr(path, "."); + char *text_extensions = ".h,.c,.html"; + if (strstr(text_extensions, ext)) { + sprintf(content_type_header, "Content-Type: %s\r\n", "text/html"); + } + sprintf(response, "HTTP/1.1 200 OK\r\n%sContent-Length:%ld\r\n\r\n", content_type_header, file_size); + if (!rhttp_send_drain(r->c, response, 0)) { + rhttp_log_error("Error sending file: %s\n", path); + } + size_t bytes = 0; + size_t bytes_sent = 0; + unsigned char file_buff[1024]; + while ((bytes = fread(file_buff, sizeof(char), sizeof(file_buff), f))) { + if (!rhttp_send_drain(r->c, file_buff, bytes)) { + rhttp_log_error("Error sending file during chunking: %s\n", path); + } + bytes_sent += bytes; + } + if (bytes_sent != file_size) { + rhttp_send_drain(r->c, file_buff, file_size - bytes_sent); + } + close(r->c); + fclose(f); + return 1; +}; + +int rhttp_file_request_handler(rhttp_request_t *r) { + char *path = r->path; + while (*path == '/' || *path == '.') + path++; + if (strstr(path, "..")) { + return 0; + } + return rhttp_file_response(r, path); +}; + +unsigned int counter = 100000000; +int rhttp_counter_request_handler(rhttp_request_t *r) { + if (!strncmp(r->path, "/counter", strlen("/counter"))) { + counter++; + unsigned int width = rhttp_calculate_number_char_count(counter); + char to_send2[1024] = {0}; + sprintf(to_send2, + "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nConnection: " + "close\r\n\r\n%d", + width, counter); + rhttp_send_drain(r->c, to_send2, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_root_request_handler(rhttp_request_t *r) { + if (!strcmp(r->path, "/")) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 200 OK\r\nContent-Length: 3\r\nConnection: " + "close\r\n\r\nOk!"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_error_404_handler(rhttp_request_t *r) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " + "0\r\nConnection: close\r\n\r\n"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; +} + +int rhttp_default_request_handler(rhttp_request_t *r) { + if (rhttp_opt_debug || rhttp_opt_request_logging) + rhttp_print_request(r); + if (rhttp_counter_request_handler(r)) { + // Counter handler + rhttp_log_info("Counter handler found for: %s\n", r->path); + + } else if (rhttp_root_request_handler(r)) { + // Root handler + rhttp_log_info("Root handler found for: %s\n", r->path); + } else if (rhttp_file_request_handler(r)) { + rhttp_log_info("File %s sent\n", r->path); + } else if (rhttp_error_404_handler(r)) { + rhttp_log_warn("Error 404 for: %s\n", r->path); + // Error handler + } else { + rhttp_log_warn("No handler found for: %s\n", r->path); + close(rhttp_c); + } + return 0; +} + +int rhttp_main(int argc, char *argv[]) { + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); + int opt; + while ((opt = getopt(argc, argv, "p:drh:bewi")) != -1) { + switch (opt) { + case 'i': + rhttp_opt_info = 1; + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + break; + case 'e': + rhttp_opt_error = 1; + rhttp_opt_warn = 0; + rhttp_opt_info = 0; + break; + case 'w': + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + rhttp_opt_info = 0; + break; + case 'p': + rhttp_opt_port = atoi(optarg); + break; + case 'b': + rhttp_opt_buffered = 1; + printf("Logging is buffered. Output may be incomplete.\n"); + break; + case 'h': + strcpy(rhttp_opt_host, optarg); + break; + case 'd': + printf("Debug enabled\n"); + rhttp_opt_debug = 1; + rhttp_opt_warn = 1; + rhttp_opt_info = 1; + rhttp_opt_error = 1; + break; + case 'r': + printf("Request logging enabled\n"); + rhttp_opt_request_logging = 1; + break; + default: + printf("Usage: %s [-p port] [-h host] [-b]\n", argv[0]); + return 1; + } + } + + printf("Starting server on: %s:%d\n", rhttp_opt_host, rhttp_opt_port); + if (rhttp_opt_buffered) + setvbuf(stdout, NULL, _IOFBF, BUFSIZ); + + rhttp_serve(rhttp_opt_host, rhttp_opt_port, 1024, rhttp_opt_request_logging, rhttp_opt_debug, rhttp_default_request_handler, NULL); + + return 0; +} + +/* CLIENT CODE */ + +typedef struct rhttp_client_request_t { + char *host; + int port; + char *path; + bool is_done; + char *request; + char *response; + pthread_t thread; + int bytes_received; +} rhttp_client_request_t; + +rhttp_client_request_t *rhttp_create_request(const char *host, int port, const char *path) { + rhttp_client_request_t *r = (rhttp_client_request_t *)malloc(sizeof(rhttp_client_request_t)); + char request_line[4096] = {0}; + sprintf(request_line, + "GET %s HTTP/1.1\r\n" + "Host: localhost:8000\r\n" + "Connection: close\r\n" + "Accept: */*\r\n" + "User-Agent: mhttpc\r\n" + "Accept-Language: en-US,en;q=0.5\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "\r\n", + path); + r->request = strdup(request_line); + r->host = strdup(host); + r->port = port; + r->path = strdup(path); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; + return r; +} + +int rhttp_execute_request(rhttp_client_request_t *r) { + int s = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(r->port); + addr.sin_addr.s_addr = inet_addr(r->host); + + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return 0; + } + + send(s, r->request, strlen(r->request), 0); + char buf[1024 * 1024] = {0}; + int ret = recv(s, buf, 1024 * 1024, 0); + if (ret > 0) { + r->response = strdup(buf); + } + + close(s); + return ret; +} +void rhttp_reset_request(rhttp_client_request_t *r) { + free(r->response); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; +} +void rhttp_free_client_request(rhttp_client_request_t *r) { + if (r->request) + free(r->request); + if (r->response) + free(r->response); + if (r->host) + free(r->host); + if (r->path) + free(r->path); + free(r); +} + +void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { + rhttp_client_request_t *requests[workers]; + while (times > 0) { + + for (int i = 0; i < workers && times; i++) { + requests[i] = rhttp_create_request(host, port, path); + rhttp_execute_request(requests[i]); + times--; + } + } +} +char *rhttp_client_get(const char *host, int port, const char *path) { + if (!rhttp_c_mutex_initialized) { + rhttp_c_mutex_initialized = 1; + pthread_mutex_init(&rhttp_c_mutex, NULL); + } + char http_response[1024 * 1024]; + http_response[0] = 0; + rhttp_client_request_t *r = rhttp_create_request(host, port, path); + unsigned int reconnects = 0; + unsigned int reconnects_max = 100000; + while (!rhttp_execute_request(r)) { + reconnects++; + tick(); + if (reconnects == reconnects_max) { + fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + rhttp_free_client_request(r); + return NULL; + } + } + r->is_done = true; + char *body = r->response ? strstr(r->response, "\r\n\r\n") : NULL; + pthread_mutex_lock(&rhttp_c_mutex); + if (body) { + strcpy(http_response, body + 4); + } else { + strcpy(http_response, r->response); + } + rhttp_free_client_request(r); + char *result = sbuf(http_response); + pthread_mutex_unlock(&rhttp_c_mutex); + return result; +} +/*END CLIENT CODE */ +#endif diff --git a/.backup.1.rhttpc.c b/.backup.1.rhttpc.c new file mode 100644 index 0000000..2590054 --- /dev/null +++ b/.backup.1.rhttpc.c @@ -0,0 +1,11 @@ +#include "rhttp.h" +#include <stdio.h> + +int main() { + while (1) { + char *response = rhttp_client_get("127.0.0.1", 8888, "/"); + if (response) + printf("%s\n", response); + } + return 0; +} diff --git a/.backup.1.ricli.c b/.backup.1.ricli.c new file mode 100644 index 0000000..60b12d4 --- /dev/null +++ b/.backup.1.ricli.c @@ -0,0 +1,336 @@ +#include "rterm.h" +#include <stdlib.h> +#include <stdbool.h> +#include "rstring.h" +#include "rrex4.h" +#include <limits.h> +#include "rautocomplete.h" + +typedef struct ricli_line_t { + unsigned int index; + char type[20]; + size_t length; + char *content; +} ricli_line_t; + +ricli_line_t *ricli_line_new() { + ricli_line_t *line = (ricli_line_t *)malloc(sizeof(ricli_line_t)); + line->index = 0; + memset(line->type, 0, sizeof(line->type)); + line->length = 0; + line->content = NULL; + return line; +} + +char *rscli_line_to_json(ricli_line_t *line) { + + char *json = (char *)malloc(sizeof(line->type) + strlen(line->content) * 2 + 10); + json[0] = 0; + strcpy(json, "{\"type\":\""); + strcat(json, line->type); + strcat(json, "\",\"content\":\""); + char content_safe[strlen(line->content) * 2]; + content_safe[0] = 0; + rstraddslashes(line->content, content_safe); + strcat(json, content_safe); + strcat(json, "\"}"); + return json; +} +typedef struct ricli_t { + ricli_line_t **lines; + int line_count; + bool line_numbers; + char input[1024 * 5]; + unsigned int history_index; + unsigned int x; + bool auto_save; + rautocomplete_t *autocomplete; + char history_file[FILENAME_MAX]; + bool reset; + void (*before_add_line)(struct ricli_t *r); + void (*after_add_line)(struct ricli_t *r); + void (*keypress)(struct ricli_t *); + void (*before_draw)(struct ricli_t *); + rterm_t *term; +} ricli_t; + +void ricli_keypress(rterm_t *rt); +void ricli_before_draw(rterm_t *rt); +void ricli_save(ricli_t *cli, char *path); +void ricli_autocomplete_execute(ricli_t *cli); +void ricli_add_autocomplete(ricli_t *cli, char *str) { + if (rautocomplete_contains(cli->autocomplete, str)) + return; + rautocomplete_add(cli->autocomplete, str); +} + +ricli_line_t *ricli_get_last_line(ricli_t *r) { + if (!r->line_count) { + return NULL; + } + return r->lines[r->line_count - 1]; +} + +void ricli_after_draw(rterm_t *rt) { + ricli_t *r = (ricli_t *)rt->session; + ricli_autocomplete_execute(r); +} + +ricli_t *ricli_terminal_new() { + ricli_t *terminal = (ricli_t *)malloc(sizeof(ricli_t)); + terminal->lines = NULL; + terminal->line_count = 0; + terminal->line_numbers = false; + terminal->reset = true; + terminal->history_index = 0; + terminal->before_add_line = NULL; + terminal->term = NULL; + terminal->history_file[0] = 0; + terminal->autocomplete = rautocomplete_new(); + terminal->auto_save = true; + terminal->x = 0; + memset(terminal->input, 0, sizeof(terminal->input)); + terminal->term = (rterm_t *)malloc(sizeof(rterm_t)); + + rterm_init(terminal->term); + terminal->line_numbers = true; + + terminal->term->after_key_press = ricli_keypress; + terminal->term->before_draw = ricli_before_draw; + terminal->term->after_draw = ricli_after_draw; + terminal->term->session = (void *)terminal; + return terminal; +} +void ricli_set_input(ricli_t *cli, const char *content); +void ricli_autocomplete_execute(ricli_t *r) { + char *result = rautocomplete_find(r->autocomplete, r->input); + unsigned int original_x = r->term->cursor.x; + unsigned int original_y = r->term->cursor.y; + if (result && result[0] != 1) { + original_x = r->x; + cursor_set(r->term, 0, r->term->size.ws_row - 1); + printf("(%d)%s", result[0], result); + cursor_set(r->term, original_x, original_y); + } +} +void ricli_add_line(ricli_t *r, char *type, char *content) { + + ricli_line_t *line = ricli_line_new(); + strcpy(line->type, type ? type : ""); + line->content = (char *)malloc(strlen(content ? content : "") + 1); + strcpy(line->content, content ? content : ""); + line->length = strlen(line->content); + if (line->length && line->content[line->length - 1] == '\n') { + line->content[line->length - 1] = 0; + line->length--; + } + if (line->length) + ricli_add_autocomplete(r, line->content); + strcpy(line->type, type ? type : ""); + line->index = r->line_count; + r->lines = realloc(r->lines, sizeof(ricli_line_t *) * (r->line_count + 1)); + r->lines[r->line_count] = line; + r->line_count++; + r->history_index = r->line_count; + r->x = 0; + + if (r->history_file[0] && r->auto_save) + ricli_save(r, r->history_file); +} + +ricli_t *rt_get_ricli(rterm_t *rt) { return (ricli_t *)rt->session; } + +void ricli_reset(rterm_t *rt) { + ricli_t *cli = rt_get_ricli(rt); + cli->reset = false; + cursor_set(rt, 0, rt->size.ws_row - 1); +} + +void ricli_before_draw(rterm_t *rt) { + ricli_t *cli = rt_get_ricli(rt); + int offset = 0; + if (cli->line_count > rt->size.ws_row - 1) { + offset = cli->line_count - rt->size.ws_row; + } + for (int i = offset; i < cli->line_count; i++) { + printf("%.5d %s\n", i + 1, cli->lines[i]->content); + } + rt->status_text = cli->input; + if (cli->reset) { + ricli_reset(rt); + } +} + +void ricli_clear_input(ricli_t *cli) { + char line[cli->term->size.ws_col + 1]; + memset(line, ' ', sizeof(line)); + line[sizeof(line) - 1] = 0; + cursor_set(cli->term, 0, cli->term->cursor.y); +} +void ricli_set_input(ricli_t *cli, const char *content) { + if (cli->input != content) { + memset(cli->input, 0, sizeof(cli->input)); + strcpy(cli->input, content); + } + strcpy(cli->term->status_text, cli->input); + ricli_clear_input(cli); + rterm_print_status_bar(cli->term, 'c', cli->input); + cursor_set(cli->term, cli->x, cli->term->size.ws_row); +} +void ricli_put_input(ricli_t *cli, char c) { + bool was_zero = cli->input[cli->x] == 0; + if (was_zero) { + + cli->input[cli->x] = c; + cli->input[cli->x + 1] = 0; + } else { + char line_first[strlen(cli->input) + 5]; + + memset(line_first, 0, sizeof(line_first)); + line_first[0] = 0; + strncpy(line_first, cli->input, cli->x); + + char line_end[strlen(cli->input) + 2]; + memset(line_end, 0, sizeof(line_end)); + + char *input_ptr = cli->input; + strcpy(line_end, input_ptr + cli->x); + char new_char[] = {c, 0}; + strcat(line_first, new_char); + strcat(line_first, line_end); + memset(cli->input, 0, sizeof(cli->input)); + strcpy(cli->input, line_first); + } + cli->history_index = cli->line_count; + rterm_print_status_bar(cli->term, 'c', cli->input); + + if (cli->x >= strlen(cli->input)) + cli->x = strlen(cli->input) - 1; + cli->x++; + cursor_set(cli->term, cli->x, cli->term->cursor.y); +} + +void ricli_load(ricli_t *cli, char *path) { + strcpy(cli->history_file, path); + size_t size = rfile_size(path); + if (size == 0) { + + return; + } + char *data = malloc(size + 1); + memset(data, 0, size + 1); + rfile_readb(path, data, size); + r4_t *r = r4(data, "\"type\":\"(.*)\",\"content\":\"(.*)\""); + while (r->match_count == 2) { + char stripped_slashes[strlen(r->matches[1]) + 1]; + memset(stripped_slashes, 0, sizeof(stripped_slashes)); + rstrstripslashes(r->matches[1], stripped_slashes); + ricli_add_line(cli, r->matches[0], stripped_slashes); + r4_next(r, NULL); + } + r4_free(r); + free(data); +} +void ricli_save(ricli_t *cli, char *path) { + FILE *f = fopen(path, "w+"); + for (int i = 0; i < cli->line_count; i++) { + if (!cli->lines[i]->length) + continue; + char *json_line = rscli_line_to_json(cli->lines[i]); + if (i != cli->line_count - 1) { + strcat(json_line, ","); + } + fwrite(json_line, 1, strlen(json_line), f); + free(json_line); + } + fclose(f); +} + +ricli_delete_input(ricli_t *cli, unsigned int index) { + if (cli->input[index + 1] == 0) { + cli->input[index] = 0; + } else { + char new_line[strlen(cli->input) + 5]; + memset(new_line, 0, sizeof(new_line)); + strncpy(new_line, cli->input, index); + char *input_ptr = cli->input; + strcat(new_line, input_ptr + index + 1); + strcpy(cli->input, new_line); + } + cursor_set(cli->term, cli->x, cli->term->cursor.y); +} + +void ricli_keypress(rterm_t *rt) { + ricli_t *cli = rt_get_ricli(rt); + if (rt->key.c == 10) { + if (cli->input[rt->cursor.x] == 0) { + cli->input[rt->cursor.x] = '\n'; + cli->input[rt->cursor.x + 1] = 0; + } + if (cli->before_add_line) { + cli->before_add_line(cli); + } + ricli_add_line(cli, "user", cli->input); + cursor_set(rt, 0, rt->cursor.y); + memset(cli->input, 0, sizeof(cli->input)); + cli->history_index = cli->line_count; + if (cli->after_add_line) { + cli->after_add_line(cli); + } + } else if (rt->key.escape && rt->key.c == 'A') { + if (cli->history_index != 0) + cli->history_index--; + + strcpy(cli->input, cli->lines[cli->history_index]->content); + cli->x = strlen(cli->input); + ricli_set_input(cli, cli->lines[cli->history_index]->content); + + } else if (rt->key.c == 127) { + + if (cli->x > 0) { + cli->x--; + cli->input[cli->x] = 0; + ricli_delete_input(cli, cli->x); + } + } else if (rt->key.escape && rt->key.c == 'B') { + if (cli->history_index < cli->line_count - 1) { + cli->history_index++; + + strcpy(cli->input, cli->lines[cli->history_index]->content); + cli->x = strlen(cli->input); + ricli_set_input(cli, cli->lines[cli->history_index]->content); + + } else { + cli->x = 0; + ricli_set_input(cli, ""); + cli->history_index = cli->line_count; + } + + } else if (rt->key.escape && rt->key.c == 'D') { + cli->x = rt->cursor.x; + cursor_set(rt, cli->x, rt->cursor.y); + } else if (rt->key.escape && rt->key.c == 'C') { + cli->x = rt->cursor.x; + if (cli->x > strlen(cli->input)) + cli->x = strlen(cli->input); + cursor_set(rt, cli->x, rt->cursor.y); + } else if (!rt->key.escape) { + if (rt->cursor.x > strlen(cli->input)) { + rt->cursor.x = strlen(cli->input); + cli->x = strlen(cli->input); + } + ricli_put_input(cli, rt->key.c); + ricli_autocomplete_execute(cli); + } + // rterm_print_status_bar(rt, 0, 0); +} + +void ricli_loop(ricli_t *r) { rterm_loop(r->term); } + +int main() { + + ricli_t *cli = ricli_terminal_new(); + ricli_load(cli, "/tmp/.ricli.json"); + ricli_loop(cli); + return 0; +} \ No newline at end of file diff --git a/.backup.1.rinterp.c b/.backup.1.rinterp.c new file mode 100644 index 0000000..050e022 --- /dev/null +++ b/.backup.1.rinterp.c @@ -0,0 +1,40 @@ +#include "rlexer.c"; + +typedef enum rip_ast_type_t { RIP_NONE = 0, RIP_BLOCK, RIP_CALL, RIP_LITERAL } rip_ast_type_t; + +typedef struct rip_ast_t { + struct rip_ast_t *children; + struct rip_ast_t *next; + struct rip_ast_t *previous; + rip_ast_type_t type; +} rip_ast_t; + +rip_ast_t *rip_ast_new() { + rip_ast_t *ast = (rip_ast_t *)malloc(sizeof(rip_ast_t)); + ast->children = NULL; + ast->next = NULL; + ast->previous = NULL; + ast->type = RIP_NONE; + return ast; +} + +rip_ast_t *rip_parse() { + rtoken_t token = rlex_next(); + if (token.type == RT_CURLY_BRACE_OPEN) { + rip_ast_t *ast = rip_ast_new(); + while () + rip_ast_t *statement = rip_parse(); + } +} + +int main() { + + char *script = "{print(\"test\")}"; + rlex(script); + while (true) { + rtoken_t token = rlex_next(); + if (token.type = RT_CURLY_BRACE_OPEN) { + rclos + } + } +} \ No newline at end of file diff --git a/.backup.1.rio.c b/.backup.1.rio.c new file mode 100644 index 0000000..1e8c61a --- /dev/null +++ b/.backup.1.rio.c @@ -0,0 +1,9 @@ +#include "rio.h" + +void cb(char *str) { printf("%s\n", str); } + +int main() { + rforfile("/tmp", cb); + + return 0; +} \ No newline at end of file diff --git a/.backup.1.rio.h b/.backup.1.rio.h new file mode 100644 index 0000000..bb15576 --- /dev/null +++ b/.backup.1.rio.h @@ -0,0 +1,117 @@ +#ifndef RLIB_RIO +#define RLIB_RIO +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <dirent.h> +#include <sys/dir.h> +#include <sys/stat.h> +#include <unistd.h> +#include "rstring_list.h" + +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; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * ms; + + int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); + return ret > 0 && FD_ISSET(fd, &read_fds); +} + +bool rfd_wait_forever(int fd) { + while ((!rfd_wait(fd, 10))) { + } + return true; +} + +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, "r"); + if (!fd) { + return 0; + } + size_t bytes_read = fread(data, sizeof(char), size, fd); + + fclose(fd); + ((char *)data)[bytes_read] = 0; + return bytes_read; +} + +#endif \ No newline at end of file diff --git a/.backup.1.rjson.c b/.backup.1.rjson.c new file mode 100644 index 0000000..d2e03fe --- /dev/null +++ b/.backup.1.rjson.c @@ -0,0 +1,19 @@ +#include "rjson.h" + +int main() { + rtest_banner("rjson"); + rjson_t *json = rjson(); + rjson_array_start(json); + rjson_object_start(json); + rjson_kv_string(json, "string", "value"); + rjson_kv_number(json, "number", 1337421984); + rjson_kv_duration(json, "duration", 1337421984); + rjson_kv_int(json, "ulonglong", 1337420); + rjson_kv_bool(json, "bool", true); + rjson_object_close(json); + rjson_array_close(json); + rassert(!strcmp(json->content, "[{\"string\":\"value\",\"number\":\"1.337.421.984\",\"duration\":\"1." + "34s\",\"ulonglong\":1337420,\"bool\":true}]")); + rjson_free(json); + return rtest_end(""); +} \ No newline at end of file diff --git a/.backup.1.rjson.h b/.backup.1.rjson.h new file mode 100644 index 0000000..b8e23c6 --- /dev/null +++ b/.backup.1.rjson.h @@ -0,0 +1,130 @@ +#ifndef RJSON_H +#define RJSON_H +#include "rmalloc.h" +#include "rtypes.h" +#include "rstring.h" +#include "rtemp.h" +#include "rtime.h" +#include "rtest.h" + +typedef struct rjson_t { + char *content; + size_t length; + size_t size; +} rjson_t; + +rjson_t *rjson() { + rjson_t *json = rmalloc(sizeof(rjson_t)); + json->size = 1024; + json->length = 0; + json->content = (char *)rmalloc(json->size); + json->content[0] = 0; + return json; +} + +void rjson_write(rjson_t *rjs, char *content) { + size_t len = strlen(content); + while (rjs->size < rjs->length + len + 1) { + rjs->content = realloc(rjs->content, rjs->size + 1024); + rjs->size += 1024; + } + strcat(rjs->content, content); + rjs->length += len; +} + +void rjson_object_start(rjson_t *rjs) { + if (rstrendswith(rjs->content, "}")) + rjson_write(rjs, ","); + rjson_write(rjs, "{"); +} +void rjson_object_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "}"); +} +void rjson_array_start(rjson_t *rjs) { + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + rjson_write(rjs, ","); + rjson_write(rjs, "["); +} +void rjson_array_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "]"); +} + +void rjson_kv_string(rjson_t *rjs, char *key, char *value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":\""); + char *value_str = (char *)rmalloc(strlen(value) + 4096); + rstraddslashes(value, value_str); + rjson_write(rjs, value_str); + free(value_str); + rjson_write(rjs, "\""); +} + +void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + char value_str[100] = {0}; + sprintf(value_str, "%lld", value); + rjson_write(rjs, value_str); +} +void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(rformat_number(value))); + rjson_write(rjs, "\""); +} + +void rjson_kv_bool(rjson_t *rjs, char *key, int value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, value > 0 ? "true" : "false"); +} + +void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(format_time(value))); + rjson_write(rjs, "\""); +} +void rjson_free(rjson_t *rsj) { + free(rsj->content); + free(rsj); +} + +void rjson_key(rjson_t *rsj, char *key) { + rjson_write(rsj, "\""); + rjson_write(rsj, key); + rjson_write(rsj, "\":"); +} +#endif \ No newline at end of file diff --git a/.backup.1.rkeytable.c b/.backup.1.rkeytable.c new file mode 100644 index 0000000..177e526 --- /dev/null +++ b/.backup.1.rkeytable.c @@ -0,0 +1,12 @@ +#include "rkeytable.h" +#include "rtest.h" +#include "rstring.h" + +int main() { + + for (int i = 0; i < 1000; i++) { + char *key = rgenerate_key(); + rkset(key, "tast"); + rasserts(!strcmp(rkget(key), "tast")); + } +} \ No newline at end of file diff --git a/.backup.1.rkeytable.h b/.backup.1.rkeytable.h new file mode 100644 index 0000000..8527a58 --- /dev/null +++ b/.backup.1.rkeytable.h @@ -0,0 +1,68 @@ +#ifndef RKEYTABLE_H +#define RKEYTABLE_H +/* + DERIVED FROM HASH TABLE K&R + */ +#include "rmalloc.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +typedef struct rnklist { + struct rnklist *next; + struct rnklist *last; + char *name; + char *defn; +} rnklist; + +static rnklist *rkeytab = NULL; + +rnklist *rlkget(char *s) { + rnklist *np; + for (np = rkeytab; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +char *rkget(char *s) { + rnklist *np = rlkget(s); + return np ? np->defn : NULL; +} + +rnklist *rkset(char *name, char *defn) { + rnklist *np; + if ((np = (rlkget(name))) == NULL) { // Not found + np = (rnklist *)malloc(sizeof(rnklist)); + np->name = strdup(name); + np->next = NULL; + np->last = NULL; + + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + + if (rkeytab == NULL) { + rkeytab = np; + rkeytab->last = np; + } else { + if (rkeytab->last) + rkeytab->last->next = np; + + rkeytab->last = np; + } + } else { + if (np->defn) + free((void *)np->defn); + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + } + return np; +} +#endif diff --git a/.backup.1.rlexer.c b/.backup.1.rlexer.c new file mode 100644 index 0000000..17c7756 --- /dev/null +++ b/.backup.1.rlexer.c @@ -0,0 +1,189 @@ +#include "rlexer.h" +#include "rio.h" +#include "rtest.h" + +void test_lexer() { + rtest_banner("Lexer"); + + rlex("123" + "-123 " + "123.22.123.33" + "-123.33" + "abc " + "_abc " + "abc_ " + "a_a" + "\"string content 123\"" + "\"!@#$%^& *()-+\"" + "\"ab\\tc\\n\\\"\\r\"" + "--++-+/*<>!@#$%^&*(){}?[]" + "\n" + "()"); + rtest_banner("Number"); + rtoken_t token = rlex_next(); + rtest_assert(token.type == RT_NUMBER); + rtest_assert(!strcmp(token.value, "123")); + rtest_banner("Negative number"); + token = rlex_next(); + rtest_assert(token.type == RT_NUMBER); + rtest_assert(!strcmp(token.value, "-123")); + rtest_banner("Decimal Number"); + token = rlex_next(); + rtest_assert(token.type == RT_NUMBER); + rtest_assert(!strcmp(token.value, "123.22")); + token = rlex_next(); + rtest_assert(token.type == RT_PUNCT); + rtest_assert(!strcmp(token.value, ".")); + token = rlex_next(); + rtest_assert(token.type == RT_NUMBER); + rtest_assert(!strcmp(token.value, "123.33")); + rtest_banner("Decimal Negative number"); + token = rlex_next(); + rtest_assert(token.type == RT_NUMBER); + rtest_assert(!strcmp(token.value, "-123.33")); + rtest_banner("Symbol"); + token = rlex_next(); + rtest_assert(token.type == RT_SYMBOL); + rtest_assert(!strcmp(token.value, "abc")); + token = rlex_next(); + rtest_assert(token.type == RT_SYMBOL); + rtest_assert(!strcmp(token.value, "_abc")); + token = rlex_next(); + + rtest_assert(token.type == RT_SYMBOL); + rtest_assert(!strcmp(token.value, "abc_")); + + token = rlex_next(); + + rtest_assert(token.type == RT_SYMBOL); + rtest_assert(!strcmp(token.value, "a_a")); + rtest_banner("String"); + token = rlex_next(); + rtest_assert(token.type == RT_STRING); + rtest_assert(!strcmp(token.value, "string content 123")); + token = rlex_next(); + rtest_assert(token.type == RT_STRING); + rtest_assert(!strcmp(token.value, "!@#$\%^& *()-+")); + token = rlex_next(); + rtest_assert(token.type == RT_STRING); + rtest_assert(!strcmp(token.value, "ab\tc\n\"\r")); + + rtest_banner("Operator"); + token = rlex_next(); + + rtest_assert(token.type == RT_OPERATOR); + rtest_assert(!strcmp(token.value, "--++-+/*<>")); + + rtest_banner("Punct") token = rlex_next(); + rtest_assert(token.type == RT_PUNCT); + rtest_assert(!strcmp(token.value, "!@#$%^")); + token = rlex_next(); + rtest_assert(token.type == RT_OPERATOR); + rtest_assert(!strcmp(token.value, "&*")); + + rtest_banner("Grouping"); + token = rlex_next(); + rtest_assert(token.type == RT_BRACE_OPEN); + rassert(!strcmp(token.value, "(")); + + token = rlex_next(); + rtest_assert(token.type == RT_BRACE_CLOSE); + rassert(!strcmp(token.value, ")")); + + token = rlex_next(); + rtest_assert(token.type == RT_CURLY_BRACE_OPEN); + rassert(!strcmp(token.value, "{")); + + token = rlex_next(); + rtest_assert(token.type == RT_CURLY_BRACE_CLOSE); + rassert(!strcmp(token.value, "}")); + + token = rlex_next(); + rtest_assert(token.type == RT_PUNCT); + rassert(!strcmp(token.value, "?")); + + token = rlex_next(); + rtest_assert(token.type == RT_BRACKET_OPEN); + rassert(!strcmp(token.value, "[")); + + token = rlex_next(); + rtest_assert(token.type == RT_BRACKET_CLOSE); + rassert(!strcmp(token.value, "]")); + + rtest_banner("Line number"); + token = rlex_next(); + rtest_assert(token.type == RT_BRACE_OPEN); + rassert(!strcmp(token.value, "(")); + rassert(token.line == 2); + token = rlex_next(); + rtest_assert(token.type == RT_BRACE_CLOSE); + rassert(!strcmp(token.value, ")")); + rassert(token.line == 2); + + rtest_banner("EOF"); + token = rlex_next(); + rtest_assert(token.type == RT_EOF); + rtest_assert(!strcmp(token.value, "eof")); + rtest_assert(token.line == 2); +} + +void test_formatter() { + rtest_banner("Formatter"); + char *formatted = rlex_format("{123{345{678}}}"); + char *expected_curly_braces = "{\n" + " 123\n" + " {\n" + " 345\n" + " {\n" + " 678\n" + " }\n \n" + " }\n \n" + "}\n"; + rtest_assert(!strcmp(formatted, expected_curly_braces)); + free(formatted); + formatted = rlex_format("\"123\",66,true,(1,2,3)"); + char *expected_comma = "\"123\", 66, true, (1, 2, 3)"; + + rtest_assert(!strcmp(formatted, expected_comma)); + free(formatted); + + formatted = rlex_format("lala lolo"); + char *expected_new_lines1 = "lala\nlolo"; + rtest_assert(!strcmp(formatted, expected_new_lines1)); + free(formatted); + + formatted = rlex_format("lala=lolo"); + char *expected_new_lines2 = "lala = lolo"; + rtest_assert(!strcmp(formatted, expected_new_lines2)); + free(formatted); + + formatted = rlex_format("lala+lolo=(1,2,3)"); + char *expected_new_lines3 = "lala + lolo = (1, 2, 3)"; + rtest_assert(!strcmp(formatted, expected_new_lines3)); + free(formatted); + + formatted = rlex_format("lala+lolo=(1,2,3) little.test=(4,5,6)"); + char *expected_new_lines4 = "lala + lolo = (1, 2, 3)\nlittle.test = (4, 5, 6)"; + rtest_assert(!strcmp(formatted, expected_new_lines4)); + free(formatted); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + test_formatter(); + test_lexer(); + return rtest_end(""); + } else { + if (!rfile_exists(argv[1])) { + rassert(false && "File does not exist."); + } + unsigned int length = rfile_size(argv[1]); + char content[length + 1]; + + length = rfile_readb(argv[1], content, length); + + content[length] = 0; + char *formatted = rlex_format(content); + printf("%s", formatted); + } +} \ No newline at end of file diff --git a/.backup.1.rlexer.h b/.backup.1.rlexer.h new file mode 100644 index 0000000..575e7bf --- /dev/null +++ b/.backup.1.rlexer.h @@ -0,0 +1,370 @@ +#ifndef RLEXER_H +#define RLEXER_H +#include "rmalloc.h" +#include "rstring.h" +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#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 == '\''); +} + +static int isoperator(char c) { + return (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '>' || c == '<' || c == '|' || c == '&'); +} + +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++; + } + token.type = RT_NUMBER; + return token; +} + +static rtoken_t rlex_symbol() { + rtoken_t token = rtoken_new(); + + 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; +} + +static rtoken_t rlex_operator() { + + 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; + } + } + 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; +} + +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 (_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; +} + +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++; + } + _content_ptr++; + token.type = RT_STRING; + return token; +} + +void rlex(char *content) { + _content = content; + _content_ptr = 0; + _content_col = 1; + _content_line = 1; +} + +static void rlex_repeat_str(char *dest, char *src, unsigned int times) { + for (size_t i = 0; i < times; i++) { + strcat(dest, src); + } +} + +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; +} + +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(); + } + } +} + +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; + } + + if (token.type == RT_STRING) { + strcat(result, "\""); + + char string_with_slashes[strlen(token.value) * 2 + 1]; + rstraddslashes(token.value, string_with_slashes); + strcat(result, string_with_slashes); + + strcat(result, "\""); + // col+= strlen(token.value) + 2; + // printf("\n"); + // printf("<<<%s>>>\n",token.value); + + 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); + + tab_index++; + + strcat(result, "\n"); + + col = 0; + + 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"); + + rlex_repeat_str(result, tab_chars, tab_index); + tab_indexed++; + + strcat(result, token.value); + strcat(result, "\n"); + col = 0; + + 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); + } + } + } + + 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, "\""); + } + + if (token.type == RT_OPERATOR) { + strcat(result, " "); + } + if (!strcmp(token.value, ",")) { + strcat(result, " "); + } + col += strlen(token.value); + memcpy(&token_previous, &token, sizeof(token)); + } + return result; +} +#endif diff --git a/.backup.1.rlib.c b/.backup.1.rlib.c new file mode 100644 index 0000000..25542ed --- /dev/null +++ b/.backup.1.rlib.c @@ -0,0 +1,3 @@ +#include "rlib.h" + +int main(int argc, char **argv) { return rlib_main(argc, argv); } \ No newline at end of file diff --git a/.backup.1.rlib.h b/.backup.1.rlib.h new file mode 100644 index 0000000..0c50255 --- /dev/null +++ b/.backup.1.rlib.h @@ -0,0 +1,8451 @@ +// RETOOR - Mar 16 2025 +// 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 + +/* + * Line below will be filtered by rmerge +<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after +tag" /> +*/ + +#ifndef RTYPES_H +#define RTYPES_H +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include <stdbool.h> +#include <stdint.h> // uint +#include <string.h> +#include <sys/types.h> // ulong +#ifndef ulonglong +#define ulonglong unsigned long long +#endif +#ifndef uint +typedef unsigned int uint; +#endif +#ifndef byte +typedef unsigned char byte; +#endif +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +#endif + +#ifndef NSOCK_H +#define NSOCK_H +#include <unistd.h> +#ifndef RMALLOC_H +#define RMALLOC_H +#ifndef RMALLOC_OVERRIDE +#define RMALLOC_OVERRIDE 1 +#endif +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#ifndef ulonglong +#define ulonglong unsigned long long +#endif +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef RTEMP_H +#define RTEMP_H +#include <pthread.h> +#ifndef RTEMPC_SLOT_COUNT +#define RTEMPC_SLOT_COUNT 20 +#endif +#ifndef RTEMPC_SLOT_SIZE +#define RTEMPC_SLOT_SIZE 1024 * 64 * 128 +#endif + +bool _rtempc_initialized = 0; +pthread_mutex_t _rtempc_thread_lock; +bool rtempc_use_mutex = true; +byte _current_rtempc_slot = 1; +char _rtempc_buffer[RTEMPC_SLOT_COUNT][RTEMPC_SLOT_SIZE]; +char *rtempc(char *data) { + + if (rtempc_use_mutex) { + if (!_rtempc_initialized) { + _rtempc_initialized = true; + pthread_mutex_init(&_rtempc_thread_lock, NULL); + } + + pthread_mutex_lock(&_rtempc_thread_lock); + } + + uint current_rtempc_slot = _current_rtempc_slot; + _rtempc_buffer[current_rtempc_slot][0] = 0; + strcpy(_rtempc_buffer[current_rtempc_slot], data); + _current_rtempc_slot++; + if (_current_rtempc_slot == RTEMPC_SLOT_COUNT) { + _current_rtempc_slot = 0; + } + if (rtempc_use_mutex) + pthread_mutex_unlock(&_rtempc_thread_lock); + return _rtempc_buffer[current_rtempc_slot]; +} + +#define sstring(_pname, _psize) \ + static char _##_pname[_psize]; \ + _##_pname[0] = 0; \ + char *_pname = _##_pname; + +#define string(_pname, _psize) \ + char _##_pname[_psize]; \ + _##_pname[0] = 0; \ + char *_pname = _##_pname; + +#define sreset(_pname, _psize) _pname = _##_pname; + +#define sbuf(val) rtempc(val) +#endif +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +ulonglong rmalloc_count = 0; +ulonglong rmalloc_alloc_count = 0; +ulonglong rmalloc_free_count = 0; +ulonglong rmalloc_total_bytes_allocated = 0; + +void *_rmalloc_prev_realloc_obj = NULL; +size_t _rmalloc_prev_realloc_obj_size = 0; + +void *rmalloc(size_t size) { + void *result; + while (!(result = malloc(size))) { + fprintf(stderr, "Warning: malloc failed, trying again.\n"); + } + rmalloc_count++; + rmalloc_alloc_count++; + rmalloc_total_bytes_allocated += size; + return result; +} +void *rcalloc(size_t count, size_t size) { + void *result; + while (!(result = calloc(count, size))) { + fprintf(stderr, "Warning: calloc failed, trying again.\n"); + } + rmalloc_alloc_count++; + rmalloc_count++; + rmalloc_total_bytes_allocated += count * size; + return result; +} +void *rrealloc(void *obj, size_t size) { + if (!obj) { + rmalloc_count++; + } + + rmalloc_alloc_count++; + if (obj == _rmalloc_prev_realloc_obj) { + rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; + _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; + + } else { + _rmalloc_prev_realloc_obj_size = size; + } + void *result; + while (!(result = realloc(obj, size))) { + fprintf(stderr, "Warning: realloc failed, trying again.\n"); + } + _rmalloc_prev_realloc_obj = result; + + return result; +} + +char *rstrdup(const char *s) { + if (!s) + return NULL; + + char *result; + size_t size = strlen(s) + 1; + + result = rmalloc(size); + memcpy(result, s, size); + rmalloc_total_bytes_allocated += size; + return result; +} +void *rfree(void *obj) { + rmalloc_count--; + rmalloc_free_count++; + free(obj); + return NULL; +} + +#if RMALLOC_OVERRIDE +#define malloc rmalloc +#define calloc rcalloc +#define realloc rrealloc +#define free rfree +#define strdup rstrdup +#endif + +char *rmalloc_lld_format(ulonglong num) { + + char res[100]; + res[0] = 0; + sprintf(res, "%'lld", num); + char *resp = res; + while (*resp) { + if (*resp == ',') + *resp = '.'; + resp++; + } + return sbuf(res); +} + +char *rmalloc_bytes_format(int factor, ulonglong num) { + char *sizes[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; + if (num > 1024) { + return rmalloc_bytes_format(factor + 1, num / 1024); + } + char res[100]; + sprintf(res, "%s %s", rmalloc_lld_format(num), sizes[factor]); + return sbuf(res); +} + +char *rmalloc_stats() { + static char res[200]; + res[0] = 0; + // int original_locale = localeconv(); + setlocale(LC_NUMERIC, "en_US.UTF-8"); + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), + + rmalloc_lld_format(rmalloc_count)); + // setlocale(LC_NUMERIC, original_locale); + + setlocale(LC_NUMERIC, ""); + return res; +} + +#endif + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <unistd.h> +#ifndef RLIB_RIO +#define RLIB_RIO +#include <dirent.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/dir.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <unistd.h> +#ifndef RSTRING_LIST_H +#define RSTRING_LIST_H +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +typedef struct rstring_list_t { + unsigned int size; + unsigned int count; + char **strings; +} rstring_list_t; + +rstring_list_t *rstring_list_new() { + rstring_list_t *rsl = (rstring_list_t *)malloc(sizeof(rstring_list_t)); + memset(rsl, 0, sizeof(rstring_list_t)); + return rsl; +} + +void rstring_list_free(rstring_list_t *rsl) { + for (unsigned int i = 0; i < rsl->size; i++) { + free(rsl->strings[i]); + } + if (rsl->strings) + free(rsl->strings); + free(rsl); + rsl = NULL; +} + +void rstring_list_add(rstring_list_t *rsl, char *str) { + if (rsl->count == rsl->size) { + rsl->size++; + + rsl->strings = (char **)realloc(rsl->strings, sizeof(char *) * rsl->size); + } + rsl->strings[rsl->count] = strdup(str); + rsl->count++; +} +bool rstring_list_contains(rstring_list_t *rsl, char *str) { + for (unsigned int i = 0; i < rsl->count; i++) { + if (!strcmp(rsl->strings[i], str)) + return true; + } + return false; +} + +#endif + +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; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * ms; + + int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); + return ret > 0 && FD_ISSET(fd, &read_fds); +} + +bool rfd_wait_forever(int fd) { + while ((!rfd_wait(fd, 10))) { + } + return true; +} + +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, "r"); + if (!fd) { + return 0; + } + size_t bytes_read = fread(data, sizeof(char), size, fd); + + fclose(fd); + ((char *)data)[bytes_read] = 0; + return bytes_read; +} + +#endif + +int *nsock_socks = NULL; +int *nsock_readable = NULL; +void **nsock_data = NULL; +int nsock_server_fd = 0; +int nsock_max_socket_fd = 0; + +typedef enum nsock_type_t { NSOCK_NONE = 0, NSOCK_SERVER, NSOCK_CLIENT, NSOCK_UPSTREAM } nsock_type_t; + +typedef struct nsock_it { + int fd; + int *upstreams; + bool connected; + bool downstream; + unsigned int upstream_count; + nsock_type_t type; +} nsock_t; + +nsock_t **nsocks = NULL; +int nsocks_count = 0; + +void (*nsock_on_connect)(int fd) = NULL; +void (*nsock_on_data)(int fd) = NULL; +void (*nsock_on_close)(int fd) = NULL; +void nsock_on_before_data(int fd); + +nsock_t *nsock_get(int fd) { + if (nsock_socks[fd] == 0) { + return NULL; + } + if (fd >= nsocks_count || nsocks[fd] == NULL) { + if (fd >= nsocks_count) { + nsocks_count = fd + 1; + nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); + nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + } + nsocks[fd]->upstreams = NULL; + nsocks[fd]->fd = fd; + nsocks[fd]->connected = false; + nsocks[fd]->downstream = false; + nsocks[fd]->upstream_count = 0; + nsocks[fd]->type = NSOCK_CLIENT; + return nsocks[fd]; + } + return nsocks[fd]; +} + +void nsock_close(int fd) { + if (nsock_on_close) + nsock_on_close(fd); + nsock_t *sock = nsock_get(fd); + if (sock && sock->connected) { + sock->connected = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + nsock_t *upstream = nsock_get(sock->upstreams[i]); + if (upstream->connected) + nsock_close(sock->upstreams[i]); + sock->upstreams[i] = 0; + } + if (sock->upstream_count) { + free(sock->upstreams); + } + sock->upstream_count = 0; + } + nsock_socks[fd] = 0; + close(fd); +} + +nsock_t *nsock_create(int fd, nsock_type_t type) { + if (fd <= 0) + return NULL; + nsock_socks[fd] = fd; + nsock_t *sock = nsock_get(fd); + sock->connected = true; + sock->downstream = false; + sock->type = type; + return sock; +} + +int *nsock_init(int socket_count) { + if (nsock_socks) { + return nsock_socks; + } + nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + if (nsock_data) { + free(nsock_data); + nsock_data = NULL; + } + nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_socks[socket_count] = -1; + return nsock_socks; +} + +void nsock_free() { + if (nsock_socks) + free(nsock_socks); + if (nsock_readable) + free(nsock_readable); + nsock_server_fd = 0; + nsock_max_socket_fd = 0; + if (nsock_data) { + exit(1); + } +} + +void nsock_add_upstream(int source, int target, bool downstream) { + if (!nsock_socks[target]) + return; + if (!nsock_socks[source]) + return; + nsock_t *sock = nsock_get(source); + nsock_t *sock_target = nsock_get(target); + sock_target->type = NSOCK_UPSTREAM; + sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->downstream = downstream; + sock->upstreams[sock->upstream_count] = target; + sock->upstream_count++; +} + +void *nsock_get_data(int socket) { return nsock_data[socket]; } +void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } + +int nsock_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = 0; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return 0; + } + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + break; + } + if (p == NULL) { + freeaddrinfo(res); + return 0; + } + freeaddrinfo(res); + if (socket_fd) { + if (nsock_socks == NULL) { + nsock_init(2048); + } + nsock_socks[socket_fd] = socket_fd; + nsock_t *sock = nsock_create(socket_fd, NSOCK_CLIENT); + sock->connected = true; + } + return socket_fd; +} + +void nsock_listen(int port) { + int server_fd; + struct sockaddr_in address; + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed"); + exit(EXIT_FAILURE); + } + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("setsockopt failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + if (listen(server_fd, 8096) < 0) { + perror("Listen failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + nsock_server_fd = server_fd; +} + +int *nsock_select(suseconds_t timeout) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout; + int server_fd = nsock_server_fd; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(server_fd, &rfds); + int *socks = nsock_socks; + fd_set efds; + FD_ZERO(&efds); + nsock_max_socket_fd = server_fd; + for (int i = 0; socks[i] != -1; i++) { + if (i == server_fd) + continue; + ; + if (!socks[i]) + continue; + if (socks[i] > nsock_max_socket_fd) { + nsock_max_socket_fd = socks[i]; + } + FD_SET(socks[i], &rfds); + FD_SET(socks[i], &efds); + } + int activity = select(nsock_max_socket_fd + 1, &rfds, NULL, &efds, timeout == 0 ? NULL : &tv); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } else if (activity == 0) { + return NULL; + } + if (FD_ISSET(server_fd, &rfds)) { + struct sockaddr_in address; + int addrlen = sizeof(address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + int new_socket = 0; + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed"); + } else { + nsock_socks[new_socket] = new_socket; + nsock_create(new_socket, NSOCK_CLIENT); + if (nsock_on_connect) + nsock_on_connect(new_socket); + if (new_socket > nsock_max_socket_fd) + nsock_max_socket_fd = new_socket; + } + } + if (nsock_readable) { + free(nsock_readable); + } + nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable[nsock_max_socket_fd + 1] = -1; + nsock_readable[0] = 0; + int readable_count = 0; + for (int i = 0; i < nsock_max_socket_fd + 1; i++) { + nsock_t *sock = nsock_get(i); + if (!sock) + continue; + if (FD_ISSET(i, &efds)) { + nsock_close(nsock_socks[i]); + nsock_socks[i] = 0; + nsock_readable[i] = 0; + } else if (FD_ISSET(i, &rfds) && i != server_fd) { + nsock_readable[i] = i; + readable_count++; + nsock_on_before_data(i); + } else { + nsock_readable[i] = 0; + sock->connected = false; + } + } + return nsock_readable; +} + +unsigned char *nsock_read(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = read(fd, buffer, length); + if (bytes_read <= 0) { + nsock_close(fd); + return NULL; + } + buffer[bytes_read] = 0; + return buffer; +} + +unsigned char *nsock_read_all(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = 0; + while (bytes_read < length) { + int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); + if (bytes_chunk <= 0) { + nsock_close(fd); + return NULL; + } + bytes_read += bytes_chunk; + } + buffer[bytes_read] = 0; + return buffer; +} + +int nsock_write_all(int fd, unsigned char *data, int length) { + if (!nsock_socks[fd]) + return 0; + int bytes_written = 0; + while (bytes_written < length) { + int bytes_chunk = write(fd, data + bytes_written, length - bytes_written); + if (bytes_chunk <= 0) { + nsock_close(fd); + return 0; + } + bytes_written += bytes_chunk; + } + return bytes_written; +} + +int nsock_execute_upstream(int source, size_t buffer_size) { + int result = 0; + nsock_t *sock = nsock_get(source); + unsigned char data[buffer_size]; + memset(data, 0, buffer_size); + int bytes_read = read(source, data, buffer_size); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + bool downstreamed = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + if (!nsock_socks[sock->upstreams[i]]) + continue; + int bytes_sent = nsock_write_all(sock->upstreams[i], data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + continue; + } + if (sock->downstream && downstreamed == false) { + downstreamed = true; + unsigned char data[4096]; + memset(data, 0, 4096); + int bytes_read = read(sock->upstreams[i], data, 4096); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + int bytes_sent = nsock_write_all(sock->fd, data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + return 0; + } + } + result++; + } + return result; +} + +void nsock_on_before_data(int fd) { + if (!nsock_socks[fd]) + return; + nsock_t *sock = nsock_get(fd); + if (sock->upstream_count) { + int upstreamed_to_count = nsock_execute_upstream(fd, 4096); + if (!upstreamed_to_count) { + nsock_close(fd); + } + return; + } else if (sock->type == NSOCK_UPSTREAM) { + while (rfd_wait(sock->fd, 0)) { + unsigned char *data = nsock_read(fd, 4096); + (void)data; + } + } + if (nsock_on_data) + nsock_on_data(fd); +} + +void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void (*on_close)(int fd)) { + nsock_init(2048); + nsock_listen(port); + nsock_on_connect = on_connect; + nsock_on_data = on_data; + nsock_on_close = on_close; + int serve_in_terminal = nsock_on_connect == NULL && nsock_on_data == NULL && nsock_on_close == NULL; + while (1) { + int *readable = nsock_select(0); + if (!serve_in_terminal) + continue; + if (!readable) + continue; + for (int i = 0; readable[i] != -1; i++) { + if (!readable[i]) + continue; + char buffer[1024] = {0}; + int bytes_read = read(readable[i], buffer, 1); + buffer[bytes_read] = 0; + if (bytes_read <= 0) { + nsock_close(readable[i]); + continue; + } + if (write(readable[i], buffer, bytes_read) <= 0) { + nsock_close(readable[i]); + continue; + } + } + } +} +#endif + +#ifndef UUID_H +#define UUID_H +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +typedef struct { + unsigned char bytes[16]; +} UUID; + +void generate_random_bytes(unsigned char *bytes, size_t len) { + for (size_t i = 0; i < len; i++) { + bytes[i] = rand() % 256; + } +} + +UUID generate_uuid4(void) { + UUID uuid; + + generate_random_bytes(uuid.bytes, 16); + + uuid.bytes[6] &= 0x0f; + uuid.bytes[6] |= 0x40; + + uuid.bytes[8] &= 0x3f; + uuid.bytes[8] |= 0x80; + + return uuid; +} + +void uuid_to_string(UUID uuid, char *str) { + sprintf(str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid.bytes[0], uuid.bytes[1], uuid.bytes[2], + uuid.bytes[3], uuid.bytes[4], uuid.bytes[5], uuid.bytes[6], uuid.bytes[7], uuid.bytes[8], uuid.bytes[9], uuid.bytes[10], + uuid.bytes[11], uuid.bytes[12], uuid.bytes[13], uuid.bytes[14], uuid.bytes[15]); +} + +char *uuid4() { + srand(time(NULL)); + UUID uuid = generate_uuid4(); + char str[37]; + uuid_to_string(uuid, str); + return sbuf(str); +} +#endif +#ifndef RNET_H +#define RNET_H +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> + +#include <sys/socket.h> +#include <sys/types.h> + +#include <unistd.h> +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +#define NET_SOCKET_MAX_CONNECTIONS 50000 + +typedef struct rnet_socket_t { + int fd; + char name[50]; + void *data; + size_t bytes_received; + size_t bytes_sent; + bool connected; + void (*on_read)(struct rnet_socket_t *); + void (*on_close)(struct rnet_socket_t *); + void (*on_connect)(struct rnet_socket_t *); +} rnet_socket_t; + +typedef struct rnet_select_result_t { + int server_fd; + rnet_socket_t **sockets; + unsigned int socket_count; +} rnet_select_result_t; + +typedef struct rnet_server_t { + int socket_fd; + rnet_socket_t **sockets; + unsigned int socket_count; + unsigned int port; + unsigned int backlog; + rnet_select_result_t *select_result; + int max_fd; + void (*on_connect)(rnet_socket_t *socket); + void (*on_close)(rnet_socket_t *socket); + void (*on_read)(rnet_socket_t *socket); +} rnet_server_t; + +void rnet_select_result_free(rnet_select_result_t *result); +int net_socket_accept(int server_fd); +int net_socket_connect(const char *, unsigned int); +int net_socket_init(); +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog); +rnet_select_result_t *net_socket_select(rnet_server_t *server); +rnet_socket_t *net_socket_wait(rnet_socket_t *socket_fd); +bool net_set_non_blocking(int sock); +bool net_socket_bind(int sock, unsigned int port); +bool net_socket_listen(int sock, unsigned int backlog); +char *net_socket_name(int sock); +size_t net_socket_write(rnet_socket_t *, unsigned char *, size_t); +rnet_socket_t *get_net_socket_by_fd(int); +unsigned char *net_socket_read(rnet_socket_t *, unsigned int buff_size); +void _net_socket_close(int sock); +void net_socket_close(rnet_socket_t *sock); + +rnet_server_t *rnet_server_new(int socket_fd, unsigned int port, unsigned int backlog) { + rnet_server_t *server = malloc(sizeof(rnet_server_t)); + server->socket_fd = socket_fd; + server->sockets = NULL; + server->socket_count = 0; + server->port = port; + server->backlog = backlog; + server->max_fd = -1; + server->select_result = NULL; + server->on_connect = NULL; + server->on_close = NULL; + server->on_read = NULL; + return server; +} + +rnet_server_t *rnet_server_add_socket(rnet_server_t *server, rnet_socket_t *sock) { + server->sockets = realloc(server->sockets, sizeof(rnet_socket_t *) * (server->socket_count + 1)); + server->sockets[server->socket_count] = sock; + server->socket_count++; + sock->on_read = server->on_read; + sock->on_connect = server->on_connect; + sock->on_close = server->on_close; + sock->connected = true; + return server; +} + +rnet_socket_t sockets[NET_SOCKET_MAX_CONNECTIONS] = {0}; +unsigned long sockets_connected = 0; +int net_socket_max_fd = 0; +unsigned long sockets_total = 0; +unsigned long sockets_disconnected = 0; +unsigned long sockets_concurrent_record = 0; +unsigned long sockets_errors = 0; + +bool net_set_non_blocking(int sock) { + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + perror("fcntl"); + return false; + } + + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + return false; + } + + return true; +} + +int net_socket_init() { + int socket_fd = -1; + memset(sockets, 0, sizeof(sockets)); + int opt = 1; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed.\n"); + return false; + } + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("Setsockopt failed.\n"); + close(socket_fd); + return false; + } + net_set_non_blocking(socket_fd); + return socket_fd; +} + +char *net_socket_name(int fd) { + rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); + if (rnet_socket) { + return rnet_socket->name; + ; + } + + // If socket disconnected or is no client from server + return NULL; +} + +bool net_socket_bind(int socket_fd, unsigned int port) { + struct sockaddr_in address; + + address.sin_family = AF_INET; // IPv4 + address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address + address.sin_port = htons(port); // Convert port to network byte order + + if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(socket_fd); + return false; + } + return true; +} + +int net_socket_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = -1; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return -1; + } + + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + + break; + } + + if (p == NULL) { + freeaddrinfo(res); + return -1; + } + + freeaddrinfo(res); + return socket_fd; +} + +bool net_socket_listen(int socket_fd, unsigned int backlog) { + if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + perror("Listen failed"); + close(socket_fd); + return false; + } + return true; +} + +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { + signal(SIGPIPE, SIG_IGN); + int socket_fd = net_socket_init(); + net_socket_bind(socket_fd, port); + net_socket_listen(socket_fd, backlog); + return rnet_server_new(socket_fd, port, backlog); +} + +int net_socket_accept(int net_socket_server_fd) { + struct sockaddr_in address; + int addrlen = sizeof(address); + int new_socket = -1; + if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + close(new_socket); + return -1; + } else { + + return new_socket; + } +} +/* +static void net_socket_stats(WrenVM *vm) +{ + + wrenSetSlotNewList(vm, 0); + + wrenSetSlotString(vm, 1, "sockets_total"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_total); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_concurrent_record"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_connected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_connected); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_disconnected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); + wrenInsertInList(vm, 0, -1, 1); +}*/ + +size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { + ssize_t sent_total = 0; + ssize_t sent = 0; + ssize_t to_send = size; + while ((sent = send(sock->fd, message, to_send, 0))) { + if (sent == -1) { + sockets_errors++; + net_socket_close(sock); + break; + } + if (sent == 0) { + printf("EDGE CASE?\n"); + exit(1); + sockets_errors++; + net_socket_close(sock); + break; + } + sent_total += sent; + if (sent_total == to_send) + break; + } + return sent_total; +} + +unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { + if (buff_size > 1024 * 1024 + 1) { + perror("Buffer too big. Maximum is 1024*1024.\n"); + exit(1); + } + static unsigned char buffer[1024 * 1024]; + buffer[0] = 0; + ssize_t received = recv(sock->fd, buffer, buff_size, 0); + if (received <= 0) { + buffer[0] = 0; + net_socket_close(sock); + if (received < 0) { + sockets_errors++; + return NULL; + } + } + buffer[received + 1] = 0; + sock->bytes_received = received; + return buffer; +} + +rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { + if (!sock) + return NULL; + if (sock->fd == -1) + return NULL; + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(sock->fd, &read_fds); + + int max_socket_fd = sock->fd; + int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + // perror("Select error"); + net_socket_close(sock); + return NULL; + } + if (FD_ISSET(sock->fd, &read_fds)) { + return sock; + } + + return NULL; +} + +void rnet_safe_str(char *str, size_t length) { + if (!str || !length || !*str) + return; + for (unsigned int i = 0; i < length; i++) { + if (str[i] < 32 || str[i] > 126) + if (str[i] != 0) + str[i] = '.'; + } + str[length] = 0; +} + +rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { + rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + memset(result, 0, sizeof(rnet_select_result_t)); + result->server_fd = socket_fd; + result->socket_count = 0; + result->sockets = NULL; + return result; +} + +void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { + result->sockets = realloc(result->sockets, sizeof(rnet_socket_t *) * (result->socket_count + 1)); + result->sockets[result->socket_count] = sock; + result->socket_count++; +} +void rnet_select_result_free(rnet_select_result_t *result) { free(result); } +rnet_select_result_t *net_socket_select(rnet_server_t *server) { + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(server->socket_fd, &read_fds); + + server->max_fd = server->socket_fd; + int socket_fd = -1; + for (unsigned int i = 0; i < server->socket_count; i++) { + socket_fd = server->sockets[i]->fd; + if (!server->sockets[i]->connected) { + continue; + } + if (socket_fd > 0) { + FD_SET(socket_fd, &read_fds); + if (socket_fd > server->max_fd) { + server->max_fd = socket_fd; + } + } + } + int new_socket = -1; + struct sockaddr_in address; + int addrlen = sizeof(struct sockaddr_in); + int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } + if (FD_ISSET(server->socket_fd, &read_fds)) { + if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed\n"); + return NULL; + } + + // net_set_non_blocking(new_socket); + char name[50] = {0}; + sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + rnet_socket_t *sock_obj = NULL; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets && server->sockets[i]->fd == -1) { + sock_obj = server->sockets[i]; + } + } + if (!sock_obj) { + sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + rnet_server_add_socket(server, sock_obj); + } + sock_obj->fd = new_socket; + strcpy(sock_obj->name, name); + sockets_connected++; + sockets_total++; + sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; + if (new_socket > net_socket_max_fd) { + net_socket_max_fd = new_socket; + } + sock_obj->connected = true; + sock_obj->on_connect(sock_obj); + } + rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); + unsigned int readable_count = 0; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets[i]->fd == -1) + continue; + if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { + rnet_select_result_add(result, server->sockets[i]); + readable_count++; + if (server->sockets[i]->on_read) { + server->sockets[i]->on_read(server->sockets[i]); + } + } + } + if (server->select_result) { + rnet_select_result_free(server->select_result); + server->select_result = NULL; + } + if (readable_count == 0) + rnet_select_result_free(result); + return readable_count ? result : NULL; +} + +rnet_socket_t *get_net_socket_by_fd(int sock) { + for (int i = 0; i < net_socket_max_fd; i++) { + if (sockets[i].fd == sock) { + return &sockets[i]; + } + } + return NULL; +} + +void _net_socket_close(int sock) { + if (sock > 0) { + sockets_connected--; + sockets_disconnected++; + if (sock > 0) { + if (close(sock) == -1) { + perror("Error closing socket.\n"); + } + } + } +} + +void net_socket_close(rnet_socket_t *sock) { + sock->connected = false; + if (sock->on_close) + sock->on_close(sock); + _net_socket_close(sock->fd); + sock->fd = -1; +} +#undef _POSIX_C_SOURCE +#endif + +#include <stdio.h> +#ifndef RLIB_RARGS_H +#define RLIB_RARGS_H +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +bool rargs_isset(int argc, char *argv[], char *key) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + return true; + } + } + return false; +} + +char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return argv[i + 1]; + } + } + } + return (char *)def; +} + +int rargs_get_option_int(int argc, char *argv[], char *key, int def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return atoi(argv[i + 1]); + } + } + } + return def; +} + +bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + if (!strcmp(argv[i + 1], "false")) + return false; + if (!strcmp(argv[i + 1], "0")) + return false; + return true; + } + } + } + + return def; +} +#endif +#ifndef RCAT_H +#define RCAT_H +#include <stdio.h> +#include <stdlib.h> + +void rcat(char *filename) { + FILE *f = fopen(filename, "rb"); + if (!f) { + printf("rcat: couldn't open \"%s\" for read.\n", filename); + return; + } + unsigned char c; + while ((c = fgetc(f)) && !feof(f)) { + printf("%c", c); + } + fclose(f); + fflush(stdout); +} + +int rcat_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [filename]\n"); + return 1; + } + rcat(argv[1]); + return 0; +} + +#endif + +#ifndef RLIZA_H +#define RLIZA_H +#ifndef RBUFFER_H +#define RBUFFER_H +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +typedef struct rbuffer_t { + unsigned char *data; + unsigned char *_data; + size_t size; + size_t pos; + bool eof; +} rbuffer_t; + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size); +void rbuffer_free(rbuffer_t *rfb); +void rbuffer_reset(rbuffer_t *rfb); +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +unsigned char rbuffer_pop(rbuffer_t *rfb); +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); + +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size) { + if (rfb->_data) { + free(rfb->_data); + rfb->_data = NULL; + rfb->data = NULL; + rfb->eof = true; + } + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->data = rfb->_data; + rfb->eof = false; + } + rfb->size = size; + rfb->pos = 0; +} + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { + rbuffer_t *rfb = (rbuffer_t *)malloc(sizeof(rbuffer_t)); + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->eof = false; + } else { + rfb->_data = NULL; + rfb->eof = true; + } + rfb->size = size; + rfb->pos = 0; + rfb->data = rfb->_data; + return rfb; +} +void rbuffer_free(rbuffer_t *rfb) { + if (rfb->_data) + free(rfb->_data); + free(rfb); +} + +size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { + if (rfb->pos < rfb->size) { + rfb->_data[rfb->pos++] = c; + return 1; + } + rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); + rfb->_data[rfb->pos++] = c; + rfb->size++; + return rfb->pos; +} +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { + unsigned char *data_ptr = (unsigned char *)data; + for (size_t i = 0; i < size; i++) { + rbuffer_push(rfb, data_ptr[i]); + } +} + +unsigned char rbuffer_peek(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos != rfb->size) { + result = rfb->_data[rfb->pos]; + return result; + } + rfb->eof = true; + return EOF; +} +unsigned char rbuffer_pop(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos <= rfb->size) { + result = rfb->_data[rfb->pos]; + rfb->pos++; + rfb->data++; + if (rfb->pos == rfb->size) { + rfb->eof = true; + } + return result; + } + rfb->eof = true; + return result; +} +void rbuffer_reset(rbuffer_t *rfb) { + rfb->data = rfb->_data; + rfb->pos = 0; +} + +unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { + return strncmp((char *)s1, (char *)s2, n); + while (n && *s1 == *s2) { + n--; + s1++; + s2++; + } + return *s1 != *s2; +} +size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +unsigned char *rbuffer_to_string(rbuffer_t *rfb) { + unsigned char *result = rfb->_data; + rfb->_data = NULL; + rfb->data = NULL; + rbuffer_free(rfb); + return result; +} + +unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { + char *option = NULL; + char options_cpy[1024] = {0}; + strcpy(options_cpy, options); + char *memory = options_cpy; + while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { + + size_t option_length = strlen(option); + if (option_length > rfb->size - rfb->pos) { + continue; + } + if (!strcmp(option, "\\d") && *rfb->data >= '0' && *rfb->data <= '9') { + return rfb->data; + } + if (rfb->size - rfb->pos >= 5 && !strcmp(option, "\\b") && + ((!ustrncmp(rfb->data, (unsigned char *)"true", 4) || !ustrncmp(rfb->data, (unsigned char *)"false", 5)))) { + return rfb->data; + } + if (!ustrncmp(rfb->data, (unsigned char *)option, option_length)) { + return rfb->data; + } + } + return NULL; +} + +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { + while (rfb->pos < rfb->size) { + if (rbuffer_match_option(rfb, options) != NULL) { + return rfb->data; + } + if (rbuffer_match_option(rfb, ignore)) { + printf("SKIP:%s\n", rfb->data); + rbuffer_pop(rfb); + continue; + } + break; + } + return NULL; +} +unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { + unsigned char *result = NULL; + if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { + rbuffer_pop(rfb); + } + return result; +} +#endif +#ifndef RSTRING_H +#define RSTRING_H +#ifndef RMATH_H +#define RMATH_H +#include <math.h> + +#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 +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +char *rstrtimestamp() { + time_t current_time; + time(¤t_time); + struct tm *local_time = localtime(¤t_time); + static char time_string[100]; + time_string[0] = 0; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); + return time_string; +} + +ulonglong _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]; + key[0] = 0; + sprintf(key, "%lld", _r_generate_key_current); + return key; +} + +char *rformat_number(long long lnumber) { + static char formatted[1024]; + + char number[1024] = {0}; + sprintf(number, "%lld", lnumber); + + int len = strlen(number); + int commas_needed = (len - 1) / 3; + int new_len = len + commas_needed; + + formatted[new_len] = '\0'; + + int i = len - 1; + int j = new_len - 1; + int count = 0; + + while (i >= 0) { + if (count == 3) { + formatted[j--] = '.'; + count = 0; + } + formatted[j--] = number[i--]; + count++; + } + if (lnumber < 0) + formatted[j--] = '-'; + return formatted; +} + +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 == '\\') { + 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 = '\\'; + i++; + } + } + result[index] = c; + index++; + } + result[index] = 0; +} + +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); +} + +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); +} + +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; + } else if (content[i] == '"') { + result[index] = '\\'; + index++; + result[index] = '"'; + index++; + continue; + } + result[index] = content[i]; + index++; + result[index] = 0; + } +} + +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] == ' ' || input[i] == '\n') { + continue; + } + count = i; + size_t j; + for (j = 0; j < len - count; j++) { + output[j] = input[j + count]; + } + output[j] = '\0'; + break; + } + return count; +} + +/* + * Converts "pony" to \"pony\". Addslashes does not + * Converts "pony\npony" to "pony\n" + * "pony" + */ +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); + output[0] = 0; + size_t new_offset = 0; + size_t j; + size_t index = 0; + + for (j = offset; j < len + offset; j++) { + if (input[j] == 0) { + index++; + break; + } + index = j - offset; + output[index] = input[j]; + + if (output[index] == '\n') { + index++; + break; + } + } + output[index] = 0; + + new_offset = index + offset; + + if (strip_nl) { + if (output[index - 1] == '\n') { + output[index - 1] = 0; + } + } + return new_offset; +} + +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); + } +} + +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; +} + +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); + } +} + +int cmp_line(const void *left, const void *right) { + char *l = *(char **)left; + char *r = *(char **)right; + + char lstripped[strlen(l) + 1]; + rstrip_whitespace(l, lstripped); + char rstripped[strlen(r) + 1]; + rstrip_whitespace(r, rstripped); + + double d1, d2; + bool found_d1 = rstrextractdouble(lstripped, &d1); + bool found_d2 = rstrextractdouble(rstripped, &d2); + + 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; +} + +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); + for (int i = 0; i < line_count; i++) { + free(lines[i]); + } + free(lines); + return line_count; +} + +#endif + +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef enum rliza_type_t { + RLIZA_STRING = 's', + RLIZA_BOOLEAN = 'b', + RLIZA_NUMBER = 'n', + RLIZA_OBJECT = 'o', + RLIZA_ARRAY = 'a', + RLIZA_NULL = 0, + RLIZA_KEY = 'k', + RLIZA_INTEGER = 'i' +} rliza_type_t; + +typedef struct rliza_t { + rliza_type_t type; + struct rliza_t *value; + char *key; + union { + char *string; + bool boolean; + double number; + struct rliza_t **map; + long long integer; + } content; + unsigned int count; + char *(*get_string)(struct rliza_t *, char *); + long long (*get_integer)(struct rliza_t *, char *); + double (*get_number)(struct rliza_t *, char *); + bool (*get_boolean)(struct rliza_t *, char *); + struct rliza_t *(*get_array)(struct rliza_t *, char *); + struct rliza_t *(*get_object)(struct rliza_t *, char *); + void (*set_string)(struct rliza_t *, char *, char *); + void (*set_integer)(struct rliza_t *, char *, long long); + void (*set_number)(struct rliza_t *, char *, double); + void (*set_boolean)(struct rliza_t *, char *, bool); + void (*set_array)(struct rliza_t *self, char *key, struct rliza_t *array); + void (*set_object)(struct rliza_t *self, char *key, struct rliza_t *object); +} rliza_t; + +void rliza_free(rliza_t *rliza) { + if (rliza->key) { + free(rliza->key); + rliza->key = NULL; + } + if (rliza->value) { + rliza_free(rliza->value); + rliza->value = NULL; + } + // if (rliza->content.array) { + // printf("JAAAA\n"); + // } + // if (rliza->content.object) { + // rliza_free(rliza->content.object); + // rliza->content.object = NULL; + //} + if (rliza->type == RLIZA_STRING) { + if (rliza->content.string) { + free(rliza->content.string); + rliza->content.string = NULL; + // else if (rliza->type == RLIZA_NUMBER) { + // printf("STDring freed\n"); + } + } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { + + if (rliza->content.map) { + for (unsigned int i = 0; i < rliza->count; i++) { + rliza_free(rliza->content.map[i]); + } + free(rliza->content.map); + } + } + // free(rliza->content.array); + //} + + free(rliza); +} + +rliza_t *rliza_new(rliza_type_t type); +rliza_t *rliza_new_string(char *string); +rliza_t *rliza_new_null(); +rliza_t *rliza_new_boolean(bool value); +rliza_t *rliza_new_number(double value); +rliza_t *rliza_new_integer(long long value); +rliza_t *rliza_new_key_value(char *key, rliza_t *value); +rliza_t *rliza_new_key_string(char *key, char *string); +rliza_t *rliza_new_key_bool(char *key, bool value); +rliza_t *rliza_new_key_number(char *key, double value); +void rliza_push(rliza_t *self, rliza_t *obj); +void rliza_push_object(rliza_t *self, rliza_t *object); +void rliza_set_object(rliza_t *self, char *key, rliza_t *object); +void rliza_set_string(rliza_t *self, char *key, char *string); +void rliza_set_boolean(rliza_t *self, char *key, bool value); +void rliza_set_number(rliza_t *self, char *key, double value); +void rliza_set_integer(rliza_t *self, char *key, long long value); +char *rliza_get_string(rliza_t *self, char *key); +long long rliza_get_integer(rliza_t *self, char *key); +double rliza_get_number(rliza_t *self, char *key); +bool rliza_get_boolean(rliza_t *self, char *key); +rliza_t *rliza_get_array(rliza_t *self, char *key); +rliza_t *rliza_get_object(rliza_t *self, char *key); +void rliza_set_array(rliza_t *self, char *key, rliza_t *array); + +char *rliza_dumps(rliza_t *rliza); +rliza_t *rliza_loads(char **content); +rliza_t *_rliza_loads(char **content); + +char *rliza_get_string(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_STRING || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.string; + } + } + } + return NULL; +} +long long rliza_get_integer(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_INTEGER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.integer; + } + } + } + return 0; +} + +double rliza_get_number(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_NUMBER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.number; + } + } + } + return 0; +} + +bool rliza_get_boolean(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_BOOLEAN || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.boolean; + } + } + } + return false; +} + +rliza_t *rliza_get_object(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + return self->content.map[i]; + } + } + return NULL; +} + +rliza_t *rliza_get_array(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_ARRAY || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]; + } + } + } + return NULL; +} + +rliza_t *rliza_new_null() { + rliza_t *rliza = rliza_new(RLIZA_NULL); + return rliza; +} +rliza_t *rliza_new_string(char *string) { + rliza_t *rliza = rliza_new(RLIZA_STRING); + if (string == NULL) { + rliza->type = RLIZA_NULL; + rliza->content.string = NULL; + return rliza; + } else { + rliza->content.string = strdup(string); + } + return rliza; +} +rliza_t *rliza_new_boolean(bool value) { + rliza_t *rliza = rliza_new(RLIZA_BOOLEAN); + rliza->content.boolean = value; + return rliza; +} + +rliza_t *rliza_new_number(double value) { + rliza_t *rliza = rliza_new(RLIZA_NUMBER); + rliza->content.number = value; + return rliza; +} + +rliza_t *rliza_new_integer(long long value) { + rliza_t *rliza = rliza_new(RLIZA_INTEGER); + rliza->content.integer = value; + return rliza; +} +rliza_t *rliza_new_key_array(char *key) { + rliza_t *rliza = rliza_new(RLIZA_ARRAY); + rliza->key = strdup(key); + return rliza; +} + +rliza_t *rliza_new_key_value(char *key, rliza_t *value) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + if (key) { + rliza->key = strdup(key); + } + rliza->value = value; + return rliza; +} + +rliza_t *rliza_new_key_string(char *key, char *string) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_string(string)); + return rliza; +} +rliza_t *rliza_new_key_bool(char *key, bool value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_boolean(value)); + return rliza; +} +rliza_t *rliza_new_key_number(char *key, double value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_number(value)); + return rliza; +} + +void rliza_set_null(rliza_t *self, char *key) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_null(); + obj->key = strdup(key); + rliza_push_object(self, obj); + } + if (obj->type == RLIZA_OBJECT) { + + rliza_free(obj->value); + obj->value = NULL; + } else if (obj->type == RLIZA_STRING) { + if (obj->content.string) + free(obj->content.string); + obj->content.string = NULL; + } else if (obj->type == RLIZA_ARRAY) { + for (unsigned int i = 0; i < obj->count; i++) { + rliza_free(obj->content.map[i]); + } + } else if (obj->type == RLIZA_NUMBER) { + obj->content.number = 0; + } else if (obj->type == RLIZA_INTEGER) { + obj->content.integer = 0; + } + obj->type = RLIZA_NULL; +} + +rliza_t *rliza_duplicate(rliza_t *rliza) { + if (!rliza) + return NULL; + char *str = rliza_dumps(rliza); + char *strp = str; + rliza_t *obj = rliza_loads(&strp); + free(str); + return obj; +} + +rliza_t *rliza_new_object(rliza_t *obj) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + rliza->value = obj; + return rliza; +} +void rliza_set_object(rliza_t *self, char *key, rliza_t *value) { + rliza_t *obj = rliza_duplicate(value); + obj->key = strdup(key); + obj->type = RLIZA_OBJECT; + rliza_push(self, obj); +} + +void rliza_set_string(rliza_t *self, char *key, char *string) { + rliza_t *obj = rliza_get_object(self, key); + + if (!obj) { + obj = rliza_new_string(string); + obj->key = strdup(key); + obj->type = RLIZA_STRING; + rliza_push_object(self, obj); + } else { + obj->content.string = strdup(string); + } +} + +void rliza_set_array(rliza_t *self, char *key, rliza_t *array) { + rliza_t *obj = rliza_get_object(self, key); + if (obj) + rliza_free(obj); + if (array->key) { + free(array->key); + array->key = strdup(key); + } + rliza_push_object(self, array); +} + +void rliza_set_number(rliza_t *self, char *key, double value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_number(value); + obj->key = strdup(key); + obj->type = RLIZA_NUMBER; + rliza_push_object(self, obj); + } else { + obj->content.number = value; + } +} + +void rliza_push_object(rliza_t *self, rliza_t *object) { + self->content.map = realloc(self->content.map, (sizeof(rliza_t **)) * (self->count + 1)); + self->content.map[self->count] = object; + self->count++; +} +void rliza_set_integer(rliza_t *self, char *key, long long value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_integer(value); + obj->key = strdup(key); + obj->type = RLIZA_INTEGER; + rliza_push_object(self, obj); + } else { + obj->content.integer = value; + } +} + +void rliza_set_boolean(rliza_t *self, char *key, bool value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_boolean(value); + obj->key = strdup(key); + obj->type = RLIZA_BOOLEAN; + + rliza_push_object(self, obj); + } else { + obj->content.boolean = value; + } +} + +rliza_t *rliza_new(rliza_type_t type) { + rliza_t *rliza = (rliza_t *)calloc(1, sizeof(rliza_t)); + rliza->type = type; + rliza->get_boolean = rliza_get_boolean; + rliza->get_integer = rliza_get_integer; + rliza->get_number = rliza_get_number; + rliza->get_string = rliza_get_string; + rliza->get_array = rliza_get_array; + rliza->get_object = rliza_get_object; + rliza->set_string = rliza_set_string; + rliza->set_number = rliza_set_number; + rliza->set_boolean = rliza_set_boolean; + rliza->set_integer = rliza_set_integer; + rliza->set_array = rliza_set_array; + rliza->set_object = rliza_set_object; + + return rliza; +} + +void *rliza_coalesce(void *result, void *default_value) { + if (result == NULL) + return default_value; + return result; +} + +char *rliza_seek_string(char **content, char **options) { + + while (**content == ' ' || **content == '\n' || **content == '\t' || **content == '\r') { + (*content)++; + } + if (**content == 0) { + return NULL; + } + + char *option = NULL; + unsigned int option_index = 0; + + while (true) { + option = options[option_index]; + if (option == NULL) + break; + option_index++; + if (option[0] == 'd') { + if (**content >= '0' && **content <= '9') { + return (char *)*content; + } + } else if (!strncmp(option, *content, strlen(option))) { + return (char *)*content; + } + } + return *content; +} + +char *rliza_extract_quotes(char **content) { + rbuffer_t *buffer = rbuffer_new(NULL, 0); + assert(**content == '"'); + char previous = 0; + while (true) { + + (*content)++; + if (!**content) { + rbuffer_free(buffer); + return NULL; + } + + if (**content == '"' && previous != '\\') { + break; + } + rbuffer_push(buffer, **content); + previous = **content; + } + assert(**content == '"'); + (*content)++; + rbuffer_push(buffer, 0); + char *result = (char *)rbuffer_to_string(buffer); + return result; +} + +rliza_t *_rliza_loads(char **content) { + static char *seek_for1[] = {"[", "{", "\"", "d", "true", "false", "null", NULL}; + char *token = (char *)rliza_seek_string(content, seek_for1); + if (!token) + return NULL; + rliza_t *rliza = rliza_new(RLIZA_NULL); + if (**content == '"') { + char *extracted = rliza_extract_quotes(content); + if (!extracted) { + rliza_free(rliza); + return NULL; + } + // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); + // rstraddslashes(extracted, extracted_with_slashes); + rliza->type = RLIZA_STRING; + rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; + // free(extracted); + return rliza; + } else if (**content == '{') { + rliza->type = RLIZA_OBJECT; + (*content)++; + char *result = NULL; + static char *seek_for2[] = {"\"", ",", "}", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for2)) != NULL && *result) { + + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (**content == ',') { + (*content)++; + if (!**content) { + rliza_free(rliza); + return NULL; + } + continue; + } + char *key = NULL; + if (**content == '"') { + key = rliza_extract_quotes((char **)content); + if (!key || !*key) { + rliza_free(rliza); + return NULL; + } + char *escaped_key = (char *)malloc(strlen((char *)key) * 2 + 1); + rstrstripslashes((char *)key, escaped_key); + static char *seek_for3[] = {":", NULL}; + char *devider = rliza_seek_string(content, seek_for3); + + if (!devider || !*devider) { + free(escaped_key); + free(key); + rliza_free(rliza); + return NULL; + } + (*content)++; + if (!**content) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + rliza_t *value = _rliza_loads(content); + if (!value) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + if (value->key) + free(value->key); + value->key = escaped_key; + free(key); + rliza_push_object(rliza, value); + } else if (**content == '}') { + break; + } else { + // Parse error + rliza_free(rliza); + return NULL; + } + }; + if ((**content != '}')) { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content == '[') { + rliza->type = RLIZA_ARRAY; + (*content)++; + char *result; + static char *seek_for4[] = {"[", "{", "\"", "d", ",", "]", "null", "true", "false", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for4)) != NULL && *result) { + if (**content == ',') { + (*content)++; + + } else if (**content == ']') { + break; + } + rliza_t *obj = _rliza_loads(content); + if (!obj) { + rliza_free(rliza); + return NULL; + } + rliza_push(rliza, obj); + if (!**content) { + rliza_free(rliza); + return NULL; + } + } + if (**content != ']') { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content >= '0' && **content <= '9') { + char *ptr = *content; + bool is_decimal = false; + + while (**content) { + if (**content == '.') { + is_decimal = true; + } else if (!isdigit(**content)) { + break; + } + (*content)++; + } + if (*(*content - 1) == '.') { + rliza_free(rliza); + return NULL; + } + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (is_decimal) { + rliza->type = RLIZA_NUMBER; + rliza->content.number = strtod(ptr, NULL); + } else { + rliza->type = RLIZA_INTEGER; + rliza->content.integer = strtoll(ptr, NULL, 10); + } + return rliza; + } else if (!strncmp(*content, "true", 4)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = true; + *content += 4; + + return rliza; + } else if (!strncmp(*content, "false", 5)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = false; + *content += 5; + + return rliza; + } else if (!strncmp(*content, "null", 4)) { + rliza->type = RLIZA_NULL; + *content += 4; + + return rliza; + } + // Parsing error + rliza_free(rliza); + return NULL; +} +rliza_t *rliza_loads(char **content) { + if (!content || !**content) { + return NULL; + } + char *original_content = *content; + rliza_t *result = _rliza_loads(content); + if (!result) { + *content = original_content; + } + return result; +} + +char *rliza_dumps(rliza_t *rliza) { + size_t size = 4096; + char *content = (char *)calloc(size, sizeof(char)); + content[0] = 0; + if (rliza->type == RLIZA_INTEGER) { + if (rliza->key) { + sprintf(content, "\"%s\":%lld", rliza->key, rliza->content.integer); + } else { + sprintf(content, "%lld", rliza->content.integer); + } + } else if (rliza->type == RLIZA_STRING) { + + // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); + char *escaped_string = rliza->content.string; + // rstrstripslashes((char *)rliza->content.string, escaped_string); + size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; + if (size < min_size) { + size = min_size + 1; + content = realloc(content, size); + } + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 20); + rstrstripslashes((char *)rliza->key, escaped_key); + if (strlen(content) > size) { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + } + sprintf(content, "\"%s\":\"%s\"", escaped_key, escaped_string); + free(escaped_key); + } else { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + sprintf(content, "\"%s\"", escaped_string); + } + // free(escaped_string); + } else if (rliza->type == RLIZA_NUMBER) { + if (rliza->key) { + sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); + } else { + sprintf(content, "%f", rliza->content.number); + } + int last_zero = 0; + bool beyond_dot = false; + for (size_t i = 0; i < strlen(content); i++) { + if (content[i] == '.') { + beyond_dot = true; + } else if (beyond_dot == true) { + if (content[i - 1] != '.') { + if (content[i] == '0') { + if (!last_zero) + last_zero = i; + } else { + last_zero = 0; + } + } + } + } + if (last_zero != 0) { + content[last_zero] = 0; + } + } else if (rliza->type == RLIZA_BOOLEAN) { + if (rliza->key) { + sprintf(content, "\"%s\":%s", rliza->key, rliza->content.boolean ? "true" : "false"); + } else { + sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); + } + } else if (rliza->type == RLIZA_OBJECT) { + + strcat(content, "{"); + if (rliza->key) { + strcat(content, "\""); + strcat(content, rliza->key); + strcat(content, "\":{"); + } + // bool add_braces = false; + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + content_chunk_stripped++; + content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + + strcat(content, ","); + } + if (content[strlen(content) - 1] == ',') { + content[strlen(content) - 1] = '\0'; + + if (rliza->key) { + strcat(content, "}"); + } + } + strcat(content, "}"); + } else if (rliza->type == RLIZA_ARRAY) { + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + if (strlen(escaped_key) > size) { + size = strlen(escaped_key) + 10; + content = realloc(content, size); + } + sprintf(content, "\"%s\":[", escaped_key); + free(escaped_key); + } else + strcpy(content, "["); + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + // content_chunk_stripped++; + // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + strcat(content, ","); + } + if (content[strlen(content) - 1] != '[') + content[strlen(content) - 1] = 0; + strcat(content, "]"); + } else if (rliza->type == RLIZA_NULL) { + + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + sprintf(content, "\"%s\":null", escaped_key); + free(escaped_key); + } else + strcpy(content, "null"); + } + return content; +} + +void rliza_dumpss(rliza_t *rliza) { + char *output = rliza_dumps(rliza); + printf("%s\n", output); + free(output); +} + +void rliza_push(rliza_t *self, rliza_t *obj) { rliza_push_object(self, obj); } + +int rliza_validate(char *json_content) { + if (!json_content || !*json_content) { + return false; + } + char *json_contentp = json_content; + rliza_t *to_object = _rliza_loads(&json_contentp); + if (to_object) { + rliza_free(to_object); + return json_contentp - json_content; + } + return false; +} + +#endif + +#ifndef RCOV_H +#define RCOV_H +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#ifndef RBENCH_H +#define RBENCH_H + +#ifndef RPRINT_H +#define RPRINT_H + +#ifndef RLIB_TIME +#define RLIB_TIME + +#ifndef _POSIX_C_SOURCE_199309L + +#define _POSIX_C_SOURCE_199309L +#endif +#include <sys/time.h> +#include <time.h> +#undef _POSIX_C_SOURCE_199309L +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 1 +#endif + +typedef uint64_t nsecs_t; +void nsleep(nsecs_t nanoseconds); + +void tick() { nsleep(1); } + +typedef unsigned long long msecs_t; + +nsecs_t nsecs() { + unsigned int lo, hi; + __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +} + +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); +} + +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; + str[i] = 0; + } + return 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 { + char *s = msecs_strms(ms); + sprintf(result, "%sMs", s); + } + return result; +} + +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; + + nanosleep(&req, &rem); +} + +void ssleep(double s) { + long nanoseconds = (long)(1000000000 * s); + + // long seconds = 0; + + // struct timespec req = {seconds, nanoseconds}; + // struct timespec rem; + + nsleep(nanoseconds); +} +void msleep(long miliseonds) { + long nanoseconds = miliseonds * 1000000; + nsleep(nanoseconds); +} + +char *format_time(int64_t nanoseconds) { + 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; + if (s > 60 * 60) { + s = s / 60 / 60; + snprintf(output, output_size, "%.2fh", s); + } else if (s > 60) { + s = s / 60; + snprintf(output, output_size, "%.2fm", s); + } else { + snprintf(output, output_size, "%.2fs", s); + } + } + return sbuf(output); +} + +#endif + +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +long rpline_number = 0; +nsecs_t rprtime = 0; + +int8_t _env_rdisable_colors = -1; +bool _rprint_enable_colors = true; + +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; + } + return _rprint_enable_colors; +} + +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; } + +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 = 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(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "", format, args); + va_end(args); +} + +void rprintf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "", format, args); + va_end(args); +} +void rprint(const 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, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\\l", format, args); + va_end(args); +} +void rprintl(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\\l", format, args); + va_end(args); +} + +// Black +void rprintkf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[30m", format, args); + va_end(args); +} +void rprintk(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[30m", format, args); + va_end(args); +} + +// Red +void rprintrf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[31m", format, args); + va_end(args); +} +void rprintr(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[31m", format, args); + va_end(args); +} + +// Green +void rprintgf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[32m", format, args); + va_end(args); +} +void rprintg(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[32m", format, args); + va_end(args); +} + +// Yellow +void rprintyf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[33m", format, args); + va_end(args); +} +void rprinty(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[33m", format, args); + va_end(args); +} + +// Blue +void rprintbf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[34m", format, args); + va_end(args); +} + +void rprintb(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[34m", format, args); + va_end(args); +} + +// Magenta +void rprintmf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[35m", format, args); + va_end(args); +} +void rprintm(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[35m", format, args); + va_end(args); +} + +// Cyan +void rprintcf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[36m", format, args); + va_end(args); +} +void rprintc(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[36m", format, args); + va_end(args); +} + +// White +void rprintwf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[37m", format, args); + va_end(args); +} +void rprintw(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[37m", format, args); + va_end(args); +} +#endif +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> + +#ifndef RLIB_TERMINAL_H +#define RLIB_TERMINAL_H + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef RTEST_H +#define RTEST_H +#ifndef REMO_H +#define REMO_H +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +typedef struct { + const char *str; + const char *description; +} remo_t; + +remo_t remo[] = { + {"\U0001F600", "Grinning Face"}, // 😀 + {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 + {"\U0001F602", "Face with Tears of Joy"}, // 😂 + {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 + {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 + {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 + {"\U0001F609", "Winking Face"}, // 😉 + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 + {"\U0001F618", "Face Blowing a Kiss"}, // 😘 + {"\U0001F617", "Kissing Face"}, // 😗 + {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 + {"\U0001F642", "Slightly Smiling Face"}, // 🙂 + {"\U0001F643", "Upside-Down Face"}, // 🙃 + {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 + {"\U0001F60B", "Face Savoring Food"}, // 😋 + {"\U0001F61B", "Face with Tongue"}, // 😛 + {"\U0001F61C", "Winking Face with Tongue"}, // 😜 + {"\U0001F92A", "Zany Face"}, // 🤪 + {"\U0001F929", "Star-Struck"}, // 🤩 + {"\U0001F631", "Face Screaming in Fear"}, // 😱 + {"\U0001F62D", "Loudly Crying Face"}, // 😭 + {"\U0001F624", "Face with Steam From Nose"}, // 😤 + {"\U0001F620", "Angry Face"}, // 😠 + {"\U0001F621", "Pouting Face"}, // 😡 + {"\U0001F47B", "Ghost"}, // 👻 + {"\U0001F480", "Skull"}, // 💀 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + {"\U0001F47D", "Alien"}, // 👽 + // Geometric Shapes + {"\U000025A0", "Black Square"}, // ■ + {"\U000025B2", "Upward Triangle"}, // ▲ + {"\U000025CF", "Black Circle"}, // ● + {"\U000025CB", "White Circle"}, // ○ + {"\U00002B1B", "Large Black Square"}, // ⬛ + {"\U00002B1C", "Large White Square"}, // ⬜ + + // Mathematical Symbols + {"\U00002200", "For All"}, // ∀ + {"\U00002203", "Exists"}, // ∃ + {"\U00002205", "Empty Set"}, // ∅ + {"\U00002207", "Nabla"}, // ∇ + {"\U0000220F", "N-Ary Product"}, // ∏ + {"\U00002212", "Minus Sign"}, // − + {"\U0000221E", "Infinity"}, // ∞ + + // Arrows + {"\U00002190", "Left Arrow"}, // ← + {"\U00002191", "Up Arrow"}, // ↑ + {"\U00002192", "Right Arrow"}, // → + {"\U00002193", "Down Arrow"}, // ↓ + {"\U00002195", "Up Down Arrow"}, // ↕ + {"\U00002197", "Up Right Arrow"}, // ↗ + {"\U00002198", "Down Right Arrow"}, // ↘ + {"\U000027A1", "Black Right Arrow"}, // ➡️ + + // Dingbats + {"\U00002714", "Check Mark"}, // ✔️ + {"\U00002716", "Heavy Multiplication X"}, // ✖️ + {"\U00002728", "Sparkles"}, // ✨ + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002795", "Heavy Plus Sign"}, // ➕ + + // Miscellaneous Symbols + {"\U00002600", "Sun"}, // ☀️ + {"\U00002614", "Umbrella with Rain Drops"}, // ☔ + {"\U00002620", "Skull and Crossbones"}, // ☠️ + {"\U000026A0", "Warning Sign"}, // ⚠️ + {"\U000026BD", "Soccer Ball"}, // ⚽ + {"\U000026C4", "Snowman"}, // ⛄ + + // Stars and Asterisks + {"\U00002733", "Eight Pointed Black Star"}, // ✳️ + {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U00002728", "Sparkles"}, // ✨ + // Animals and Nature + {"\U0001F98A", "Fox"}, // 🦊 + {"\U0001F415", "Dog"}, // 🐕 + {"\U0001F431", "Cat Face"}, // 🐱 + {"\U0001F435", "Monkey Face"}, // 🐵 + {"\U0001F408", "Black Cat"}, // 🐈 + {"\U0001F98C", "Deer"}, // 🦌 + {"\U0001F344", "Mushroom"}, // 🍄 + {"\U0001F333", "Tree"}, // 🌳 + + // Weather and Space Symbols + {"\U0001F308", "Rainbow"}, // 🌈 + {"\U0001F320", "Shooting Star"}, // 🌠 + {"\U00002600", "Sun"}, // ☀️ + {"\U00002601", "Cloud"}, // ☁️ + {"\U000026A1", "High Voltage"}, // ⚡ + {"\U0001F525", "Fire"}, // 🔥 + {"\U000026C4", "Snowman"}, // ⛄ + {"\U0001F30A", "Water Wave"}, // 🌊 + + // Transport and Map Symbols + {"\U0001F68C", "Bus"}, // 🚌 + {"\U0001F697", "Car"}, // 🚗 + {"\U0001F6B2", "Bicycle"}, // 🚲 + {"\U0001F6A2", "Ship"}, // 🚢 + {"\U0001F681", "Helicopter"}, // 🚁 + {"\U0001F680", "Rocket"}, // 🚀 + {"\U0001F6EB", "Airplane"}, // 🛫 + + // Currency Symbols + {"\U00000024", "Dollar Sign"}, // $ + {"\U000000A3", "Pound Sign"}, // £ + {"\U000000A5", "Yen Sign"}, // ¥ + {"\U000020AC", "Euro Sign"}, // € + {"\U0001F4B5", "Dollar Banknote"}, // 💵 + {"\U0001F4B4", "Yen Banknote"}, // 💴 + + // Card Suits + {"\U00002660", "Black Spade Suit"}, // ♠️ + {"\U00002663", "Black Club Suit"}, // ♣️ + {"\U00002665", "Black Heart Suit"}, // ♥️ + {"\U00002666", "Black Diamond Suit"}, // ♦️ + {"\U0001F0CF", "Joker Card"}, // 🃏 + + // Office Supplies and Objects + {"\U0001F4DA", "Books"}, // 📚 + {"\U0001F4D7", "Green Book"}, // 📗 + {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 + {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 + {"\U0001F4B0", "Money Bag"}, // 💰 + {"\U0001F4B8", "Money with Wings"}, // 💸 + {"\U0001F4E6", "Package"}, // 📦 + + // Miscellaneous Symbols + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U00002714", "Check Mark"}, // ✔️ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002705", "Check Mark Button"}, // ✅ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U0001F4A1", "Light Bulb"}, // 💡 + {"\U0001F4A3", "Bomb"}, // 💣 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + // Musical Symbols + {"\U0001F3B5", "Musical Note"}, // 🎵 + {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 + {"\U0001F3BC", "Musical Score"}, // 🎼 + {"\U0001F399", "Studio Microphone"}, // 🎙️ + {"\U0001F3A4", "Microphone"}, // 🎤 + + // Food and Drink + {"\U0001F35F", "Cheese Wedge"}, // 🧀 + {"\U0001F355", "Slice of Pizza"}, // 🍕 + {"\U0001F32D", "Taco"}, // 🌮 + {"\U0001F37D", "Beer Mug"}, // 🍻 + {"\U0001F96B", "Cup with Straw"}, // 🥤 + {"\U0001F32E", "Hot Pepper"}, // 🌶️ + {"\U0001F95A", "Potato"}, // 🥔 + + // Zodiac Signs + {"\U00002600", "Aries"}, // ♈ + {"\U00002601", "Taurus"}, // ♉ + {"\U00002602", "Gemini"}, // ♊ + {"\U00002603", "Cancer"}, // ♋ + {"\U00002604", "Leo"}, // ♌ + {"\U00002605", "Virgo"}, // ♍ + {"\U00002606", "Libra"}, // ♎ + {"\U00002607", "Scorpio"}, // ♏ + {"\U00002608", "Sagittarius"}, // ♐ + {"\U00002609", "Capricorn"}, // ♑ + {"\U0000260A", "Aquarius"}, // ♒ + {"\U0000260B", "Pisces"}, // ♓ + + // Miscellaneous Shapes + {"\U0001F4C8", "Chart Increasing"}, // 📈 + {"\U0001F4C9", "Chart Decreasing"}, // 📉 + {"\U0001F4CA", "Bar Chart"}, // 📊 + {"\U0001F7E6", "Orange Circle"}, // 🟠 + {"\U0001F7E7", "Yellow Circle"}, // 🟡 + {"\U0001F7E8", "Green Circle"}, // 🟢 + {"\U0001F7E9", "Blue Circle"}, // 🔵 + {"\U0001F7EA", "Purple Circle"}, // 🟣 + + // Flags + {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 + + // Additional Miscellaneous Symbols + {"\U0001F4A5", "Collision"}, // 💥 + {"\U0001F4A6", "Sweat Droplets"}, // 💦 + {"\U0001F4A8", "Dashing Away"}, // 💨 + {"\U0001F50B", "Battery"}, // 🔋 + {"\U0001F4BB", "Laptop Computer"}, // 💻 + {"\U0001F4DE", "Telephone"}, // 📞 + {"\U0001F4E7", "Incoming Envelope"}, // 📧 +}; +size_t remo_count = sizeof(remo) / sizeof(remo[0]); + +void rstrtolower(const char *input, char *output) { + while (*input) { + *output = tolower(*input); + input++; + output++; + } + *output = 0; +} +bool rstrinstr(const char *haystack, const char *needle) { + char lower1[strlen(haystack) + 1]; + char lower2[strlen(needle) + 1]; + rstrtolower(haystack, lower1); + rstrtolower(needle, lower2); + return strstr(lower1, lower2) ? true : false; +} + +void remo_print() { + + for (size_t i = 0; i < remo_count; i++) { + printf("%s - %s\n", remo[i].str, remo[i].description); + } +} + +const char *remo_get(char *name) { + for (size_t i = 0; i < remo_count; i++) { + if (rstrinstr(remo[i].description, name)) { + return remo[i].str; + } + } + return NULL; +} + +#endif +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#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%s\n", rmalloc_stats(), rmalloc_count == 0 ? remo_get("rainbow") : "fire"); + + if (rmalloc_count != 0) { + printf("MEMORY ERROR %s\n", remo_get("cross mark")); + 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, "%s", remo_get("Slightly Smiling Face")); + return true; + } + rprintrf(stderr, "\nERROR %s on line %d: %s\n", remo_get("skull"), 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); } +void rtest_test_assert(char *expr, int res, int line) { + if (rtest_test_true(expr, res, line)) { + return; + } + 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 + +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; + +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; + } +} + +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; + +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; +} + +void rprogressbar_free(rprogressbar_t *pbar) { free(pbar); } + +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; + } + 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, " "); + } + strcat(content, "\r"); + } + fprintf(pbar->fout, "%s", content); + fflush(pbar->fout); +} + +bool rprogressbar_update(rprogressbar_t *pbar, unsigned long value) { + if (value == pbar->current_value) { + return false; + } + 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; +} + +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 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); +} + +#endif + +#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 { +#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; + + nsecs_t average_execution_time; + nsecs_t total_execution_time; +} rbench_function_t; + +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); + +} 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; + } + } +} +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; + } +} + +rbench_t *rbench_new(); + +rbench_t *_rbench = NULL; +rbench_function_t *rbf; +rbench_t *rbench() { + if (_rbench == NULL) { + _rbench = rbench_new(); + } + return _rbench; +} + +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 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]); + } +} +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; +} + +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); + 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; + ; + // 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; +} +struct rbench_t *rbench_execute(rbench_t *r, long times) { + + for (unsigned int i = 0; i < r->function_count; i++) { + + 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; +} + +struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { + + 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); + } + return r; +} + +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; +} + +struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { + + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); + + 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; +} + +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; +} +void rbench_free(rbench_t *r) { free(r); } + +#endif +bool check_lcov() { + char buffer[1024 * 64]; + FILE *fp; + fp = popen("lcov --help", "r"); + if (fp == NULL) { + return false; + } + if (fgets(buffer, sizeof(buffer), fp) == NULL) { + return false; + } + pclose(fp); + return strstr(buffer, "lcov: not found") ? false : true; +} + +int rcov_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [source.c]\n"); + return 1; + } + char argstr[4096] = {0}; + for (int i = 2; i < argc; i++) { + strcat(argstr, argv[i]); + strcat(argstr, " "); + } + if (!check_lcov()) { + + printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); + return 1; + } + char *source_file = argv[1]; + char *commands[] = {"rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", + "gcc -pg -fprofile-arcs -ftest-coverage -g -o %s_coverage.o %s", + "./%s_coverage.o", + "lcov --capture --directory . --output-file %s.coverage.info", + "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", + "rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", + + "gprof %s_coverage.o gmon.out > output.rcov_analysis", + + "rm -f gmon.out", + "cat output.rcov_analysis", + "rm output.rcov_analysis", + "rm -f %s_coverage.o", + + "google-chrome /tmp/%s.coverage/index.html"}; + uint command_count = sizeof(commands) / sizeof(commands[0]); + RBENCH(1,{ + for (uint i = 0; i < command_count; i++) { + char *formatted_command = sbuf(""); + sprintf(formatted_command, commands[i], source_file, source_file); + // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { + strcat(formatted_command, " "); + strcat(formatted_command, argstr); + } + + if (system(formatted_command)) { + printf("`%s` returned non-zero code.\n", formatted_command); + } + }); + } + return 0; +} +#endif + +#ifndef RHTTP_H +#define RHTTP_H +#include <arpa/inet.h> +#include <pthread.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#define BUFF_SIZE 8096 +#define RHTTP_MAX_CONNECTIONS 100 + +int rhttp_opt_error = 1; +int rhttp_opt_warn = 1; +int rhttp_opt_info = 1; +int rhttp_opt_port = 8080; +int rhttp_opt_debug = 0; +int rhttp_opt_request_logging = 0; +int rhttp_sock = 0; +int rhttp_opt_buffered = 0; +int rhttp_c = 0; +int rhttp_c_mutex_initialized = 0; +pthread_mutex_t rhttp_c_mutex; +char rhttp_opt_host[1024] = "0.0.0.0"; +unsigned int rhttp_connections_handled = 0; + +typedef struct rhttp_header_t { + char *name; + char *value; + struct rhttp_header_t *next; +} rhttp_header_t; + +typedef struct rhttp_request_t { + int c; + int closed; + bool keep_alive; + nsecs_t start; + char *raw; + char *line; + char *body; + char *method; + char *path; + char *version; + void *context; + unsigned int bytes_received; + rhttp_header_t *headers; +} rhttp_request_t; + +char *rhttp_current_timestamp() { + time_t current_time; + time(¤t_time); + struct tm *local_time = localtime(¤t_time); + static char time_string[100]; + time_string[0] = 0; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); + + return time_string; +} + +void rhttp_logs(const char *prefix, const char *level, const char *format, va_list args) { + char buf[strlen(format) + BUFSIZ + 1]; + buf[0] = 0; + sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); + vfprintf(stdout, buf, args); +} +void rhttp_log_info(const char *format, ...) { + if (!rhttp_opt_info) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[32m", "INFO ", format, args); + va_end(args); +} +void rhttp_log_debug(const char *format, ...) { + if (!rhttp_opt_debug) + return; + va_list args; + va_start(args, format); + if (rhttp_opt_debug) + rhttp_logs("\e[33m", "DEBUG", format, args); + + va_end(args); +} +void rhttp_log_warn(const char *format, ...) { + if (!rhttp_opt_warn) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[34m", "WARN ", format, args); + + va_end(args); +} +void rhttp_log_error(const char *format, ...) { + if (!rhttp_opt_error) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[35m", "ERROR", format, args); + + va_end(args); +} + +void http_request_init(rhttp_request_t *r) { + r->raw = NULL; + r->line = NULL; + r->body = NULL; + r->method = NULL; + r->path = NULL; + r->version = NULL; + r->start = 0; + r->headers = NULL; + r->bytes_received = 0; + r->closed = 0; +} + +void rhttp_free_header(rhttp_header_t *h) { + if (!h) + return; + rhttp_header_t *next = h->next; + free(h->name); + free(h->value); + free(h); + if (next) + rhttp_free_header(next); +} +void rhttp_rhttp_free_headers(rhttp_request_t *r) { + if (!r->headers) + return; + rhttp_free_header(r->headers); + r->headers = NULL; +} + +rhttp_header_t *rhttp_parse_headers(rhttp_request_t *s) { + int first = 1; + char *body = strdup(s->body); + char *body_original = body; + while (body && *body) { + char *line = __strtok_r(first ? body : NULL, "\r\n", &body); + if (!line) + break; + rhttp_header_t *h = (rhttp_header_t *)malloc(sizeof(rhttp_header_t)); + h->name = NULL; + h->value = NULL; + h->next = NULL; + char *name = __strtok_r(line, ": ", &line); + first = 0; + if (!name) { + rhttp_free_header(h); + break; + } + h->name = strdup(name); + char *value = __strtok_r(NULL, "\r\n", &line); + if (!value) { + rhttp_free_header(h); + break; + } + h->value = value ? strdup(value + 1) : strdup(""); + h->next = s->headers; + s->headers = h; + } + free(body_original); + return s->headers; +} + +void rhttp_free_request(rhttp_request_t *r) { + if (r->raw) { + free(r->raw); + free(r->body); + free(r->method); + free(r->path); + free(r->version); + rhttp_rhttp_free_headers(r); + } + free(r); +} + +long rhttp_header_get_long(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return strtol(h->value, NULL, 10); + h = h->next; + } + return -1; +} +char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return h->value && *h->value ? h->value : NULL; + h = h->next; + } + return NULL; +} + +void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } +void rhttp_print_headers(rhttp_header_t *h) { + while (h) { + rhttp_print_header(h); + h = h->next; + } +} +void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } +void rhttp_print_request(rhttp_request_t *r) { + rhttp_print_request_line(r); + if (rhttp_opt_debug) + rhttp_print_headers(r->headers); +} +void rhttp_close(rhttp_request_t *r) { + if (!r) + return; + if (!r->closed) + close(r->c); + rhttp_free_request(r); +} +rhttp_request_t *rhttp_parse_request(int s) { + rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); + http_request_init(request); + char buf[BUFF_SIZE] = {0}; + request->c = s; + int breceived = 0; + while (!rstrendswith(buf, "\r\n\r\n")) { + int chunk_size = read(s, buf + breceived, 1); + if (chunk_size <= 0) { + close(request->c); + request->closed = 1; + return request; + } + breceived += chunk_size; + } + if (breceived <= 0) { + close(request->c); + request->closed = 1; + return request; + } + buf[breceived] = '\0'; + char *original_buf = buf; + + char *b = original_buf; + request->raw = strdup(b); + b = original_buf; + char *line = strtok(b, "\r\n"); + b = original_buf; + char *body = b + strlen(line) + 2; + request->body = strdup(body); + b = original_buf; + char *method = strtok(b, " "); + char *path = strtok(NULL, " "); + char *version = strtok(NULL, " "); + request->bytes_received = breceived; + request->line = line; + request->start = nsecs(); + request->method = strdup(method); + request->path = strdup(path); + request->version = strdup(version); + request->headers = NULL; + request->keep_alive = false; + if (rhttp_parse_headers(request)) { + char *keep_alive_string = rhttp_header_get_string(request, "Connection"); + if (keep_alive_string && !strcmp(keep_alive_string, "keep-alive")) { + request->keep_alive = 1; + } + } + return request; +} + +void rhttp_close_server() { + close(rhttp_sock); + close(rhttp_c); + printf("Connections handled: %d\n", rhttp_connections_handled); + printf("Gracefully closed\n"); + exit(0); +} + +size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { + if (to_send_len == 0 && *(unsigned char *)tsend) { + to_send_len = strlen(tsend); + } + unsigned char *to_send = (unsigned char *)malloc(to_send_len); + unsigned char *to_send_original = to_send; + + memcpy(to_send, tsend, to_send_len); + // to_send[to_send_len] = '\0'; + long bytes_sent = 0; + long bytes_sent_total = 0; + while (1) { + bytes_sent = send(s, to_send + bytes_sent_total, to_send_len - bytes_sent_total, 0); + if (bytes_sent <= 0) { + bytes_sent_total = 0; + break; + } + bytes_sent_total += bytes_sent; + + if (bytes_sent_total == (long)to_send_len) { + break; + } else if (!bytes_sent) { + bytes_sent_total = 0; + // error + break; + } else { + rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); + } + } + + free(to_send_original); + return bytes_sent_total; +} + +typedef int (*rhttp_request_handler_t)(rhttp_request_t *r); + +void rhttp_serve(const char *host, int port, int backlog, int request_logging, int request_debug, rhttp_request_handler_t handler, + void *context) { + signal(SIGPIPE, SIG_IGN); + rhttp_sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(host ? host : "0.0.0.0"); + rhttp_opt_debug = request_debug; + rhttp_opt_request_logging = request_logging; + int opt = 1; + setsockopt(rhttp_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (bind(rhttp_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + printf("Binding error\n"); + exit(1); + } + listen(rhttp_sock, backlog); + while (1) { + struct sockaddr_in client_addr; + int addrlen = sizeof(client_addr); + + rhttp_c = accept(rhttp_sock, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen); + + rhttp_connections_handled++; + while (true) { + rhttp_request_t *r = rhttp_parse_request(rhttp_c); + r->context = context; + if (!r->closed) { + if (!handler(r) && !r->closed) { + rhttp_close(r); + } + } + if (!r->keep_alive && !r->closed) { + rhttp_close(r); + } else if (r->keep_alive && !r->closed) { + } + if (r->closed) { + break; + } + rhttp_free_request(r); + } + } +} + +unsigned int rhttp_calculate_number_char_count(unsigned int number) { + unsigned int width = 1; + unsigned int tcounter = number; + while (tcounter / 10 >= 1) { + tcounter = tcounter / 10; + width++; + } + return width; +} + +int rhttp_file_response(rhttp_request_t *r, char *path) { + if (!*path) + return 0; + FILE *f = fopen(path, "rb"); + if (f == NULL) + return 0; + size_t file_size = rfile_size(path); + char response[1024] = {0}; + char content_type_header[100] = {0}; + char *ext = strstr(path, "."); + char *text_extensions = ".h,.c,.html"; + if (strstr(text_extensions, ext)) { + sprintf(content_type_header, "Content-Type: %s\r\n", "text/html"); + } + sprintf(response, "HTTP/1.1 200 OK\r\n%sContent-Length:%ld\r\n\r\n", content_type_header, file_size); + if (!rhttp_send_drain(r->c, response, 0)) { + rhttp_log_error("Error sending file: %s\n", path); + } + size_t bytes = 0; + size_t bytes_sent = 0; + unsigned char file_buff[1024]; + while ((bytes = fread(file_buff, sizeof(char), sizeof(file_buff), f))) { + if (!rhttp_send_drain(r->c, file_buff, bytes)) { + rhttp_log_error("Error sending file during chunking: %s\n", path); + } + bytes_sent += bytes; + } + if (bytes_sent != file_size) { + rhttp_send_drain(r->c, file_buff, file_size - bytes_sent); + } + close(r->c); + fclose(f); + return 1; +}; + +int rhttp_file_request_handler(rhttp_request_t *r) { + char *path = r->path; + while (*path == '/' || *path == '.') + path++; + if (strstr(path, "..")) { + return 0; + } + return rhttp_file_response(r, path); +}; + +unsigned int counter = 100000000; +int rhttp_counter_request_handler(rhttp_request_t *r) { + if (!strncmp(r->path, "/counter", strlen("/counter"))) { + counter++; + unsigned int width = rhttp_calculate_number_char_count(counter); + char to_send2[1024] = {0}; + sprintf(to_send2, + "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nConnection: " + "close\r\n\r\n%d", + width, counter); + rhttp_send_drain(r->c, to_send2, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_root_request_handler(rhttp_request_t *r) { + if (!strcmp(r->path, "/")) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 200 OK\r\nContent-Length: 3\r\nConnection: " + "close\r\n\r\nOk!"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_error_404_handler(rhttp_request_t *r) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " + "0\r\nConnection: close\r\n\r\n"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; +} + +int rhttp_default_request_handler(rhttp_request_t *r) { + if (rhttp_opt_debug || rhttp_opt_request_logging) + rhttp_print_request(r); + if (rhttp_counter_request_handler(r)) { + // Counter handler + rhttp_log_info("Counter handler found for: %s\n", r->path); + + } else if (rhttp_root_request_handler(r)) { + // Root handler + rhttp_log_info("Root handler found for: %s\n", r->path); + } else if (rhttp_file_request_handler(r)) { + rhttp_log_info("File %s sent\n", r->path); + } else if (rhttp_error_404_handler(r)) { + rhttp_log_warn("Error 404 for: %s\n", r->path); + // Error handler + } else { + rhttp_log_warn("No handler found for: %s\n", r->path); + close(rhttp_c); + } + return 0; +} + +int rhttp_main(int argc, char *argv[]) { + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); + int opt; + while ((opt = getopt(argc, argv, "p:drh:bewi")) != -1) { + switch (opt) { + case 'i': + rhttp_opt_info = 1; + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + break; + case 'e': + rhttp_opt_error = 1; + rhttp_opt_warn = 0; + rhttp_opt_info = 0; + break; + case 'w': + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + rhttp_opt_info = 0; + break; + case 'p': + rhttp_opt_port = atoi(optarg); + break; + case 'b': + rhttp_opt_buffered = 1; + printf("Logging is buffered. Output may be incomplete.\n"); + break; + case 'h': + strcpy(rhttp_opt_host, optarg); + break; + case 'd': + printf("Debug enabled\n"); + rhttp_opt_debug = 1; + rhttp_opt_warn = 1; + rhttp_opt_info = 1; + rhttp_opt_error = 1; + break; + case 'r': + printf("Request logging enabled\n"); + rhttp_opt_request_logging = 1; + break; + default: + printf("Usage: %s [-p port] [-h host] [-b]\n", argv[0]); + return 1; + } + } + + printf("Starting server on: %s:%d\n", rhttp_opt_host, rhttp_opt_port); + if (rhttp_opt_buffered) + setvbuf(stdout, NULL, _IOFBF, BUFSIZ); + + rhttp_serve(rhttp_opt_host, rhttp_opt_port, 1024, rhttp_opt_request_logging, rhttp_opt_debug, rhttp_default_request_handler, NULL); + + return 0; +} + +/* CLIENT CODE */ + +typedef struct rhttp_client_request_t { + char *host; + int port; + char *path; + bool is_done; + char *request; + char *response; + pthread_t thread; + int bytes_received; +} rhttp_client_request_t; + +rhttp_client_request_t *rhttp_create_request(const char *host, int port, const char *path) { + rhttp_client_request_t *r = (rhttp_client_request_t *)malloc(sizeof(rhttp_client_request_t)); + char request_line[4096] = {0}; + sprintf(request_line, + "GET %s HTTP/1.1\r\n" + "Host: localhost:8000\r\n" + "Connection: close\r\n" + "Accept: */*\r\n" + "User-Agent: mhttpc\r\n" + "Accept-Language: en-US,en;q=0.5\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "\r\n", + path); + r->request = strdup(request_line); + r->host = strdup(host); + r->port = port; + r->path = strdup(path); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; + return r; +} + +int rhttp_execute_request(rhttp_client_request_t *r) { + int s = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(r->port); + addr.sin_addr.s_addr = inet_addr(r->host); + + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return 0; + } + + send(s, r->request, strlen(r->request), 0); + char buf[1024 * 1024] = {0}; + int ret = recv(s, buf, 1024 * 1024, 0); + if (ret > 0) { + r->response = strdup(buf); + } + + close(s); + return ret; +} +void rhttp_reset_request(rhttp_client_request_t *r) { + free(r->response); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; +} +void rhttp_free_client_request(rhttp_client_request_t *r) { + if (r->request) + free(r->request); + if (r->response) + free(r->response); + if (r->host) + free(r->host); + if (r->path) + free(r->path); + free(r); +} + +void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { + rhttp_client_request_t *requests[workers]; + while (times > 0) { + + for (int i = 0; i < workers && times; i++) { + requests[i] = rhttp_create_request(host, port, path); + rhttp_execute_request(requests[i]); + times--; + } + } +} +char *rhttp_client_get(const char *host, int port, const char *path) { + if (!rhttp_c_mutex_initialized) { + rhttp_c_mutex_initialized = 1; + pthread_mutex_init(&rhttp_c_mutex, NULL); + } + char http_response[1024 * 1024]; + http_response[0] = 0; + rhttp_client_request_t *r = rhttp_create_request(host, port, path); + unsigned int reconnects = 0; + unsigned int reconnects_max = 100000; + while (!rhttp_execute_request(r)) { + reconnects++; + tick(); + if (reconnects == reconnects_max) { + fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + rhttp_free_client_request(r); + return NULL; + } + } + r->is_done = true; + char *body = r->response ? strstr(r->response, "\r\n\r\n") : NULL; + pthread_mutex_lock(&rhttp_c_mutex); + if (body) { + strcpy(http_response, body + 4); + } else { + strcpy(http_response, r->response); + } + rhttp_free_client_request(r); + char *result = sbuf(http_response); + pthread_mutex_unlock(&rhttp_c_mutex); + return result; +} +/*END CLIENT CODE */ +#endif + +#ifndef RJSON_H +#define RJSON_H + +typedef struct rjson_t { + char *content; + size_t length; + size_t size; +} rjson_t; + +rjson_t *rjson() { + rjson_t *json = rmalloc(sizeof(rjson_t)); + json->size = 1024; + json->length = 0; + json->content = (char *)rmalloc(json->size); + json->content[0] = 0; + return json; +} + +void rjson_write(rjson_t *rjs, char *content) { + size_t len = strlen(content); + while (rjs->size < rjs->length + len + 1) { + rjs->content = realloc(rjs->content, rjs->size + 1024); + rjs->size += 1024; + } + strcat(rjs->content, content); + rjs->length += len; +} + +void rjson_object_start(rjson_t *rjs) { + if (rstrendswith(rjs->content, "}")) + rjson_write(rjs, ","); + rjson_write(rjs, "{"); +} +void rjson_object_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "}"); +} +void rjson_array_start(rjson_t *rjs) { + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + rjson_write(rjs, ","); + rjson_write(rjs, "["); +} +void rjson_array_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "]"); +} + +void rjson_kv_string(rjson_t *rjs, char *key, char *value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":\""); + char *value_str = (char *)rmalloc(strlen(value) + 4096); + rstraddslashes(value, value_str); + rjson_write(rjs, value_str); + free(value_str); + rjson_write(rjs, "\""); +} + +void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + char value_str[100] = {0}; + sprintf(value_str, "%lld", value); + rjson_write(rjs, value_str); +} +void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(rformat_number(value))); + rjson_write(rjs, "\""); +} + +void rjson_kv_bool(rjson_t *rjs, char *key, int value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, value > 0 ? "true" : "false"); +} + +void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(format_time(value))); + rjson_write(rjs, "\""); +} +void rjson_free(rjson_t *rsj) { + free(rsj->content); + free(rsj); +} + +void rjson_key(rjson_t *rsj, char *key) { + rjson_write(rsj, "\""); + rjson_write(rsj, key); + rjson_write(rsj, "\":"); +} +#endif +#ifndef RAUTOCOMPLETE_H +#define RAUTOCOMPLETE_H +#define R4_DEBUG +#ifndef RREX4_H +#define RREX4_H +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define R4_DEBUG_a + +#ifdef R4_DEBUG +static int _r4_debug = 1; +#else +static int _r4_debug = 0; +#endif + +static char *_format_function_name(const char *name) { + static char result[100]; + result[0] = 0; + + char *new_name = (char *)name; + new_name += 11; + if (new_name[0] == '_') + new_name += 1; + if (strlen(new_name) == 0) { + return " -"; + } + strcpy(result, new_name); + return result; +} + +#define DEBUG_VALIDATE_FUNCTION \ + if (_r4_debug || r4->debug) \ + printf("DEBUG: %s %s <%s> \"%s\"\n", _format_function_name(__func__), r4->valid ? "valid" : "INVALID", r4->expr, r4->str); + +struct r4_t; + +void r4_enable_debug() { _r4_debug = true; } +void r4_disable_debug() { _r4_debug = false; } + +typedef bool (*r4_function)(struct r4_t *); + +typedef struct r4_t { + bool debug; + bool valid; + bool in_block; + bool is_greedy; + bool in_range; + unsigned int backtracking; + unsigned int loop_count; + unsigned int in_group; + unsigned int match_count; + unsigned int validation_count; + unsigned int start; + unsigned int end; + unsigned int length; + bool (*functions[254])(struct r4_t *); + bool (*slash_functions[254])(struct r4_t *); + char *_str; + char *_expr; + char *match; + char *str; + char *expr; + char *str_previous; + char *expr_previous; + char **matches; +} r4_t; + +static bool v4_initiated = false; +typedef bool (*v4_function_map)(r4_t *); +v4_function_map v4_function_map_global[256]; +v4_function_map v4_function_map_slash[256]; +v4_function_map v4_function_map_block[256]; + +void r4_free_matches(r4_t *r) { + if (!r) + return; + if (r->match) { + free(r->match); + r->match = NULL; + } + if (!r->match_count) { + return; + } + for (unsigned i = 0; i < r->match_count; i++) { + free(r->matches[i]); + } + free(r->matches); + r->match_count = 0; + r->matches = NULL; +} + +void r4_free(r4_t *r) { + if (!r) + return; + r4_free_matches(r); + free(r); +} + +static bool r4_backtrack(r4_t *r4); +static bool r4_validate(r4_t *r4); +static void r4_match_add(r4_t *r4, char *extracted); + +static bool r4_validate_literal(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!r4->valid) + return false; + if (*r4->str != *r4->expr) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_question_mark(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = true; + r4->expr++; + return r4_validate(r4); +} + +static bool r4_validate_plus(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == false) { + return r4_validate(r4); + } + char *expr_left = r4->expr_previous; + char *expr_right = r4->expr; + char *str = r4->str; + char *return_expr = NULL; + if (*expr_right == ')') { + return_expr = expr_right; + expr_right++; + } + r4->is_greedy = false; + r4->expr = expr_left; + while (r4->valid) { + if (*expr_right) { + r4->expr = expr_right; + r4->is_greedy = true; + if (r4_backtrack(r4)) { + + if (return_expr) { + r4->str = str; + r4->expr = return_expr; + } + return r4_validate(r4); + } else { + r4->is_greedy = false; + } + } + r4->valid = true; + r4->expr = expr_left; + r4->str = str; + r4_validate(r4); + str = r4->str; + } + r4->is_greedy = true; + r4->valid = true; + r4->expr = return_expr ? return_expr : expr_right; + return r4_validate(r4); +} + +static bool r4_validate_dollar(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + r4->valid = *r4->str == 0; + return r4_validate(r4); +} + +static bool r4_validate_roof(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (r4->str != r4->_str) { + return false; + } + r4->expr++; + return r4_validate(r4); +} + +static bool r4_validate_dot(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (*r4->str == 0) { + return false; + } + r4->expr++; + r4->valid = *r4->str != '\n'; + r4->str++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_asterisk(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == false) { + r4->valid = true; + return r4->valid; + // return r4_validate(r4); + } + char *expr_left = r4->expr_previous; + char *expr_right = r4->expr; + char *str = r4->str; + char *return_expr = NULL; + if (*expr_right == ')') { + return_expr = expr_right; + expr_right++; + } + r4->is_greedy = false; + r4->expr = expr_left; + while (r4->valid) { + if (*expr_right) { + r4->expr = expr_right; + r4->is_greedy = true; + if (r4_backtrack(r4)) { + + if (return_expr) { + r4->str = str; + r4->expr = return_expr; + } + return r4_validate(r4); + } else { + r4->is_greedy = false; + } + } + r4->valid = true; + r4->expr = expr_left; + r4->str = str; + r4_validate(r4); + str = r4->str; + } + r4->is_greedy = true; + r4->valid = true; + r4->expr = return_expr ? return_expr : expr_right; + return r4_validate(r4); +} + +static bool r4_validate_pipe(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == true) { + return true; + } else { + r4->valid = true; + } + return r4_validate(r4); +} + +static bool r4_validate_digit(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!isdigit(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_digit(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (isdigit(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_word(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!isalpha(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_word(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (isalpha(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_isrange(char *s) { + if (!isalnum(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isalnum(*(s + 2)); +} + +static bool r4_validate_block_open(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (r4->valid == false) { + return false; + } + char *expr_self = r4->expr; + r4->expr++; + bool reversed = *r4->expr == '^'; + if (reversed) { + r4->expr++; + } + + bool valid_once = false; + r4->in_block = true; + while (*r4->expr != ']') { + r4->valid = true; + if (r4_isrange(r4->expr)) { + char s = *r4->expr; + char e = *(r4->expr + 2); + r4->expr += 2; + if (s > e) { + char tempc = s; + s = e; + e = tempc; + } + if (*r4->str >= s && *r4->str <= e) { + if (!reversed) { + r4->str++; + } + valid_once = true; + break; + } else { + r4->expr++; + } + } else if (r4_validate(r4)) { + valid_once = true; + if (reversed) + r4->str--; + break; + } + } + char *expr_end = strchr(r4->expr, ']'); + + r4->expr = expr_end ? expr_end : r4->expr; + r4->in_block = false; + r4->valid = expr_end && (!reversed ? valid_once : !valid_once); + r4->expr++; + r4->expr_previous = expr_self; + + if (r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_whitespace(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = strchr("\r\t \n", *r4->str) != NULL; + r4->expr++; + if (r4->valid) { + r4->str++; + } + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_whitespace(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = strchr("\r\t \n", *r4->str) == NULL; + r4->expr++; + if (r4->valid) { + r4->str++; + } + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_range(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION; + if (r4->valid == false) { + r4->expr++; + return false; + } + char *previous = r4->expr_previous; + r4->in_range = true; + r4->expr++; + unsigned int start = 0; + while (isdigit(*r4->expr)) { + start = 10 * start; + start += *r4->expr - '0'; + r4->expr++; + } + if (start != 0) + start--; + + unsigned int end = 0; + bool variable_end_range = false; + if (*r4->expr == ',') { + r4->expr++; + if (!isdigit(*r4->expr)) { + variable_end_range = true; + } + } + while (isdigit(*r4->expr)) { + end = end * 10; + end += *r4->expr - '0'; + r4->expr++; + } + r4->expr++; + + bool valid = true; + char *expr_right = r4->expr; + for (unsigned int i = 0; i < start; i++) { + r4->expr = previous; + valid = r4_validate(r4); + if (!*r4->str) + break; + if (!valid) { + break; + } + } + r4->expr = expr_right; + r4->in_range = false; + if (!r4->valid) + return false; + return r4_validate(r4); + + for (unsigned int i = start; i < end; i++) { + r4->expr = previous; + valid = r4_validate(r4); + if (!valid) { + break; + } + } + + while (variable_end_range) { + r4->in_range = false; + valid = r4_validate(r4); + r4->in_range = true; + if (valid) { + break; + } + r4->in_range = true; + valid = r4_validate(r4); + r4->in_range = false; + if (!valid) { + break; + } + } + r4->valid = valid; + + return r4_validate(r4); +} + +static bool r4_validate_group_close(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + return r4->valid; +} + +static bool r4_validate_group_open(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + char *expr_previous = r4->expr_previous; + r4->expr++; + bool save_match = r4->in_group == 0; + r4->in_group++; + char *str_extract_start = r4->str; + bool valid = r4_validate(r4); + + if (!valid || *r4->expr != ')') { + // this is a valid case if not everything between () matches + r4->in_group--; + if (save_match == false) { + r4->valid = true; + } + + // Not direct return? Not sure + return r4_validate(r4); + } + // if(save_match){ + // r4->match_count++; + // } + if (save_match) { + char *str_extract_end = r4->str; + unsigned int extracted_length = str_extract_end - str_extract_start; + // strlen(str_extract_start) - strlen(str_extract_end); + char *str_extracted = (char *)calloc(sizeof(char), extracted_length + 1); + strncpy(str_extracted, str_extract_start, extracted_length); + r4_match_add(r4, str_extracted); + } + assert(*r4->expr == ')'); + r4->expr++; + r4->in_group--; + r4->expr_previous = expr_previous; + return r4_validate(r4); +} + +static bool r4_validate_slash(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + // The handling code for handling slashes is implemented in r4_validate + char *expr_previous = r4->expr_previous; + r4->expr++; + r4_function f = v4_function_map_slash[(int)*r4->expr]; + r4->expr_previous = expr_previous; + return f(r4); +} + +static void r4_match_add(r4_t *r4, char *extracted) { + r4->matches = (char **)realloc(r4->matches, (r4->match_count + 1) * sizeof(char *)); + r4->matches[r4->match_count] = extracted; + r4->match_count++; +} + +static bool r4_validate_word_boundary_start(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (!r4->valid) { + return r4->valid; + } + r4->valid = isalpha(*r4->str) && (r4->str == r4->_str || !isalpha(*(r4->str - 1))); + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_word_boundary_end(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (!r4->valid) { + return r4->valid; + } + r4->valid = isalpha(*r4->str) && (*(r4->str + 1) == 0 || !isalpha(*(r4->str + 1))); + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static void v4_init_function_maps() { + if (v4_initiated) + return; + v4_initiated = true; + for (__uint8_t i = 0; i < 255; i++) { + v4_function_map_global[i] = r4_validate_literal; + v4_function_map_slash[i] = r4_validate_literal; + v4_function_map_block[i] = r4_validate_literal; + } + v4_function_map_global['*'] = r4_validate_asterisk; + v4_function_map_global['?'] = r4_validate_question_mark; + v4_function_map_global['+'] = r4_validate_plus; + v4_function_map_global['$'] = r4_validate_dollar; + v4_function_map_global['^'] = r4_validate_roof; + v4_function_map_global['.'] = r4_validate_dot; + v4_function_map_global['|'] = r4_validate_pipe; + v4_function_map_global['\\'] = r4_validate_slash; + v4_function_map_global['['] = r4_validate_block_open; + v4_function_map_global['{'] = r4_validate_range; + v4_function_map_global['('] = r4_validate_group_open; + v4_function_map_global[')'] = r4_validate_group_close; + v4_function_map_slash['b'] = r4_validate_word_boundary_start; + v4_function_map_slash['B'] = r4_validate_word_boundary_end; + v4_function_map_slash['d'] = r4_validate_digit; + v4_function_map_slash['w'] = r4_validate_word; + v4_function_map_slash['D'] = r4_validate_not_digit; + v4_function_map_slash['W'] = r4_validate_not_word; + v4_function_map_slash['s'] = r4_validate_whitespace; + v4_function_map_slash['S'] = r4_validate_not_whitespace; + v4_function_map_block['\\'] = r4_validate_slash; + + v4_function_map_block['{'] = r4_validate_range; +} + +void r4_init(r4_t *r4) { + v4_init_function_maps(); + if (r4 == NULL) + return; + r4->debug = _r4_debug; + r4->valid = true; + r4->validation_count = 0; + r4->match_count = 0; + r4->start = 0; + r4->end = 0; + r4->length = 0; + r4->matches = NULL; +} + +static bool r4_looks_behind(char c) { return strchr("?*+{", c) != NULL; } + +r4_t *r4_new() { + r4_t *r4 = (r4_t *)malloc(sizeof(r4_t)); + + r4_init(r4); + + return r4; +} + +static bool r4_pipe_next(r4_t *r4) { + char *expr = r4->expr; + while (*expr) { + if (*expr == '|') { + r4->expr = expr + 1; + r4->valid = true; + return true; + } + expr++; + } + return false; +} + +static bool r4_backtrack(r4_t *r4) { + if (_r4_debug) + printf("\033[36mDEBUG: backtrack start (%d)\n", r4->backtracking); + r4->backtracking++; + char *str = r4->str; + char *expr = r4->expr; + bool result = r4_validate(r4); + r4->backtracking--; + if (result == false) { + r4->expr = expr; + r4->str = str; + } + if (_r4_debug) + printf("DEBUG: backtrack end (%d) result: %d %s\n", r4->backtracking, result, r4->backtracking == 0 ? "\033[0m" : ""); + return result; +} + +static bool r4_validate(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->validation_count++; + char c_val = *r4->expr; + if (c_val == 0) { + return r4->valid; + } + if (!r4_looks_behind(c_val)) { + r4->expr_previous = r4->expr; + } else if (r4->expr == r4->_expr) { + // Regex may not start with a look behind ufnction + return false; + } + + if (!r4->valid && !r4_looks_behind(*r4->expr)) { + if (!r4_pipe_next(r4)) { + return false; + } + } + r4_function f; + if (r4->in_block) { + f = v4_function_map_block[(int)c_val]; + } else { + f = v4_function_map_global[(int)c_val]; + } + + r4->valid = f(r4); + return r4->valid; +} + +char *r4_get_match(r4_t *r) { + char *match = (char *)malloc(r->length + 1); + strncpy(match, r->_str + r->start, r->length); + match[r->length] = 0; + return match; +} + +static bool r4_search(r4_t *r) { + bool valid = true; + char *str_next = r->str; + while (*r->str) { + if (!(valid = r4_validate(r))) { + // Move next until we find a match + if (!r->backtracking) { + r->start++; + } + str_next++; + r->str = str_next; + r->expr = r->_expr; + r->valid = true; + } else { + /// HIGH DOUBT + if (!r->backtracking) { + // r->start = 0; + } + break; + } + } + r->valid = valid; + if (r->valid) { + r->end = strlen(r->_str) - strlen(r->str); + r->length = r->end - r->start; + r->match = r4_get_match(r); + } + return r->valid; +} + +r4_t *r4(const char *str, const char *expr) { + r4_t *r = r4_new(); + r->_str = (char *)str; + r->_expr = (char *)expr; + r->match = NULL; + r->str = r->_str; + r->expr = r->_expr; + r->str_previous = r->_str; + r->expr_previous = r->expr; + r->in_block = false; + r->is_greedy = true; + r->in_group = 0; + r->loop_count = 0; + r->backtracking = 0; + r->in_range = false; + r4_search(r); + return r; +} + +r4_t *r4_next(r4_t *r, char *expr) { + if (expr) { + r->_expr = expr; + } + r->backtracking = 0; + r->expr = r->_expr; + r->is_greedy = true; + r->in_block = false; + r->in_range = false; + r->in_group = false; + r4_free_matches(r); + r4_search(r); + return r; +} + +bool r4_match(char *str, char *expr) { + r4_t *r = r4(str, expr); + bool result = r->valid; + r4_free(r); + return result; +} +#endif +#define rautocomplete_new rstring_list_new +#define rautocomplete_free rstring_list_free +#define rautocomplete_add rstring_list_add +#define rautocomplete_find rstring_list_find +#define rautocomplete_t rstring_list_t +#define rautocomplete_contains rstring_list_contains + +char *r4_escape(char *content) { + size_t size = strlen(content) * 2 + 1; + char *escaped = (char *)calloc(size, sizeof(char)); + char *espr = escaped; + char *to_escape = "?*+()[]{}^$\\"; + *espr = '('; + espr++; + while (*content) { + if (strchr(to_escape, *content)) { + *espr = '\\'; + espr++; + } + *espr = *content; + espr++; + content++; + } + *espr = '.'; + espr++; + *espr = '+'; + espr++; + *espr = ')'; + espr++; + *espr = 0; + return escaped; +} + +char *rautocomplete_find(rstring_list_t *list, char *expr) { + if (!list->count) + return NULL; + if (!expr || !strlen(expr)) + return NULL; + + char *escaped = r4_escape(expr); + + for (unsigned int i = list->count - 1; i == 0; i--) { + char *match; + r4_t *r = r4(list->strings[i], escaped); + if (r->valid && r->match_count == 1) { + match = strdup(r->matches[0]); + } + r4_free(r); + if (match) { + + free(escaped); + return match; + } + } + free(escaped); + return NULL; +} +#endif +#ifndef RKEYTABLE_H +#define RKEYTABLE_H +/* + DERIVED FROM HASH TABLE K&R + */ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct rnklist { + struct rnklist *next; + struct rnklist *last; + char *name; + char *defn; +} rnklist; + +static rnklist *rkeytab = NULL; + +rnklist *rlkget(char *s) { + rnklist *np; + for (np = rkeytab; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +char *rkget(char *s) { + rnklist *np = rlkget(s); + return np ? np->defn : NULL; +} + +rnklist *rkset(char *name, char *defn) { + rnklist *np; + if ((np = (rlkget(name))) == NULL) { // Not found + np = (rnklist *)malloc(sizeof(rnklist)); + np->name = strdup(name); + np->next = NULL; + np->last = NULL; + + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + + if (rkeytab == NULL) { + rkeytab = np; + rkeytab->last = np; + } else { + if (rkeytab->last) + rkeytab->last->next = np; + + rkeytab->last = np; + } + } else { + if (np->defn) + free((void *)np->defn); + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + } + return np; +} +#endif + +#ifndef RHASHTABLE_H +#define RHASHTABLE_H +/* + ORIGINAL SOURCE IS FROM K&R + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HASHSIZE 101 + +// Structure for the table entries +typedef struct rnlist { + struct rnlist *next; + char *name; + char *defn; +} rnlist; + +// Hash table array +static rnlist *rhashtab[HASHSIZE]; + +// Hash function +unsigned rhash(char *s) { + unsigned hashval; + for (hashval = 0; *s != '\0'; s++) + hashval = *s + 31 * hashval; + return hashval % HASHSIZE; +} + +rnlist *rlget(char *s) { + rnlist *np; + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +// Lookup function +char *rget(char *s) { + rnlist *np = rlget(s); + return np ? np->defn : NULL; +} + +// Install function (adds a name and definition to the table) +struct rnlist *rset(char *name, char *defn) { + struct rnlist *np = NULL; + unsigned hashval; + + if ((rlget(name)) == NULL) { // Not found + np = (struct rnlist *)malloc(sizeof(*np)); + if (np == NULL || (np->name = strdup(name)) == NULL) + return NULL; + hashval = rhash(name); + np->next = rhashtab[hashval]; + rhashtab[hashval] = np; + } else { + if (np->defn) + free((void *)np->defn); + np->defn = NULL; + } + if ((np->defn = strdup(defn)) == NULL) + return NULL; + return np; +} +#endif + +#ifndef RREX3_H +#define RREX3_H +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#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->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 == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK\n"); + // exit(1); + } + if (rrex3->valid == false) { + rrex3->expr++; + return; + } + + 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_plus2(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_plus(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->expr++; + return; + } + + char *left = rrex3->previous.expr; + // printf("%s\n",rrex3->str); + char *right = rrex3->expr + 1; + if (*right == ')') { + right++; + } + int right_valid = 0; + bool right_valid_once = false; + char *expr = right; + char *right_str = rrex3->str; + ; + char *right_expr = NULL; + char *str = rrex3->str; + bool first_time = true; + bool left_valid = true; + char *str_prev = NULL; + bool valid_from_start = true; + ; + while (*rrex3->str) { + if (!left_valid && !right_valid) { + break; + } + if (right_valid && !left_valid) { + str = right_str; + break; + } + + rrex3->expr = right; + rrex3->str = str; +#if RREX3_DEBUG == 1 + printf("r"); +#endif + if (*rrex3->str && rrex3_move(rrex3, false)) { + right_valid++; + right_str = rrex3->str; + expr = rrex3->expr; + if (!right_valid_once) { + right_expr = rrex3->expr; + right_valid_once = true; + } + } else { + right_valid = 0; + } + if (first_time) { + first_time = false; + valid_from_start = right_valid; + } + + if (right_valid && !valid_from_start && right_valid > 0) { + expr = right_expr - 1; + ; + if (*(right - 1) == ')') { + expr = right - 1; + } + break; + } + + if ((!right_valid && right_valid_once)) { + expr = right_expr; + if (*(right - 1) == ')') { + str = str_prev; + expr = right - 1; + } + break; + } + + str_prev = str; + rrex3->valid = true; + rrex3->str = str; + rrex3->expr = left; +#if RREX3_DEBUG == 1 + printf("l"); +#endif + if (rrex3_move(rrex3, false)) { + left_valid = true; + + str = rrex3->str; + } else { + left_valid = false; + } + } + + rrex3->expr = expr; + rrex3->str = 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_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; + } + + rrex3->str = rrex3->previous.str; + char *left = rrex3->previous.expr; + // printf("%s\n",rrex3->str); + char *right = rrex3->expr + 1; + if (*right == ')') { + right++; + } + int right_valid = 0; + bool right_valid_once = false; + char *expr = right; + char *right_str = rrex3->str; + ; + char *right_expr = NULL; + char *str = rrex3->str; + bool first_time = true; + bool left_valid = true; + char *str_prev = NULL; + bool valid_from_start = true; + ; + while (*rrex3->str) { + if (!left_valid && !right_valid) { + break; + } + if (right_valid && !left_valid) { + str = right_str; + break; + } + + rrex3->expr = right; + rrex3->str = str; +#if RREX3_DEBUG == 1 + printf("r"); +#endif + if (*rrex3->str && rrex3_move(rrex3, false)) { + right_valid++; + right_str = rrex3->str; + expr = rrex3->expr; + if (!right_valid_once) { + right_expr = rrex3->expr; + right_valid_once = true; + } + } else { + right_valid = 0; + } + if (first_time) { + first_time = false; + valid_from_start = right_valid; + } + + if (right_valid && !valid_from_start && right_valid > 0) { + expr = right_expr - 1; + if (*(right - 1) == ')') { + expr = right - 1; + } + break; + } + + if ((!right_valid && right_valid_once)) { + expr = right_expr; + if (*(right - 1) == ')') { + str = str_prev; + expr = right - 1; + } + break; + } + + str_prev = str; + rrex3->valid = true; + rrex3->str = str; + rrex3->expr = left; +#if RREX3_DEBUG == 1 + printf("l"); +#endif + if (rrex3_move(rrex3, false)) { + left_valid = true; + str = rrex3->str; + } else { + left_valid = false; + } + } + + rrex3->expr = expr; + rrex3->str = 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_asterisk2(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) { + if (!success_next_once) { + 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("<Roof check: %c:%c:%d\n", *rrex3->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) { +#if RREX3_DEBUG == 1 + if (*rrex3->expr != 'B') { + printf("Check word start or end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); + } + +#endif + 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) { +#if RREX3_DEBUG == 1 + printf("Check word NOT start or end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); + +#endif + 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 + + rrex3_set_previous(rrex3); + if (!rrex3->valid) { + rrex3->expr++; + return; + } + 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; + } else if (!*rrex3->expr) { + // rrex3->valid = 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; + } + } else { + } + 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; + } + rrex3->expr = rrex3->_expr; + 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, "\"stdio.h\"\"string.h\"\"sys/time.h\"", "\"(.*)\"\"(.*)\"\"(.*)\"")); + + 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 chars + 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 <stdio.h>", "#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 <stdio.h>", "#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, "int abc ", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + assert(rrex3(rrex, "int abc;", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + assert(rrex3(rrex, "int abc", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + + rrex3_free(rrex); +} +#endif +#ifndef RARENA_H +#define RARENA_H + +#include <stdlib.h> +#include <string.h> + +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 RCASE_H +#define RCASE_H +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#define RCAMEL_CASE 1 +#define RSNAKE_CASE 2 +#define RINVALID_CASE 0 +#define RCONST_TEST_T 4; + +int rdetermine_case(const char *str) { + int length = strlen(str); + + char p = 0; + while (*str) { + if (p == '_' && islower(*str)) + return RSNAKE_CASE; + if (p != '_' && !isupper(p) && isupper(*str)) + return RCAMEL_CASE; + p = *str; + str++; + } + return RINVALID_CASE; + + if (length == 0) { + return RINVALID_CASE; + } + if (strchr(str, '_')) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + return RINVALID_CASE; + } + for (int i = 0; i < length; i++) { + if (!islower(str[i]) && str[i] != '_') { + return RINVALID_CASE; + } + } + return RSNAKE_CASE; + } else { + + if (!islower(str[0])) { + return RINVALID_CASE; + } + for (int i = 1; i < length; i++) { + if (str[i] == '_') { + return RINVALID_CASE; + } + if (isupper(str[i]) && isupper(str[i - 1])) { + return RINVALID_CASE; + } + } + return RCAMEL_CASE; + } +} + +char *rsnake_to_camel(const char *snake_case) { + int length = strlen(snake_case); + char *camel_case = (char *)malloc(length + 1); + int j = 0; + int toUpper = 0; + + for (int i = 0; i < length; i++) { + if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { + toUpper = 1; + if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + + toUpper = 0; + } + } + if (snake_case[i] == '_' && snake_case[i + 1] != 't') { + toUpper = 1; + if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + toUpper = 0; + } + } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { + toUpper = 1; + } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { + toUpper = 1; + camel_case[j++] = '_'; + j++; + } else { + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; + } else { + camel_case[j++] = snake_case[i]; + } + } + } + + camel_case[j] = '\0'; + return camel_case; +} +char *rcamel_to_snake(const char *camelCase) { + int length = strlen(camelCase); + char *snake_case = (char *)malloc(2 * length + 1); + int j = 0; + + for (int i = 0; i < length; i++) { + if (isupper(camelCase[i])) { + if (i != 0) { + snake_case[j++] = '_'; + } + snake_case[j++] = tolower(camelCase[i]); + } else { + snake_case[j++] = camelCase[i]; + } + } + + snake_case[j] = '\0'; + return snake_case; +} + +char *rflip_case(char *content) { + if (rdetermine_case(content) == RSNAKE_CASE) { + return rcamel_to_snake(content); + } else if (rdetermine_case(content) == RCAMEL_CASE) { + return rsnake_to_camel(content); + } else { + rprintr("Could not determine case\n"); + return NULL; + } +} + +char *rflip_case_file(char *filepath) { + size_t file_size = rfile_size(filepath); + if (file_size == 0) { + return NULL; + } + char *content = (char *)malloc(file_size); + char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { + result = rflip_case(content); + if (result) { + free(content); + return result; + } else { + return content; + } + } + return result; +} + +int rcase_main(int argc, char *argv[]) { + if (argc < 2) { + printf("usage: rcase <file>\n"); + return 1; + } + for (int i = 1; i < argc; i++) { + char *result = rflip_case_file(argv[i]); + if (result) { + printf("%s\n", result); + free(result); + } + } + return 0; +} +#endif + +#ifndef RTERM_H +#define RTERM_H +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> +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; + int ms_tick; + 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 (*after_draw)(struct rterm_t *); + void *session; + unsigned long iterations; + void (*tick)(struct rterm_t *); + char *status_text; + char *_status_text_previous; + 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->cursor.x = 0; + rterm->cursor.y = 0; + rterm->ms_tick = 100; + rterm->_status_text_previous = NULL; +} + +void rterm_getwinsize(winsize_t *w) { + // Get the terminal size + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, w) == -1) { + perror("ioctl"); + exit(EXIT_FAILURE); + } +} + +void rrawfd(int fd) { + struct termios orig_termios; + tcgetattr(fd, &orig_termios); // Get current terminal attributes + + struct termios raw = orig_termios; + raw.c_lflag &= ~(ICANON | ISIG | ECHO); // ECHO // Disable canonical mode and echoing + raw.c_cc[VMIN] = 1; + raw.c_cc[VTIME] = 240; // Set timeout for read input + + tcsetattr(fd, TCSAFLUSH, &raw); +} + +// 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] = 1; + raw.c_cc[VTIME] = 240; // 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[34m"); // 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) { + if (rt->_status_text_previous && !strcmp(rt->_status_text_previous, rt->status_text)) { + return; + } + if (rt->_status_text_previous) { + free(rt->_status_text_previous); + } + rt->_status_text_previous = strdup(rt->status_text); + winsize_t ws = rt->size; + cursor_set(rt, rt->cursor.x, rt->cursor.y); + 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(rterm_t *rt) { + static rshell_keypress_t press; + press.c = 0; + press.ctrl = false; + press.shift = false; + press.escape = false; + press.pressed = rfd_wait(0, rt->ms_tick); + if (!press.pressed) { + return press; + } + 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 if (ch == 27) { + press.escape = true; + press.c = ch; + } 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->after_draw) { + rt->after_draw(rt); + } + if (!rt->iterations || (x != rt->cursor.x || y != rt->cursor.y)) { + if (rt->cursor.y == rt->size.ws_row) { + rt->cursor.y--; + } + if (rt->cursor.y < 0) { + rt->cursor.y = 0; + } + x = rt->cursor.x; + y = rt->cursor.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(rt); + 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 + if (key.c == -1) { + nsleep(1000 * 1000); + } + // Escape + if (key.escape) { + switch (key.c) { + case 65: // Move up + if (rt->cursor.y > -1) + rt->cursor.y--; + break; + case 66: // Move down + if (rt->cursor.y < rt->size.ws_row) + rt->cursor.y++; + break; + case 68: // Move left + if (rt->cursor.x > 0) + rt->cursor.x--; + if (key.ctrl) + rt->cursor.x -= 4; + break; + case 67: // Move right + if (rt->cursor.x < rt->size.ws_col) { + rt->cursor.x++; + } + if (key.ctrl) { + rt->cursor.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 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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; +} + +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; +} + +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; + } + return NULL; +} + +void rtree_free(rtree_t *b) { + if (!b) + return; + rtree_free(b->children); + rtree_free(b->next); + rfree(b); +} + +void *rtree_get(rtree_t *b, char *c) { + rtree_t *t = rtree_find(b, c); + if (t) { + return t->data; + } + return NULL; +} +#endif +#ifndef RLEXER_H +#define RLEXER_H +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#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 == '\''); +} + +static int isoperator(char c) { + return (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '>' || c == '<' || c == '|' || c == '&'); +} + +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++; + } + token.type = RT_NUMBER; + return token; +} + +static rtoken_t rlex_symbol() { + rtoken_t token = rtoken_new(); + + 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; +} + +static rtoken_t rlex_operator() { + + 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; + } + } + 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; +} + +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 (_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; +} + +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++; + } + _content_ptr++; + token.type = RT_STRING; + return token; +} + +void rlex(char *content) { + _content = content; + _content_ptr = 0; + _content_col = 1; + _content_line = 1; +} + +static void rlex_repeat_str(char *dest, char *src, unsigned int times) { + for (size_t i = 0; i < times; i++) { + strcat(dest, src); + } +} + +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; +} + +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(); + } + } +} + +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; + } + + if (token.type == RT_STRING) { + strcat(result, "\""); + + char string_with_slashes[strlen(token.value) * 2 + 1]; + rstraddslashes(token.value, string_with_slashes); + strcat(result, string_with_slashes); + + strcat(result, "\""); + // col+= strlen(token.value) + 2; + // printf("\n"); + // printf("<<<%s>>>\n",token.value); + + 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); + + tab_index++; + + strcat(result, "\n"); + + col = 0; + + 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"); + + rlex_repeat_str(result, tab_chars, tab_index); + tab_indexed++; + + strcat(result, token.value); + strcat(result, "\n"); + col = 0; + + 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); + } + } + } + + 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, "\""); + } + + if (token.type == RT_OPERATOR) { + strcat(result, " "); + } + if (!strcmp(token.value, ",")) { + strcat(result, " "); + } + col += strlen(token.value); + memcpy(&token_previous, &token, sizeof(token)); + } + return result; +} +#endif + +#ifndef RLIB_MAIN +#define RLIB_MAIN +#ifndef RMERGE_H +#define RMERGE_H +// #include "../mrex/rmatch.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +bool has_error = false; + +char *extract_script_src_include(char *line, char *include_path) { + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *extract_c_local_include(char *line, char *include_path) { + // + /* + char res; + res= rmatch_extract(line, "#include.*"\".*\""); + + + printf("%MATCH:%s\n", res); + */ + + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *rmerge_readline(FILE *f) { + static char data[4096]; + data[0] = 0; + int index = 0; + char c; + while ((c = fgetc(f)) != EOF) { + if (c != '\0') { + data[index] = c; + index++; + if (c == '\n') + break; + } + } + data[index] = 0; + if (data[0] == 0) + return NULL; + return data; +} +void writestring(FILE *f, char *line) { + char c; + while ((c = *line) != '\0') { + fputc(c, f); + line++; + } +} +char files_history[8096]; +char files_duplicate[8096]; +bool is_merging = false; + +void merge_file(char *source, FILE *d) { + if (is_merging == false) { + is_merging = true; + files_history[0] = 0; + files_duplicate[0] = 0; + } + if (strstr(files_history, source)) { + if (strstr(files_duplicate, source)) { + rprintmf(stderr, "\\l Already included: %s. Already on duplicate list.\n", source); + } else { + rprintcf(stderr, "\\l Already included: %s. Adding to duplicate list.\n", source); + strcat(files_duplicate, source); + strcat(files_duplicate, "\n"); + } + return; + } else { + rprintgf(stderr, "\\l Merging: %s.\n", source); + strcat(files_history, source); + strcat(files_history, "\n"); + } + FILE *fd = fopen(source, "rb"); + if (!fd) { + rprintrf(stderr, "\\l File does not exist: %s\n", source); + has_error = true; + return; + } + + char *line; + char include_path[4096]; + while ((line = rmerge_readline(fd))) { + + include_path[0] = 0; + if (!*line) + break; + + // + char *inc = extract_c_local_include(line, include_path); + if (!inc) + inc = extract_script_src_include(line, include_path); + + /* + if (!strncmp(line, "#include ", 9)) { + int index = 0; + while (line[index] != '"' && line[index] != 0) { + index++; + } + if (line[index] == '"') { + int pindex = 0; + index++; + while (line[index] != '"') { + include_path[pindex] = line[index]; + pindex++; + index++; + } + if (line[index] != '"') { + include_path[0] = 0; + } else { + include_path[pindex] = '\0'; + } + } + }*/ + if (inc) { + merge_file(inc, d); + } else { + writestring(d, line); + } + } + fclose(fd); + writestring(d, "\n"); +} + +int rmerge_main(int argc, char *argv[]) { + char *file_input = NULL; + if (argc != 2) { + printf("Usage: <input-file>\n"); + } else { + file_input = argv[1]; + // file_output = argv[2]; + } + FILE *f = tmpfile(); + printf("// RETOOR - %s\n", __DATE__); + merge_file(file_input, f); + rewind(f); + char *data; + int line_number = 0; + while ((data = rmerge_readline(f))) { + if (line_number) { + printf("/*%.5d*/ ", line_number); + line_number++; + } + printf("%s", data); + } + printf("\n"); + if (has_error) { + rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); + } else { + rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + } + return 0; +} +#endif + +void forward_argument(int *argcc, char *argv[]) { + int argc = *argcc; + for (int i = 0; i < argc; i++) { + argv[i] = argv[i + 1]; + } + argc--; + *argcc = argc; +} + +int rlib_main(int argc, char *argv[]) { + + if (argc == 1) { + printf("rlib\n\n"); + printf("options:\n"); + printf(" httpd - a http file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts c source files to one file \n" + " with local includes by giving main file as argument.\n"); + printf(" rcov - coverage tool theat cleans up after himself. Based on " + "lcov.\n"); + printf(" rcase - tool to swap input file automatically between" + " camel case and snake case.\n"); + return 0; + } + + forward_argument(&argc, argv); + + if (!strcmp(argv[0], "httpd")) { + + return rhttp_main(argc, argv); + } + if (!strcmp(argv[0], "rmerge")) { + return rmerge_main(argc, argv); + } + if (!strcmp(argv[0], "rcov")) { + return rcov_main(argc, argv); + } + if (!strcmp(argv[0], "rcase")) { + return rcase_main(argc, argv); + } + + return 0; +} + +#endif + +// END OF RLIB +#endif diff --git a/.backup.1.rlibrlibso.c b/.backup.1.rlibrlibso.c new file mode 100644 index 0000000..0c50255 --- /dev/null +++ b/.backup.1.rlibrlibso.c @@ -0,0 +1,8451 @@ +// RETOOR - Mar 16 2025 +// 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 + +/* + * Line below will be filtered by rmerge +<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after +tag" /> +*/ + +#ifndef RTYPES_H +#define RTYPES_H +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include <stdbool.h> +#include <stdint.h> // uint +#include <string.h> +#include <sys/types.h> // ulong +#ifndef ulonglong +#define ulonglong unsigned long long +#endif +#ifndef uint +typedef unsigned int uint; +#endif +#ifndef byte +typedef unsigned char byte; +#endif +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +#endif + +#ifndef NSOCK_H +#define NSOCK_H +#include <unistd.h> +#ifndef RMALLOC_H +#define RMALLOC_H +#ifndef RMALLOC_OVERRIDE +#define RMALLOC_OVERRIDE 1 +#endif +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#ifndef ulonglong +#define ulonglong unsigned long long +#endif +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef RTEMP_H +#define RTEMP_H +#include <pthread.h> +#ifndef RTEMPC_SLOT_COUNT +#define RTEMPC_SLOT_COUNT 20 +#endif +#ifndef RTEMPC_SLOT_SIZE +#define RTEMPC_SLOT_SIZE 1024 * 64 * 128 +#endif + +bool _rtempc_initialized = 0; +pthread_mutex_t _rtempc_thread_lock; +bool rtempc_use_mutex = true; +byte _current_rtempc_slot = 1; +char _rtempc_buffer[RTEMPC_SLOT_COUNT][RTEMPC_SLOT_SIZE]; +char *rtempc(char *data) { + + if (rtempc_use_mutex) { + if (!_rtempc_initialized) { + _rtempc_initialized = true; + pthread_mutex_init(&_rtempc_thread_lock, NULL); + } + + pthread_mutex_lock(&_rtempc_thread_lock); + } + + uint current_rtempc_slot = _current_rtempc_slot; + _rtempc_buffer[current_rtempc_slot][0] = 0; + strcpy(_rtempc_buffer[current_rtempc_slot], data); + _current_rtempc_slot++; + if (_current_rtempc_slot == RTEMPC_SLOT_COUNT) { + _current_rtempc_slot = 0; + } + if (rtempc_use_mutex) + pthread_mutex_unlock(&_rtempc_thread_lock); + return _rtempc_buffer[current_rtempc_slot]; +} + +#define sstring(_pname, _psize) \ + static char _##_pname[_psize]; \ + _##_pname[0] = 0; \ + char *_pname = _##_pname; + +#define string(_pname, _psize) \ + char _##_pname[_psize]; \ + _##_pname[0] = 0; \ + char *_pname = _##_pname; + +#define sreset(_pname, _psize) _pname = _##_pname; + +#define sbuf(val) rtempc(val) +#endif +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +ulonglong rmalloc_count = 0; +ulonglong rmalloc_alloc_count = 0; +ulonglong rmalloc_free_count = 0; +ulonglong rmalloc_total_bytes_allocated = 0; + +void *_rmalloc_prev_realloc_obj = NULL; +size_t _rmalloc_prev_realloc_obj_size = 0; + +void *rmalloc(size_t size) { + void *result; + while (!(result = malloc(size))) { + fprintf(stderr, "Warning: malloc failed, trying again.\n"); + } + rmalloc_count++; + rmalloc_alloc_count++; + rmalloc_total_bytes_allocated += size; + return result; +} +void *rcalloc(size_t count, size_t size) { + void *result; + while (!(result = calloc(count, size))) { + fprintf(stderr, "Warning: calloc failed, trying again.\n"); + } + rmalloc_alloc_count++; + rmalloc_count++; + rmalloc_total_bytes_allocated += count * size; + return result; +} +void *rrealloc(void *obj, size_t size) { + if (!obj) { + rmalloc_count++; + } + + rmalloc_alloc_count++; + if (obj == _rmalloc_prev_realloc_obj) { + rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; + _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; + + } else { + _rmalloc_prev_realloc_obj_size = size; + } + void *result; + while (!(result = realloc(obj, size))) { + fprintf(stderr, "Warning: realloc failed, trying again.\n"); + } + _rmalloc_prev_realloc_obj = result; + + return result; +} + +char *rstrdup(const char *s) { + if (!s) + return NULL; + + char *result; + size_t size = strlen(s) + 1; + + result = rmalloc(size); + memcpy(result, s, size); + rmalloc_total_bytes_allocated += size; + return result; +} +void *rfree(void *obj) { + rmalloc_count--; + rmalloc_free_count++; + free(obj); + return NULL; +} + +#if RMALLOC_OVERRIDE +#define malloc rmalloc +#define calloc rcalloc +#define realloc rrealloc +#define free rfree +#define strdup rstrdup +#endif + +char *rmalloc_lld_format(ulonglong num) { + + char res[100]; + res[0] = 0; + sprintf(res, "%'lld", num); + char *resp = res; + while (*resp) { + if (*resp == ',') + *resp = '.'; + resp++; + } + return sbuf(res); +} + +char *rmalloc_bytes_format(int factor, ulonglong num) { + char *sizes[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; + if (num > 1024) { + return rmalloc_bytes_format(factor + 1, num / 1024); + } + char res[100]; + sprintf(res, "%s %s", rmalloc_lld_format(num), sizes[factor]); + return sbuf(res); +} + +char *rmalloc_stats() { + static char res[200]; + res[0] = 0; + // int original_locale = localeconv(); + setlocale(LC_NUMERIC, "en_US.UTF-8"); + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), + + rmalloc_lld_format(rmalloc_count)); + // setlocale(LC_NUMERIC, original_locale); + + setlocale(LC_NUMERIC, ""); + return res; +} + +#endif + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <unistd.h> +#ifndef RLIB_RIO +#define RLIB_RIO +#include <dirent.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/dir.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <unistd.h> +#ifndef RSTRING_LIST_H +#define RSTRING_LIST_H +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +typedef struct rstring_list_t { + unsigned int size; + unsigned int count; + char **strings; +} rstring_list_t; + +rstring_list_t *rstring_list_new() { + rstring_list_t *rsl = (rstring_list_t *)malloc(sizeof(rstring_list_t)); + memset(rsl, 0, sizeof(rstring_list_t)); + return rsl; +} + +void rstring_list_free(rstring_list_t *rsl) { + for (unsigned int i = 0; i < rsl->size; i++) { + free(rsl->strings[i]); + } + if (rsl->strings) + free(rsl->strings); + free(rsl); + rsl = NULL; +} + +void rstring_list_add(rstring_list_t *rsl, char *str) { + if (rsl->count == rsl->size) { + rsl->size++; + + rsl->strings = (char **)realloc(rsl->strings, sizeof(char *) * rsl->size); + } + rsl->strings[rsl->count] = strdup(str); + rsl->count++; +} +bool rstring_list_contains(rstring_list_t *rsl, char *str) { + for (unsigned int i = 0; i < rsl->count; i++) { + if (!strcmp(rsl->strings[i], str)) + return true; + } + return false; +} + +#endif + +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; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * ms; + + int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); + return ret > 0 && FD_ISSET(fd, &read_fds); +} + +bool rfd_wait_forever(int fd) { + while ((!rfd_wait(fd, 10))) { + } + return true; +} + +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, "r"); + if (!fd) { + return 0; + } + size_t bytes_read = fread(data, sizeof(char), size, fd); + + fclose(fd); + ((char *)data)[bytes_read] = 0; + return bytes_read; +} + +#endif + +int *nsock_socks = NULL; +int *nsock_readable = NULL; +void **nsock_data = NULL; +int nsock_server_fd = 0; +int nsock_max_socket_fd = 0; + +typedef enum nsock_type_t { NSOCK_NONE = 0, NSOCK_SERVER, NSOCK_CLIENT, NSOCK_UPSTREAM } nsock_type_t; + +typedef struct nsock_it { + int fd; + int *upstreams; + bool connected; + bool downstream; + unsigned int upstream_count; + nsock_type_t type; +} nsock_t; + +nsock_t **nsocks = NULL; +int nsocks_count = 0; + +void (*nsock_on_connect)(int fd) = NULL; +void (*nsock_on_data)(int fd) = NULL; +void (*nsock_on_close)(int fd) = NULL; +void nsock_on_before_data(int fd); + +nsock_t *nsock_get(int fd) { + if (nsock_socks[fd] == 0) { + return NULL; + } + if (fd >= nsocks_count || nsocks[fd] == NULL) { + if (fd >= nsocks_count) { + nsocks_count = fd + 1; + nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); + nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + } + nsocks[fd]->upstreams = NULL; + nsocks[fd]->fd = fd; + nsocks[fd]->connected = false; + nsocks[fd]->downstream = false; + nsocks[fd]->upstream_count = 0; + nsocks[fd]->type = NSOCK_CLIENT; + return nsocks[fd]; + } + return nsocks[fd]; +} + +void nsock_close(int fd) { + if (nsock_on_close) + nsock_on_close(fd); + nsock_t *sock = nsock_get(fd); + if (sock && sock->connected) { + sock->connected = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + nsock_t *upstream = nsock_get(sock->upstreams[i]); + if (upstream->connected) + nsock_close(sock->upstreams[i]); + sock->upstreams[i] = 0; + } + if (sock->upstream_count) { + free(sock->upstreams); + } + sock->upstream_count = 0; + } + nsock_socks[fd] = 0; + close(fd); +} + +nsock_t *nsock_create(int fd, nsock_type_t type) { + if (fd <= 0) + return NULL; + nsock_socks[fd] = fd; + nsock_t *sock = nsock_get(fd); + sock->connected = true; + sock->downstream = false; + sock->type = type; + return sock; +} + +int *nsock_init(int socket_count) { + if (nsock_socks) { + return nsock_socks; + } + nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + if (nsock_data) { + free(nsock_data); + nsock_data = NULL; + } + nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_socks[socket_count] = -1; + return nsock_socks; +} + +void nsock_free() { + if (nsock_socks) + free(nsock_socks); + if (nsock_readable) + free(nsock_readable); + nsock_server_fd = 0; + nsock_max_socket_fd = 0; + if (nsock_data) { + exit(1); + } +} + +void nsock_add_upstream(int source, int target, bool downstream) { + if (!nsock_socks[target]) + return; + if (!nsock_socks[source]) + return; + nsock_t *sock = nsock_get(source); + nsock_t *sock_target = nsock_get(target); + sock_target->type = NSOCK_UPSTREAM; + sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->downstream = downstream; + sock->upstreams[sock->upstream_count] = target; + sock->upstream_count++; +} + +void *nsock_get_data(int socket) { return nsock_data[socket]; } +void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } + +int nsock_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = 0; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return 0; + } + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + break; + } + if (p == NULL) { + freeaddrinfo(res); + return 0; + } + freeaddrinfo(res); + if (socket_fd) { + if (nsock_socks == NULL) { + nsock_init(2048); + } + nsock_socks[socket_fd] = socket_fd; + nsock_t *sock = nsock_create(socket_fd, NSOCK_CLIENT); + sock->connected = true; + } + return socket_fd; +} + +void nsock_listen(int port) { + int server_fd; + struct sockaddr_in address; + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed"); + exit(EXIT_FAILURE); + } + int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("setsockopt failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + if (listen(server_fd, 8096) < 0) { + perror("Listen failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + nsock_server_fd = server_fd; +} + +int *nsock_select(suseconds_t timeout) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout; + int server_fd = nsock_server_fd; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(server_fd, &rfds); + int *socks = nsock_socks; + fd_set efds; + FD_ZERO(&efds); + nsock_max_socket_fd = server_fd; + for (int i = 0; socks[i] != -1; i++) { + if (i == server_fd) + continue; + ; + if (!socks[i]) + continue; + if (socks[i] > nsock_max_socket_fd) { + nsock_max_socket_fd = socks[i]; + } + FD_SET(socks[i], &rfds); + FD_SET(socks[i], &efds); + } + int activity = select(nsock_max_socket_fd + 1, &rfds, NULL, &efds, timeout == 0 ? NULL : &tv); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } else if (activity == 0) { + return NULL; + } + if (FD_ISSET(server_fd, &rfds)) { + struct sockaddr_in address; + int addrlen = sizeof(address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + int new_socket = 0; + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed"); + } else { + nsock_socks[new_socket] = new_socket; + nsock_create(new_socket, NSOCK_CLIENT); + if (nsock_on_connect) + nsock_on_connect(new_socket); + if (new_socket > nsock_max_socket_fd) + nsock_max_socket_fd = new_socket; + } + } + if (nsock_readable) { + free(nsock_readable); + } + nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable[nsock_max_socket_fd + 1] = -1; + nsock_readable[0] = 0; + int readable_count = 0; + for (int i = 0; i < nsock_max_socket_fd + 1; i++) { + nsock_t *sock = nsock_get(i); + if (!sock) + continue; + if (FD_ISSET(i, &efds)) { + nsock_close(nsock_socks[i]); + nsock_socks[i] = 0; + nsock_readable[i] = 0; + } else if (FD_ISSET(i, &rfds) && i != server_fd) { + nsock_readable[i] = i; + readable_count++; + nsock_on_before_data(i); + } else { + nsock_readable[i] = 0; + sock->connected = false; + } + } + return nsock_readable; +} + +unsigned char *nsock_read(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = read(fd, buffer, length); + if (bytes_read <= 0) { + nsock_close(fd); + return NULL; + } + buffer[bytes_read] = 0; + return buffer; +} + +unsigned char *nsock_read_all(int fd, int length) { + if (!nsock_socks[fd]) + return NULL; + unsigned char *buffer = (unsigned char *)malloc(length + 1); + int bytes_read = 0; + while (bytes_read < length) { + int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); + if (bytes_chunk <= 0) { + nsock_close(fd); + return NULL; + } + bytes_read += bytes_chunk; + } + buffer[bytes_read] = 0; + return buffer; +} + +int nsock_write_all(int fd, unsigned char *data, int length) { + if (!nsock_socks[fd]) + return 0; + int bytes_written = 0; + while (bytes_written < length) { + int bytes_chunk = write(fd, data + bytes_written, length - bytes_written); + if (bytes_chunk <= 0) { + nsock_close(fd); + return 0; + } + bytes_written += bytes_chunk; + } + return bytes_written; +} + +int nsock_execute_upstream(int source, size_t buffer_size) { + int result = 0; + nsock_t *sock = nsock_get(source); + unsigned char data[buffer_size]; + memset(data, 0, buffer_size); + int bytes_read = read(source, data, buffer_size); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + bool downstreamed = false; + for (unsigned int i = 0; i < sock->upstream_count; i++) { + if (!nsock_socks[sock->upstreams[i]]) + continue; + int bytes_sent = nsock_write_all(sock->upstreams[i], data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + continue; + } + if (sock->downstream && downstreamed == false) { + downstreamed = true; + unsigned char data[4096]; + memset(data, 0, 4096); + int bytes_read = read(sock->upstreams[i], data, 4096); + if (bytes_read <= 0) { + nsock_close(source); + return 0; + } + int bytes_sent = nsock_write_all(sock->fd, data, bytes_read); + if (bytes_sent <= 0) { + nsock_close(sock->upstreams[i]); + return 0; + } + } + result++; + } + return result; +} + +void nsock_on_before_data(int fd) { + if (!nsock_socks[fd]) + return; + nsock_t *sock = nsock_get(fd); + if (sock->upstream_count) { + int upstreamed_to_count = nsock_execute_upstream(fd, 4096); + if (!upstreamed_to_count) { + nsock_close(fd); + } + return; + } else if (sock->type == NSOCK_UPSTREAM) { + while (rfd_wait(sock->fd, 0)) { + unsigned char *data = nsock_read(fd, 4096); + (void)data; + } + } + if (nsock_on_data) + nsock_on_data(fd); +} + +void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void (*on_close)(int fd)) { + nsock_init(2048); + nsock_listen(port); + nsock_on_connect = on_connect; + nsock_on_data = on_data; + nsock_on_close = on_close; + int serve_in_terminal = nsock_on_connect == NULL && nsock_on_data == NULL && nsock_on_close == NULL; + while (1) { + int *readable = nsock_select(0); + if (!serve_in_terminal) + continue; + if (!readable) + continue; + for (int i = 0; readable[i] != -1; i++) { + if (!readable[i]) + continue; + char buffer[1024] = {0}; + int bytes_read = read(readable[i], buffer, 1); + buffer[bytes_read] = 0; + if (bytes_read <= 0) { + nsock_close(readable[i]); + continue; + } + if (write(readable[i], buffer, bytes_read) <= 0) { + nsock_close(readable[i]); + continue; + } + } + } +} +#endif + +#ifndef UUID_H +#define UUID_H +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +typedef struct { + unsigned char bytes[16]; +} UUID; + +void generate_random_bytes(unsigned char *bytes, size_t len) { + for (size_t i = 0; i < len; i++) { + bytes[i] = rand() % 256; + } +} + +UUID generate_uuid4(void) { + UUID uuid; + + generate_random_bytes(uuid.bytes, 16); + + uuid.bytes[6] &= 0x0f; + uuid.bytes[6] |= 0x40; + + uuid.bytes[8] &= 0x3f; + uuid.bytes[8] |= 0x80; + + return uuid; +} + +void uuid_to_string(UUID uuid, char *str) { + sprintf(str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid.bytes[0], uuid.bytes[1], uuid.bytes[2], + uuid.bytes[3], uuid.bytes[4], uuid.bytes[5], uuid.bytes[6], uuid.bytes[7], uuid.bytes[8], uuid.bytes[9], uuid.bytes[10], + uuid.bytes[11], uuid.bytes[12], uuid.bytes[13], uuid.bytes[14], uuid.bytes[15]); +} + +char *uuid4() { + srand(time(NULL)); + UUID uuid = generate_uuid4(); + char str[37]; + uuid_to_string(uuid, str); + return sbuf(str); +} +#endif +#ifndef RNET_H +#define RNET_H +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> + +#include <sys/socket.h> +#include <sys/types.h> + +#include <unistd.h> +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +#define NET_SOCKET_MAX_CONNECTIONS 50000 + +typedef struct rnet_socket_t { + int fd; + char name[50]; + void *data; + size_t bytes_received; + size_t bytes_sent; + bool connected; + void (*on_read)(struct rnet_socket_t *); + void (*on_close)(struct rnet_socket_t *); + void (*on_connect)(struct rnet_socket_t *); +} rnet_socket_t; + +typedef struct rnet_select_result_t { + int server_fd; + rnet_socket_t **sockets; + unsigned int socket_count; +} rnet_select_result_t; + +typedef struct rnet_server_t { + int socket_fd; + rnet_socket_t **sockets; + unsigned int socket_count; + unsigned int port; + unsigned int backlog; + rnet_select_result_t *select_result; + int max_fd; + void (*on_connect)(rnet_socket_t *socket); + void (*on_close)(rnet_socket_t *socket); + void (*on_read)(rnet_socket_t *socket); +} rnet_server_t; + +void rnet_select_result_free(rnet_select_result_t *result); +int net_socket_accept(int server_fd); +int net_socket_connect(const char *, unsigned int); +int net_socket_init(); +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog); +rnet_select_result_t *net_socket_select(rnet_server_t *server); +rnet_socket_t *net_socket_wait(rnet_socket_t *socket_fd); +bool net_set_non_blocking(int sock); +bool net_socket_bind(int sock, unsigned int port); +bool net_socket_listen(int sock, unsigned int backlog); +char *net_socket_name(int sock); +size_t net_socket_write(rnet_socket_t *, unsigned char *, size_t); +rnet_socket_t *get_net_socket_by_fd(int); +unsigned char *net_socket_read(rnet_socket_t *, unsigned int buff_size); +void _net_socket_close(int sock); +void net_socket_close(rnet_socket_t *sock); + +rnet_server_t *rnet_server_new(int socket_fd, unsigned int port, unsigned int backlog) { + rnet_server_t *server = malloc(sizeof(rnet_server_t)); + server->socket_fd = socket_fd; + server->sockets = NULL; + server->socket_count = 0; + server->port = port; + server->backlog = backlog; + server->max_fd = -1; + server->select_result = NULL; + server->on_connect = NULL; + server->on_close = NULL; + server->on_read = NULL; + return server; +} + +rnet_server_t *rnet_server_add_socket(rnet_server_t *server, rnet_socket_t *sock) { + server->sockets = realloc(server->sockets, sizeof(rnet_socket_t *) * (server->socket_count + 1)); + server->sockets[server->socket_count] = sock; + server->socket_count++; + sock->on_read = server->on_read; + sock->on_connect = server->on_connect; + sock->on_close = server->on_close; + sock->connected = true; + return server; +} + +rnet_socket_t sockets[NET_SOCKET_MAX_CONNECTIONS] = {0}; +unsigned long sockets_connected = 0; +int net_socket_max_fd = 0; +unsigned long sockets_total = 0; +unsigned long sockets_disconnected = 0; +unsigned long sockets_concurrent_record = 0; +unsigned long sockets_errors = 0; + +bool net_set_non_blocking(int sock) { + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + perror("fcntl"); + return false; + } + + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + return false; + } + + return true; +} + +int net_socket_init() { + int socket_fd = -1; + memset(sockets, 0, sizeof(sockets)); + int opt = 1; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed.\n"); + return false; + } + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("Setsockopt failed.\n"); + close(socket_fd); + return false; + } + net_set_non_blocking(socket_fd); + return socket_fd; +} + +char *net_socket_name(int fd) { + rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); + if (rnet_socket) { + return rnet_socket->name; + ; + } + + // If socket disconnected or is no client from server + return NULL; +} + +bool net_socket_bind(int socket_fd, unsigned int port) { + struct sockaddr_in address; + + address.sin_family = AF_INET; // IPv4 + address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address + address.sin_port = htons(port); // Convert port to network byte order + + if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(socket_fd); + return false; + } + return true; +} + +int net_socket_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = -1; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return -1; + } + + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + + break; + } + + if (p == NULL) { + freeaddrinfo(res); + return -1; + } + + freeaddrinfo(res); + return socket_fd; +} + +bool net_socket_listen(int socket_fd, unsigned int backlog) { + if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + perror("Listen failed"); + close(socket_fd); + return false; + } + return true; +} + +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { + signal(SIGPIPE, SIG_IGN); + int socket_fd = net_socket_init(); + net_socket_bind(socket_fd, port); + net_socket_listen(socket_fd, backlog); + return rnet_server_new(socket_fd, port, backlog); +} + +int net_socket_accept(int net_socket_server_fd) { + struct sockaddr_in address; + int addrlen = sizeof(address); + int new_socket = -1; + if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + close(new_socket); + return -1; + } else { + + return new_socket; + } +} +/* +static void net_socket_stats(WrenVM *vm) +{ + + wrenSetSlotNewList(vm, 0); + + wrenSetSlotString(vm, 1, "sockets_total"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_total); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_concurrent_record"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_connected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_connected); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_disconnected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); + wrenInsertInList(vm, 0, -1, 1); +}*/ + +size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { + ssize_t sent_total = 0; + ssize_t sent = 0; + ssize_t to_send = size; + while ((sent = send(sock->fd, message, to_send, 0))) { + if (sent == -1) { + sockets_errors++; + net_socket_close(sock); + break; + } + if (sent == 0) { + printf("EDGE CASE?\n"); + exit(1); + sockets_errors++; + net_socket_close(sock); + break; + } + sent_total += sent; + if (sent_total == to_send) + break; + } + return sent_total; +} + +unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { + if (buff_size > 1024 * 1024 + 1) { + perror("Buffer too big. Maximum is 1024*1024.\n"); + exit(1); + } + static unsigned char buffer[1024 * 1024]; + buffer[0] = 0; + ssize_t received = recv(sock->fd, buffer, buff_size, 0); + if (received <= 0) { + buffer[0] = 0; + net_socket_close(sock); + if (received < 0) { + sockets_errors++; + return NULL; + } + } + buffer[received + 1] = 0; + sock->bytes_received = received; + return buffer; +} + +rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { + if (!sock) + return NULL; + if (sock->fd == -1) + return NULL; + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(sock->fd, &read_fds); + + int max_socket_fd = sock->fd; + int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + // perror("Select error"); + net_socket_close(sock); + return NULL; + } + if (FD_ISSET(sock->fd, &read_fds)) { + return sock; + } + + return NULL; +} + +void rnet_safe_str(char *str, size_t length) { + if (!str || !length || !*str) + return; + for (unsigned int i = 0; i < length; i++) { + if (str[i] < 32 || str[i] > 126) + if (str[i] != 0) + str[i] = '.'; + } + str[length] = 0; +} + +rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { + rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + memset(result, 0, sizeof(rnet_select_result_t)); + result->server_fd = socket_fd; + result->socket_count = 0; + result->sockets = NULL; + return result; +} + +void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { + result->sockets = realloc(result->sockets, sizeof(rnet_socket_t *) * (result->socket_count + 1)); + result->sockets[result->socket_count] = sock; + result->socket_count++; +} +void rnet_select_result_free(rnet_select_result_t *result) { free(result); } +rnet_select_result_t *net_socket_select(rnet_server_t *server) { + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(server->socket_fd, &read_fds); + + server->max_fd = server->socket_fd; + int socket_fd = -1; + for (unsigned int i = 0; i < server->socket_count; i++) { + socket_fd = server->sockets[i]->fd; + if (!server->sockets[i]->connected) { + continue; + } + if (socket_fd > 0) { + FD_SET(socket_fd, &read_fds); + if (socket_fd > server->max_fd) { + server->max_fd = socket_fd; + } + } + } + int new_socket = -1; + struct sockaddr_in address; + int addrlen = sizeof(struct sockaddr_in); + int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } + if (FD_ISSET(server->socket_fd, &read_fds)) { + if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed\n"); + return NULL; + } + + // net_set_non_blocking(new_socket); + char name[50] = {0}; + sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + rnet_socket_t *sock_obj = NULL; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets && server->sockets[i]->fd == -1) { + sock_obj = server->sockets[i]; + } + } + if (!sock_obj) { + sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + rnet_server_add_socket(server, sock_obj); + } + sock_obj->fd = new_socket; + strcpy(sock_obj->name, name); + sockets_connected++; + sockets_total++; + sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; + if (new_socket > net_socket_max_fd) { + net_socket_max_fd = new_socket; + } + sock_obj->connected = true; + sock_obj->on_connect(sock_obj); + } + rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); + unsigned int readable_count = 0; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets[i]->fd == -1) + continue; + if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { + rnet_select_result_add(result, server->sockets[i]); + readable_count++; + if (server->sockets[i]->on_read) { + server->sockets[i]->on_read(server->sockets[i]); + } + } + } + if (server->select_result) { + rnet_select_result_free(server->select_result); + server->select_result = NULL; + } + if (readable_count == 0) + rnet_select_result_free(result); + return readable_count ? result : NULL; +} + +rnet_socket_t *get_net_socket_by_fd(int sock) { + for (int i = 0; i < net_socket_max_fd; i++) { + if (sockets[i].fd == sock) { + return &sockets[i]; + } + } + return NULL; +} + +void _net_socket_close(int sock) { + if (sock > 0) { + sockets_connected--; + sockets_disconnected++; + if (sock > 0) { + if (close(sock) == -1) { + perror("Error closing socket.\n"); + } + } + } +} + +void net_socket_close(rnet_socket_t *sock) { + sock->connected = false; + if (sock->on_close) + sock->on_close(sock); + _net_socket_close(sock->fd); + sock->fd = -1; +} +#undef _POSIX_C_SOURCE +#endif + +#include <stdio.h> +#ifndef RLIB_RARGS_H +#define RLIB_RARGS_H +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +bool rargs_isset(int argc, char *argv[], char *key) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + return true; + } + } + return false; +} + +char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return argv[i + 1]; + } + } + } + return (char *)def; +} + +int rargs_get_option_int(int argc, char *argv[], char *key, int def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + return atoi(argv[i + 1]); + } + } + } + return def; +} + +bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { + + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], key)) { + if (i < argc - 1) { + if (!strcmp(argv[i + 1], "false")) + return false; + if (!strcmp(argv[i + 1], "0")) + return false; + return true; + } + } + } + + return def; +} +#endif +#ifndef RCAT_H +#define RCAT_H +#include <stdio.h> +#include <stdlib.h> + +void rcat(char *filename) { + FILE *f = fopen(filename, "rb"); + if (!f) { + printf("rcat: couldn't open \"%s\" for read.\n", filename); + return; + } + unsigned char c; + while ((c = fgetc(f)) && !feof(f)) { + printf("%c", c); + } + fclose(f); + fflush(stdout); +} + +int rcat_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [filename]\n"); + return 1; + } + rcat(argv[1]); + return 0; +} + +#endif + +#ifndef RLIZA_H +#define RLIZA_H +#ifndef RBUFFER_H +#define RBUFFER_H +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +typedef struct rbuffer_t { + unsigned char *data; + unsigned char *_data; + size_t size; + size_t pos; + bool eof; +} rbuffer_t; + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size); +void rbuffer_free(rbuffer_t *rfb); +void rbuffer_reset(rbuffer_t *rfb); +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +unsigned char rbuffer_pop(rbuffer_t *rfb); +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); + +void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size) { + if (rfb->_data) { + free(rfb->_data); + rfb->_data = NULL; + rfb->data = NULL; + rfb->eof = true; + } + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->data = rfb->_data; + rfb->eof = false; + } + rfb->size = size; + rfb->pos = 0; +} + +rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { + rbuffer_t *rfb = (rbuffer_t *)malloc(sizeof(rbuffer_t)); + if (size) { + rfb->_data = (unsigned char *)malloc(size); + memcpy(rfb->_data, data, size); + rfb->eof = false; + } else { + rfb->_data = NULL; + rfb->eof = true; + } + rfb->size = size; + rfb->pos = 0; + rfb->data = rfb->_data; + return rfb; +} +void rbuffer_free(rbuffer_t *rfb) { + if (rfb->_data) + free(rfb->_data); + free(rfb); +} + +size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { + if (rfb->pos < rfb->size) { + rfb->_data[rfb->pos++] = c; + return 1; + } + rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); + rfb->_data[rfb->pos++] = c; + rfb->size++; + return rfb->pos; +} +void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { + unsigned char *data_ptr = (unsigned char *)data; + for (size_t i = 0; i < size; i++) { + rbuffer_push(rfb, data_ptr[i]); + } +} + +unsigned char rbuffer_peek(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos != rfb->size) { + result = rfb->_data[rfb->pos]; + return result; + } + rfb->eof = true; + return EOF; +} +unsigned char rbuffer_pop(rbuffer_t *rfb) { + unsigned char result = EOF; + if (rfb->pos <= rfb->size) { + result = rfb->_data[rfb->pos]; + rfb->pos++; + rfb->data++; + if (rfb->pos == rfb->size) { + rfb->eof = true; + } + return result; + } + rfb->eof = true; + return result; +} +void rbuffer_reset(rbuffer_t *rfb) { + rfb->data = rfb->_data; + rfb->pos = 0; +} + +unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { + return strncmp((char *)s1, (char *)s2, n); + while (n && *s1 == *s2) { + n--; + s1++; + s2++; + } + return *s1 != *s2; +} +size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +unsigned char *rbuffer_to_string(rbuffer_t *rfb) { + unsigned char *result = rfb->_data; + rfb->_data = NULL; + rfb->data = NULL; + rbuffer_free(rfb); + return result; +} + +unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { + char *option = NULL; + char options_cpy[1024] = {0}; + strcpy(options_cpy, options); + char *memory = options_cpy; + while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { + + size_t option_length = strlen(option); + if (option_length > rfb->size - rfb->pos) { + continue; + } + if (!strcmp(option, "\\d") && *rfb->data >= '0' && *rfb->data <= '9') { + return rfb->data; + } + if (rfb->size - rfb->pos >= 5 && !strcmp(option, "\\b") && + ((!ustrncmp(rfb->data, (unsigned char *)"true", 4) || !ustrncmp(rfb->data, (unsigned char *)"false", 5)))) { + return rfb->data; + } + if (!ustrncmp(rfb->data, (unsigned char *)option, option_length)) { + return rfb->data; + } + } + return NULL; +} + +unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { + while (rfb->pos < rfb->size) { + if (rbuffer_match_option(rfb, options) != NULL) { + return rfb->data; + } + if (rbuffer_match_option(rfb, ignore)) { + printf("SKIP:%s\n", rfb->data); + rbuffer_pop(rfb); + continue; + } + break; + } + return NULL; +} +unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { + unsigned char *result = NULL; + if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { + rbuffer_pop(rfb); + } + return result; +} +#endif +#ifndef RSTRING_H +#define RSTRING_H +#ifndef RMATH_H +#define RMATH_H +#include <math.h> + +#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 +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +char *rstrtimestamp() { + time_t current_time; + time(¤t_time); + struct tm *local_time = localtime(¤t_time); + static char time_string[100]; + time_string[0] = 0; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); + return time_string; +} + +ulonglong _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]; + key[0] = 0; + sprintf(key, "%lld", _r_generate_key_current); + return key; +} + +char *rformat_number(long long lnumber) { + static char formatted[1024]; + + char number[1024] = {0}; + sprintf(number, "%lld", lnumber); + + int len = strlen(number); + int commas_needed = (len - 1) / 3; + int new_len = len + commas_needed; + + formatted[new_len] = '\0'; + + int i = len - 1; + int j = new_len - 1; + int count = 0; + + while (i >= 0) { + if (count == 3) { + formatted[j--] = '.'; + count = 0; + } + formatted[j--] = number[i--]; + count++; + } + if (lnumber < 0) + formatted[j--] = '-'; + return formatted; +} + +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 == '\\') { + 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 = '\\'; + i++; + } + } + result[index] = c; + index++; + } + result[index] = 0; +} + +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); +} + +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); +} + +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; + } else if (content[i] == '"') { + result[index] = '\\'; + index++; + result[index] = '"'; + index++; + continue; + } + result[index] = content[i]; + index++; + result[index] = 0; + } +} + +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] == ' ' || input[i] == '\n') { + continue; + } + count = i; + size_t j; + for (j = 0; j < len - count; j++) { + output[j] = input[j + count]; + } + output[j] = '\0'; + break; + } + return count; +} + +/* + * Converts "pony" to \"pony\". Addslashes does not + * Converts "pony\npony" to "pony\n" + * "pony" + */ +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); + output[0] = 0; + size_t new_offset = 0; + size_t j; + size_t index = 0; + + for (j = offset; j < len + offset; j++) { + if (input[j] == 0) { + index++; + break; + } + index = j - offset; + output[index] = input[j]; + + if (output[index] == '\n') { + index++; + break; + } + } + output[index] = 0; + + new_offset = index + offset; + + if (strip_nl) { + if (output[index - 1] == '\n') { + output[index - 1] = 0; + } + } + return new_offset; +} + +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); + } +} + +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; +} + +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); + } +} + +int cmp_line(const void *left, const void *right) { + char *l = *(char **)left; + char *r = *(char **)right; + + char lstripped[strlen(l) + 1]; + rstrip_whitespace(l, lstripped); + char rstripped[strlen(r) + 1]; + rstrip_whitespace(r, rstripped); + + double d1, d2; + bool found_d1 = rstrextractdouble(lstripped, &d1); + bool found_d2 = rstrextractdouble(rstripped, &d2); + + 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; +} + +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); + for (int i = 0; i < line_count; i++) { + free(lines[i]); + } + free(lines); + return line_count; +} + +#endif + +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef enum rliza_type_t { + RLIZA_STRING = 's', + RLIZA_BOOLEAN = 'b', + RLIZA_NUMBER = 'n', + RLIZA_OBJECT = 'o', + RLIZA_ARRAY = 'a', + RLIZA_NULL = 0, + RLIZA_KEY = 'k', + RLIZA_INTEGER = 'i' +} rliza_type_t; + +typedef struct rliza_t { + rliza_type_t type; + struct rliza_t *value; + char *key; + union { + char *string; + bool boolean; + double number; + struct rliza_t **map; + long long integer; + } content; + unsigned int count; + char *(*get_string)(struct rliza_t *, char *); + long long (*get_integer)(struct rliza_t *, char *); + double (*get_number)(struct rliza_t *, char *); + bool (*get_boolean)(struct rliza_t *, char *); + struct rliza_t *(*get_array)(struct rliza_t *, char *); + struct rliza_t *(*get_object)(struct rliza_t *, char *); + void (*set_string)(struct rliza_t *, char *, char *); + void (*set_integer)(struct rliza_t *, char *, long long); + void (*set_number)(struct rliza_t *, char *, double); + void (*set_boolean)(struct rliza_t *, char *, bool); + void (*set_array)(struct rliza_t *self, char *key, struct rliza_t *array); + void (*set_object)(struct rliza_t *self, char *key, struct rliza_t *object); +} rliza_t; + +void rliza_free(rliza_t *rliza) { + if (rliza->key) { + free(rliza->key); + rliza->key = NULL; + } + if (rliza->value) { + rliza_free(rliza->value); + rliza->value = NULL; + } + // if (rliza->content.array) { + // printf("JAAAA\n"); + // } + // if (rliza->content.object) { + // rliza_free(rliza->content.object); + // rliza->content.object = NULL; + //} + if (rliza->type == RLIZA_STRING) { + if (rliza->content.string) { + free(rliza->content.string); + rliza->content.string = NULL; + // else if (rliza->type == RLIZA_NUMBER) { + // printf("STDring freed\n"); + } + } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { + + if (rliza->content.map) { + for (unsigned int i = 0; i < rliza->count; i++) { + rliza_free(rliza->content.map[i]); + } + free(rliza->content.map); + } + } + // free(rliza->content.array); + //} + + free(rliza); +} + +rliza_t *rliza_new(rliza_type_t type); +rliza_t *rliza_new_string(char *string); +rliza_t *rliza_new_null(); +rliza_t *rliza_new_boolean(bool value); +rliza_t *rliza_new_number(double value); +rliza_t *rliza_new_integer(long long value); +rliza_t *rliza_new_key_value(char *key, rliza_t *value); +rliza_t *rliza_new_key_string(char *key, char *string); +rliza_t *rliza_new_key_bool(char *key, bool value); +rliza_t *rliza_new_key_number(char *key, double value); +void rliza_push(rliza_t *self, rliza_t *obj); +void rliza_push_object(rliza_t *self, rliza_t *object); +void rliza_set_object(rliza_t *self, char *key, rliza_t *object); +void rliza_set_string(rliza_t *self, char *key, char *string); +void rliza_set_boolean(rliza_t *self, char *key, bool value); +void rliza_set_number(rliza_t *self, char *key, double value); +void rliza_set_integer(rliza_t *self, char *key, long long value); +char *rliza_get_string(rliza_t *self, char *key); +long long rliza_get_integer(rliza_t *self, char *key); +double rliza_get_number(rliza_t *self, char *key); +bool rliza_get_boolean(rliza_t *self, char *key); +rliza_t *rliza_get_array(rliza_t *self, char *key); +rliza_t *rliza_get_object(rliza_t *self, char *key); +void rliza_set_array(rliza_t *self, char *key, rliza_t *array); + +char *rliza_dumps(rliza_t *rliza); +rliza_t *rliza_loads(char **content); +rliza_t *_rliza_loads(char **content); + +char *rliza_get_string(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_STRING || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.string; + } + } + } + return NULL; +} +long long rliza_get_integer(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_INTEGER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.integer; + } + } + } + return 0; +} + +double rliza_get_number(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_NUMBER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.number; + } + } + } + return 0; +} + +bool rliza_get_boolean(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_BOOLEAN || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.boolean; + } + } + } + return false; +} + +rliza_t *rliza_get_object(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + return self->content.map[i]; + } + } + return NULL; +} + +rliza_t *rliza_get_array(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_ARRAY || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]; + } + } + } + return NULL; +} + +rliza_t *rliza_new_null() { + rliza_t *rliza = rliza_new(RLIZA_NULL); + return rliza; +} +rliza_t *rliza_new_string(char *string) { + rliza_t *rliza = rliza_new(RLIZA_STRING); + if (string == NULL) { + rliza->type = RLIZA_NULL; + rliza->content.string = NULL; + return rliza; + } else { + rliza->content.string = strdup(string); + } + return rliza; +} +rliza_t *rliza_new_boolean(bool value) { + rliza_t *rliza = rliza_new(RLIZA_BOOLEAN); + rliza->content.boolean = value; + return rliza; +} + +rliza_t *rliza_new_number(double value) { + rliza_t *rliza = rliza_new(RLIZA_NUMBER); + rliza->content.number = value; + return rliza; +} + +rliza_t *rliza_new_integer(long long value) { + rliza_t *rliza = rliza_new(RLIZA_INTEGER); + rliza->content.integer = value; + return rliza; +} +rliza_t *rliza_new_key_array(char *key) { + rliza_t *rliza = rliza_new(RLIZA_ARRAY); + rliza->key = strdup(key); + return rliza; +} + +rliza_t *rliza_new_key_value(char *key, rliza_t *value) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + if (key) { + rliza->key = strdup(key); + } + rliza->value = value; + return rliza; +} + +rliza_t *rliza_new_key_string(char *key, char *string) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_string(string)); + return rliza; +} +rliza_t *rliza_new_key_bool(char *key, bool value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_boolean(value)); + return rliza; +} +rliza_t *rliza_new_key_number(char *key, double value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_number(value)); + return rliza; +} + +void rliza_set_null(rliza_t *self, char *key) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_null(); + obj->key = strdup(key); + rliza_push_object(self, obj); + } + if (obj->type == RLIZA_OBJECT) { + + rliza_free(obj->value); + obj->value = NULL; + } else if (obj->type == RLIZA_STRING) { + if (obj->content.string) + free(obj->content.string); + obj->content.string = NULL; + } else if (obj->type == RLIZA_ARRAY) { + for (unsigned int i = 0; i < obj->count; i++) { + rliza_free(obj->content.map[i]); + } + } else if (obj->type == RLIZA_NUMBER) { + obj->content.number = 0; + } else if (obj->type == RLIZA_INTEGER) { + obj->content.integer = 0; + } + obj->type = RLIZA_NULL; +} + +rliza_t *rliza_duplicate(rliza_t *rliza) { + if (!rliza) + return NULL; + char *str = rliza_dumps(rliza); + char *strp = str; + rliza_t *obj = rliza_loads(&strp); + free(str); + return obj; +} + +rliza_t *rliza_new_object(rliza_t *obj) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + rliza->value = obj; + return rliza; +} +void rliza_set_object(rliza_t *self, char *key, rliza_t *value) { + rliza_t *obj = rliza_duplicate(value); + obj->key = strdup(key); + obj->type = RLIZA_OBJECT; + rliza_push(self, obj); +} + +void rliza_set_string(rliza_t *self, char *key, char *string) { + rliza_t *obj = rliza_get_object(self, key); + + if (!obj) { + obj = rliza_new_string(string); + obj->key = strdup(key); + obj->type = RLIZA_STRING; + rliza_push_object(self, obj); + } else { + obj->content.string = strdup(string); + } +} + +void rliza_set_array(rliza_t *self, char *key, rliza_t *array) { + rliza_t *obj = rliza_get_object(self, key); + if (obj) + rliza_free(obj); + if (array->key) { + free(array->key); + array->key = strdup(key); + } + rliza_push_object(self, array); +} + +void rliza_set_number(rliza_t *self, char *key, double value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_number(value); + obj->key = strdup(key); + obj->type = RLIZA_NUMBER; + rliza_push_object(self, obj); + } else { + obj->content.number = value; + } +} + +void rliza_push_object(rliza_t *self, rliza_t *object) { + self->content.map = realloc(self->content.map, (sizeof(rliza_t **)) * (self->count + 1)); + self->content.map[self->count] = object; + self->count++; +} +void rliza_set_integer(rliza_t *self, char *key, long long value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_integer(value); + obj->key = strdup(key); + obj->type = RLIZA_INTEGER; + rliza_push_object(self, obj); + } else { + obj->content.integer = value; + } +} + +void rliza_set_boolean(rliza_t *self, char *key, bool value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_boolean(value); + obj->key = strdup(key); + obj->type = RLIZA_BOOLEAN; + + rliza_push_object(self, obj); + } else { + obj->content.boolean = value; + } +} + +rliza_t *rliza_new(rliza_type_t type) { + rliza_t *rliza = (rliza_t *)calloc(1, sizeof(rliza_t)); + rliza->type = type; + rliza->get_boolean = rliza_get_boolean; + rliza->get_integer = rliza_get_integer; + rliza->get_number = rliza_get_number; + rliza->get_string = rliza_get_string; + rliza->get_array = rliza_get_array; + rliza->get_object = rliza_get_object; + rliza->set_string = rliza_set_string; + rliza->set_number = rliza_set_number; + rliza->set_boolean = rliza_set_boolean; + rliza->set_integer = rliza_set_integer; + rliza->set_array = rliza_set_array; + rliza->set_object = rliza_set_object; + + return rliza; +} + +void *rliza_coalesce(void *result, void *default_value) { + if (result == NULL) + return default_value; + return result; +} + +char *rliza_seek_string(char **content, char **options) { + + while (**content == ' ' || **content == '\n' || **content == '\t' || **content == '\r') { + (*content)++; + } + if (**content == 0) { + return NULL; + } + + char *option = NULL; + unsigned int option_index = 0; + + while (true) { + option = options[option_index]; + if (option == NULL) + break; + option_index++; + if (option[0] == 'd') { + if (**content >= '0' && **content <= '9') { + return (char *)*content; + } + } else if (!strncmp(option, *content, strlen(option))) { + return (char *)*content; + } + } + return *content; +} + +char *rliza_extract_quotes(char **content) { + rbuffer_t *buffer = rbuffer_new(NULL, 0); + assert(**content == '"'); + char previous = 0; + while (true) { + + (*content)++; + if (!**content) { + rbuffer_free(buffer); + return NULL; + } + + if (**content == '"' && previous != '\\') { + break; + } + rbuffer_push(buffer, **content); + previous = **content; + } + assert(**content == '"'); + (*content)++; + rbuffer_push(buffer, 0); + char *result = (char *)rbuffer_to_string(buffer); + return result; +} + +rliza_t *_rliza_loads(char **content) { + static char *seek_for1[] = {"[", "{", "\"", "d", "true", "false", "null", NULL}; + char *token = (char *)rliza_seek_string(content, seek_for1); + if (!token) + return NULL; + rliza_t *rliza = rliza_new(RLIZA_NULL); + if (**content == '"') { + char *extracted = rliza_extract_quotes(content); + if (!extracted) { + rliza_free(rliza); + return NULL; + } + // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); + // rstraddslashes(extracted, extracted_with_slashes); + rliza->type = RLIZA_STRING; + rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; + // free(extracted); + return rliza; + } else if (**content == '{') { + rliza->type = RLIZA_OBJECT; + (*content)++; + char *result = NULL; + static char *seek_for2[] = {"\"", ",", "}", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for2)) != NULL && *result) { + + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (**content == ',') { + (*content)++; + if (!**content) { + rliza_free(rliza); + return NULL; + } + continue; + } + char *key = NULL; + if (**content == '"') { + key = rliza_extract_quotes((char **)content); + if (!key || !*key) { + rliza_free(rliza); + return NULL; + } + char *escaped_key = (char *)malloc(strlen((char *)key) * 2 + 1); + rstrstripslashes((char *)key, escaped_key); + static char *seek_for3[] = {":", NULL}; + char *devider = rliza_seek_string(content, seek_for3); + + if (!devider || !*devider) { + free(escaped_key); + free(key); + rliza_free(rliza); + return NULL; + } + (*content)++; + if (!**content) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + rliza_t *value = _rliza_loads(content); + if (!value) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + if (value->key) + free(value->key); + value->key = escaped_key; + free(key); + rliza_push_object(rliza, value); + } else if (**content == '}') { + break; + } else { + // Parse error + rliza_free(rliza); + return NULL; + } + }; + if ((**content != '}')) { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content == '[') { + rliza->type = RLIZA_ARRAY; + (*content)++; + char *result; + static char *seek_for4[] = {"[", "{", "\"", "d", ",", "]", "null", "true", "false", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for4)) != NULL && *result) { + if (**content == ',') { + (*content)++; + + } else if (**content == ']') { + break; + } + rliza_t *obj = _rliza_loads(content); + if (!obj) { + rliza_free(rliza); + return NULL; + } + rliza_push(rliza, obj); + if (!**content) { + rliza_free(rliza); + return NULL; + } + } + if (**content != ']') { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content >= '0' && **content <= '9') { + char *ptr = *content; + bool is_decimal = false; + + while (**content) { + if (**content == '.') { + is_decimal = true; + } else if (!isdigit(**content)) { + break; + } + (*content)++; + } + if (*(*content - 1) == '.') { + rliza_free(rliza); + return NULL; + } + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (is_decimal) { + rliza->type = RLIZA_NUMBER; + rliza->content.number = strtod(ptr, NULL); + } else { + rliza->type = RLIZA_INTEGER; + rliza->content.integer = strtoll(ptr, NULL, 10); + } + return rliza; + } else if (!strncmp(*content, "true", 4)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = true; + *content += 4; + + return rliza; + } else if (!strncmp(*content, "false", 5)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = false; + *content += 5; + + return rliza; + } else if (!strncmp(*content, "null", 4)) { + rliza->type = RLIZA_NULL; + *content += 4; + + return rliza; + } + // Parsing error + rliza_free(rliza); + return NULL; +} +rliza_t *rliza_loads(char **content) { + if (!content || !**content) { + return NULL; + } + char *original_content = *content; + rliza_t *result = _rliza_loads(content); + if (!result) { + *content = original_content; + } + return result; +} + +char *rliza_dumps(rliza_t *rliza) { + size_t size = 4096; + char *content = (char *)calloc(size, sizeof(char)); + content[0] = 0; + if (rliza->type == RLIZA_INTEGER) { + if (rliza->key) { + sprintf(content, "\"%s\":%lld", rliza->key, rliza->content.integer); + } else { + sprintf(content, "%lld", rliza->content.integer); + } + } else if (rliza->type == RLIZA_STRING) { + + // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); + char *escaped_string = rliza->content.string; + // rstrstripslashes((char *)rliza->content.string, escaped_string); + size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; + if (size < min_size) { + size = min_size + 1; + content = realloc(content, size); + } + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 20); + rstrstripslashes((char *)rliza->key, escaped_key); + if (strlen(content) > size) { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + } + sprintf(content, "\"%s\":\"%s\"", escaped_key, escaped_string); + free(escaped_key); + } else { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + sprintf(content, "\"%s\"", escaped_string); + } + // free(escaped_string); + } else if (rliza->type == RLIZA_NUMBER) { + if (rliza->key) { + sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); + } else { + sprintf(content, "%f", rliza->content.number); + } + int last_zero = 0; + bool beyond_dot = false; + for (size_t i = 0; i < strlen(content); i++) { + if (content[i] == '.') { + beyond_dot = true; + } else if (beyond_dot == true) { + if (content[i - 1] != '.') { + if (content[i] == '0') { + if (!last_zero) + last_zero = i; + } else { + last_zero = 0; + } + } + } + } + if (last_zero != 0) { + content[last_zero] = 0; + } + } else if (rliza->type == RLIZA_BOOLEAN) { + if (rliza->key) { + sprintf(content, "\"%s\":%s", rliza->key, rliza->content.boolean ? "true" : "false"); + } else { + sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); + } + } else if (rliza->type == RLIZA_OBJECT) { + + strcat(content, "{"); + if (rliza->key) { + strcat(content, "\""); + strcat(content, rliza->key); + strcat(content, "\":{"); + } + // bool add_braces = false; + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + content_chunk_stripped++; + content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + + strcat(content, ","); + } + if (content[strlen(content) - 1] == ',') { + content[strlen(content) - 1] = '\0'; + + if (rliza->key) { + strcat(content, "}"); + } + } + strcat(content, "}"); + } else if (rliza->type == RLIZA_ARRAY) { + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + if (strlen(escaped_key) > size) { + size = strlen(escaped_key) + 10; + content = realloc(content, size); + } + sprintf(content, "\"%s\":[", escaped_key); + free(escaped_key); + } else + strcpy(content, "["); + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + // content_chunk_stripped++; + // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + strcat(content, ","); + } + if (content[strlen(content) - 1] != '[') + content[strlen(content) - 1] = 0; + strcat(content, "]"); + } else if (rliza->type == RLIZA_NULL) { + + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + sprintf(content, "\"%s\":null", escaped_key); + free(escaped_key); + } else + strcpy(content, "null"); + } + return content; +} + +void rliza_dumpss(rliza_t *rliza) { + char *output = rliza_dumps(rliza); + printf("%s\n", output); + free(output); +} + +void rliza_push(rliza_t *self, rliza_t *obj) { rliza_push_object(self, obj); } + +int rliza_validate(char *json_content) { + if (!json_content || !*json_content) { + return false; + } + char *json_contentp = json_content; + rliza_t *to_object = _rliza_loads(&json_contentp); + if (to_object) { + rliza_free(to_object); + return json_contentp - json_content; + } + return false; +} + +#endif + +#ifndef RCOV_H +#define RCOV_H +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#ifndef RBENCH_H +#define RBENCH_H + +#ifndef RPRINT_H +#define RPRINT_H + +#ifndef RLIB_TIME +#define RLIB_TIME + +#ifndef _POSIX_C_SOURCE_199309L + +#define _POSIX_C_SOURCE_199309L +#endif +#include <sys/time.h> +#include <time.h> +#undef _POSIX_C_SOURCE_199309L +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 1 +#endif + +typedef uint64_t nsecs_t; +void nsleep(nsecs_t nanoseconds); + +void tick() { nsleep(1); } + +typedef unsigned long long msecs_t; + +nsecs_t nsecs() { + unsigned int lo, hi; + __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +} + +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); +} + +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; + str[i] = 0; + } + return 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 { + char *s = msecs_strms(ms); + sprintf(result, "%sMs", s); + } + return result; +} + +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; + + nanosleep(&req, &rem); +} + +void ssleep(double s) { + long nanoseconds = (long)(1000000000 * s); + + // long seconds = 0; + + // struct timespec req = {seconds, nanoseconds}; + // struct timespec rem; + + nsleep(nanoseconds); +} +void msleep(long miliseonds) { + long nanoseconds = miliseonds * 1000000; + nsleep(nanoseconds); +} + +char *format_time(int64_t nanoseconds) { + 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; + if (s > 60 * 60) { + s = s / 60 / 60; + snprintf(output, output_size, "%.2fh", s); + } else if (s > 60) { + s = s / 60; + snprintf(output, output_size, "%.2fm", s); + } else { + snprintf(output, output_size, "%.2fs", s); + } + } + return sbuf(output); +} + +#endif + +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +long rpline_number = 0; +nsecs_t rprtime = 0; + +int8_t _env_rdisable_colors = -1; +bool _rprint_enable_colors = true; + +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; + } + return _rprint_enable_colors; +} + +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; } + +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 = 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(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "", format, args); + va_end(args); +} + +void rprintf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "", format, args); + va_end(args); +} +void rprint(const 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, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\\l", format, args); + va_end(args); +} +void rprintl(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\\l", format, args); + va_end(args); +} + +// Black +void rprintkf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[30m", format, args); + va_end(args); +} +void rprintk(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[30m", format, args); + va_end(args); +} + +// Red +void rprintrf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[31m", format, args); + va_end(args); +} +void rprintr(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[31m", format, args); + va_end(args); +} + +// Green +void rprintgf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[32m", format, args); + va_end(args); +} +void rprintg(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[32m", format, args); + va_end(args); +} + +// Yellow +void rprintyf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[33m", format, args); + va_end(args); +} +void rprinty(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[33m", format, args); + va_end(args); +} + +// Blue +void rprintbf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[34m", format, args); + va_end(args); +} + +void rprintb(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[34m", format, args); + va_end(args); +} + +// Magenta +void rprintmf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[35m", format, args); + va_end(args); +} +void rprintm(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[35m", format, args); + va_end(args); +} + +// Cyan +void rprintcf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[36m", format, args); + va_end(args); +} +void rprintc(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[36m", format, args); + va_end(args); +} + +// White +void rprintwf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[37m", format, args); + va_end(args); +} +void rprintw(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[37m", format, args); + va_end(args); +} +#endif +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> + +#ifndef RLIB_TERMINAL_H +#define RLIB_TERMINAL_H + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef RTEST_H +#define RTEST_H +#ifndef REMO_H +#define REMO_H +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +typedef struct { + const char *str; + const char *description; +} remo_t; + +remo_t remo[] = { + {"\U0001F600", "Grinning Face"}, // 😀 + {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 + {"\U0001F602", "Face with Tears of Joy"}, // 😂 + {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 + {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 + {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 + {"\U0001F609", "Winking Face"}, // 😉 + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 + {"\U0001F618", "Face Blowing a Kiss"}, // 😘 + {"\U0001F617", "Kissing Face"}, // 😗 + {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 + {"\U0001F642", "Slightly Smiling Face"}, // 🙂 + {"\U0001F643", "Upside-Down Face"}, // 🙃 + {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 + {"\U0001F60B", "Face Savoring Food"}, // 😋 + {"\U0001F61B", "Face with Tongue"}, // 😛 + {"\U0001F61C", "Winking Face with Tongue"}, // 😜 + {"\U0001F92A", "Zany Face"}, // 🤪 + {"\U0001F929", "Star-Struck"}, // 🤩 + {"\U0001F631", "Face Screaming in Fear"}, // 😱 + {"\U0001F62D", "Loudly Crying Face"}, // 😭 + {"\U0001F624", "Face with Steam From Nose"}, // 😤 + {"\U0001F620", "Angry Face"}, // 😠 + {"\U0001F621", "Pouting Face"}, // 😡 + {"\U0001F47B", "Ghost"}, // 👻 + {"\U0001F480", "Skull"}, // 💀 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + {"\U0001F47D", "Alien"}, // 👽 + // Geometric Shapes + {"\U000025A0", "Black Square"}, // ■ + {"\U000025B2", "Upward Triangle"}, // ▲ + {"\U000025CF", "Black Circle"}, // ● + {"\U000025CB", "White Circle"}, // ○ + {"\U00002B1B", "Large Black Square"}, // ⬛ + {"\U00002B1C", "Large White Square"}, // ⬜ + + // Mathematical Symbols + {"\U00002200", "For All"}, // ∀ + {"\U00002203", "Exists"}, // ∃ + {"\U00002205", "Empty Set"}, // ∅ + {"\U00002207", "Nabla"}, // ∇ + {"\U0000220F", "N-Ary Product"}, // ∏ + {"\U00002212", "Minus Sign"}, // − + {"\U0000221E", "Infinity"}, // ∞ + + // Arrows + {"\U00002190", "Left Arrow"}, // ← + {"\U00002191", "Up Arrow"}, // ↑ + {"\U00002192", "Right Arrow"}, // → + {"\U00002193", "Down Arrow"}, // ↓ + {"\U00002195", "Up Down Arrow"}, // ↕ + {"\U00002197", "Up Right Arrow"}, // ↗ + {"\U00002198", "Down Right Arrow"}, // ↘ + {"\U000027A1", "Black Right Arrow"}, // ➡️ + + // Dingbats + {"\U00002714", "Check Mark"}, // ✔️ + {"\U00002716", "Heavy Multiplication X"}, // ✖️ + {"\U00002728", "Sparkles"}, // ✨ + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002795", "Heavy Plus Sign"}, // ➕ + + // Miscellaneous Symbols + {"\U00002600", "Sun"}, // ☀️ + {"\U00002614", "Umbrella with Rain Drops"}, // ☔ + {"\U00002620", "Skull and Crossbones"}, // ☠️ + {"\U000026A0", "Warning Sign"}, // ⚠️ + {"\U000026BD", "Soccer Ball"}, // ⚽ + {"\U000026C4", "Snowman"}, // ⛄ + + // Stars and Asterisks + {"\U00002733", "Eight Pointed Black Star"}, // ✳️ + {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U00002728", "Sparkles"}, // ✨ + // Animals and Nature + {"\U0001F98A", "Fox"}, // 🦊 + {"\U0001F415", "Dog"}, // 🐕 + {"\U0001F431", "Cat Face"}, // 🐱 + {"\U0001F435", "Monkey Face"}, // 🐵 + {"\U0001F408", "Black Cat"}, // 🐈 + {"\U0001F98C", "Deer"}, // 🦌 + {"\U0001F344", "Mushroom"}, // 🍄 + {"\U0001F333", "Tree"}, // 🌳 + + // Weather and Space Symbols + {"\U0001F308", "Rainbow"}, // 🌈 + {"\U0001F320", "Shooting Star"}, // 🌠 + {"\U00002600", "Sun"}, // ☀️ + {"\U00002601", "Cloud"}, // ☁️ + {"\U000026A1", "High Voltage"}, // ⚡ + {"\U0001F525", "Fire"}, // 🔥 + {"\U000026C4", "Snowman"}, // ⛄ + {"\U0001F30A", "Water Wave"}, // 🌊 + + // Transport and Map Symbols + {"\U0001F68C", "Bus"}, // 🚌 + {"\U0001F697", "Car"}, // 🚗 + {"\U0001F6B2", "Bicycle"}, // 🚲 + {"\U0001F6A2", "Ship"}, // 🚢 + {"\U0001F681", "Helicopter"}, // 🚁 + {"\U0001F680", "Rocket"}, // 🚀 + {"\U0001F6EB", "Airplane"}, // 🛫 + + // Currency Symbols + {"\U00000024", "Dollar Sign"}, // $ + {"\U000000A3", "Pound Sign"}, // £ + {"\U000000A5", "Yen Sign"}, // ¥ + {"\U000020AC", "Euro Sign"}, // € + {"\U0001F4B5", "Dollar Banknote"}, // 💵 + {"\U0001F4B4", "Yen Banknote"}, // 💴 + + // Card Suits + {"\U00002660", "Black Spade Suit"}, // ♠️ + {"\U00002663", "Black Club Suit"}, // ♣️ + {"\U00002665", "Black Heart Suit"}, // ♥️ + {"\U00002666", "Black Diamond Suit"}, // ♦️ + {"\U0001F0CF", "Joker Card"}, // 🃏 + + // Office Supplies and Objects + {"\U0001F4DA", "Books"}, // 📚 + {"\U0001F4D7", "Green Book"}, // 📗 + {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 + {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 + {"\U0001F4B0", "Money Bag"}, // 💰 + {"\U0001F4B8", "Money with Wings"}, // 💸 + {"\U0001F4E6", "Package"}, // 📦 + + // Miscellaneous Symbols + {"\U00002757", "Exclamation Mark"}, // ❗ + {"\U00002714", "Check Mark"}, // ✔️ + {"\U0000274C", "Cross Mark"}, // ❌ + {"\U00002705", "Check Mark Button"}, // ✅ + {"\U00002B50", "White Star"}, // ⭐ + {"\U0001F31F", "Glowing Star"}, // 🌟 + {"\U0001F4A1", "Light Bulb"}, // 💡 + {"\U0001F4A3", "Bomb"}, // 💣 + {"\U0001F4A9", "Pile of Poo"}, // 💩 + // Musical Symbols + {"\U0001F3B5", "Musical Note"}, // 🎵 + {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 + {"\U0001F3BC", "Musical Score"}, // 🎼 + {"\U0001F399", "Studio Microphone"}, // 🎙️ + {"\U0001F3A4", "Microphone"}, // 🎤 + + // Food and Drink + {"\U0001F35F", "Cheese Wedge"}, // 🧀 + {"\U0001F355", "Slice of Pizza"}, // 🍕 + {"\U0001F32D", "Taco"}, // 🌮 + {"\U0001F37D", "Beer Mug"}, // 🍻 + {"\U0001F96B", "Cup with Straw"}, // 🥤 + {"\U0001F32E", "Hot Pepper"}, // 🌶️ + {"\U0001F95A", "Potato"}, // 🥔 + + // Zodiac Signs + {"\U00002600", "Aries"}, // ♈ + {"\U00002601", "Taurus"}, // ♉ + {"\U00002602", "Gemini"}, // ♊ + {"\U00002603", "Cancer"}, // ♋ + {"\U00002604", "Leo"}, // ♌ + {"\U00002605", "Virgo"}, // ♍ + {"\U00002606", "Libra"}, // ♎ + {"\U00002607", "Scorpio"}, // ♏ + {"\U00002608", "Sagittarius"}, // ♐ + {"\U00002609", "Capricorn"}, // ♑ + {"\U0000260A", "Aquarius"}, // ♒ + {"\U0000260B", "Pisces"}, // ♓ + + // Miscellaneous Shapes + {"\U0001F4C8", "Chart Increasing"}, // 📈 + {"\U0001F4C9", "Chart Decreasing"}, // 📉 + {"\U0001F4CA", "Bar Chart"}, // 📊 + {"\U0001F7E6", "Orange Circle"}, // 🟠 + {"\U0001F7E7", "Yellow Circle"}, // 🟡 + {"\U0001F7E8", "Green Circle"}, // 🟢 + {"\U0001F7E9", "Blue Circle"}, // 🔵 + {"\U0001F7EA", "Purple Circle"}, // 🟣 + + // Flags + {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 + + // Additional Miscellaneous Symbols + {"\U0001F4A5", "Collision"}, // 💥 + {"\U0001F4A6", "Sweat Droplets"}, // 💦 + {"\U0001F4A8", "Dashing Away"}, // 💨 + {"\U0001F50B", "Battery"}, // 🔋 + {"\U0001F4BB", "Laptop Computer"}, // 💻 + {"\U0001F4DE", "Telephone"}, // 📞 + {"\U0001F4E7", "Incoming Envelope"}, // 📧 +}; +size_t remo_count = sizeof(remo) / sizeof(remo[0]); + +void rstrtolower(const char *input, char *output) { + while (*input) { + *output = tolower(*input); + input++; + output++; + } + *output = 0; +} +bool rstrinstr(const char *haystack, const char *needle) { + char lower1[strlen(haystack) + 1]; + char lower2[strlen(needle) + 1]; + rstrtolower(haystack, lower1); + rstrtolower(needle, lower2); + return strstr(lower1, lower2) ? true : false; +} + +void remo_print() { + + for (size_t i = 0; i < remo_count; i++) { + printf("%s - %s\n", remo[i].str, remo[i].description); + } +} + +const char *remo_get(char *name) { + for (size_t i = 0; i < remo_count; i++) { + if (rstrinstr(remo[i].description, name)) { + return remo[i].str; + } + } + return NULL; +} + +#endif +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#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%s\n", rmalloc_stats(), rmalloc_count == 0 ? remo_get("rainbow") : "fire"); + + if (rmalloc_count != 0) { + printf("MEMORY ERROR %s\n", remo_get("cross mark")); + 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, "%s", remo_get("Slightly Smiling Face")); + return true; + } + rprintrf(stderr, "\nERROR %s on line %d: %s\n", remo_get("skull"), 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); } +void rtest_test_assert(char *expr, int res, int line) { + if (rtest_test_true(expr, res, line)) { + return; + } + 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 + +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; + +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; + } +} + +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; + +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; +} + +void rprogressbar_free(rprogressbar_t *pbar) { free(pbar); } + +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; + } + 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, " "); + } + strcat(content, "\r"); + } + fprintf(pbar->fout, "%s", content); + fflush(pbar->fout); +} + +bool rprogressbar_update(rprogressbar_t *pbar, unsigned long value) { + if (value == pbar->current_value) { + return false; + } + 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; +} + +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 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); +} + +#endif + +#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 { +#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; + + nsecs_t average_execution_time; + nsecs_t total_execution_time; +} rbench_function_t; + +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); + +} 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; + } + } +} +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; + } +} + +rbench_t *rbench_new(); + +rbench_t *_rbench = NULL; +rbench_function_t *rbf; +rbench_t *rbench() { + if (_rbench == NULL) { + _rbench = rbench_new(); + } + return _rbench; +} + +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 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]); + } +} +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; +} + +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); + 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; + ; + // 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; +} +struct rbench_t *rbench_execute(rbench_t *r, long times) { + + for (unsigned int i = 0; i < r->function_count; i++) { + + 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; +} + +struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { + + 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); + } + return r; +} + +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; +} + +struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { + + for (unsigned int i = 0; i < r->function_count; i++) { + rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); + + 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; +} + +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; +} +void rbench_free(rbench_t *r) { free(r); } + +#endif +bool check_lcov() { + char buffer[1024 * 64]; + FILE *fp; + fp = popen("lcov --help", "r"); + if (fp == NULL) { + return false; + } + if (fgets(buffer, sizeof(buffer), fp) == NULL) { + return false; + } + pclose(fp); + return strstr(buffer, "lcov: not found") ? false : true; +} + +int rcov_main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: [source.c]\n"); + return 1; + } + char argstr[4096] = {0}; + for (int i = 2; i < argc; i++) { + strcat(argstr, argv[i]); + strcat(argstr, " "); + } + if (!check_lcov()) { + + printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); + return 1; + } + char *source_file = argv[1]; + char *commands[] = {"rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", + "gcc -pg -fprofile-arcs -ftest-coverage -g -o %s_coverage.o %s", + "./%s_coverage.o", + "lcov --capture --directory . --output-file %s.coverage.info", + "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", + "rm -f *.gcda 2>/dev/null", + "rm -f *.gcno 2>/dev/null", + "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", + + "gprof %s_coverage.o gmon.out > output.rcov_analysis", + + "rm -f gmon.out", + "cat output.rcov_analysis", + "rm output.rcov_analysis", + "rm -f %s_coverage.o", + + "google-chrome /tmp/%s.coverage/index.html"}; + uint command_count = sizeof(commands) / sizeof(commands[0]); + RBENCH(1,{ + for (uint i = 0; i < command_count; i++) { + char *formatted_command = sbuf(""); + sprintf(formatted_command, commands[i], source_file, source_file); + // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { + strcat(formatted_command, " "); + strcat(formatted_command, argstr); + } + + if (system(formatted_command)) { + printf("`%s` returned non-zero code.\n", formatted_command); + } + }); + } + return 0; +} +#endif + +#ifndef RHTTP_H +#define RHTTP_H +#include <arpa/inet.h> +#include <pthread.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#define BUFF_SIZE 8096 +#define RHTTP_MAX_CONNECTIONS 100 + +int rhttp_opt_error = 1; +int rhttp_opt_warn = 1; +int rhttp_opt_info = 1; +int rhttp_opt_port = 8080; +int rhttp_opt_debug = 0; +int rhttp_opt_request_logging = 0; +int rhttp_sock = 0; +int rhttp_opt_buffered = 0; +int rhttp_c = 0; +int rhttp_c_mutex_initialized = 0; +pthread_mutex_t rhttp_c_mutex; +char rhttp_opt_host[1024] = "0.0.0.0"; +unsigned int rhttp_connections_handled = 0; + +typedef struct rhttp_header_t { + char *name; + char *value; + struct rhttp_header_t *next; +} rhttp_header_t; + +typedef struct rhttp_request_t { + int c; + int closed; + bool keep_alive; + nsecs_t start; + char *raw; + char *line; + char *body; + char *method; + char *path; + char *version; + void *context; + unsigned int bytes_received; + rhttp_header_t *headers; +} rhttp_request_t; + +char *rhttp_current_timestamp() { + time_t current_time; + time(¤t_time); + struct tm *local_time = localtime(¤t_time); + static char time_string[100]; + time_string[0] = 0; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); + + return time_string; +} + +void rhttp_logs(const char *prefix, const char *level, const char *format, va_list args) { + char buf[strlen(format) + BUFSIZ + 1]; + buf[0] = 0; + sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); + vfprintf(stdout, buf, args); +} +void rhttp_log_info(const char *format, ...) { + if (!rhttp_opt_info) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[32m", "INFO ", format, args); + va_end(args); +} +void rhttp_log_debug(const char *format, ...) { + if (!rhttp_opt_debug) + return; + va_list args; + va_start(args, format); + if (rhttp_opt_debug) + rhttp_logs("\e[33m", "DEBUG", format, args); + + va_end(args); +} +void rhttp_log_warn(const char *format, ...) { + if (!rhttp_opt_warn) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[34m", "WARN ", format, args); + + va_end(args); +} +void rhttp_log_error(const char *format, ...) { + if (!rhttp_opt_error) + return; + va_list args; + va_start(args, format); + rhttp_logs("\e[35m", "ERROR", format, args); + + va_end(args); +} + +void http_request_init(rhttp_request_t *r) { + r->raw = NULL; + r->line = NULL; + r->body = NULL; + r->method = NULL; + r->path = NULL; + r->version = NULL; + r->start = 0; + r->headers = NULL; + r->bytes_received = 0; + r->closed = 0; +} + +void rhttp_free_header(rhttp_header_t *h) { + if (!h) + return; + rhttp_header_t *next = h->next; + free(h->name); + free(h->value); + free(h); + if (next) + rhttp_free_header(next); +} +void rhttp_rhttp_free_headers(rhttp_request_t *r) { + if (!r->headers) + return; + rhttp_free_header(r->headers); + r->headers = NULL; +} + +rhttp_header_t *rhttp_parse_headers(rhttp_request_t *s) { + int first = 1; + char *body = strdup(s->body); + char *body_original = body; + while (body && *body) { + char *line = __strtok_r(first ? body : NULL, "\r\n", &body); + if (!line) + break; + rhttp_header_t *h = (rhttp_header_t *)malloc(sizeof(rhttp_header_t)); + h->name = NULL; + h->value = NULL; + h->next = NULL; + char *name = __strtok_r(line, ": ", &line); + first = 0; + if (!name) { + rhttp_free_header(h); + break; + } + h->name = strdup(name); + char *value = __strtok_r(NULL, "\r\n", &line); + if (!value) { + rhttp_free_header(h); + break; + } + h->value = value ? strdup(value + 1) : strdup(""); + h->next = s->headers; + s->headers = h; + } + free(body_original); + return s->headers; +} + +void rhttp_free_request(rhttp_request_t *r) { + if (r->raw) { + free(r->raw); + free(r->body); + free(r->method); + free(r->path); + free(r->version); + rhttp_rhttp_free_headers(r); + } + free(r); +} + +long rhttp_header_get_long(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return strtol(h->value, NULL, 10); + h = h->next; + } + return -1; +} +char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { + rhttp_header_t *h = r->headers; + while (h) { + if (!strcmp(h->name, name)) + return h->value && *h->value ? h->value : NULL; + h = h->next; + } + return NULL; +} + +void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } +void rhttp_print_headers(rhttp_header_t *h) { + while (h) { + rhttp_print_header(h); + h = h->next; + } +} +void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } +void rhttp_print_request(rhttp_request_t *r) { + rhttp_print_request_line(r); + if (rhttp_opt_debug) + rhttp_print_headers(r->headers); +} +void rhttp_close(rhttp_request_t *r) { + if (!r) + return; + if (!r->closed) + close(r->c); + rhttp_free_request(r); +} +rhttp_request_t *rhttp_parse_request(int s) { + rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); + http_request_init(request); + char buf[BUFF_SIZE] = {0}; + request->c = s; + int breceived = 0; + while (!rstrendswith(buf, "\r\n\r\n")) { + int chunk_size = read(s, buf + breceived, 1); + if (chunk_size <= 0) { + close(request->c); + request->closed = 1; + return request; + } + breceived += chunk_size; + } + if (breceived <= 0) { + close(request->c); + request->closed = 1; + return request; + } + buf[breceived] = '\0'; + char *original_buf = buf; + + char *b = original_buf; + request->raw = strdup(b); + b = original_buf; + char *line = strtok(b, "\r\n"); + b = original_buf; + char *body = b + strlen(line) + 2; + request->body = strdup(body); + b = original_buf; + char *method = strtok(b, " "); + char *path = strtok(NULL, " "); + char *version = strtok(NULL, " "); + request->bytes_received = breceived; + request->line = line; + request->start = nsecs(); + request->method = strdup(method); + request->path = strdup(path); + request->version = strdup(version); + request->headers = NULL; + request->keep_alive = false; + if (rhttp_parse_headers(request)) { + char *keep_alive_string = rhttp_header_get_string(request, "Connection"); + if (keep_alive_string && !strcmp(keep_alive_string, "keep-alive")) { + request->keep_alive = 1; + } + } + return request; +} + +void rhttp_close_server() { + close(rhttp_sock); + close(rhttp_c); + printf("Connections handled: %d\n", rhttp_connections_handled); + printf("Gracefully closed\n"); + exit(0); +} + +size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { + if (to_send_len == 0 && *(unsigned char *)tsend) { + to_send_len = strlen(tsend); + } + unsigned char *to_send = (unsigned char *)malloc(to_send_len); + unsigned char *to_send_original = to_send; + + memcpy(to_send, tsend, to_send_len); + // to_send[to_send_len] = '\0'; + long bytes_sent = 0; + long bytes_sent_total = 0; + while (1) { + bytes_sent = send(s, to_send + bytes_sent_total, to_send_len - bytes_sent_total, 0); + if (bytes_sent <= 0) { + bytes_sent_total = 0; + break; + } + bytes_sent_total += bytes_sent; + + if (bytes_sent_total == (long)to_send_len) { + break; + } else if (!bytes_sent) { + bytes_sent_total = 0; + // error + break; + } else { + rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); + } + } + + free(to_send_original); + return bytes_sent_total; +} + +typedef int (*rhttp_request_handler_t)(rhttp_request_t *r); + +void rhttp_serve(const char *host, int port, int backlog, int request_logging, int request_debug, rhttp_request_handler_t handler, + void *context) { + signal(SIGPIPE, SIG_IGN); + rhttp_sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(host ? host : "0.0.0.0"); + rhttp_opt_debug = request_debug; + rhttp_opt_request_logging = request_logging; + int opt = 1; + setsockopt(rhttp_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + if (bind(rhttp_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + printf("Binding error\n"); + exit(1); + } + listen(rhttp_sock, backlog); + while (1) { + struct sockaddr_in client_addr; + int addrlen = sizeof(client_addr); + + rhttp_c = accept(rhttp_sock, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen); + + rhttp_connections_handled++; + while (true) { + rhttp_request_t *r = rhttp_parse_request(rhttp_c); + r->context = context; + if (!r->closed) { + if (!handler(r) && !r->closed) { + rhttp_close(r); + } + } + if (!r->keep_alive && !r->closed) { + rhttp_close(r); + } else if (r->keep_alive && !r->closed) { + } + if (r->closed) { + break; + } + rhttp_free_request(r); + } + } +} + +unsigned int rhttp_calculate_number_char_count(unsigned int number) { + unsigned int width = 1; + unsigned int tcounter = number; + while (tcounter / 10 >= 1) { + tcounter = tcounter / 10; + width++; + } + return width; +} + +int rhttp_file_response(rhttp_request_t *r, char *path) { + if (!*path) + return 0; + FILE *f = fopen(path, "rb"); + if (f == NULL) + return 0; + size_t file_size = rfile_size(path); + char response[1024] = {0}; + char content_type_header[100] = {0}; + char *ext = strstr(path, "."); + char *text_extensions = ".h,.c,.html"; + if (strstr(text_extensions, ext)) { + sprintf(content_type_header, "Content-Type: %s\r\n", "text/html"); + } + sprintf(response, "HTTP/1.1 200 OK\r\n%sContent-Length:%ld\r\n\r\n", content_type_header, file_size); + if (!rhttp_send_drain(r->c, response, 0)) { + rhttp_log_error("Error sending file: %s\n", path); + } + size_t bytes = 0; + size_t bytes_sent = 0; + unsigned char file_buff[1024]; + while ((bytes = fread(file_buff, sizeof(char), sizeof(file_buff), f))) { + if (!rhttp_send_drain(r->c, file_buff, bytes)) { + rhttp_log_error("Error sending file during chunking: %s\n", path); + } + bytes_sent += bytes; + } + if (bytes_sent != file_size) { + rhttp_send_drain(r->c, file_buff, file_size - bytes_sent); + } + close(r->c); + fclose(f); + return 1; +}; + +int rhttp_file_request_handler(rhttp_request_t *r) { + char *path = r->path; + while (*path == '/' || *path == '.') + path++; + if (strstr(path, "..")) { + return 0; + } + return rhttp_file_response(r, path); +}; + +unsigned int counter = 100000000; +int rhttp_counter_request_handler(rhttp_request_t *r) { + if (!strncmp(r->path, "/counter", strlen("/counter"))) { + counter++; + unsigned int width = rhttp_calculate_number_char_count(counter); + char to_send2[1024] = {0}; + sprintf(to_send2, + "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nConnection: " + "close\r\n\r\n%d", + width, counter); + rhttp_send_drain(r->c, to_send2, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_root_request_handler(rhttp_request_t *r) { + if (!strcmp(r->path, "/")) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 200 OK\r\nContent-Length: 3\r\nConnection: " + "close\r\n\r\nOk!"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; + } + return 0; +} +int rhttp_error_404_handler(rhttp_request_t *r) { + char to_send[1024] = {0}; + sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " + "0\r\nConnection: close\r\n\r\n"); + rhttp_send_drain(r->c, to_send, 0); + close(r->c); + return 1; +} + +int rhttp_default_request_handler(rhttp_request_t *r) { + if (rhttp_opt_debug || rhttp_opt_request_logging) + rhttp_print_request(r); + if (rhttp_counter_request_handler(r)) { + // Counter handler + rhttp_log_info("Counter handler found for: %s\n", r->path); + + } else if (rhttp_root_request_handler(r)) { + // Root handler + rhttp_log_info("Root handler found for: %s\n", r->path); + } else if (rhttp_file_request_handler(r)) { + rhttp_log_info("File %s sent\n", r->path); + } else if (rhttp_error_404_handler(r)) { + rhttp_log_warn("Error 404 for: %s\n", r->path); + // Error handler + } else { + rhttp_log_warn("No handler found for: %s\n", r->path); + close(rhttp_c); + } + return 0; +} + +int rhttp_main(int argc, char *argv[]) { + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); + int opt; + while ((opt = getopt(argc, argv, "p:drh:bewi")) != -1) { + switch (opt) { + case 'i': + rhttp_opt_info = 1; + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + break; + case 'e': + rhttp_opt_error = 1; + rhttp_opt_warn = 0; + rhttp_opt_info = 0; + break; + case 'w': + rhttp_opt_warn = 1; + rhttp_opt_error = 1; + rhttp_opt_info = 0; + break; + case 'p': + rhttp_opt_port = atoi(optarg); + break; + case 'b': + rhttp_opt_buffered = 1; + printf("Logging is buffered. Output may be incomplete.\n"); + break; + case 'h': + strcpy(rhttp_opt_host, optarg); + break; + case 'd': + printf("Debug enabled\n"); + rhttp_opt_debug = 1; + rhttp_opt_warn = 1; + rhttp_opt_info = 1; + rhttp_opt_error = 1; + break; + case 'r': + printf("Request logging enabled\n"); + rhttp_opt_request_logging = 1; + break; + default: + printf("Usage: %s [-p port] [-h host] [-b]\n", argv[0]); + return 1; + } + } + + printf("Starting server on: %s:%d\n", rhttp_opt_host, rhttp_opt_port); + if (rhttp_opt_buffered) + setvbuf(stdout, NULL, _IOFBF, BUFSIZ); + + rhttp_serve(rhttp_opt_host, rhttp_opt_port, 1024, rhttp_opt_request_logging, rhttp_opt_debug, rhttp_default_request_handler, NULL); + + return 0; +} + +/* CLIENT CODE */ + +typedef struct rhttp_client_request_t { + char *host; + int port; + char *path; + bool is_done; + char *request; + char *response; + pthread_t thread; + int bytes_received; +} rhttp_client_request_t; + +rhttp_client_request_t *rhttp_create_request(const char *host, int port, const char *path) { + rhttp_client_request_t *r = (rhttp_client_request_t *)malloc(sizeof(rhttp_client_request_t)); + char request_line[4096] = {0}; + sprintf(request_line, + "GET %s HTTP/1.1\r\n" + "Host: localhost:8000\r\n" + "Connection: close\r\n" + "Accept: */*\r\n" + "User-Agent: mhttpc\r\n" + "Accept-Language: en-US,en;q=0.5\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "\r\n", + path); + r->request = strdup(request_line); + r->host = strdup(host); + r->port = port; + r->path = strdup(path); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; + return r; +} + +int rhttp_execute_request(rhttp_client_request_t *r) { + int s = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(r->port); + addr.sin_addr.s_addr = inet_addr(r->host); + + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return 0; + } + + send(s, r->request, strlen(r->request), 0); + char buf[1024 * 1024] = {0}; + int ret = recv(s, buf, 1024 * 1024, 0); + if (ret > 0) { + r->response = strdup(buf); + } + + close(s); + return ret; +} +void rhttp_reset_request(rhttp_client_request_t *r) { + free(r->response); + r->is_done = false; + r->response = NULL; + r->bytes_received = 0; +} +void rhttp_free_client_request(rhttp_client_request_t *r) { + if (r->request) + free(r->request); + if (r->response) + free(r->response); + if (r->host) + free(r->host); + if (r->path) + free(r->path); + free(r); +} + +void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { + rhttp_client_request_t *requests[workers]; + while (times > 0) { + + for (int i = 0; i < workers && times; i++) { + requests[i] = rhttp_create_request(host, port, path); + rhttp_execute_request(requests[i]); + times--; + } + } +} +char *rhttp_client_get(const char *host, int port, const char *path) { + if (!rhttp_c_mutex_initialized) { + rhttp_c_mutex_initialized = 1; + pthread_mutex_init(&rhttp_c_mutex, NULL); + } + char http_response[1024 * 1024]; + http_response[0] = 0; + rhttp_client_request_t *r = rhttp_create_request(host, port, path); + unsigned int reconnects = 0; + unsigned int reconnects_max = 100000; + while (!rhttp_execute_request(r)) { + reconnects++; + tick(); + if (reconnects == reconnects_max) { + fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + rhttp_free_client_request(r); + return NULL; + } + } + r->is_done = true; + char *body = r->response ? strstr(r->response, "\r\n\r\n") : NULL; + pthread_mutex_lock(&rhttp_c_mutex); + if (body) { + strcpy(http_response, body + 4); + } else { + strcpy(http_response, r->response); + } + rhttp_free_client_request(r); + char *result = sbuf(http_response); + pthread_mutex_unlock(&rhttp_c_mutex); + return result; +} +/*END CLIENT CODE */ +#endif + +#ifndef RJSON_H +#define RJSON_H + +typedef struct rjson_t { + char *content; + size_t length; + size_t size; +} rjson_t; + +rjson_t *rjson() { + rjson_t *json = rmalloc(sizeof(rjson_t)); + json->size = 1024; + json->length = 0; + json->content = (char *)rmalloc(json->size); + json->content[0] = 0; + return json; +} + +void rjson_write(rjson_t *rjs, char *content) { + size_t len = strlen(content); + while (rjs->size < rjs->length + len + 1) { + rjs->content = realloc(rjs->content, rjs->size + 1024); + rjs->size += 1024; + } + strcat(rjs->content, content); + rjs->length += len; +} + +void rjson_object_start(rjson_t *rjs) { + if (rstrendswith(rjs->content, "}")) + rjson_write(rjs, ","); + rjson_write(rjs, "{"); +} +void rjson_object_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "}"); +} +void rjson_array_start(rjson_t *rjs) { + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + rjson_write(rjs, ","); + rjson_write(rjs, "["); +} +void rjson_array_close(rjson_t *rjs) { + if (rstrendswith(rjs->content, ",")) { + rjs->content[rjs->length - 1] = 0; + rjs->length--; + } + rjson_write(rjs, "]"); +} + +void rjson_kv_string(rjson_t *rjs, char *key, char *value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":\""); + char *value_str = (char *)rmalloc(strlen(value) + 4096); + rstraddslashes(value, value_str); + rjson_write(rjs, value_str); + free(value_str); + rjson_write(rjs, "\""); +} + +void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + char value_str[100] = {0}; + sprintf(value_str, "%lld", value); + rjson_write(rjs, value_str); +} +void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(rformat_number(value))); + rjson_write(rjs, "\""); +} + +void rjson_kv_bool(rjson_t *rjs, char *key, int value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, value > 0 ? "true" : "false"); +} + +void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { + if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { + rjson_write(rjs, ","); + } + rjson_write(rjs, "\""); + rjson_write(rjs, key); + rjson_write(rjs, "\":"); + rjson_write(rjs, "\""); + + rjson_write(rjs, sbuf(format_time(value))); + rjson_write(rjs, "\""); +} +void rjson_free(rjson_t *rsj) { + free(rsj->content); + free(rsj); +} + +void rjson_key(rjson_t *rsj, char *key) { + rjson_write(rsj, "\""); + rjson_write(rsj, key); + rjson_write(rsj, "\":"); +} +#endif +#ifndef RAUTOCOMPLETE_H +#define RAUTOCOMPLETE_H +#define R4_DEBUG +#ifndef RREX4_H +#define RREX4_H +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define R4_DEBUG_a + +#ifdef R4_DEBUG +static int _r4_debug = 1; +#else +static int _r4_debug = 0; +#endif + +static char *_format_function_name(const char *name) { + static char result[100]; + result[0] = 0; + + char *new_name = (char *)name; + new_name += 11; + if (new_name[0] == '_') + new_name += 1; + if (strlen(new_name) == 0) { + return " -"; + } + strcpy(result, new_name); + return result; +} + +#define DEBUG_VALIDATE_FUNCTION \ + if (_r4_debug || r4->debug) \ + printf("DEBUG: %s %s <%s> \"%s\"\n", _format_function_name(__func__), r4->valid ? "valid" : "INVALID", r4->expr, r4->str); + +struct r4_t; + +void r4_enable_debug() { _r4_debug = true; } +void r4_disable_debug() { _r4_debug = false; } + +typedef bool (*r4_function)(struct r4_t *); + +typedef struct r4_t { + bool debug; + bool valid; + bool in_block; + bool is_greedy; + bool in_range; + unsigned int backtracking; + unsigned int loop_count; + unsigned int in_group; + unsigned int match_count; + unsigned int validation_count; + unsigned int start; + unsigned int end; + unsigned int length; + bool (*functions[254])(struct r4_t *); + bool (*slash_functions[254])(struct r4_t *); + char *_str; + char *_expr; + char *match; + char *str; + char *expr; + char *str_previous; + char *expr_previous; + char **matches; +} r4_t; + +static bool v4_initiated = false; +typedef bool (*v4_function_map)(r4_t *); +v4_function_map v4_function_map_global[256]; +v4_function_map v4_function_map_slash[256]; +v4_function_map v4_function_map_block[256]; + +void r4_free_matches(r4_t *r) { + if (!r) + return; + if (r->match) { + free(r->match); + r->match = NULL; + } + if (!r->match_count) { + return; + } + for (unsigned i = 0; i < r->match_count; i++) { + free(r->matches[i]); + } + free(r->matches); + r->match_count = 0; + r->matches = NULL; +} + +void r4_free(r4_t *r) { + if (!r) + return; + r4_free_matches(r); + free(r); +} + +static bool r4_backtrack(r4_t *r4); +static bool r4_validate(r4_t *r4); +static void r4_match_add(r4_t *r4, char *extracted); + +static bool r4_validate_literal(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!r4->valid) + return false; + if (*r4->str != *r4->expr) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_question_mark(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = true; + r4->expr++; + return r4_validate(r4); +} + +static bool r4_validate_plus(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == false) { + return r4_validate(r4); + } + char *expr_left = r4->expr_previous; + char *expr_right = r4->expr; + char *str = r4->str; + char *return_expr = NULL; + if (*expr_right == ')') { + return_expr = expr_right; + expr_right++; + } + r4->is_greedy = false; + r4->expr = expr_left; + while (r4->valid) { + if (*expr_right) { + r4->expr = expr_right; + r4->is_greedy = true; + if (r4_backtrack(r4)) { + + if (return_expr) { + r4->str = str; + r4->expr = return_expr; + } + return r4_validate(r4); + } else { + r4->is_greedy = false; + } + } + r4->valid = true; + r4->expr = expr_left; + r4->str = str; + r4_validate(r4); + str = r4->str; + } + r4->is_greedy = true; + r4->valid = true; + r4->expr = return_expr ? return_expr : expr_right; + return r4_validate(r4); +} + +static bool r4_validate_dollar(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + r4->valid = *r4->str == 0; + return r4_validate(r4); +} + +static bool r4_validate_roof(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (r4->str != r4->_str) { + return false; + } + r4->expr++; + return r4_validate(r4); +} + +static bool r4_validate_dot(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (*r4->str == 0) { + return false; + } + r4->expr++; + r4->valid = *r4->str != '\n'; + r4->str++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_asterisk(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == false) { + r4->valid = true; + return r4->valid; + // return r4_validate(r4); + } + char *expr_left = r4->expr_previous; + char *expr_right = r4->expr; + char *str = r4->str; + char *return_expr = NULL; + if (*expr_right == ')') { + return_expr = expr_right; + expr_right++; + } + r4->is_greedy = false; + r4->expr = expr_left; + while (r4->valid) { + if (*expr_right) { + r4->expr = expr_right; + r4->is_greedy = true; + if (r4_backtrack(r4)) { + + if (return_expr) { + r4->str = str; + r4->expr = return_expr; + } + return r4_validate(r4); + } else { + r4->is_greedy = false; + } + } + r4->valid = true; + r4->expr = expr_left; + r4->str = str; + r4_validate(r4); + str = r4->str; + } + r4->is_greedy = true; + r4->valid = true; + r4->expr = return_expr ? return_expr : expr_right; + return r4_validate(r4); +} + +static bool r4_validate_pipe(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (r4->valid == true) { + return true; + } else { + r4->valid = true; + } + return r4_validate(r4); +} + +static bool r4_validate_digit(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!isdigit(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_digit(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (isdigit(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_word(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (!isalpha(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_word(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (isalpha(*r4->str)) { + r4->valid = false; + } else { + r4->str++; + } + r4->expr++; + + if (r4->in_block || r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_isrange(char *s) { + if (!isalnum(*s)) { + return false; + } + if (*(s + 1) != '-') { + return false; + } + return isalnum(*(s + 2)); +} + +static bool r4_validate_block_open(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + if (r4->valid == false) { + return false; + } + char *expr_self = r4->expr; + r4->expr++; + bool reversed = *r4->expr == '^'; + if (reversed) { + r4->expr++; + } + + bool valid_once = false; + r4->in_block = true; + while (*r4->expr != ']') { + r4->valid = true; + if (r4_isrange(r4->expr)) { + char s = *r4->expr; + char e = *(r4->expr + 2); + r4->expr += 2; + if (s > e) { + char tempc = s; + s = e; + e = tempc; + } + if (*r4->str >= s && *r4->str <= e) { + if (!reversed) { + r4->str++; + } + valid_once = true; + break; + } else { + r4->expr++; + } + } else if (r4_validate(r4)) { + valid_once = true; + if (reversed) + r4->str--; + break; + } + } + char *expr_end = strchr(r4->expr, ']'); + + r4->expr = expr_end ? expr_end : r4->expr; + r4->in_block = false; + r4->valid = expr_end && (!reversed ? valid_once : !valid_once); + r4->expr++; + r4->expr_previous = expr_self; + + if (r4->in_range || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_whitespace(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = strchr("\r\t \n", *r4->str) != NULL; + r4->expr++; + if (r4->valid) { + r4->str++; + } + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_not_whitespace(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->valid = strchr("\r\t \n", *r4->str) == NULL; + r4->expr++; + if (r4->valid) { + r4->str++; + } + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static bool r4_validate_range(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION; + if (r4->valid == false) { + r4->expr++; + return false; + } + char *previous = r4->expr_previous; + r4->in_range = true; + r4->expr++; + unsigned int start = 0; + while (isdigit(*r4->expr)) { + start = 10 * start; + start += *r4->expr - '0'; + r4->expr++; + } + if (start != 0) + start--; + + unsigned int end = 0; + bool variable_end_range = false; + if (*r4->expr == ',') { + r4->expr++; + if (!isdigit(*r4->expr)) { + variable_end_range = true; + } + } + while (isdigit(*r4->expr)) { + end = end * 10; + end += *r4->expr - '0'; + r4->expr++; + } + r4->expr++; + + bool valid = true; + char *expr_right = r4->expr; + for (unsigned int i = 0; i < start; i++) { + r4->expr = previous; + valid = r4_validate(r4); + if (!*r4->str) + break; + if (!valid) { + break; + } + } + r4->expr = expr_right; + r4->in_range = false; + if (!r4->valid) + return false; + return r4_validate(r4); + + for (unsigned int i = start; i < end; i++) { + r4->expr = previous; + valid = r4_validate(r4); + if (!valid) { + break; + } + } + + while (variable_end_range) { + r4->in_range = false; + valid = r4_validate(r4); + r4->in_range = true; + if (valid) { + break; + } + r4->in_range = true; + valid = r4_validate(r4); + r4->in_range = false; + if (!valid) { + break; + } + } + r4->valid = valid; + + return r4_validate(r4); +} + +static bool r4_validate_group_close(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + return r4->valid; +} + +static bool r4_validate_group_open(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + char *expr_previous = r4->expr_previous; + r4->expr++; + bool save_match = r4->in_group == 0; + r4->in_group++; + char *str_extract_start = r4->str; + bool valid = r4_validate(r4); + + if (!valid || *r4->expr != ')') { + // this is a valid case if not everything between () matches + r4->in_group--; + if (save_match == false) { + r4->valid = true; + } + + // Not direct return? Not sure + return r4_validate(r4); + } + // if(save_match){ + // r4->match_count++; + // } + if (save_match) { + char *str_extract_end = r4->str; + unsigned int extracted_length = str_extract_end - str_extract_start; + // strlen(str_extract_start) - strlen(str_extract_end); + char *str_extracted = (char *)calloc(sizeof(char), extracted_length + 1); + strncpy(str_extracted, str_extract_start, extracted_length); + r4_match_add(r4, str_extracted); + } + assert(*r4->expr == ')'); + r4->expr++; + r4->in_group--; + r4->expr_previous = expr_previous; + return r4_validate(r4); +} + +static bool r4_validate_slash(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + // The handling code for handling slashes is implemented in r4_validate + char *expr_previous = r4->expr_previous; + r4->expr++; + r4_function f = v4_function_map_slash[(int)*r4->expr]; + r4->expr_previous = expr_previous; + return f(r4); +} + +static void r4_match_add(r4_t *r4, char *extracted) { + r4->matches = (char **)realloc(r4->matches, (r4->match_count + 1) * sizeof(char *)); + r4->matches[r4->match_count] = extracted; + r4->match_count++; +} + +static bool r4_validate_word_boundary_start(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (!r4->valid) { + return r4->valid; + } + r4->valid = isalpha(*r4->str) && (r4->str == r4->_str || !isalpha(*(r4->str - 1))); + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} +static bool r4_validate_word_boundary_end(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->expr++; + if (!r4->valid) { + return r4->valid; + } + r4->valid = isalpha(*r4->str) && (*(r4->str + 1) == 0 || !isalpha(*(r4->str + 1))); + if (r4->in_range || r4->in_block || !r4->is_greedy) { + return r4->valid; + } + return r4_validate(r4); +} + +static void v4_init_function_maps() { + if (v4_initiated) + return; + v4_initiated = true; + for (__uint8_t i = 0; i < 255; i++) { + v4_function_map_global[i] = r4_validate_literal; + v4_function_map_slash[i] = r4_validate_literal; + v4_function_map_block[i] = r4_validate_literal; + } + v4_function_map_global['*'] = r4_validate_asterisk; + v4_function_map_global['?'] = r4_validate_question_mark; + v4_function_map_global['+'] = r4_validate_plus; + v4_function_map_global['$'] = r4_validate_dollar; + v4_function_map_global['^'] = r4_validate_roof; + v4_function_map_global['.'] = r4_validate_dot; + v4_function_map_global['|'] = r4_validate_pipe; + v4_function_map_global['\\'] = r4_validate_slash; + v4_function_map_global['['] = r4_validate_block_open; + v4_function_map_global['{'] = r4_validate_range; + v4_function_map_global['('] = r4_validate_group_open; + v4_function_map_global[')'] = r4_validate_group_close; + v4_function_map_slash['b'] = r4_validate_word_boundary_start; + v4_function_map_slash['B'] = r4_validate_word_boundary_end; + v4_function_map_slash['d'] = r4_validate_digit; + v4_function_map_slash['w'] = r4_validate_word; + v4_function_map_slash['D'] = r4_validate_not_digit; + v4_function_map_slash['W'] = r4_validate_not_word; + v4_function_map_slash['s'] = r4_validate_whitespace; + v4_function_map_slash['S'] = r4_validate_not_whitespace; + v4_function_map_block['\\'] = r4_validate_slash; + + v4_function_map_block['{'] = r4_validate_range; +} + +void r4_init(r4_t *r4) { + v4_init_function_maps(); + if (r4 == NULL) + return; + r4->debug = _r4_debug; + r4->valid = true; + r4->validation_count = 0; + r4->match_count = 0; + r4->start = 0; + r4->end = 0; + r4->length = 0; + r4->matches = NULL; +} + +static bool r4_looks_behind(char c) { return strchr("?*+{", c) != NULL; } + +r4_t *r4_new() { + r4_t *r4 = (r4_t *)malloc(sizeof(r4_t)); + + r4_init(r4); + + return r4; +} + +static bool r4_pipe_next(r4_t *r4) { + char *expr = r4->expr; + while (*expr) { + if (*expr == '|') { + r4->expr = expr + 1; + r4->valid = true; + return true; + } + expr++; + } + return false; +} + +static bool r4_backtrack(r4_t *r4) { + if (_r4_debug) + printf("\033[36mDEBUG: backtrack start (%d)\n", r4->backtracking); + r4->backtracking++; + char *str = r4->str; + char *expr = r4->expr; + bool result = r4_validate(r4); + r4->backtracking--; + if (result == false) { + r4->expr = expr; + r4->str = str; + } + if (_r4_debug) + printf("DEBUG: backtrack end (%d) result: %d %s\n", r4->backtracking, result, r4->backtracking == 0 ? "\033[0m" : ""); + return result; +} + +static bool r4_validate(r4_t *r4) { + DEBUG_VALIDATE_FUNCTION + r4->validation_count++; + char c_val = *r4->expr; + if (c_val == 0) { + return r4->valid; + } + if (!r4_looks_behind(c_val)) { + r4->expr_previous = r4->expr; + } else if (r4->expr == r4->_expr) { + // Regex may not start with a look behind ufnction + return false; + } + + if (!r4->valid && !r4_looks_behind(*r4->expr)) { + if (!r4_pipe_next(r4)) { + return false; + } + } + r4_function f; + if (r4->in_block) { + f = v4_function_map_block[(int)c_val]; + } else { + f = v4_function_map_global[(int)c_val]; + } + + r4->valid = f(r4); + return r4->valid; +} + +char *r4_get_match(r4_t *r) { + char *match = (char *)malloc(r->length + 1); + strncpy(match, r->_str + r->start, r->length); + match[r->length] = 0; + return match; +} + +static bool r4_search(r4_t *r) { + bool valid = true; + char *str_next = r->str; + while (*r->str) { + if (!(valid = r4_validate(r))) { + // Move next until we find a match + if (!r->backtracking) { + r->start++; + } + str_next++; + r->str = str_next; + r->expr = r->_expr; + r->valid = true; + } else { + /// HIGH DOUBT + if (!r->backtracking) { + // r->start = 0; + } + break; + } + } + r->valid = valid; + if (r->valid) { + r->end = strlen(r->_str) - strlen(r->str); + r->length = r->end - r->start; + r->match = r4_get_match(r); + } + return r->valid; +} + +r4_t *r4(const char *str, const char *expr) { + r4_t *r = r4_new(); + r->_str = (char *)str; + r->_expr = (char *)expr; + r->match = NULL; + r->str = r->_str; + r->expr = r->_expr; + r->str_previous = r->_str; + r->expr_previous = r->expr; + r->in_block = false; + r->is_greedy = true; + r->in_group = 0; + r->loop_count = 0; + r->backtracking = 0; + r->in_range = false; + r4_search(r); + return r; +} + +r4_t *r4_next(r4_t *r, char *expr) { + if (expr) { + r->_expr = expr; + } + r->backtracking = 0; + r->expr = r->_expr; + r->is_greedy = true; + r->in_block = false; + r->in_range = false; + r->in_group = false; + r4_free_matches(r); + r4_search(r); + return r; +} + +bool r4_match(char *str, char *expr) { + r4_t *r = r4(str, expr); + bool result = r->valid; + r4_free(r); + return result; +} +#endif +#define rautocomplete_new rstring_list_new +#define rautocomplete_free rstring_list_free +#define rautocomplete_add rstring_list_add +#define rautocomplete_find rstring_list_find +#define rautocomplete_t rstring_list_t +#define rautocomplete_contains rstring_list_contains + +char *r4_escape(char *content) { + size_t size = strlen(content) * 2 + 1; + char *escaped = (char *)calloc(size, sizeof(char)); + char *espr = escaped; + char *to_escape = "?*+()[]{}^$\\"; + *espr = '('; + espr++; + while (*content) { + if (strchr(to_escape, *content)) { + *espr = '\\'; + espr++; + } + *espr = *content; + espr++; + content++; + } + *espr = '.'; + espr++; + *espr = '+'; + espr++; + *espr = ')'; + espr++; + *espr = 0; + return escaped; +} + +char *rautocomplete_find(rstring_list_t *list, char *expr) { + if (!list->count) + return NULL; + if (!expr || !strlen(expr)) + return NULL; + + char *escaped = r4_escape(expr); + + for (unsigned int i = list->count - 1; i == 0; i--) { + char *match; + r4_t *r = r4(list->strings[i], escaped); + if (r->valid && r->match_count == 1) { + match = strdup(r->matches[0]); + } + r4_free(r); + if (match) { + + free(escaped); + return match; + } + } + free(escaped); + return NULL; +} +#endif +#ifndef RKEYTABLE_H +#define RKEYTABLE_H +/* + DERIVED FROM HASH TABLE K&R + */ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct rnklist { + struct rnklist *next; + struct rnklist *last; + char *name; + char *defn; +} rnklist; + +static rnklist *rkeytab = NULL; + +rnklist *rlkget(char *s) { + rnklist *np; + for (np = rkeytab; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +char *rkget(char *s) { + rnklist *np = rlkget(s); + return np ? np->defn : NULL; +} + +rnklist *rkset(char *name, char *defn) { + rnklist *np; + if ((np = (rlkget(name))) == NULL) { // Not found + np = (rnklist *)malloc(sizeof(rnklist)); + np->name = strdup(name); + np->next = NULL; + np->last = NULL; + + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + + if (rkeytab == NULL) { + rkeytab = np; + rkeytab->last = np; + } else { + if (rkeytab->last) + rkeytab->last->next = np; + + rkeytab->last = np; + } + } else { + if (np->defn) + free((void *)np->defn); + if (defn) { + np->defn = strdup(defn); + } else { + np->defn = NULL; + } + } + return np; +} +#endif + +#ifndef RHASHTABLE_H +#define RHASHTABLE_H +/* + ORIGINAL SOURCE IS FROM K&R + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define HASHSIZE 101 + +// Structure for the table entries +typedef struct rnlist { + struct rnlist *next; + char *name; + char *defn; +} rnlist; + +// Hash table array +static rnlist *rhashtab[HASHSIZE]; + +// Hash function +unsigned rhash(char *s) { + unsigned hashval; + for (hashval = 0; *s != '\0'; s++) + hashval = *s + 31 * hashval; + return hashval % HASHSIZE; +} + +rnlist *rlget(char *s) { + rnlist *np; + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + if (strcmp(s, np->name) == 0) + return np; // Found + return NULL; // Not found +} + +// Lookup function +char *rget(char *s) { + rnlist *np = rlget(s); + return np ? np->defn : NULL; +} + +// Install function (adds a name and definition to the table) +struct rnlist *rset(char *name, char *defn) { + struct rnlist *np = NULL; + unsigned hashval; + + if ((rlget(name)) == NULL) { // Not found + np = (struct rnlist *)malloc(sizeof(*np)); + if (np == NULL || (np->name = strdup(name)) == NULL) + return NULL; + hashval = rhash(name); + np->next = rhashtab[hashval]; + rhashtab[hashval] = np; + } else { + if (np->defn) + free((void *)np->defn); + np->defn = NULL; + } + if ((np->defn = strdup(defn)) == NULL) + return NULL; + return np; +} +#endif + +#ifndef RREX3_H +#define RREX3_H +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#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->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 == 0 && !*rrex3->str) { + printf("ERROR, EMPTY CHECK\n"); + // exit(1); + } + if (rrex3->valid == false) { + rrex3->expr++; + return; + } + + 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_plus2(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_plus(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->expr++; + return; + } + + char *left = rrex3->previous.expr; + // printf("%s\n",rrex3->str); + char *right = rrex3->expr + 1; + if (*right == ')') { + right++; + } + int right_valid = 0; + bool right_valid_once = false; + char *expr = right; + char *right_str = rrex3->str; + ; + char *right_expr = NULL; + char *str = rrex3->str; + bool first_time = true; + bool left_valid = true; + char *str_prev = NULL; + bool valid_from_start = true; + ; + while (*rrex3->str) { + if (!left_valid && !right_valid) { + break; + } + if (right_valid && !left_valid) { + str = right_str; + break; + } + + rrex3->expr = right; + rrex3->str = str; +#if RREX3_DEBUG == 1 + printf("r"); +#endif + if (*rrex3->str && rrex3_move(rrex3, false)) { + right_valid++; + right_str = rrex3->str; + expr = rrex3->expr; + if (!right_valid_once) { + right_expr = rrex3->expr; + right_valid_once = true; + } + } else { + right_valid = 0; + } + if (first_time) { + first_time = false; + valid_from_start = right_valid; + } + + if (right_valid && !valid_from_start && right_valid > 0) { + expr = right_expr - 1; + ; + if (*(right - 1) == ')') { + expr = right - 1; + } + break; + } + + if ((!right_valid && right_valid_once)) { + expr = right_expr; + if (*(right - 1) == ')') { + str = str_prev; + expr = right - 1; + } + break; + } + + str_prev = str; + rrex3->valid = true; + rrex3->str = str; + rrex3->expr = left; +#if RREX3_DEBUG == 1 + printf("l"); +#endif + if (rrex3_move(rrex3, false)) { + left_valid = true; + + str = rrex3->str; + } else { + left_valid = false; + } + } + + rrex3->expr = expr; + rrex3->str = 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_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; + } + + rrex3->str = rrex3->previous.str; + char *left = rrex3->previous.expr; + // printf("%s\n",rrex3->str); + char *right = rrex3->expr + 1; + if (*right == ')') { + right++; + } + int right_valid = 0; + bool right_valid_once = false; + char *expr = right; + char *right_str = rrex3->str; + ; + char *right_expr = NULL; + char *str = rrex3->str; + bool first_time = true; + bool left_valid = true; + char *str_prev = NULL; + bool valid_from_start = true; + ; + while (*rrex3->str) { + if (!left_valid && !right_valid) { + break; + } + if (right_valid && !left_valid) { + str = right_str; + break; + } + + rrex3->expr = right; + rrex3->str = str; +#if RREX3_DEBUG == 1 + printf("r"); +#endif + if (*rrex3->str && rrex3_move(rrex3, false)) { + right_valid++; + right_str = rrex3->str; + expr = rrex3->expr; + if (!right_valid_once) { + right_expr = rrex3->expr; + right_valid_once = true; + } + } else { + right_valid = 0; + } + if (first_time) { + first_time = false; + valid_from_start = right_valid; + } + + if (right_valid && !valid_from_start && right_valid > 0) { + expr = right_expr - 1; + if (*(right - 1) == ')') { + expr = right - 1; + } + break; + } + + if ((!right_valid && right_valid_once)) { + expr = right_expr; + if (*(right - 1) == ')') { + str = str_prev; + expr = right - 1; + } + break; + } + + str_prev = str; + rrex3->valid = true; + rrex3->str = str; + rrex3->expr = left; +#if RREX3_DEBUG == 1 + printf("l"); +#endif + if (rrex3_move(rrex3, false)) { + left_valid = true; + str = rrex3->str; + } else { + left_valid = false; + } + } + + rrex3->expr = expr; + rrex3->str = 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_asterisk2(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) { + if (!success_next_once) { + 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("<Roof check: %c:%c:%d\n", *rrex3->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) { +#if RREX3_DEBUG == 1 + if (*rrex3->expr != 'B') { + printf("Check word start or end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); + } + +#endif + 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) { +#if RREX3_DEBUG == 1 + printf("Check word NOT start or end: %c:%c:%d\n", *rrex3->expr, *rrex3->str, rrex3->valid); + +#endif + 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 + + rrex3_set_previous(rrex3); + if (!rrex3->valid) { + rrex3->expr++; + return; + } + 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; + } else if (!*rrex3->expr) { + // rrex3->valid = 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; + } + } else { + } + 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; + } + rrex3->expr = rrex3->_expr; + 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, "\"stdio.h\"\"string.h\"\"sys/time.h\"", "\"(.*)\"\"(.*)\"\"(.*)\"")); + + 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 chars + 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 <stdio.h>", "#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 <stdio.h>", "#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, "int abc ", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + assert(rrex3(rrex, "int abc;", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + assert(rrex3(rrex, "int abc", "int (.*)[; ]?$")); + assert(!strcmp(rrex->matches[0], "abc")); + + rrex3_free(rrex); +} +#endif +#ifndef RARENA_H +#define RARENA_H + +#include <stdlib.h> +#include <string.h> + +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 RCASE_H +#define RCASE_H +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#define RCAMEL_CASE 1 +#define RSNAKE_CASE 2 +#define RINVALID_CASE 0 +#define RCONST_TEST_T 4; + +int rdetermine_case(const char *str) { + int length = strlen(str); + + char p = 0; + while (*str) { + if (p == '_' && islower(*str)) + return RSNAKE_CASE; + if (p != '_' && !isupper(p) && isupper(*str)) + return RCAMEL_CASE; + p = *str; + str++; + } + return RINVALID_CASE; + + if (length == 0) { + return RINVALID_CASE; + } + if (strchr(str, '_')) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + return RINVALID_CASE; + } + for (int i = 0; i < length; i++) { + if (!islower(str[i]) && str[i] != '_') { + return RINVALID_CASE; + } + } + return RSNAKE_CASE; + } else { + + if (!islower(str[0])) { + return RINVALID_CASE; + } + for (int i = 1; i < length; i++) { + if (str[i] == '_') { + return RINVALID_CASE; + } + if (isupper(str[i]) && isupper(str[i - 1])) { + return RINVALID_CASE; + } + } + return RCAMEL_CASE; + } +} + +char *rsnake_to_camel(const char *snake_case) { + int length = strlen(snake_case); + char *camel_case = (char *)malloc(length + 1); + int j = 0; + int toUpper = 0; + + for (int i = 0; i < length; i++) { + if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { + toUpper = 1; + if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + + toUpper = 0; + } + } + if (snake_case[i] == '_' && snake_case[i + 1] != 't') { + toUpper = 1; + if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { + toUpper = 0; + } + } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { + toUpper = 1; + } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { + toUpper = 1; + camel_case[j++] = '_'; + j++; + } else { + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; + } else { + camel_case[j++] = snake_case[i]; + } + } + } + + camel_case[j] = '\0'; + return camel_case; +} +char *rcamel_to_snake(const char *camelCase) { + int length = strlen(camelCase); + char *snake_case = (char *)malloc(2 * length + 1); + int j = 0; + + for (int i = 0; i < length; i++) { + if (isupper(camelCase[i])) { + if (i != 0) { + snake_case[j++] = '_'; + } + snake_case[j++] = tolower(camelCase[i]); + } else { + snake_case[j++] = camelCase[i]; + } + } + + snake_case[j] = '\0'; + return snake_case; +} + +char *rflip_case(char *content) { + if (rdetermine_case(content) == RSNAKE_CASE) { + return rcamel_to_snake(content); + } else if (rdetermine_case(content) == RCAMEL_CASE) { + return rsnake_to_camel(content); + } else { + rprintr("Could not determine case\n"); + return NULL; + } +} + +char *rflip_case_file(char *filepath) { + size_t file_size = rfile_size(filepath); + if (file_size == 0) { + return NULL; + } + char *content = (char *)malloc(file_size); + char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { + result = rflip_case(content); + if (result) { + free(content); + return result; + } else { + return content; + } + } + return result; +} + +int rcase_main(int argc, char *argv[]) { + if (argc < 2) { + printf("usage: rcase <file>\n"); + return 1; + } + for (int i = 1; i < argc; i++) { + char *result = rflip_case_file(argv[i]); + if (result) { + printf("%s\n", result); + free(result); + } + } + return 0; +} +#endif + +#ifndef RTERM_H +#define RTERM_H +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> +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; + int ms_tick; + 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 (*after_draw)(struct rterm_t *); + void *session; + unsigned long iterations; + void (*tick)(struct rterm_t *); + char *status_text; + char *_status_text_previous; + 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->cursor.x = 0; + rterm->cursor.y = 0; + rterm->ms_tick = 100; + rterm->_status_text_previous = NULL; +} + +void rterm_getwinsize(winsize_t *w) { + // Get the terminal size + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, w) == -1) { + perror("ioctl"); + exit(EXIT_FAILURE); + } +} + +void rrawfd(int fd) { + struct termios orig_termios; + tcgetattr(fd, &orig_termios); // Get current terminal attributes + + struct termios raw = orig_termios; + raw.c_lflag &= ~(ICANON | ISIG | ECHO); // ECHO // Disable canonical mode and echoing + raw.c_cc[VMIN] = 1; + raw.c_cc[VTIME] = 240; // Set timeout for read input + + tcsetattr(fd, TCSAFLUSH, &raw); +} + +// 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] = 1; + raw.c_cc[VTIME] = 240; // 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[34m"); // 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) { + if (rt->_status_text_previous && !strcmp(rt->_status_text_previous, rt->status_text)) { + return; + } + if (rt->_status_text_previous) { + free(rt->_status_text_previous); + } + rt->_status_text_previous = strdup(rt->status_text); + winsize_t ws = rt->size; + cursor_set(rt, rt->cursor.x, rt->cursor.y); + 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(rterm_t *rt) { + static rshell_keypress_t press; + press.c = 0; + press.ctrl = false; + press.shift = false; + press.escape = false; + press.pressed = rfd_wait(0, rt->ms_tick); + if (!press.pressed) { + return press; + } + 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 if (ch == 27) { + press.escape = true; + press.c = ch; + } 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->after_draw) { + rt->after_draw(rt); + } + if (!rt->iterations || (x != rt->cursor.x || y != rt->cursor.y)) { + if (rt->cursor.y == rt->size.ws_row) { + rt->cursor.y--; + } + if (rt->cursor.y < 0) { + rt->cursor.y = 0; + } + x = rt->cursor.x; + y = rt->cursor.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(rt); + 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 + if (key.c == -1) { + nsleep(1000 * 1000); + } + // Escape + if (key.escape) { + switch (key.c) { + case 65: // Move up + if (rt->cursor.y > -1) + rt->cursor.y--; + break; + case 66: // Move down + if (rt->cursor.y < rt->size.ws_row) + rt->cursor.y++; + break; + case 68: // Move left + if (rt->cursor.x > 0) + rt->cursor.x--; + if (key.ctrl) + rt->cursor.x -= 4; + break; + case 67: // Move right + if (rt->cursor.x < rt->size.ws_col) { + rt->cursor.x++; + } + if (key.ctrl) { + rt->cursor.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 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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; +} + +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; +} + +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; + } + return NULL; +} + +void rtree_free(rtree_t *b) { + if (!b) + return; + rtree_free(b->children); + rtree_free(b->next); + rfree(b); +} + +void *rtree_get(rtree_t *b, char *c) { + rtree_t *t = rtree_find(b, c); + if (t) { + return t->data; + } + return NULL; +} +#endif +#ifndef RLEXER_H +#define RLEXER_H +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#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 == '\''); +} + +static int isoperator(char c) { + return (c == '+' || c == '-' || c == '/' || c == '*' || c == '=' || c == '>' || c == '<' || c == '|' || c == '&'); +} + +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++; + } + token.type = RT_NUMBER; + return token; +} + +static rtoken_t rlex_symbol() { + rtoken_t token = rtoken_new(); + + 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; +} + +static rtoken_t rlex_operator() { + + 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; + } + } + 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; +} + +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 (_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; +} + +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++; + } + _content_ptr++; + token.type = RT_STRING; + return token; +} + +void rlex(char *content) { + _content = content; + _content_ptr = 0; + _content_col = 1; + _content_line = 1; +} + +static void rlex_repeat_str(char *dest, char *src, unsigned int times) { + for (size_t i = 0; i < times; i++) { + strcat(dest, src); + } +} + +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; +} + +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(); + } + } +} + +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; + } + + if (token.type == RT_STRING) { + strcat(result, "\""); + + char string_with_slashes[strlen(token.value) * 2 + 1]; + rstraddslashes(token.value, string_with_slashes); + strcat(result, string_with_slashes); + + strcat(result, "\""); + // col+= strlen(token.value) + 2; + // printf("\n"); + // printf("<<<%s>>>\n",token.value); + + 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); + + tab_index++; + + strcat(result, "\n"); + + col = 0; + + 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"); + + rlex_repeat_str(result, tab_chars, tab_index); + tab_indexed++; + + strcat(result, token.value); + strcat(result, "\n"); + col = 0; + + 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); + } + } + } + + 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, "\""); + } + + if (token.type == RT_OPERATOR) { + strcat(result, " "); + } + if (!strcmp(token.value, ",")) { + strcat(result, " "); + } + col += strlen(token.value); + memcpy(&token_previous, &token, sizeof(token)); + } + return result; +} +#endif + +#ifndef RLIB_MAIN +#define RLIB_MAIN +#ifndef RMERGE_H +#define RMERGE_H +// #include "../mrex/rmatch.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +bool has_error = false; + +char *extract_script_src_include(char *line, char *include_path) { + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *extract_c_local_include(char *line, char *include_path) { + // + /* + char res; + res= rmatch_extract(line, "#include.*"\".*\""); + + + printf("%MATCH:%s\n", res); + */ + + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *rmerge_readline(FILE *f) { + static char data[4096]; + data[0] = 0; + int index = 0; + char c; + while ((c = fgetc(f)) != EOF) { + if (c != '\0') { + data[index] = c; + index++; + if (c == '\n') + break; + } + } + data[index] = 0; + if (data[0] == 0) + return NULL; + return data; +} +void writestring(FILE *f, char *line) { + char c; + while ((c = *line) != '\0') { + fputc(c, f); + line++; + } +} +char files_history[8096]; +char files_duplicate[8096]; +bool is_merging = false; + +void merge_file(char *source, FILE *d) { + if (is_merging == false) { + is_merging = true; + files_history[0] = 0; + files_duplicate[0] = 0; + } + if (strstr(files_history, source)) { + if (strstr(files_duplicate, source)) { + rprintmf(stderr, "\\l Already included: %s. Already on duplicate list.\n", source); + } else { + rprintcf(stderr, "\\l Already included: %s. Adding to duplicate list.\n", source); + strcat(files_duplicate, source); + strcat(files_duplicate, "\n"); + } + return; + } else { + rprintgf(stderr, "\\l Merging: %s.\n", source); + strcat(files_history, source); + strcat(files_history, "\n"); + } + FILE *fd = fopen(source, "rb"); + if (!fd) { + rprintrf(stderr, "\\l File does not exist: %s\n", source); + has_error = true; + return; + } + + char *line; + char include_path[4096]; + while ((line = rmerge_readline(fd))) { + + include_path[0] = 0; + if (!*line) + break; + + // + char *inc = extract_c_local_include(line, include_path); + if (!inc) + inc = extract_script_src_include(line, include_path); + + /* + if (!strncmp(line, "#include ", 9)) { + int index = 0; + while (line[index] != '"' && line[index] != 0) { + index++; + } + if (line[index] == '"') { + int pindex = 0; + index++; + while (line[index] != '"') { + include_path[pindex] = line[index]; + pindex++; + index++; + } + if (line[index] != '"') { + include_path[0] = 0; + } else { + include_path[pindex] = '\0'; + } + } + }*/ + if (inc) { + merge_file(inc, d); + } else { + writestring(d, line); + } + } + fclose(fd); + writestring(d, "\n"); +} + +int rmerge_main(int argc, char *argv[]) { + char *file_input = NULL; + if (argc != 2) { + printf("Usage: <input-file>\n"); + } else { + file_input = argv[1]; + // file_output = argv[2]; + } + FILE *f = tmpfile(); + printf("// RETOOR - %s\n", __DATE__); + merge_file(file_input, f); + rewind(f); + char *data; + int line_number = 0; + while ((data = rmerge_readline(f))) { + if (line_number) { + printf("/*%.5d*/ ", line_number); + line_number++; + } + printf("%s", data); + } + printf("\n"); + if (has_error) { + rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); + } else { + rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + } + return 0; +} +#endif + +void forward_argument(int *argcc, char *argv[]) { + int argc = *argcc; + for (int i = 0; i < argc; i++) { + argv[i] = argv[i + 1]; + } + argc--; + *argcc = argc; +} + +int rlib_main(int argc, char *argv[]) { + + if (argc == 1) { + printf("rlib\n\n"); + printf("options:\n"); + printf(" httpd - a http file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts c source files to one file \n" + " with local includes by giving main file as argument.\n"); + printf(" rcov - coverage tool theat cleans up after himself. Based on " + "lcov.\n"); + printf(" rcase - tool to swap input file automatically between" + " camel case and snake case.\n"); + return 0; + } + + forward_argument(&argc, argv); + + if (!strcmp(argv[0], "httpd")) { + + return rhttp_main(argc, argv); + } + if (!strcmp(argv[0], "rmerge")) { + return rmerge_main(argc, argv); + } + if (!strcmp(argv[0], "rcov")) { + return rcov_main(argc, argv); + } + if (!strcmp(argv[0], "rcase")) { + return rcase_main(argc, argv); + } + + return 0; +} + +#endif + +// END OF RLIB +#endif diff --git a/.backup.1.rlibso.c b/.backup.1.rlibso.c new file mode 100644 index 0000000..6a9dbf1 --- /dev/null +++ b/.backup.1.rlibso.c @@ -0,0 +1,18 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +void *rmalloc(size_t); +void *rfree(void *); +int rtest_end(char *); +void rprintgf(FILE *f, char *format, ...); + +int main() { + for (int i = 0; i < 100; i++) { + void *data = rmalloc(5000); + memset(data, 0, 5000); + rfree(data); + } + rprintgf(stdout, "Hello from .so library!"); + return rtest_end(""); +} \ No newline at end of file diff --git a/.backup.1.rliza.c b/.backup.1.rliza.c new file mode 100644 index 0000000..eafcfc5 --- /dev/null +++ b/.backup.1.rliza.c @@ -0,0 +1,156 @@ +#define RMALLOC_OVERRIDE 1 +#include "rtest.h" +#include "rliza.h" +#include "rio.h" +#include "rbench.h" +void performance_test() { + size_t size = rfile_size("resources/large.json"); + char *data = malloc(size + 1); + rfile_readb("resources/large.json", data, size); + data[size] = 0; + RBENCH(1, { + int length = rliza_validate(data); + (void)length; + }); + free(data); +} + +int main() { + rtest_banner("rliza"); + + for (int i = 0; i < 100; i++) { + char *long_data = + "{\"event\": \"execute\", \"query\": \"update session set bytes = ?, ex= ? where key = ?\", \"params\": [\"{\\\"created\\\": " + "1731034143, \\\"session\\\": {\\\"req_id\\\": 1, \\\"much_data\\\": " + "\\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"}}\", null, \"AIOHTTP_SESSION_5a2510809b85492b8f14e8d3e2f11da3\"]}"; + rassert(rliza_validate(long_data)); + rliza_t *a = rliza_loads(&long_data); + rliza_free(a); + } + char *nested_obj = "{\"test\":123,\"test2\":{\"test3\":123}}"; + rliza_t *a = rliza_loads(&nested_obj); + char *b = rliza_dumps(a); + printf("%s\n", b); + // rliza_dumpss(a); + rliza_free(a); + free(b); + + rtest_banner("performance test"); + performance_test(); + rtest_banner("serialize/deserialize"); + char *json_content = "{\"error\":\"not \\\"aaa\\\" " + "found\",\"rows\":[{\"a\":true},{\"b\":false},{\"c\":null},[1,23],[1,23],[1,23,true,false,5.5,5.505,6.1]]}"; + + rassert(rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"rows\":[[1,23],[1,23],[1,23,true,false,5.5,5.505]]}")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"rows\":[[1,23],[1,23],[1,23,true,false,5.5,5.505,6.]]}")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"rows\"")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"rows\":[")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"rows")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",\"")); + rassert(!rliza_validate("{\"error\":\"not \\\"aaa\\\" found\",")); + + char *double_content = "{}{}[]"; + free(rliza_loads(&double_content)); + rassert(!strcmp(double_content, "{}[]")); + free(rliza_loads(&double_content)); + rassert(!strcmp(double_content, "[]")); + char *error_content = "{}*{}"; + free(rliza_loads(&error_content)); + rassert(!strcmp(error_content, "*{}")); + rliza_loads(&error_content); + rassert(!strcmp(error_content, "*{}")); + + rassert(rliza_validate("{}")); + rassert(!rliza_validate("{")); + rassert(!rliza_validate("}")); + + rassert(!rliza_validate("[")); + rassert(!rliza_validate("]")); + rassert(!rliza_validate("\\")); + rassert(!rliza_validate("*")); + rassert(!rliza_validate("!")); + char *json_contentp = json_content; + rliza_t *to_object = rliza_loads(&json_contentp); + char *to_string = (char *)rliza_dumps(to_object); + rassert(!strcmp(to_string, json_content)); + printf("\n<%s>\n", to_string); + printf("<%s>\n", json_content); + free(to_string); + + rliza_free(to_object); + + // rliza_free(to_object); + rtest_banner("manually building new object"); + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + rliza_set_integer(rliza, "a", 1); + rliza_set_integer(rliza, "b", 2); + rliza_set_integer(rliza, "c", 3); + rliza_set_integer(rliza, "d", 4); + rliza_set_integer(rliza, "e", 5); + rliza_set_integer(rliza, "f", 6); + rliza_set_string(rliza, "str1", "str1value"); + + rliza_set_null(rliza, "q"); + + char *original_content = rliza_dumps(rliza); + printf("1:%s\n", original_content); + char *content = original_content; + + printf("2:%s %d\n", content, content[strlen((char *)content)] == 0); + + rliza_t *rliza2 = rliza_loads(&content); + + printf("HAAAh\n"); + char *content2 = rliza_dumps(rliza2); + printf("HAAAh\n"); + content = original_content; + rassert(!(strcmp((char *)content, + (char *)content2))); // strcmp(content,content2); + char *content2p = original_content; + content = original_content; + rliza_t *rliza3 = rliza_loads((char **)&content2p); + char *content3 = rliza_dumps(rliza2); + + rtest_banner("compare several serilizations. Should be equal.\n"); + content = original_content; + printf("content1:<%s>\n", content); + printf("content2:<%s>\n", content2); + printf("content3:<%s>\n", content3); + rassert(!strncmp(content2, content3, strlen((char *)content2))); + rassert(!strncmp(content, content2, strlen((char *)content))); + rliza_free(rliza2); + rliza_free(rliza3); + free(original_content); + free(content2); + free(content3); + printf("Coalesce %s\n", (char *)rliza_coalesce(rliza_get_string(rliza, "a"), "#1")); + printf("Coalesce %s\n", (char *)rliza_coalesce(rliza_get_string(rliza, "b"), "#2")); + + rliza_free(rliza); + + return rtest_end(""); +} diff --git a/.backup.1.rliza.h b/.backup.1.rliza.h new file mode 100644 index 0000000..c742729 --- /dev/null +++ b/.backup.1.rliza.h @@ -0,0 +1,775 @@ +#ifndef RLIZA_H +#define RLIZA_H +#include "rbuffer.h" +#include "rmalloc.h" +#include "rstring.h" +#include <assert.h> +#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef enum rliza_type_t { + RLIZA_STRING = 's', + RLIZA_BOOLEAN = 'b', + RLIZA_NUMBER = 'n', + RLIZA_OBJECT = 'o', + RLIZA_ARRAY = 'a', + RLIZA_NULL = 0, + RLIZA_KEY = 'k', + RLIZA_INTEGER = 'i' +} rliza_type_t; + +typedef struct rliza_t { + rliza_type_t type; + struct rliza_t *value; + char *key; + union { + char *string; + bool boolean; + double number; + struct rliza_t **map; + long long integer; + } content; + unsigned int count; + char *(*get_string)(struct rliza_t *, char *); + long long (*get_integer)(struct rliza_t *, char *); + double (*get_number)(struct rliza_t *, char *); + bool (*get_boolean)(struct rliza_t *, char *); + struct rliza_t *(*get_array)(struct rliza_t *, char *); + struct rliza_t *(*get_object)(struct rliza_t *, char *); + void (*set_string)(struct rliza_t *, char *, char *); + void (*set_integer)(struct rliza_t *, char *, long long); + void (*set_number)(struct rliza_t *, char *, double); + void (*set_boolean)(struct rliza_t *, char *, bool); + void (*set_array)(struct rliza_t *self, char *key, struct rliza_t *array); + void (*set_object)(struct rliza_t *self, char *key, struct rliza_t *object); +} rliza_t; + +void rliza_free(rliza_t *rliza) { + if (rliza->key) { + free(rliza->key); + rliza->key = NULL; + } + if (rliza->value) { + rliza_free(rliza->value); + rliza->value = NULL; + } + // if (rliza->content.array) { + // printf("JAAAA\n"); + // } + // if (rliza->content.object) { + // rliza_free(rliza->content.object); + // rliza->content.object = NULL; + //} + if (rliza->type == RLIZA_STRING) { + if (rliza->content.string) { + free(rliza->content.string); + rliza->content.string = NULL; + // else if (rliza->type == RLIZA_NUMBER) { + // printf("STDring freed\n"); + } + } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { + + if (rliza->content.map) { + for (unsigned int i = 0; i < rliza->count; i++) { + rliza_free(rliza->content.map[i]); + } + free(rliza->content.map); + } + } + // free(rliza->content.array); + //} + + free(rliza); +} + +rliza_t *rliza_new(rliza_type_t type); +rliza_t *rliza_new_string(char *string); +rliza_t *rliza_new_null(); +rliza_t *rliza_new_boolean(bool value); +rliza_t *rliza_new_number(double value); +rliza_t *rliza_new_integer(long long value); +rliza_t *rliza_new_key_value(char *key, rliza_t *value); +rliza_t *rliza_new_key_string(char *key, char *string); +rliza_t *rliza_new_key_bool(char *key, bool value); +rliza_t *rliza_new_key_number(char *key, double value); +void rliza_push(rliza_t *self, rliza_t *obj); +void rliza_push_object(rliza_t *self, rliza_t *object); +void rliza_set_object(rliza_t *self, char *key, rliza_t *object); +void rliza_set_string(rliza_t *self, char *key, char *string); +void rliza_set_boolean(rliza_t *self, char *key, bool value); +void rliza_set_number(rliza_t *self, char *key, double value); +void rliza_set_integer(rliza_t *self, char *key, long long value); +char *rliza_get_string(rliza_t *self, char *key); +long long rliza_get_integer(rliza_t *self, char *key); +double rliza_get_number(rliza_t *self, char *key); +bool rliza_get_boolean(rliza_t *self, char *key); +rliza_t *rliza_get_array(rliza_t *self, char *key); +rliza_t *rliza_get_object(rliza_t *self, char *key); +void rliza_set_array(rliza_t *self, char *key, rliza_t *array); + +char *rliza_dumps(rliza_t *rliza); +rliza_t *rliza_loads(char **content); +rliza_t *_rliza_loads(char **content); + +char *rliza_get_string(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_STRING || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.string; + } + } + } + return NULL; +} +long long rliza_get_integer(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_INTEGER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.integer; + } + } + } + return 0; +} + +double rliza_get_number(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_NUMBER || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.number; + } + } + } + return 0; +} + +bool rliza_get_boolean(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_BOOLEAN || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]->content.boolean; + } + } + } + return false; +} + +rliza_t *rliza_get_object(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + return self->content.map[i]; + } + } + return NULL; +} + +rliza_t *rliza_get_array(rliza_t *self, char *key) { + for (unsigned int i = 0; i < self->count; i++) { + if (self->content.map[i]->key != NULL && strcmp(self->content.map[i]->key, key) == 0) { + if (self->content.map[i]->type == RLIZA_ARRAY || self->content.map[i]->type == RLIZA_NULL) { + return self->content.map[i]; + } + } + } + return NULL; +} + +rliza_t *rliza_new_null() { + rliza_t *rliza = rliza_new(RLIZA_NULL); + return rliza; +} +rliza_t *rliza_new_string(char *string) { + rliza_t *rliza = rliza_new(RLIZA_STRING); + if (string == NULL) { + rliza->type = RLIZA_NULL; + rliza->content.string = NULL; + return rliza; + } else { + rliza->content.string = strdup(string); + } + return rliza; +} +rliza_t *rliza_new_boolean(bool value) { + rliza_t *rliza = rliza_new(RLIZA_BOOLEAN); + rliza->content.boolean = value; + return rliza; +} + +rliza_t *rliza_new_number(double value) { + rliza_t *rliza = rliza_new(RLIZA_NUMBER); + rliza->content.number = value; + return rliza; +} + +rliza_t *rliza_new_integer(long long value) { + rliza_t *rliza = rliza_new(RLIZA_INTEGER); + rliza->content.integer = value; + return rliza; +} +rliza_t *rliza_new_key_array(char *key) { + rliza_t *rliza = rliza_new(RLIZA_ARRAY); + rliza->key = strdup(key); + return rliza; +} + +rliza_t *rliza_new_key_value(char *key, rliza_t *value) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + if (key) { + rliza->key = strdup(key); + } + rliza->value = value; + return rliza; +} + +rliza_t *rliza_new_key_string(char *key, char *string) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_string(string)); + return rliza; +} +rliza_t *rliza_new_key_bool(char *key, bool value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_boolean(value)); + return rliza; +} +rliza_t *rliza_new_key_number(char *key, double value) { + rliza_t *rliza = rliza_new_key_value(key, rliza_new_number(value)); + return rliza; +} + +void rliza_set_null(rliza_t *self, char *key) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_null(); + obj->key = strdup(key); + rliza_push_object(self, obj); + } + if (obj->type == RLIZA_OBJECT) { + + rliza_free(obj->value); + obj->value = NULL; + } else if (obj->type == RLIZA_STRING) { + if (obj->content.string) + free(obj->content.string); + obj->content.string = NULL; + } else if (obj->type == RLIZA_ARRAY) { + for (unsigned int i = 0; i < obj->count; i++) { + rliza_free(obj->content.map[i]); + } + } else if (obj->type == RLIZA_NUMBER) { + obj->content.number = 0; + } else if (obj->type == RLIZA_INTEGER) { + obj->content.integer = 0; + } + obj->type = RLIZA_NULL; +} + +rliza_t *rliza_duplicate(rliza_t *rliza) { + if (!rliza) + return NULL; + char *str = rliza_dumps(rliza); + char *strp = str; + rliza_t *obj = rliza_loads(&strp); + free(str); + return obj; +} + +rliza_t *rliza_new_object(rliza_t *obj) { + rliza_t *rliza = rliza_new(RLIZA_OBJECT); + rliza->value = obj; + return rliza; +} +void rliza_set_object(rliza_t *self, char *key, rliza_t *value) { + rliza_t *obj = rliza_duplicate(value); + obj->key = strdup(key); + obj->type = RLIZA_OBJECT; + rliza_push(self, obj); +} + +void rliza_set_string(rliza_t *self, char *key, char *string) { + rliza_t *obj = rliza_get_object(self, key); + + if (!obj) { + obj = rliza_new_string(string); + obj->key = strdup(key); + obj->type = RLIZA_STRING; + rliza_push_object(self, obj); + } else { + obj->content.string = strdup(string); + } +} + +void rliza_set_array(rliza_t *self, char *key, rliza_t *array) { + rliza_t *obj = rliza_get_object(self, key); + if (obj) + rliza_free(obj); + if (array->key) { + free(array->key); + array->key = strdup(key); + } + rliza_push_object(self, array); +} + +void rliza_set_number(rliza_t *self, char *key, double value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_number(value); + obj->key = strdup(key); + obj->type = RLIZA_NUMBER; + rliza_push_object(self, obj); + } else { + obj->content.number = value; + } +} + +void rliza_push_object(rliza_t *self, rliza_t *object) { + self->content.map = realloc(self->content.map, (sizeof(rliza_t **)) * (self->count + 1)); + self->content.map[self->count] = object; + self->count++; +} +void rliza_set_integer(rliza_t *self, char *key, long long value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_integer(value); + obj->key = strdup(key); + obj->type = RLIZA_INTEGER; + rliza_push_object(self, obj); + } else { + obj->content.integer = value; + } +} + +void rliza_set_boolean(rliza_t *self, char *key, bool value) { + rliza_t *obj = rliza_get_object(self, key); + if (!obj) { + obj = rliza_new_boolean(value); + obj->key = strdup(key); + obj->type = RLIZA_BOOLEAN; + + rliza_push_object(self, obj); + } else { + obj->content.boolean = value; + } +} + +rliza_t *rliza_new(rliza_type_t type) { + rliza_t *rliza = (rliza_t *)calloc(1, sizeof(rliza_t)); + rliza->type = type; + rliza->get_boolean = rliza_get_boolean; + rliza->get_integer = rliza_get_integer; + rliza->get_number = rliza_get_number; + rliza->get_string = rliza_get_string; + rliza->get_array = rliza_get_array; + rliza->get_object = rliza_get_object; + rliza->set_string = rliza_set_string; + rliza->set_number = rliza_set_number; + rliza->set_boolean = rliza_set_boolean; + rliza->set_integer = rliza_set_integer; + rliza->set_array = rliza_set_array; + rliza->set_object = rliza_set_object; + + return rliza; +} + +void *rliza_coalesce(void *result, void *default_value) { + if (result == NULL) + return default_value; + return result; +} + +char *rliza_seek_string(char **content, char **options) { + + while (**content == ' ' || **content == '\n' || **content == '\t' || **content == '\r') { + (*content)++; + } + if (**content == 0) { + return NULL; + } + + char *option = NULL; + unsigned int option_index = 0; + + while (true) { + option = options[option_index]; + if (option == NULL) + break; + option_index++; + if (option[0] == 'd') { + if (**content >= '0' && **content <= '9') { + return (char *)*content; + } + } else if (!strncmp(option, *content, strlen(option))) { + return (char *)*content; + } + } + return *content; +} + +char *rliza_extract_quotes(char **content) { + rbuffer_t *buffer = rbuffer_new(NULL, 0); + assert(**content == '"'); + char previous = 0; + while (true) { + + (*content)++; + if (!**content) { + rbuffer_free(buffer); + return NULL; + } + + if (**content == '"' && previous != '\\') { + break; + } + rbuffer_push(buffer, **content); + previous = **content; + } + assert(**content == '"'); + (*content)++; + rbuffer_push(buffer, 0); + char *result = (char *)rbuffer_to_string(buffer); + return result; +} + +rliza_t *_rliza_loads(char **content) { + static char *seek_for1[] = {"[", "{", "\"", "d", "true", "false", "null", NULL}; + char *token = (char *)rliza_seek_string(content, seek_for1); + if (!token) + return NULL; + rliza_t *rliza = rliza_new(RLIZA_NULL); + if (**content == '"') { + char *extracted = rliza_extract_quotes(content); + if (!extracted) { + rliza_free(rliza); + return NULL; + } + // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); + // rstraddslashes(extracted, extracted_with_slashes); + rliza->type = RLIZA_STRING; + rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; + // free(extracted); + return rliza; + } else if (**content == '{') { + rliza->type = RLIZA_OBJECT; + (*content)++; + char *result = NULL; + static char *seek_for2[] = {"\"", ",", "}", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for2)) != NULL && *result) { + + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (**content == ',') { + (*content)++; + if (!**content) { + rliza_free(rliza); + return NULL; + } + continue; + } + char *key = NULL; + if (**content == '"') { + key = rliza_extract_quotes((char **)content); + if (!key || !*key) { + rliza_free(rliza); + return NULL; + } + char *escaped_key = (char *)malloc(strlen((char *)key) * 2 + 1); + rstrstripslashes((char *)key, escaped_key); + static char *seek_for3[] = {":", NULL}; + char *devider = rliza_seek_string(content, seek_for3); + + if (!devider || !*devider) { + free(escaped_key); + free(key); + rliza_free(rliza); + return NULL; + } + (*content)++; + if (!**content) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + rliza_t *value = _rliza_loads(content); + if (!value) { + free(key); + free(escaped_key); + rliza_free(rliza); + return NULL; + } + if (value->key) + free(value->key); + value->key = escaped_key; + free(key); + rliza_push_object(rliza, value); + } else if (**content == '}') { + break; + } else { + // Parse error + rliza_free(rliza); + return NULL; + } + }; + if ((**content != '}')) { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content == '[') { + rliza->type = RLIZA_ARRAY; + (*content)++; + char *result; + static char *seek_for4[] = {"[", "{", "\"", "d", ",", "]", "null", "true", "false", NULL}; + while ((result = (char *)rliza_seek_string(content, seek_for4)) != NULL && *result) { + if (**content == ',') { + (*content)++; + + } else if (**content == ']') { + break; + } + rliza_t *obj = _rliza_loads(content); + if (!obj) { + rliza_free(rliza); + return NULL; + } + rliza_push(rliza, obj); + if (!**content) { + rliza_free(rliza); + return NULL; + } + } + if (**content != ']') { + rliza_free(rliza); + return NULL; + } + (*content)++; + return rliza; + } else if (**content >= '0' && **content <= '9') { + char *ptr = *content; + bool is_decimal = false; + + while (**content) { + if (**content == '.') { + is_decimal = true; + } else if (!isdigit(**content)) { + break; + } + (*content)++; + } + if (*(*content - 1) == '.') { + rliza_free(rliza); + return NULL; + } + if (!**content) { + rliza_free(rliza); + return NULL; + } + if (is_decimal) { + rliza->type = RLIZA_NUMBER; + rliza->content.number = strtod(ptr, NULL); + } else { + rliza->type = RLIZA_INTEGER; + rliza->content.integer = strtoll(ptr, NULL, 10); + } + return rliza; + } else if (!strncmp(*content, "true", 4)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = true; + *content += 4; + + return rliza; + } else if (!strncmp(*content, "false", 5)) { + rliza->type = RLIZA_BOOLEAN; + rliza->content.boolean = false; + *content += 5; + + return rliza; + } else if (!strncmp(*content, "null", 4)) { + rliza->type = RLIZA_NULL; + *content += 4; + + return rliza; + } + // Parsing error + rliza_free(rliza); + return NULL; +} +rliza_t *rliza_loads(char **content) { + if (!content || !**content) { + return NULL; + } + char *original_content = *content; + rliza_t *result = _rliza_loads(content); + if (!result) { + *content = original_content; + } + return result; +} + +char *rliza_dumps(rliza_t *rliza) { + size_t size = 4096; + char *content = (char *)calloc(size, sizeof(char)); + content[0] = 0; + if (rliza->type == RLIZA_INTEGER) { + if (rliza->key) { + sprintf(content, "\"%s\":%lld", rliza->key, rliza->content.integer); + } else { + sprintf(content, "%lld", rliza->content.integer); + } + } else if (rliza->type == RLIZA_STRING) { + + // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); + char *escaped_string = rliza->content.string; + // rstrstripslashes((char *)rliza->content.string, escaped_string); + size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; + if (size < min_size) { + size = min_size + 1; + content = realloc(content, size); + } + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 20); + rstrstripslashes((char *)rliza->key, escaped_key); + if (strlen(content) > size) { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + } + sprintf(content, "\"%s\":\"%s\"", escaped_key, escaped_string); + free(escaped_key); + } else { + size = size + strlen(escaped_string) + 20; + content = realloc(content, size); + sprintf(content, "\"%s\"", escaped_string); + } + // free(escaped_string); + } else if (rliza->type == RLIZA_NUMBER) { + if (rliza->key) { + sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); + } else { + sprintf(content, "%f", rliza->content.number); + } + int last_zero = 0; + bool beyond_dot = false; + for (size_t i = 0; i < strlen(content); i++) { + if (content[i] == '.') { + beyond_dot = true; + } else if (beyond_dot == true) { + if (content[i - 1] != '.') { + if (content[i] == '0') { + if (!last_zero) + last_zero = i; + } else { + last_zero = 0; + } + } + } + } + if (last_zero != 0) { + content[last_zero] = 0; + } + } else if (rliza->type == RLIZA_BOOLEAN) { + if (rliza->key) { + sprintf(content, "\"%s\":%s", rliza->key, rliza->content.boolean ? "true" : "false"); + } else { + sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); + } + } else if (rliza->type == RLIZA_OBJECT) { + + strcat(content, "{"); + if (rliza->key) { + strcat(content, "\""); + strcat(content, rliza->key); + strcat(content, "\":{"); + } + // bool add_braces = false; + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + content_chunk_stripped++; + content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + + strcat(content, ","); + } + if (content[strlen(content) - 1] == ',') { + content[strlen(content) - 1] = '\0'; + + if (rliza->key) { + strcat(content, "}"); + } + } + strcat(content, "}"); + } else if (rliza->type == RLIZA_ARRAY) { + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + if (strlen(escaped_key) > size) { + size = strlen(escaped_key) + 10; + content = realloc(content, size); + } + sprintf(content, "\"%s\":[", escaped_key); + free(escaped_key); + } else + strcpy(content, "["); + for (unsigned i = 0; i < rliza->count; i++) { + char *content_chunk = rliza_dumps(rliza->content.map[i]); + char *content_chunk_stripped = content_chunk; + if (*content_chunk_stripped == '{') { + // content_chunk_stripped++; + // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; + } + if (strlen(content_chunk_stripped) + strlen(content) > size) { + size += strlen(content_chunk_stripped) + 20; + content = realloc(content, size); + } + strcat(content, content_chunk_stripped); + free(content_chunk); + strcat(content, ","); + } + if (content[strlen(content) - 1] != '[') + content[strlen(content) - 1] = 0; + strcat(content, "]"); + } else if (rliza->type == RLIZA_NULL) { + + if (rliza->key) { + char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); + rstraddslashes((char *)rliza->key, escaped_key); + sprintf(content, "\"%s\":null", escaped_key); + free(escaped_key); + } else + strcpy(content, "null"); + } + return content; +} + +void rliza_dumpss(rliza_t *rliza) { + char *output = rliza_dumps(rliza); + printf("%s\n", output); + free(output); +} + +void rliza_push(rliza_t *self, rliza_t *obj) { rliza_push_object(self, obj); } + +int rliza_validate(char *json_content) { + if (!json_content || !*json_content) { + return false; + } + char *json_contentp = json_content; + rliza_t *to_object = _rliza_loads(&json_contentp); + if (to_object) { + rliza_free(to_object); + return json_contentp - json_content; + } + return false; +} + +#endif diff --git a/.backup.1.rmalloc.c b/.backup.1.rmalloc.c new file mode 100644 index 0000000..4a8d3db --- /dev/null +++ b/.backup.1.rmalloc.c @@ -0,0 +1,44 @@ +#include "rtest.h" + +#include "rmalloc.h" + +void rtest_malloc() { + rtest_banner("count"); + void *x = malloc(10); + void *y = malloc(10); + void *z = malloc(10); + void *ptr = NULL; + realloc(ptr, 10); + void *w = calloc(1, 10); + rtest_true(rmalloc_alloc_count == 5); + + rtest_banner("free") x = free(x); + rtest_true(x == NULL); + rtest_true(rmalloc_count == 4); + + rtest_banner("another free") y = free(y); + rtest_true(y == NULL); + rtest_true(rmalloc_count == 3); + + rtest_banner("third free") z = free(z); + rtest_true(z == NULL); + rtest_true(rmalloc_count == 2); + + rtest_banner("third four") w = free(w); + rtest_true(w == NULL); + rtest_true(rmalloc_count == 1); + + rtest_banner("third five") ptr = free(ptr); + rtest_true(ptr == NULL); + rtest_true(rmalloc_count == 0); + + rtest_banner("totals") rtest_true(rmalloc_alloc_count == 5); + rtest_true(rmalloc_free_count == 5); + rtest_true(rmalloc_count == 0); +} + +int main() { + rtest_banner("malloc.h"); + rtest_malloc(); + return rtest_end("rtest_malloc"); +} \ No newline at end of file diff --git a/.backup.1.rmalloc.h b/.backup.1.rmalloc.h new file mode 100644 index 0000000..444b155 --- /dev/null +++ b/.backup.1.rmalloc.h @@ -0,0 +1,145 @@ +#ifndef RMALLOC_H +#define RMALLOC_H +#ifndef RMALLOC_OVERRIDE +#define RMALLOC_OVERRIDE 1 +#endif +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#ifndef ulonglong +#define ulonglong unsigned long long +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include "rtemp.h" +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +ulonglong rmalloc_count = 0; +ulonglong rmalloc_alloc_count = 0; +ulonglong rmalloc_free_count = 0; +ulonglong rmalloc_total_bytes_allocated = 0; + +void *_rmalloc_prev_realloc_obj = NULL; +size_t _rmalloc_prev_realloc_obj_size = 0; + +void *rmalloc(size_t size) { + void *result; + while (!(result = malloc(size))) { + fprintf(stderr, "Warning: malloc failed, trying again.\n"); + } + rmalloc_count++; + rmalloc_alloc_count++; + rmalloc_total_bytes_allocated += size; + return result; +} +void *rcalloc(size_t count, size_t size) { + void *result; + while (!(result = calloc(count, size))) { + fprintf(stderr, "Warning: calloc failed, trying again.\n"); + } + rmalloc_alloc_count++; + rmalloc_count++; + rmalloc_total_bytes_allocated += count * size; + return result; +} +void *rrealloc(void *obj, size_t size) { + if (!obj) { + rmalloc_count++; + } + + rmalloc_alloc_count++; + if (obj == _rmalloc_prev_realloc_obj) { + rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; + _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; + + } else { + _rmalloc_prev_realloc_obj_size = size; + } + void *result; + while (!(result = realloc(obj, size))) { + fprintf(stderr, "Warning: realloc failed, trying again.\n"); + } + _rmalloc_prev_realloc_obj = result; + + return result; +} + +char *rstrdup(const char *s) { + if (!s) + return NULL; + + char *result; + size_t size = strlen(s) + 1; + + result = rmalloc(size); + memcpy(result, s, size); + rmalloc_total_bytes_allocated += size; + return result; +} +void *rfree(void *obj) { + rmalloc_count--; + rmalloc_free_count++; + free(obj); + return NULL; +} + +#if RMALLOC_OVERRIDE +#define malloc rmalloc +#define calloc rcalloc +#define realloc rrealloc +#define free rfree +#define strdup rstrdup +#endif + +char *rmalloc_lld_format(ulonglong num) { + + char res[100]; + res[0] = 0; + sprintf(res, "%'lld", num); + char *resp = res; + while (*resp) { + if (*resp == ',') + *resp = '.'; + resp++; + } + return sbuf(res); +} + +char *rmalloc_bytes_format(int factor, ulonglong num) { + char *sizes[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; + if (num > 1024) { + return rmalloc_bytes_format(factor + 1, num / 1024); + } + char res[100]; + sprintf(res, "%s %s", rmalloc_lld_format(num), sizes[factor]); + return sbuf(res); +} + +char *rmalloc_stats() { + static char res[200]; + res[0] = 0; + // int original_locale = localeconv(); + setlocale(LC_NUMERIC, "en_US.UTF-8"); + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), + + rmalloc_lld_format(rmalloc_count)); + // setlocale(LC_NUMERIC, original_locale); + + setlocale(LC_NUMERIC, ""); + return res; +} + +#endif diff --git a/.backup.1.rmath.h b/.backup.1.rmath.h new file mode 100644 index 0000000..454dae4 --- /dev/null +++ b/.backup.1.rmath.h @@ -0,0 +1,35 @@ +#ifndef RMATH_H +#define RMATH_H +#include <math.h> + +#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 \ No newline at end of file diff --git a/.backup.1.rmerge.c b/.backup.1.rmerge.c new file mode 100644 index 0000000..064d4dd --- /dev/null +++ b/.backup.1.rmerge.c @@ -0,0 +1,3 @@ +#include "rmerge.h" + +int main(int argc, char *argv[]) { return rmerge_main(argc, argv); } diff --git a/.backup.1.rmerge.h b/.backup.1.rmerge.h new file mode 100644 index 0000000..be5852e --- /dev/null +++ b/.backup.1.rmerge.h @@ -0,0 +1,178 @@ +#ifndef RMERGE_H +#define RMERGE_H +// #include "../mrex/rmatch.h" +#include "rlexer.h" +#include "rmalloc.h" +#include "rprint.h" +#include "rrex3.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include "remo.h" + +bool has_error = false; + +char *extract_script_src_include(char *line, char *include_path) { + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *extract_c_local_include(char *line, char *include_path) { + // + /* + char res; + res= rmatch_extract(line, "#include.*"\".*\""); + + + printf("%MATCH:%s\n", res); + */ + + include_path[0] = 0; + rrex3_t *rrex; + rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + if (rrex) { + strcpy(include_path, rrex->matches[0]); + rrex3_free(rrex); + return include_path; + } + return NULL; +} + +char *rmerge_readline(FILE *f) { + static char data[4096]; + data[0] = 0; + int index = 0; + char c; + while ((c = fgetc(f)) != EOF) { + if (c != '\0') { + data[index] = c; + index++; + if (c == '\n') + break; + } + } + data[index] = 0; + if (data[0] == 0) + return NULL; + return data; +} +void writestring(FILE *f, char *line) { + char c; + while ((c = *line) != '\0') { + fputc(c, f); + line++; + } +} +char files_history[8096]; +char files_duplicate[8096]; +bool is_merging = false; + +void merge_file(char *source, FILE *d) { + if (is_merging == false) { + is_merging = true; + files_history[0] = 0; + files_duplicate[0] = 0; + } + if (strstr(files_history, source)) { + if (strstr(files_duplicate, source)) { + rprintmf(stderr, "\\l Already included: %s. Already on duplicate list.\n", source); + } else { + rprintcf(stderr, "\\l Already included: %s. Adding to duplicate list.\n", source); + strcat(files_duplicate, source); + strcat(files_duplicate, "\n"); + } + return; + } else { + rprintgf(stderr, "\\l Merging: %s.\n", source); + strcat(files_history, source); + strcat(files_history, "\n"); + } + FILE *fd = fopen(source, "rb"); + if (!fd) { + rprintrf(stderr, "\\l File does not exist: %s\n", source); + has_error = true; + return; + } + + char *line; + char include_path[4096]; + while ((line = rmerge_readline(fd))) { + + include_path[0] = 0; + if (!*line) + break; + + // + char *inc = extract_c_local_include(line, include_path); + if (!inc) + inc = extract_script_src_include(line, include_path); + + /* + if (!strncmp(line, "#include ", 9)) { + int index = 0; + while (line[index] != '"' && line[index] != 0) { + index++; + } + if (line[index] == '"') { + int pindex = 0; + index++; + while (line[index] != '"') { + include_path[pindex] = line[index]; + pindex++; + index++; + } + if (line[index] != '"') { + include_path[0] = 0; + } else { + include_path[pindex] = '\0'; + } + } + }*/ + if (inc) { + merge_file(inc, d); + } else { + writestring(d, line); + } + } + fclose(fd); + writestring(d, "\n"); +} + +int rmerge_main(int argc, char *argv[]) { + char *file_input = NULL; + if (argc != 2) { + printf("Usage: <input-file>\n"); + } else { + file_input = argv[1]; + // file_output = argv[2]; + } + FILE *f = tmpfile(); + printf("// RETOOR - %s\n", __DATE__); + merge_file(file_input, f); + rewind(f); + char *data; + int line_number = 0; + while ((data = rmerge_readline(f))) { + if (line_number) { + printf("/*%.5d*/ ", line_number); + line_number++; + } + printf("%s", data); + } + printf("\n"); + if (has_error) { + rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); + } else { + rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + } + return 0; +} +#endif diff --git a/.backup.1.rnet.c b/.backup.1.rnet.c new file mode 100644 index 0000000..f471df7 --- /dev/null +++ b/.backup.1.rnet.c @@ -0,0 +1,42 @@ +#include "rnet.h" + +void on_client_connect(rnet_socket_t *sock) { printf("%s connected\n", sock->name); } +void on_client_read(rnet_socket_t *sock) { + unsigned char *data = net_socket_read(sock, 4096); + if (!data) + return; + char *http_headers = "HTTP/1.1 200 OK\r\nContent-Length: 10\r\nConnection: close\r\n\r\n"; + net_socket_write(sock, (unsigned char *)http_headers, strlen(http_headers)); + rnet_safe_str((char *)data, sock->bytes_received); + // data[11] = 0; + printf("%s: %.30s\n", sock->name, data); + net_socket_write(sock, data, strlen((char *)data)); + if (!strncmp((char *)data, "GET ", 4)) + net_socket_close(sock); +} +void on_client_close(rnet_socket_t *sock) { printf("%s disconnected\n", sock->name); } + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("usage: [port].\n"); + return 1; + } + for (int i = 0; i < argc; i++) { + if (strcmp(argv[i], "test") == 0) { + printf("Skipping rnet tests.\n"); + return 0; + } + } + rnet_server_t *server = net_socket_serve((unsigned int)atoi(argv[1]), 10); + server->on_connect = on_client_connect; + server->on_read = on_client_read; + server->on_close = on_client_close; + while (true) { + if (net_socket_select(server)) { + printf("Handled all events.\n"); + } else { + printf("No events to handle.\n"); + } + } + return 0; +} diff --git a/.backup.1.rnet.h b/.backup.1.rnet.h new file mode 100644 index 0000000..83ea58f --- /dev/null +++ b/.backup.1.rnet.h @@ -0,0 +1,480 @@ +#ifndef RNET_H +#define RNET_H +#ifdef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <unistd.h> +#ifdef _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP +#undef _POSIX_C_SOURCE_TEMP +#else +#undef _POSIX_C_SOURCE +#endif +#define NET_SOCKET_MAX_CONNECTIONS 50000 + +typedef struct rnet_socket_t { + int fd; + char name[50]; + void *data; + size_t bytes_received; + size_t bytes_sent; + bool connected; + void (*on_read)(struct rnet_socket_t *); + void (*on_close)(struct rnet_socket_t *); + void (*on_connect)(struct rnet_socket_t *); +} rnet_socket_t; + +typedef struct rnet_select_result_t { + int server_fd; + rnet_socket_t **sockets; + unsigned int socket_count; +} rnet_select_result_t; + +typedef struct rnet_server_t { + int socket_fd; + rnet_socket_t **sockets; + unsigned int socket_count; + unsigned int port; + unsigned int backlog; + rnet_select_result_t *select_result; + int max_fd; + void (*on_connect)(rnet_socket_t *socket); + void (*on_close)(rnet_socket_t *socket); + void (*on_read)(rnet_socket_t *socket); +} rnet_server_t; + +void rnet_select_result_free(rnet_select_result_t *result); +int net_socket_accept(int server_fd); +int net_socket_connect(const char *, unsigned int); +int net_socket_init(); +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog); +rnet_select_result_t *net_socket_select(rnet_server_t *server); +rnet_socket_t *net_socket_wait(rnet_socket_t *socket_fd); +bool net_set_non_blocking(int sock); +bool net_socket_bind(int sock, unsigned int port); +bool net_socket_listen(int sock, unsigned int backlog); +char *net_socket_name(int sock); +size_t net_socket_write(rnet_socket_t *, unsigned char *, size_t); +rnet_socket_t *get_net_socket_by_fd(int); +unsigned char *net_socket_read(rnet_socket_t *, unsigned int buff_size); +void _net_socket_close(int sock); +void net_socket_close(rnet_socket_t *sock); + +rnet_server_t *rnet_server_new(int socket_fd, unsigned int port, unsigned int backlog) { + rnet_server_t *server = malloc(sizeof(rnet_server_t)); + server->socket_fd = socket_fd; + server->sockets = NULL; + server->socket_count = 0; + server->port = port; + server->backlog = backlog; + server->max_fd = -1; + server->select_result = NULL; + server->on_connect = NULL; + server->on_close = NULL; + server->on_read = NULL; + return server; +} + +rnet_server_t *rnet_server_add_socket(rnet_server_t *server, rnet_socket_t *sock) { + server->sockets = realloc(server->sockets, sizeof(rnet_socket_t *) * (server->socket_count + 1)); + server->sockets[server->socket_count] = sock; + server->socket_count++; + sock->on_read = server->on_read; + sock->on_connect = server->on_connect; + sock->on_close = server->on_close; + sock->connected = true; + return server; +} + +rnet_socket_t sockets[NET_SOCKET_MAX_CONNECTIONS] = {0}; +unsigned long sockets_connected = 0; +int net_socket_max_fd = 0; +unsigned long sockets_total = 0; +unsigned long sockets_disconnected = 0; +unsigned long sockets_concurrent_record = 0; +unsigned long sockets_errors = 0; + +bool net_set_non_blocking(int sock) { + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + perror("fcntl"); + return false; + } + + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + return false; + } + + return true; +} + +int net_socket_init() { + int socket_fd = -1; + memset(sockets, 0, sizeof(sockets)); + int opt = 1; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Socket failed.\n"); + return false; + } + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("Setsockopt failed.\n"); + close(socket_fd); + return false; + } + net_set_non_blocking(socket_fd); + return socket_fd; +} + +char *net_socket_name(int fd) { + rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); + if (rnet_socket) { + return rnet_socket->name; + ; + } + + // If socket disconnected or is no client from server + return NULL; +} + +bool net_socket_bind(int socket_fd, unsigned int port) { + struct sockaddr_in address; + + address.sin_family = AF_INET; // IPv4 + address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address + address.sin_port = htons(port); // Convert port to network byte order + + if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(socket_fd); + return false; + } + return true; +} + +int net_socket_connect(const char *host, unsigned int port) { + char port_str[10] = {0}; + sprintf(port_str, "%d", port); + int status; + int socket_fd = -1; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *p; + if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return false; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + return -1; + } + + for (p = res; p != NULL; p = p->ai_next) { + if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + + if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { + close(socket_fd); + continue; + } + + break; + } + + if (p == NULL) { + freeaddrinfo(res); + return -1; + } + + freeaddrinfo(res); + return socket_fd; +} + +bool net_socket_listen(int socket_fd, unsigned int backlog) { + if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + perror("Listen failed"); + close(socket_fd); + return false; + } + return true; +} + +rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { + signal(SIGPIPE, SIG_IGN); + int socket_fd = net_socket_init(); + net_socket_bind(socket_fd, port); + net_socket_listen(socket_fd, backlog); + return rnet_server_new(socket_fd, port, backlog); +} + +int net_socket_accept(int net_socket_server_fd) { + struct sockaddr_in address; + int addrlen = sizeof(address); + int new_socket = -1; + if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + close(new_socket); + return -1; + } else { + + return new_socket; + } +} +/* +static void net_socket_stats(WrenVM *vm) +{ + + wrenSetSlotNewList(vm, 0); + + wrenSetSlotString(vm, 1, "sockets_total"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_total); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_concurrent_record"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_connected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_connected); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotString(vm, 1, "sockets_disconnected"); + wrenInsertInList(vm, 0, -1, 1); + + wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); + wrenInsertInList(vm, 0, -1, 1); +}*/ + +size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { + ssize_t sent_total = 0; + ssize_t sent = 0; + ssize_t to_send = size; + while ((sent = send(sock->fd, message, to_send, 0))) { + if (sent == -1) { + sockets_errors++; + net_socket_close(sock); + break; + } + if (sent == 0) { + printf("EDGE CASE?\n"); + exit(1); + sockets_errors++; + net_socket_close(sock); + break; + } + sent_total += sent; + if (sent_total == to_send) + break; + } + return sent_total; +} + +unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { + if (buff_size > 1024 * 1024 + 1) { + perror("Buffer too big. Maximum is 1024*1024.\n"); + exit(1); + } + static unsigned char buffer[1024 * 1024]; + buffer[0] = 0; + ssize_t received = recv(sock->fd, buffer, buff_size, 0); + if (received <= 0) { + buffer[0] = 0; + net_socket_close(sock); + if (received < 0) { + sockets_errors++; + return NULL; + } + } + buffer[received + 1] = 0; + sock->bytes_received = received; + return buffer; +} + +rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { + if (!sock) + return NULL; + if (sock->fd == -1) + return NULL; + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(sock->fd, &read_fds); + + int max_socket_fd = sock->fd; + int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + // perror("Select error"); + net_socket_close(sock); + return NULL; + } + if (FD_ISSET(sock->fd, &read_fds)) { + return sock; + } + + return NULL; +} + +void rnet_safe_str(char *str, size_t length) { + if (!str || !length || !*str) + return; + for (unsigned int i = 0; i < length; i++) { + if (str[i] < 32 || str[i] > 126) + if (str[i] != 0) + str[i] = '.'; + } + str[length] = 0; +} + +rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { + rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + memset(result, 0, sizeof(rnet_select_result_t)); + result->server_fd = socket_fd; + result->socket_count = 0; + result->sockets = NULL; + return result; +} + +void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { + result->sockets = realloc(result->sockets, sizeof(rnet_socket_t *) * (result->socket_count + 1)); + result->sockets[result->socket_count] = sock; + result->socket_count++; +} +void rnet_select_result_free(rnet_select_result_t *result) { free(result); } +rnet_select_result_t *net_socket_select(rnet_server_t *server) { + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(server->socket_fd, &read_fds); + + server->max_fd = server->socket_fd; + int socket_fd = -1; + for (unsigned int i = 0; i < server->socket_count; i++) { + socket_fd = server->sockets[i]->fd; + if (!server->sockets[i]->connected) { + continue; + } + if (socket_fd > 0) { + FD_SET(socket_fd, &read_fds); + if (socket_fd > server->max_fd) { + server->max_fd = socket_fd; + } + } + } + int new_socket = -1; + struct sockaddr_in address; + int addrlen = sizeof(struct sockaddr_in); + int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); + if ((activity < 0) && (errno != EINTR)) { + perror("Select error\n"); + return NULL; + } + if (FD_ISSET(server->socket_fd, &read_fds)) { + if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + perror("Accept failed\n"); + return NULL; + } + + // net_set_non_blocking(new_socket); + char name[50] = {0}; + sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + rnet_socket_t *sock_obj = NULL; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets && server->sockets[i]->fd == -1) { + sock_obj = server->sockets[i]; + } + } + if (!sock_obj) { + sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + rnet_server_add_socket(server, sock_obj); + } + sock_obj->fd = new_socket; + strcpy(sock_obj->name, name); + sockets_connected++; + sockets_total++; + sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; + if (new_socket > net_socket_max_fd) { + net_socket_max_fd = new_socket; + } + sock_obj->connected = true; + sock_obj->on_connect(sock_obj); + } + rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); + unsigned int readable_count = 0; + for (unsigned int i = 0; i < server->socket_count; i++) { + if (server->sockets[i]->fd == -1) + continue; + if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { + rnet_select_result_add(result, server->sockets[i]); + readable_count++; + if (server->sockets[i]->on_read) { + server->sockets[i]->on_read(server->sockets[i]); + } + } + } + if (server->select_result) { + rnet_select_result_free(server->select_result); + server->select_result = NULL; + } + if (readable_count == 0) + rnet_select_result_free(result); + return readable_count ? result : NULL; +} + +rnet_socket_t *get_net_socket_by_fd(int sock) { + for (int i = 0; i < net_socket_max_fd; i++) { + if (sockets[i].fd == sock) { + return &sockets[i]; + } + } + return NULL; +} + +void _net_socket_close(int sock) { + if (sock > 0) { + sockets_connected--; + sockets_disconnected++; + if (sock > 0) { + if (close(sock) == -1) { + perror("Error closing socket.\n"); + } + } + } +} + +void net_socket_close(rnet_socket_t *sock) { + sock->connected = false; + if (sock->on_close) + sock->on_close(sock); + _net_socket_close(sock->fd); + sock->fd = -1; +} +#undef _POSIX_C_SOURCE +#endif diff --git a/.backup.1.rprint.c b/.backup.1.rprint.c new file mode 100644 index 0000000..b297293 --- /dev/null +++ b/.backup.1.rprint.c @@ -0,0 +1,47 @@ +#include "rprint.h" +#include "rbench.h" + +void test_putc(void *arg) { + char *str = (char *)arg; + char c; + while ((c = *str++)) { + putc('\r', stdout); + } +} + +void test_putchar(void *arg) { + char *str = (char *)arg; + char c; + while ((c = *str++)) { + putchar('\r'); + } +} +void test_fwrite(void *arg) { + int length; + if (rbf->first) { + length = strlen((char *)arg); + rbf->data = (void *)&length; + } else { + length = (intptr_t)&rbf->data; + } + fwrite((char *)arg, 1, length, stdout); +} +void test_printf(void *arg) { printf("%s", (char *)arg); } +void test_rprint(void *arg) { rprint("%s", (char *)arg); } +void test_rprintr(void *arg) { rprintr("%s", (char *)arg); } + +int main() { + rbench_t *r = rbench_new(); + r->stdout = false; + r->silent = true; + long times = 100000; + r->add_function(r, "putc", "chrloop", test_putc); + r->add_function(r, "putchar", "chrloop", test_putchar); + r->add_function(r, "fwrite", "fileio", test_fwrite); + r->add_function(r, "printf", "default", test_printf); + r->add_function(r, "rprint", "custom", test_rprint); + r->add_function(r, "rprintr", "color", test_rprintr); + r->execute1(r, times, " \r"); + r->execute1(r, times, "\\c\\T\\l\\L \r"); + return rtest_end(""); +} diff --git a/.backup.1.rprint.h b/.backup.1.rprint.h new file mode 100644 index 0000000..2b615ee --- /dev/null +++ b/.backup.1.rprint.h @@ -0,0 +1,287 @@ +#ifndef RPRINT_H +#define RPRINT_H +#include "rtime.h" +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +long rpline_number = 0; +nsecs_t rprtime = 0; + +int8_t _env_rdisable_colors = -1; +bool _rprint_enable_colors = true; + +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; + } + return _rprint_enable_colors; +} + +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; } + +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 = 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(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "", format, args); + va_end(args); +} + +void rprintf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "", format, args); + va_end(args); +} +void rprint(const 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, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\\l", format, args); + va_end(args); +} +void rprintl(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\\l", format, args); + va_end(args); +} + +// Black +void rprintkf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[30m", format, args); + va_end(args); +} +void rprintk(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[30m", format, args); + va_end(args); +} + +// Red +void rprintrf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[31m", format, args); + va_end(args); +} +void rprintr(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[31m", format, args); + va_end(args); +} + +// Green +void rprintgf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[32m", format, args); + va_end(args); +} +void rprintg(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[32m", format, args); + va_end(args); +} + +// Yellow +void rprintyf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[33m", format, args); + va_end(args); +} +void rprinty(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[33m", format, args); + va_end(args); +} + +// Blue +void rprintbf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[34m", format, args); + va_end(args); +} + +void rprintb(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[34m", format, args); + va_end(args); +} + +// Magenta +void rprintmf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[35m", format, args); + va_end(args); +} +void rprintm(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[35m", format, args); + va_end(args); +} + +// Cyan +void rprintcf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[36m", format, args); + va_end(args); +} +void rprintc(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[36m", format, args); + va_end(args); +} + +// White +void rprintwf(FILE *f, const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(f, "\e[37m", format, args); + va_end(args); +} +void rprintw(const char *format, ...) { + va_list args; + va_start(args, format); + rprintpf(stdout, "\e[37m", format, args); + va_end(args); +} +#endif \ No newline at end of file diff --git a/.backup.1.rrex3.c b/.backup.1.rrex3.c new file mode 100644 index 0000000..80ab15f --- /dev/null +++ b/.backup.1.rrex3.c @@ -0,0 +1,10 @@ + +#include "rrex3.h" +#include "rtest.h" + +int main() { + printf("Testing rrex3 regular expression parser."); + rrex3_test(); + return 0; + // return rtest_end(""); +} diff --git a/.backup.1.rrex4.c b/.backup.1.rrex4.c new file mode 100644 index 0000000..a37b08a --- /dev/null +++ b/.backup.1.rrex4.c @@ -0,0 +1,158 @@ +#include "rrex4.h" +#include "rtest.h" +#include "rbench.h" +#include <regex.h> + +bool bench_r4(unsigned int times, char *str, char *expr) { + RBENCH(times, { + r4_t *r = r4(str, expr); + + if (r->valid == false) { + + printf("Bench r4 error\n"); + exit(1); + } + + r4_free(r); + }); + return true; +} + +void bench_c(unsigned int times, char *str, char *expr) { + regex_t regex; + if (regcomp(®ex, expr, REG_EXTENDED)) { + printf("Creg: error in regular expression.\n"); + exit(1); + } + RBENCH(times, { + if (regexec(®ex, str, 0, NULL, 0)) { + printf("Creg: error executing regular expression.\n"); + exit(1); + } + }); + + regfree(®ex); +} + +bool bench(unsigned int times, char *str, char *expr) { + printf("%d:(%s)<%s>\n", times, str, expr); + printf("c:"); + bench_c(times, str, expr); + printf("r:"); + bench_r4(times, str, expr); + return true; +} + +void test_r4_next() { + r4_t *r = r4_new(); + char *str = "abcdefghijklmnop"; + char *reg = "(\\w\\w\\w\\w)"; + r = r4(str, reg); + assert(r->valid); + assert(r->match_count == 1); + assert(!strcmp(r->matches[0], "abcd")); + // Again with same regex as parameter + r = r4_next(r, reg); + assert(r->valid); + assert(r->match_count == 1); + assert(!strcmp(r->matches[0], "efgh")); + // Again with same regex as parameter + r = r4_next(r, reg); + assert(r->valid); + assert(r->match_count == 1); + assert(!strcmp(r->matches[0], "ijkl")); + // Reuse expression, NULL parameter + r = r4_next(r, NULL); + assert(r->valid); + assert(r->match_count == 1); + assert(!strcmp(r->matches[0], "mnop")); + // No results using r4_next + r = r4_next(r, NULL); + assert(r->valid); + assert(r->match_count == 0); + // Again no results using r4_next, Shouldn't crash + r = r4_next(r, NULL); + assert(r->valid); + assert(r->match_count == 0); + r4_free(r); +} + +void bench_all(unsigned int times) { + assert(bench(times, "suvw", + "[abcdefghijklmnopqrstuvw][abcdefghijklmnopqrstuvw][" + "abcdefghijklmnopqrstuvw][abcdefghijklmnopqrstuvw]")); + assert(bench(times, "ponyyy", "^p+o.*yyy$$$$")); + assert(bench(times, " ponyyzd", "p+o.*yyzd$$$$")); + assert(bench(times, "abc", "def|gek|abc")); + assert(bench(times, "abc", "def|a?b?c|def")); + assert(bench(times, "NL18RABO0322309700", "([A-Z]{2})([0-9]{2})([A-Z]{4}[0-9])([0-9]+)$")); +} + +bool r4_match_stats(char *str, char *expr) { + r4_t *r = r4(str, expr); + bool result = r->valid; + printf("%d:(%s)<%s>\n", r->validation_count, r->_str, r->_expr); + for (unsigned i = 0; i < r->match_count; i++) { + printf(" - match: \"%s\"\n", r->matches[i]); + } + r4_free(r); + return result; +} + +int main() { + + assert(r4_match_stats("NL18RABO0322309700", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d{10})")); + + unsigned int times = 1000; + bench_all(times); + + RBENCH(1, { + assert(r4_match_stats("#define DEFINETEST 1\n", "#define\\s+(\\w[\\d\\w_]+)\\s+([\\w\\d_]+)")); + assert(r4_match_stats("#define DEFINETEST 1\n", "#define\\s+(\\w[\\d\\w_]+)\\s+([\\w\\d_]+)")); + assert(r4_match_stats("ponyyy", "^p+o.*yyy$$$$")); + assert(!r4_match_stats("ponyyy", "p%+o.*yyy$$$$")); + assert(!r4_match_stats("ponyyyd", "^p+o.*yyz$$$$")); + assert(r4_match_stats("123", "[0-2][2-2][1-3]$")); + assert(r4_match_stats("aaaabC5", "(a)(\\w)a*(a)\\w[A-Z][0-9]$")); + assert(r4_match_stats("abcdeeeeee", "ab(cdeee)e")); + assert(r4_match_stats("1234567", "12(.*)67$")); + assert(r4_match_stats("12111678993", "12(.*)67(.*)3$")); + assert(r4_match_stats("NL17RABO0322309700", "NL(.*)R(.*)0(.*)0(.*)0$")); + + assert(r4_match_stats("NL18RABO0322309700", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d+)$")); + assert(r4_match_stats("NL18RABO0322309700garbage", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d+)")); + assert(r4_match_stats("NL18RABO0322309700", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d+)$")); + assert(r4_match_stats(" NL18RABO0322309700", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d+)$")); + assert(r4_match_stats(" NL18RABO0322309700", "(\\w{2})(\\d{2})(\\w{4}\\d)(\\d+)$")); + assert(r4_match_stats("NL18RABO0", "(\\w\\w)(\\d\\d)(\\w\\w\\w\\w\\d)$")); + assert(r4_match_stats("q", "\\q$")); + assert(r4_match_stats("ab123", "[a-z0-9]+$")); + assert(r4_match_stats("ppppony", "p*pppony")); + assert(r4_match_stats("aa", "a{2}$")); + assert(r4_match_stats("A23", "[0-2A-z][2-2][1-3]$")); + assert(r4_match_stats("z23", "[0-2A-z][2-2][1-3]$")); + assert(r4_match_stats("r23", "[0-2Ar][2-2][1-3]$")); + assert(r4_match_stats("test", "\\w\\w\\w\\w$")); + assert(!r4_match_stats("test", "\\W\\w\\w\\w$")); + assert(r4_match_stats("1est", "\\W\\w\\w\\w$")); + assert(r4_match_stats("1est", "\\d\\w\\w\\w$")); + assert(r4_match_stats("Aest", "\\D\\w\\w\\w$")); + assert(r4_match_stats("abc", "[ab]+")); + assert(!r4_match_stats("abc", "[ab]+$")); + assert(r4_match_stats("abc", "[abc]+$")); + assert(!r4_match_stats("a", "[^ba]")); + assert(!r4_match_stats("a", "[^ab]")); + assert(r4_match_stats(" ponyyzd", "p+o.*yyzd$$$$")); + assert(r4_match_stats("abc", "def|gek|abc")); + assert(!r4_match_stats("abc", "def|gek|abd")); + assert(r4_match_stats("abc", "def|abc|def")); + assert(r4_match_stats("suwv", "[abcdesfghijklmnopqrtuvw][abcdefghijklmnopqrstuvw][" + "abcdefghijklmnopqrstuvw][abcdefghijklmnopqrstuvw]")); + test_r4_next(); + r4_enable_debug(); + + assert(r4_match_stats("123", "(.*)(.*)(.*)")); + }); + + return 0; +} diff --git a/.backup.1.rstring.c b/.backup.1.rstring.c new file mode 100644 index 0000000..96404ca --- /dev/null +++ b/.backup.1.rstring.c @@ -0,0 +1,179 @@ + +#include "rstring.h" +#include "rtest.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +void rstring_test_whitespace() { + char *str = malloc(30); + str[0] = 0; + char *str2 = rcat(10, 10); + printf("Numbers: %s\n", str2); + char *str3 = "Cool"; + rcat(str, str3); + rcat(str, ' '); + rcat(str, 13.37); + printf("String: %s\n", str); + free(str); + + rtest_banner("rstrip_whitespace"); + char output[1024]; + // Test 1 + char *string1 = " Test 1"; + rstrip_whitespace(string1, output); + rassert(strlen(output) == 6); + + char *string2 = " Test 1"; + rstrip_whitespace(string2, output); + rassert(strlen(output) == 6); + + char *string3 = "Test 1"; + rstrip_whitespace(string3, output); + rassert(strlen(output) == 6); + + char *string4 = ""; + rstrip_whitespace(string4, output); + rassert(strlen(output) == 0); +} + +void rstring_test_rstrtokline() { + rtest_banner("rstrtokline"); + char lines[1024] = "Line 1\nLine 2\nLine 3\nLine 4\n333.29\n3.2221"; + char line[1024]; + size_t offset = 0; + // Test 1 + while ((offset = rstrtokline(lines, line, offset, true)) && *line) { + rassert(strlen(line) == 6); + } + // Test 2 + offset = 0; + int count = 0; + while ((offset = rstrtokline(lines, line, offset, false)) && *line) { + size_t expected_length = count < 5 ? 7 : 6; + count++; + rassert(strlen(line) == expected_length); + } + // Test 3 + offset = 0; + strcat(lines, "\n"); + count = 0; + while ((offset = rstrtokline(lines, line, offset, true)) && *line) { + count++; + size_t expected_length = 6; + rassert(strlen(line) == expected_length); + } +} + +void sort_test(char *text, char *text_sort_expected) { + char sorted_text[4096]; + rstrsort(text, sorted_text); + rassert(!strcmp(text_sort_expected, sorted_text)); +} + +void rstring_test_rstrsort() { + rtest_banner("Sorting string content"); + sort_test("Line 3\nLine 2\nLine 4\nLine 1\nQQ 333.29\n3.22\n1337.29\n3.22\n", + "Line 1\nLine 2\nLine 3\nLine 4\n3.22\n3.22\nQQ 333.29\n1337.29\n"); + sort_test("333.29\n3.22\n1337.29\n3.22\nLine 3\nThe original line 2\nLine " + "4\nLine 1\n", + "Line 1\nThe original line 2\nLine 3\nLine " + "4\n3.22\n3.22\n333.29\n1337.29\n"); +} + +void rstring_test_rformat_number() { + rtest_banner("Format number to human readable"); + rassert(!strcmp(rformat_number(100), "100")); + rassert(!strcmp(rformat_number(1001), "1.001")); + rassert(!strcmp(rformat_number(10001), "10.001")); + rassert(!strcmp(rformat_number(100001), "100.001")); + rassert(!strcmp(rformat_number(1000001), "1.000.001")); + rassert(!strcmp(rformat_number(1000000001), "1.000.000.001")); + rassert(!strcmp(rformat_number(1000000000001), "1.000.000.000.001")); + rassert(!strcmp(rformat_number(1000000000000001), "1.000.000.000.000.001")); + rassert(!strcmp(rformat_number(-1000000000000001), "-1.000.000.000.000.001")); +} + +void rstring_test_rstraddslashes() { + rtest_banner("Addslashes"); + char input[] = "\r\t\n\b\f test"; + char output[100]; + rstraddslashes(input, output); + rassert(!strcmp((char *)output, "\\r\\t\\n\\b\\f test")); +} + +void rstring_test_rstrstripslashes() { + rtest_banner("Stripslashes"); + char input[] = "\\r\\t\\n\\b\\f\" test"; + char output[100]; + rstrstripslashes(input, output); + rassert(!strcmp((char *)output, "\r\t\n\b\f\" test")); +} + +void rstring_test_rstrstartswith() { + rtest_banner("Starts with"); + rassert(rstrstartswith("abc", "abc")); + rassert(rstrstartswith("abc", "ab")); + rassert(rstrstartswith("abc", "a")); + rassert(rstrstartswith("", "")); + rassert(!rstrstartswith("abc", "abcdef")); + rassert(!rstrstartswith("abc", "b")); + rassert(!rstrstartswith("abc", "bc")); + rassert(!rstrstartswith("abc", "c")); +} + +void rstring_test_rstrendswith() { + rtest_banner("Ends with"); + rassert(rstrendswith("abc", "abc")); + rassert(rstrendswith("abc", "bc")); + rassert(rstrendswith("abc", "c")); + rassert(rstrendswith("", "")); + rassert(!rstrendswith("abc", "a")); + rassert(!rstrendswith("abc", "ab")); + rassert(!rstrendswith("abc", "abcdef")); +} + +void rstring_test_rstrmove() { + rtest_banner("Move str"); + // Test 1 + char to_move_1[] = "abc?"; + rstrmove(to_move_1, 3, 1, 0); + rassert(!strcmp(to_move_1, "?abc")); + // Test 2 + char to_move_2[] = "abc?defgabc"; + rstrmove(to_move_2, 3, 5, 0); + rassert(!strcmp(to_move_2, "?defgabcabc")); + // Test 3 + char to_move_3[] = "abc?defg"; + rstrmove(to_move_3, 0, 3, 7); + rassert(!strcmp(to_move_3, "?defgabc")); + + // Test 4 + char to_move_4[] = "abc?defgaa"; + rstrmove2(to_move_4, 3, 5, 0); + rassert(!strcmp(to_move_4, "?defgabcaa")); + + // Test 5 + char to_move_5[] = "?defgabcaa"; + rstrmove2(to_move_5, 0, 5, 3); + rassert(!strcmp(to_move_5, "abc?defgaa")); + + // Test 6 + char to_move_6[] = "?defgabcaa"; + rstrmove2(to_move_6, 0, 5, 6); + rassert(!strcmp(to_move_6, "abcaa?defg")); +} + +int main() { + rtest_banner("rstring"); + rstring_test_whitespace(); + rstring_test_rstrtokline(); + rstring_test_rstrsort(); + rstring_test_rformat_number(); + rstring_test_rstraddslashes(); + rstring_test_rstrstripslashes(); + rstring_test_rstrstartswith(); + rstring_test_rstrendswith(); + rstring_test_rstrmove(); + return rtest_end(""); +} diff --git a/.backup.1.rstring_list.c b/.backup.1.rstring_list.c new file mode 100644 index 0000000..c87526c --- /dev/null +++ b/.backup.1.rstring_list.c @@ -0,0 +1,27 @@ +#include "rstring_list.h" +#include "rtest.h" + +void test_rstring_list() { + rtest_banner("new"); + rstring_list_t *rsl = rstring_list_new(); + rassert(rsl->count == 0); + rassert(rsl->count == 0); + rtest_banner("add"); + rstring_list_add(rsl, "test1"); + rassert(rsl->count == 1); + rassert(rsl->count == 1); + rstring_list_add(rsl, "test2"); + rassert(rsl->count == 2); + rassert(rsl->count == 2); + rtest_banner("contains"); + rassert(rstring_list_contains(rsl, "test1")); + rassert(rstring_list_contains(rsl, "test2")); + rassert(!rstring_list_contains(rsl, "test3")); + rtest_banner("free"); + rstring_list_free(rsl); +} + +int main() { + test_rstring_list(); + return rtest_end(""); +} diff --git a/.backup.1.rtemp.c b/.backup.1.rtemp.c new file mode 100644 index 0000000..65dfd4d --- /dev/null +++ b/.backup.1.rtemp.c @@ -0,0 +1,38 @@ +#include "rtemp.h" +#include "rtest.h" +#include <string.h> + +char *classic(char *content) { + sstring(result, 1024); + strcpy(result, content); + result++; + return result; +} + +void rtemp_test_rtempc() { + rtest_banner("rtempc"); + char *res1 = sbuf("test1"); + char *res2 = sbuf("test2"); + char *res3 = sbuf("test3"); + char *res4 = sbuf("test4"); + char *res5 = sbuf("test5"); + rassert(!strcmp(res5, "test5")); + rassert(!strcmp(res4, "test4")); + rassert(!strcmp(res3, "test3")); + rassert(!strcmp(res2, "test2")); + rassert(!strcmp(res1, "test1")); + char line[1024] = {0}; + sprintf(line, "%s%s%s", rtempc("test1"), rtempc("test2"), rtempc("test3")); + rassert(!strcmp(line, "test1test2test3")); + line[0] = 0; + sprintf(line, "%s%s%s", classic("test1"), classic("test2"), classic("test3")); + rassert(strcmp(line, "test1test2test3")); +} + +int main() { + rtest_banner("rtemp"); + + rtemp_test_rtempc(); + + return rtest_end(""); +} diff --git a/.backup.1.rterm.c b/.backup.1.rterm.c new file mode 100644 index 0000000..f25c74b --- /dev/null +++ b/.backup.1.rterm.c @@ -0,0 +1,34 @@ +#include "rterm.h" + +void before_cursor_move(rterm_t *rterm) { + // printf("Before cursor update: %d:%d\n",rterm->cursor.x,rterm->cursor.y); +} +void after_cursor_move(rterm_t *rterm) { + + // rterm->cursor.x++; +} +void before_key_press(rterm_t *rterm) { + + // if(rterm->key.c == 65 && rterm->key.escape){ + // rterm->key.c = 66; + //} +} +void tick(rterm_t *rt) { + static char status_text[1024]; + status_text[0] = 0; + sprintf(status_text, "\rp:%d:%d | k:%c:%d | i:%ld ", rt->cursor.x + 1, rt->cursor.y + 1, rt->key.c == 0 ? '0' : rt->key.c, rt->key.c, + rt->iterations); + rt->status_text = status_text; +} + +int main() { + rterm_t rt; + rterm_init(&rt); + rt.show_cursor = true; + rt.before_key_press = before_key_press; + rt.before_cursor_move = before_cursor_move; + rt.after_cursor_move = after_cursor_move; + rt.tick = tick; + rterm_loop(&rt); + return 0; +} \ No newline at end of file diff --git a/.backup.1.rterminal.c b/.backup.1.rterminal.c new file mode 100644 index 0000000..baa1d3e --- /dev/null +++ b/.backup.1.rterminal.c @@ -0,0 +1,4 @@ +#include "rterminal.h" +#include "rtest.h" + +int main() { rlib_test_progressbar(); } \ No newline at end of file diff --git a/.backup.1.rtime.c b/.backup.1.rtime.c new file mode 100644 index 0000000..9ad9f0b --- /dev/null +++ b/.backup.1.rtime.c @@ -0,0 +1,19 @@ +#include "rtime.h" +#include "rtest.h" +#include <string.h> + +int main() { + rtest_banner("time"); + rtest_banner("Milliseconds tests"); + rtest_assert(!strcmp(msecs_str(0), "0Ms")); + rtest_assert(!strcmp(msecs_str(1), "1Ms")); + rtest_assert(!strcmp(msecs_str(12), "12Ms")); + rtest_assert(!strcmp(msecs_str(123), "123Ms")); + rtest_assert(!strcmp(msecs_str(999), "999Ms")); + rtest_banner("Second tests"); + rtest_assert(!strcmp(msecs_str(1000), "1s")); + rtest_assert(!strcmp(msecs_str(1100), "1.1s")); + rtest_assert(!strcmp(msecs_str(1234), "1.234s")); + rtest_assert(!strcmp(msecs_str(12345), "12.345s")); + return rtest_end("successs"); +} \ No newline at end of file diff --git a/.backup.1.rtree.c b/.backup.1.rtree.c new file mode 100644 index 0000000..ac91229 --- /dev/null +++ b/.backup.1.rtree.c @@ -0,0 +1,67 @@ +#include "rtree.h" +#include "rbench.h" +#include "rtest.h" +#include <string.h> + +typedef struct rtree_bench_data_t { + rtree_t *rtree; + char *value; +} rtree_bench_data_t; + +void rtree_bench_f() { + rtree_bench_data_t *bd = rbf->data; + if (rbf->first) { + static rtree_bench_data_t bds; + bds.rtree = rtree_new(); + bds.value = strdup(rgenerate_key()); + rbf->data = &bds; + bd = rbf->data; + } + char *key = rgenerate_key(); + rtree_set(bd->rtree, key, bd->value); + char *value = (char *)rtree_get(bd->rtree, key); + rassert(!strcmp(value, bd->value)); + if (rbf->last) { + free(bd->value); + rtree_free(bd->rtree); + } +} + +void rtree_bench(long item_count) { + rbench_t *b = rbench_new(); + b->stdout = false; + b->silent = true; + b->add_function(b, "random_key", "rtree_rw", rtree_bench_f); + b->execute(b, 1000000); + // rassert(rnsecs_to_msecs(b->execution_time) < 700); // faster than 700ms + printf("r/w %ld items and deallocated in %s\n", item_count, format_time(b->execution_time)); + rbench_free(b); +} + +int main() { + rtest_banner("rtree"); + rtree_t *rtree = rtree_new(); + // Test new object default valuess + rtest_banner("New object default values"); + rtest_assert(rtree->c == 0); + rtest_assert(rtree->next == NULL); + rtest_assert(rtree->children == NULL); + rtest_assert(rtree->data == NULL); + // Test set + rtest_banner("Set"); + rtree_set(rtree, "a", "data"); + rtest_assert(rtree->c == 'a'); + rtest_assert(!strcmp(rtree->data, "data")); + // Second element should be filled + rtree_set(rtree, "b", "data2"); + rtest_assert(rtree->next->c == 'b'); + rtest_assert(!strcmp(rtree->next->data, "data2")); + // First child of second element should be filled + rtree_set(rtree, "bc", "data3"); + rtest_assert(rtree->next->children->c == 'c'); + rtest_assert(!strcmp(rtree->next->children->data, "data3")); + rtree_free(rtree); + rtest_banner("Benchmark"); + rtree_bench(1000000); + return rtest_end(""); +} diff --git a/.backup.1.rtypes.c b/.backup.1.rtypes.c new file mode 100644 index 0000000..3e2ecf4 --- /dev/null +++ b/.backup.1.rtypes.c @@ -0,0 +1,14 @@ +#include "rtest.h" +#include "rtypes.h" + +int main() { + rtest_banner("rtypes"); + uint test1 = 1000; + rassert(test1 == 1000) ulong test2 = -1000; + rassert(test2 == -1000); + byte test3 = 123; + rassert(test3 == 123); + byte test4 = 'A'; + rassert(test4 == 65); + return rtest_end(""); +} diff --git a/.r_history b/.r_history new file mode 100644 index 0000000..11d1364 --- /dev/null +++ b/.r_history @@ -0,0 +1,8 @@ +load work directory +investigage project +investigage project +investiate +investiate +create commit message +yes +yes diff --git a/_rlib.h b/_rlib.h index 7dec69c..922b16c 100644 --- a/_rlib.h +++ b/_rlib.h @@ -1,13 +1,20 @@ +// Written by retoor@molodetz.nl + +// This source code includes and uses multiple modules and libraries to provide comprehensive networking, +// memory management, mathematical functions, and additional functionalities for developing a variety of applications. + +// Includes not part of the core language: "license.h", "rtypes.h", "nsock.h", "rmalloc.h", "uuid.h", +// "rnet.h", "rargs.h", "rcat.h", "rliza.h", "rcov.h", "rtemp.h", "rhttp.h", "rjson.h", "rstring_list.h", +// "rautocomplete.h", "rrex4.h", "rprint.h", "rmath.h", "rtest.h", "rkeytable.h", "rhashtable.h", +// "rrex3.h", "rtime.h", "arena.h", "rio.h", "rstring.h", "rcase.h", "rterminal.h", "rterm.h", +// "rtree.h", "rlexer.h", "rbench.h", "main.h" + +// MIT License + #include "license.h" #ifndef RLIB_H #define RLIB_H -// BEGIN OF RLIB -/* - * Line below will be filtered by rmerge -<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after -tag" /> -*/ #include "rtypes.h" #include "nsock.h" #include "rmalloc.h" @@ -41,5 +48,5 @@ tag" /> #include "rlexer.h" #include "rbench.h" #include "main.h" -// END OF RLIB -#endif + +#endif \ No newline at end of file diff --git a/arena.h b/arena.h index 64bec59..622e332 100644 --- a/arena.h +++ b/arena.h @@ -1,3 +1,13 @@ +// Written by retoor@molodetz.nl + +// This code provides a simple memory arena implementation, which allows dynamic memory allocation within a predefined size. It includes +// functions for constructing a new arena, allocating memory within the arena, resetting, and freeing the arena. + +// The code utilizes rmalloc and rfree for custom memory allocation, which are likely part of another library not defined within the +// standard C library. + +// MIT License + #ifndef RARENA_H #define RARENA_H @@ -36,7 +46,6 @@ void *arena_alloc(arena_t *arena, size_t size) { } void arena_free(arena_t *arena) { - // Just constructed and unused arena memory is NULL so no free needed if (arena->memory) { rfree(arena->memory); } @@ -44,4 +53,5 @@ void arena_free(arena_t *arena) { } void arena_reset(arena_t *arena) { arena->pointer = 0; } + #endif \ No newline at end of file diff --git a/license.h b/license.h index 40a1554..8e9185c 100644 --- a/license.h +++ b/license.h @@ -1,18 +1,24 @@ +// Written by retoor@molodetz.nl + +// This source code provides the implementation and licensing information for software available under the MIT License. + +// No external libraries or frameworks are used in this source code. + // 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 diff --git a/main.h b/main.h index 40d1545..6b88fe6 100644 --- a/main.h +++ b/main.h @@ -1,3 +1,15 @@ +Written by retoor@molodetz.nl + +This code provides an entry point for a library with command-line utilities. It forwards arguments to the corresponding tool based on the user's input. + +Includes used: +- rhttp.h: Provides functionality for an HTTP file server. +- rmerge.h: Includes a tool for merging C source files. +- rcov.h: Implements a code coverage tool based on lcov. +- rcase.h: Contains a utility to convert file naming conventions between camel case and snake case. + +MIT License + #ifndef RLIB_MAIN #define RLIB_MAIN #include "rhttp.h" @@ -10,19 +22,17 @@ void forward_argument(int *argcc, char *argv[]) { for (int i = 0; i < argc; i++) { argv[i] = argv[i + 1]; } - argc--; - *argcc = argc; + (*argcc)--; } int rlib_main(int argc, char *argv[]) { - if (argc == 1) { printf("rlib\n\n"); printf("options:\n"); - printf(" httpd - a http file server. Accepts port as argument.\n"); - printf(" rmerge - a merge tool. Converts c source files to one file \n" + printf(" httpd - a HTTP file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts C source files to one file \n" " with local includes by giving main file as argument.\n"); - printf(" rcov - coverage tool theat cleans up after himself. Based on " + printf(" rcov - coverage tool that cleans up after itself. Based on " "lcov.\n"); printf(" rcase - tool to swap input file automatically between" " camel case and snake case.\n"); @@ -32,7 +42,6 @@ int rlib_main(int argc, char *argv[]) { forward_argument(&argc, argv); if (!strcmp(argv[0], "httpd")) { - return rhttp_main(argc, argv); } if (!strcmp(argv[0], "rmerge")) { @@ -48,4 +57,4 @@ int rlib_main(int argc, char *argv[]) { return 0; } -#endif +#endif \ No newline at end of file diff --git a/nsock.h b/nsock.h index 55cc84f..b97f7ba 100644 --- a/nsock.h +++ b/nsock.h @@ -1,3 +1,31 @@ +// Written by retoor@molodetz.nl + +// The code is an implementation for managing network sockets. It provides functionality to create, connect, and manage a server or client +// sockets, handle multiple connections, read and write data, and handle events such as connecting, receiving data, and closing a +// connection. + +// External import summary: +// This code uses external libraries such as rmalloc.h and rio.h for memory allocation and I/O operations. + +// MIT License: +// 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 NSOCK_H #define NSOCK_H #include <unistd.h> @@ -47,8 +75,8 @@ nsock_t *nsock_get(int fd) { if (fd >= nsocks_count || nsocks[fd] == NULL) { if (fd >= nsocks_count) { nsocks_count = fd + 1; - nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); - nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + nsocks = realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * nsocks_count); + nsocks[fd] = calloc(1, sizeof(nsock_t)); } nsocks[fd]->upstreams = NULL; nsocks[fd]->fd = fd; @@ -97,12 +125,12 @@ int *nsock_init(int socket_count) { if (nsock_socks) { return nsock_socks; } - nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + nsock_socks = calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); if (nsock_data) { free(nsock_data); nsock_data = NULL; } - nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_data = malloc(sizeof(void **) * socket_count + 1); nsock_socks[socket_count] = -1; return nsock_socks; } @@ -127,13 +155,14 @@ void nsock_add_upstream(int source, int target, bool downstream) { nsock_t *sock = nsock_get(source); nsock_t *sock_target = nsock_get(target); sock_target->type = NSOCK_UPSTREAM; - sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->upstreams = realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); sock->downstream = downstream; sock->upstreams[sock->upstream_count] = target; sock->upstream_count++; } void *nsock_get_data(int socket) { return nsock_data[socket]; } + void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } int nsock_connect(const char *host, unsigned int port) { @@ -223,7 +252,6 @@ int *nsock_select(suseconds_t timeout) { for (int i = 0; socks[i] != -1; i++) { if (i == server_fd) continue; - ; if (!socks[i]) continue; if (socks[i] > nsock_max_socket_fd) { @@ -259,7 +287,7 @@ int *nsock_select(suseconds_t timeout) { if (nsock_readable) { free(nsock_readable); } - nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable = calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); nsock_readable[nsock_max_socket_fd + 1] = -1; nsock_readable[0] = 0; int readable_count = 0; @@ -286,7 +314,7 @@ int *nsock_select(suseconds_t timeout) { unsigned char *nsock_read(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = read(fd, buffer, length); if (bytes_read <= 0) { nsock_close(fd); @@ -299,7 +327,7 @@ unsigned char *nsock_read(int fd, int length) { unsigned char *nsock_read_all(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = 0; while (bytes_read < length) { int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); @@ -347,7 +375,7 @@ int nsock_execute_upstream(int source, size_t buffer_size) { nsock_close(sock->upstreams[i]); continue; } - if (sock->downstream && downstreamed == false) { + if (sock->downstream && !downstreamed) { downstreamed = true; unsigned char data[4096]; memset(data, 0, 4096); @@ -417,4 +445,4 @@ void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void ( } } } -#endif +#endif \ No newline at end of file diff --git a/rargs.h b/rargs.h index 3050042..1407459 100644 --- a/rargs.h +++ b/rargs.h @@ -1,14 +1,23 @@ -#include <stdio.h> +// Written by retoor@molodetz.nl + +// This source code implements a simple argument parsing utility for C programs, +// facilitating the checking or retrieval of command line argument values. + +// This file uses the standard C libraries: <stdio.h>, <string.h>, <stdlib.h>, <stdbool.h> + +// MIT License + #ifndef RLIB_RARGS_H #define RLIB_RARGS_H + +#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> bool rargs_isset(int argc, char *argv[], char *key) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { return true; } } @@ -16,9 +25,8 @@ bool rargs_isset(int argc, char *argv[], char *key) { } char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return argv[i + 1]; } @@ -28,9 +36,8 @@ char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def } int rargs_get_option_int(int argc, char *argv[], char *key, int def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return atoi(argv[i + 1]); } @@ -40,19 +47,17 @@ int rargs_get_option_int(int argc, char *argv[], char *key, int def) { } bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { - if (!strcmp(argv[i + 1], "false")) - return false; - if (!strcmp(argv[i + 1], "0")) + if (strcmp(argv[i + 1], "false") == 0 || strcmp(argv[i + 1], "0") == 0) { return false; + } return true; } } } - return def; } + #endif \ No newline at end of file diff --git a/rautocomplete.h b/rautocomplete.h index 0579e71..b175e3d 100644 --- a/rautocomplete.h +++ b/rautocomplete.h @@ -1,6 +1,33 @@ +// Written by retoor@molodetz.nl + +// This source code provides a simple autocomplete functionality by leveraging string list management and pattern matching with escaping +// characters where necessary. + +// No external imports or includes other than basic string operations and standard library functions are used in the source code. + +// MIT License +// +// 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 RAUTOCOMPLETE_H #define RAUTOCOMPLETE_H -#define R4_DEBUG + #include "rrex4.h" #include "rstring_list.h" #define rautocomplete_new rstring_list_new @@ -12,7 +39,7 @@ char *r4_escape(char *content) { size_t size = strlen(content) * 2 + 1; - char *escaped = (char *)calloc(size, sizeof(char)); + char *escaped = calloc(size, sizeof(char)); char *espr = escaped; char *to_escape = "?*+()[]{}^$\\"; *espr = '('; @@ -37,22 +64,19 @@ char *r4_escape(char *content) { } char *rautocomplete_find(rstring_list_t *list, char *expr) { - if (!list->count) - return NULL; - if (!expr || !strlen(expr)) + if (!list->count || !expr || !strlen(expr)) return NULL; char *escaped = r4_escape(expr); - for (unsigned int i = list->count - 1; i == 0; i--) { - char *match; + for (unsigned int i = list->count - 1; i >= 0; i--) { + char *match = NULL; r4_t *r = r4(list->strings[i], escaped); if (r->valid && r->match_count == 1) { match = strdup(r->matches[0]); } r4_free(r); if (match) { - free(escaped); return match; } @@ -60,4 +84,5 @@ char *rautocomplete_find(rstring_list_t *list, char *expr) { free(escaped); return NULL; } + #endif \ No newline at end of file diff --git a/rbench.h b/rbench.h index ea6a2d6..04b018a 100644 --- a/rbench.h +++ b/rbench.h @@ -1,3 +1,26 @@ +/* Written by retoor@molodetz.nl */ + +/* This source code defines a benchmarking utility for measuring the execution time of functions in C. It provides functionalities for + * adding, resetting, and executing functions multiple times while tracking their execution time. The code also includes progress tracking + * and functions for executing with varying numbers of arguments. */ + +/* Dependencies not part of the language itself: + - These likely include custom headers such as "rprint.h", "rtime.h", "rstring.h", and "rterminal.h" +*/ + +/* +MIT License + +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 RBENCH_H #define RBENCH_H @@ -11,7 +34,6 @@ #include <string.h> #include <sys/time.h> #include <time.h> - #include "rstring.h" #include "rterminal.h" @@ -43,7 +65,6 @@ if (percentage_changed) { \ printf("\r%d%%", percentage); \ fflush(stdout); \ - \ prev_percentage = percentage; \ } \ } \ @@ -67,7 +88,6 @@ typedef struct rbench_function_t { bool last; int argc; unsigned long times_executed; - nsecs_t average_execution_time; nsecs_t total_execution_time; } rbench_function_t; @@ -93,7 +113,6 @@ typedef struct rbench_t { 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; @@ -101,23 +120,18 @@ FILE *_rbench_stdnull = NULL; void rbench_toggle_stdout(rbench_t *r) { if (!r->stdout) { - if (_rbench_stdout == NULL) { + if (!_rbench_stdout) { _rbench_stdout = stdout; } - if (_rbench_stdnull == NULL) { + if (!_rbench_stdnull) { _rbench_stdnull = fopen("/dev/null", "wb"); } - if (stdout == _rbench_stdout) { - stdout = _rbench_stdnull; - } else { - stdout = _rbench_stdout; - } + stdout = (stdout == _rbench_stdout) ? _rbench_stdnull : _rbench_stdout; } } + void rbench_restore_stdout(rbench_t *r) { - if (r->stdout) - return; - if (_rbench_stdout) { + if (!r->stdout && _rbench_stdout) { stdout = _rbench_stdout; } if (_rbench_stdnull) { @@ -130,8 +144,9 @@ rbench_t *rbench_new(); rbench_t *_rbench = NULL; rbench_function_t *rbf; + rbench_t *rbench() { - if (_rbench == NULL) { + if (!_rbench) { _rbench = rbench_new(); } return _rbench; @@ -147,8 +162,7 @@ void rbench_add_function(rbench_t *rp, const char *name, const char *group, void #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++; + rbench_function_t *f = &rp->functions[rp->function_count++]; f->average_execution_time = 0; f->total_execution_time = 0; f->times_executed = 0; @@ -164,47 +178,42 @@ void rbench_reset_function(rbench_function_t *f) { } void rbench_reset(rbench_t *rp) { - for (unsigned int i = 0; i < rp->function_count; i++) { + for (unsigned int i = 0; i < rp->function_count; ++i) { rbench_reset_function(&rp->functions[i]); } } + 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) { + for (unsigned int i = 0; i < r->function_count; ++i) { + if (!time || 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; -} + +bool rbench_was_last_function(rbench_t *r) { return r->current == &r->functions[r->function_count - 1]; } rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, int argc) { rbench_toggle_stdout(r); - if (findex == 0) { + if (!findex) { r->execution_time = 0; } rbench_function_t *rf = &r->functions[findex]; rf->argc = argc; rbf = rf; r->current = rf; - if (r->show_progress) + 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); if (r->progress_bar) { @@ -212,42 +221,35 @@ void rbench_execute_finish(rbench_t *r) { 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) + if (!r->silent) { rprintgf(stderr, "Benchmark results:\n"); + } nsecs_t total_time = 0; - - for (unsigned int i = 0; i < r->function_count; i++) { + 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 (is_winner && !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) + if (!r->silent) { rprintgf(stderr, "Total execution time: %s\n", format_time(total_time)); + } } rbench_restore_stdout(r); rbf = NULL; r->current = NULL; } + struct rbench_t *rbench_execute(rbench_t *r, long times) { - - for (unsigned int i = 0; i < r->function_count; i++) { - + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); rbench_call c = (rbench_call)f->call; nsecs_t start = nsecs(); @@ -256,7 +258,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -272,8 +274,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { } struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -282,7 +283,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -298,8 +299,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { } struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -308,7 +308,7 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -324,10 +324,8 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 } struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { - - for (unsigned int i = 0; i < r->function_count; i++) { + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); - rbench_call3 c = (rbench_call3)f->call; nsecs_t start = nsecs(); f->first = true; @@ -335,7 +333,7 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2, arg3); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -350,7 +348,6 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 } 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; @@ -365,6 +362,7 @@ rbench_t *rbench_new() { r->show_progress = true; return r; } + void rbench_free(rbench_t *r) { free(r); } #endif \ No newline at end of file diff --git a/rbuffer.h b/rbuffer.h index decdd9c..119b248 100644 --- a/rbuffer.h +++ b/rbuffer.h @@ -1,3 +1,32 @@ +// Written by retoor@molodetz.nl + +// A ring buffer implementation in C that provides functionalities such as +// creating a new buffer, freeing, resetting, writing data, pushing data, +// popping data, matching options and more. It efficiently manages dynamic +// memory to handle data of varying sizes and applies basic buffer manipulation techniques. + +// This code includes the utility "rmalloc.h". It is assumed that this file +// contains custom memory management functions which are not specified here. + +// MIT License +// 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 RBUFFER_H #define RBUFFER_H #include "rmalloc.h" @@ -6,6 +35,7 @@ #include <string.h> #include <stdbool.h> #include <assert.h> + typedef struct rbuffer_t { unsigned char *data; unsigned char *_data; @@ -18,7 +48,7 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size); void rbuffer_free(rbuffer_t *rfb); void rbuffer_reset(rbuffer_t *rfb); void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); -size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data); unsigned char rbuffer_pop(rbuffer_t *rfb); unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); @@ -55,42 +85,42 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { rfb->data = rfb->_data; return rfb; } + void rbuffer_free(rbuffer_t *rfb) { - if (rfb->_data) + if (rfb->_data) { free(rfb->_data); + } free(rfb); } -size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data) { if (rfb->pos < rfb->size) { - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; return 1; } rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; rfb->size++; return rfb->pos; } + void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { - unsigned char *data_ptr = (unsigned char *)data; for (size_t i = 0; i < size; i++) { - rbuffer_push(rfb, data_ptr[i]); + rbuffer_push(rfb, data[i]); } } unsigned char rbuffer_peek(rbuffer_t *rfb) { - unsigned char result = EOF; if (rfb->pos != rfb->size) { - result = rfb->_data[rfb->pos]; - return result; + return rfb->_data[rfb->pos]; } rfb->eof = true; return EOF; } + unsigned char rbuffer_pop(rbuffer_t *rfb) { - unsigned char result = EOF; - if (rfb->pos <= rfb->size) { - result = rfb->_data[rfb->pos]; + if (rfb->pos < rfb->size) { + unsigned char result = rfb->_data[rfb->pos]; rfb->pos++; rfb->data++; if (rfb->pos == rfb->size) { @@ -99,23 +129,19 @@ unsigned char rbuffer_pop(rbuffer_t *rfb) { return result; } rfb->eof = true; - return result; + return EOF; } + void rbuffer_reset(rbuffer_t *rfb) { rfb->data = rfb->_data; rfb->pos = 0; } unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { - return strncmp((char *)s1, (char *)s2, n); - while (n && *s1 == *s2) { - n--; - s1++; - s2++; - } - return *s1 != *s2; + return strncmp((const char *)s1, (const char *)s2, n); } -size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +size_t ustrlen(const unsigned char *s) { return strlen((const char *)s); } unsigned char *rbuffer_to_string(rbuffer_t *rfb) { unsigned char *result = rfb->_data; @@ -131,7 +157,6 @@ unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { strcpy(options_cpy, options); char *memory = options_cpy; while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { - size_t option_length = strlen(option); if (option_length > rfb->size - rfb->pos) { continue; @@ -164,6 +189,7 @@ unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { } return NULL; } + unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { unsigned char *result = NULL; if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { @@ -171,4 +197,5 @@ unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { } return result; } + #endif \ No newline at end of file diff --git a/rcase.h b/rcase.h index 4c32f3c..c7c37a7 100644 --- a/rcase.h +++ b/rcase.h @@ -1,5 +1,15 @@ +// Written by retoor@molodetz.nl + +// This code provides functions to determine and convert between snake_case and camelCase strings. It reads from files and processes string +// formats, outputting converted formats. + +// The source code includes custom headers: "rio.h", "rmalloc.h", "rprint.h", "rstring.h". + +// MIT License + #ifndef RCASE_H #define RCASE_H + #include "rio.h" #include "rmalloc.h" #include "rprint.h" @@ -13,47 +23,42 @@ #define RCAMEL_CASE 1 #define RSNAKE_CASE 2 #define RINVALID_CASE 0 -#define RCONST_TEST_T 4; +#define RCONST_TEST_T 4 int rdetermine_case(const char *str) { + char previousChar = 0; int length = strlen(str); - char p = 0; while (*str) { - if (p == '_' && islower(*str)) + if (previousChar == '_' && islower(*str)) return RSNAKE_CASE; - if (p != '_' && !isupper(p) && isupper(*str)) + if (previousChar != '_' && !isupper(previousChar) && isupper(*str)) return RCAMEL_CASE; - p = *str; + previousChar = *str; str++; } - return RINVALID_CASE; - if (length == 0) { + if (length == 0) return RINVALID_CASE; - } + if (strchr(str, '_')) { - if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) return RINVALID_CASE; - } + for (int i = 0; i < length; i++) { - if (!islower(str[i]) && str[i] != '_') { + if (!islower(str[i]) && str[i] != '_') return RINVALID_CASE; - } } return RSNAKE_CASE; } else { - - if (!islower(str[0])) { + if (!islower(str[0])) return RINVALID_CASE; - } + for (int i = 1; i < length; i++) { - if (str[i] == '_') { + if (str[i] == '_') return RINVALID_CASE; - } - if (isupper(str[i]) && isupper(str[i - 1])) { + if (isupper(str[i]) && isupper(str[i - 1])) return RINVALID_CASE; - } } return RCAMEL_CASE; } @@ -66,37 +71,24 @@ char *rsnake_to_camel(const char *snake_case) { int toUpper = 0; for (int i = 0; i < length; i++) { - if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { - toUpper = 1; - if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - - toUpper = 0; + if (snake_case[i] == '_') { + if (snake_case[i + 1] == 'T' || (snake_case[i + 1] == 't' && !isspace(snake_case[i + 2]))) { + toUpper = 1; } + continue; } - if (snake_case[i] == '_' && snake_case[i + 1] != 't') { - toUpper = 1; - if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - toUpper = 0; - } - } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { - toUpper = 1; - } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { - toUpper = 1; - camel_case[j++] = '_'; - j++; + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; } else { - if (toUpper) { - camel_case[j++] = toupper(snake_case[i]); - toUpper = 0; - } else { - camel_case[j++] = snake_case[i]; - } + camel_case[j++] = snake_case[i]; } } camel_case[j] = '\0'; return camel_case; } + char *rcamel_to_snake(const char *camelCase) { int length = strlen(camelCase); char *snake_case = (char *)malloc(2 * length + 1); @@ -104,9 +96,8 @@ char *rcamel_to_snake(const char *camelCase) { for (int i = 0; i < length; i++) { if (isupper(camelCase[i])) { - if (i != 0) { + if (i != 0) snake_case[j++] = '_'; - } snake_case[j++] = tolower(camelCase[i]); } else { snake_case[j++] = camelCase[i]; @@ -118,11 +109,12 @@ char *rcamel_to_snake(const char *camelCase) { } char *rflip_case(char *content) { - if (rdetermine_case(content) == RSNAKE_CASE) { + switch (rdetermine_case(content)) { + case RSNAKE_CASE: return rcamel_to_snake(content); - } else if (rdetermine_case(content) == RCAMEL_CASE) { + case RCAMEL_CASE: return rsnake_to_camel(content); - } else { + default: rprintr("Could not determine case\n"); return NULL; } @@ -130,20 +122,17 @@ char *rflip_case(char *content) { char *rflip_case_file(char *filepath) { size_t file_size = rfile_size(filepath); - if (file_size == 0) { + if (file_size == 0) return NULL; - } + char *content = (char *)malloc(file_size); char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { result = rflip_case(content); - if (result) { - free(content); - return result; - } else { - return content; - } + free(content); } + return result; } @@ -152,6 +141,7 @@ int rcase_main(int argc, char *argv[]) { printf("usage: rcase <file>\n"); return 1; } + for (int i = 1; i < argc; i++) { char *result = rflip_case_file(argv[i]); if (result) { @@ -161,4 +151,5 @@ int rcase_main(int argc, char *argv[]) { } return 0; } -#endif + +#endif \ No newline at end of file diff --git a/rcat.h b/rcat.h index ce780f0..117d1e0 100644 --- a/rcat.h +++ b/rcat.h @@ -1,5 +1,15 @@ +// Written by retoor@molodetz.nl + +// This code provides a simple implementation of a reverse cat (rcat) function, which attempts to read a file in binary mode and outputs its +// contents to the standard output. + +// No external libraries apart from the standard C library are used here. + +// MIT License + #ifndef RCAT_H #define RCAT_H + #include <stdio.h> #include <stdlib.h> @@ -10,7 +20,7 @@ void rcat(char *filename) { return; } unsigned char c; - while ((c = fgetc(f)) && !feof(f)) { + while ((c = fgetc(f)) != EOF) { printf("%c", c); } fclose(f); @@ -26,4 +36,4 @@ int rcat_main(int argc, char *argv[]) { return 0; } -#endif +#endif \ No newline at end of file diff --git a/rcov.h b/rcov.h index 42779bc..c93d1ab 100644 --- a/rcov.h +++ b/rcov.h @@ -1,5 +1,16 @@ +// Written by retoor@molodetz.nl + +// This code provides a console utility for performing code coverage analysis on a specified C source file using lcov and genhtml. It checks +// for lcov installation, compiles the source file with coverage options, runs it, and generates an HTML report. + +// The code uses lcov and genhtml for coverage analysis and viewing, google-chrome for displaying the HTML report, and it requires gcc for +// compilation. + +// MIT License + #ifndef RCOV_H #define RCOV_H + #include "rtypes.h" #include "rtemp.h" #include <unistd.h> @@ -7,10 +18,10 @@ #include <stdio.h> #include <string.h> #include "rbench.h" + bool check_lcov() { char buffer[1024 * 64]; - FILE *fp; - fp = popen("lcov --help", "r"); + FILE *fp = popen("lcov --help", "r"); if (fp == NULL) { return false; } @@ -32,7 +43,6 @@ int rcov_main(int argc, char *argv[]) { strcat(argstr, " "); } if (!check_lcov()) { - printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); return 1; } @@ -46,22 +56,19 @@ int rcov_main(int argc, char *argv[]) { "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", "rm -f *.gcda 2>/dev/null", "rm -f *.gcno 2>/dev/null", - "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", - + "rm -f %s.coverage.info 2>/dev/null", "gprof %s_coverage.o gmon.out > output.rcov_analysis", - "rm -f gmon.out", "cat output.rcov_analysis", "rm output.rcov_analysis", "rm -f %s_coverage.o", - "google-chrome /tmp/%s.coverage/index.html"}; uint command_count = sizeof(commands) / sizeof(commands[0]); - RBENCH(1,{ + RBENCH(1, { for (uint i = 0; i < command_count; i++) { char *formatted_command = sbuf(""); sprintf(formatted_command, commands[i], source_file, source_file); - // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { strcat(formatted_command, " "); strcat(formatted_command, argstr); @@ -70,8 +77,9 @@ int rcov_main(int argc, char *argv[]) { if (system(formatted_command)) { printf("`%s` returned non-zero code.\n", formatted_command); } - }); - } + } + }); return 0; } -#endif + +#endif \ No newline at end of file diff --git a/remo.h b/remo.h index 7219f11..0417f6c 100644 --- a/remo.h +++ b/remo.h @@ -1,3 +1,13 @@ +// Written by retoor@molodetz.nl + +// This header file defines a structure `remo_t` used to store emoji representations and their descriptions. It includes functions to +// convert strings to lowercase, search for substrings case insensitively, print all emojis with their descriptions, and retrieve an emoji +// by its description. + +// No third-party imports or includes are used outside the language's standard library. + +// MIT License + #ifndef REMO_H #define REMO_H #include <stdio.h> @@ -10,206 +20,169 @@ typedef struct { const char *description; } remo_t; -remo_t remo[] = { - {"\U0001F600", "Grinning Face"}, // 😀 - {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 - {"\U0001F602", "Face with Tears of Joy"}, // 😂 - {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 - {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 - {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 - {"\U0001F609", "Winking Face"}, // 😉 - {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 - {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 - {"\U0001F618", "Face Blowing a Kiss"}, // 😘 - {"\U0001F617", "Kissing Face"}, // 😗 - {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 - {"\U0001F642", "Slightly Smiling Face"}, // 🙂 - {"\U0001F643", "Upside-Down Face"}, // 🙃 - {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 - {"\U0001F60B", "Face Savoring Food"}, // 😋 - {"\U0001F61B", "Face with Tongue"}, // 😛 - {"\U0001F61C", "Winking Face with Tongue"}, // 😜 - {"\U0001F92A", "Zany Face"}, // 🤪 - {"\U0001F929", "Star-Struck"}, // 🤩 - {"\U0001F631", "Face Screaming in Fear"}, // 😱 - {"\U0001F62D", "Loudly Crying Face"}, // 😭 - {"\U0001F624", "Face with Steam From Nose"}, // 😤 - {"\U0001F620", "Angry Face"}, // 😠 - {"\U0001F621", "Pouting Face"}, // 😡 - {"\U0001F47B", "Ghost"}, // 👻 - {"\U0001F480", "Skull"}, // 💀 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - {"\U0001F47D", "Alien"}, // 👽 - // Geometric Shapes - {"\U000025A0", "Black Square"}, // ■ - {"\U000025B2", "Upward Triangle"}, // ▲ - {"\U000025CF", "Black Circle"}, // ● - {"\U000025CB", "White Circle"}, // ○ - {"\U00002B1B", "Large Black Square"}, // ⬛ - {"\U00002B1C", "Large White Square"}, // ⬜ - - // Mathematical Symbols - {"\U00002200", "For All"}, // ∀ - {"\U00002203", "Exists"}, // ∃ - {"\U00002205", "Empty Set"}, // ∅ - {"\U00002207", "Nabla"}, // ∇ - {"\U0000220F", "N-Ary Product"}, // ∏ - {"\U00002212", "Minus Sign"}, // − - {"\U0000221E", "Infinity"}, // ∞ - - // Arrows - {"\U00002190", "Left Arrow"}, // ← - {"\U00002191", "Up Arrow"}, // ↑ - {"\U00002192", "Right Arrow"}, // → - {"\U00002193", "Down Arrow"}, // ↓ - {"\U00002195", "Up Down Arrow"}, // ↕ - {"\U00002197", "Up Right Arrow"}, // ↗ - {"\U00002198", "Down Right Arrow"}, // ↘ - {"\U000027A1", "Black Right Arrow"}, // ➡️ - - // Dingbats - {"\U00002714", "Check Mark"}, // ✔️ - {"\U00002716", "Heavy Multiplication X"}, // ✖️ - {"\U00002728", "Sparkles"}, // ✨ - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002795", "Heavy Plus Sign"}, // ➕ - - // Miscellaneous Symbols - {"\U00002600", "Sun"}, // ☀️ - {"\U00002614", "Umbrella with Rain Drops"}, // ☔ - {"\U00002620", "Skull and Crossbones"}, // ☠️ - {"\U000026A0", "Warning Sign"}, // ⚠️ - {"\U000026BD", "Soccer Ball"}, // ⚽ - {"\U000026C4", "Snowman"}, // ⛄ - - // Stars and Asterisks - {"\U00002733", "Eight Pointed Black Star"}, // ✳️ - {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U00002728", "Sparkles"}, // ✨ - // Animals and Nature - {"\U0001F98A", "Fox"}, // 🦊 - {"\U0001F415", "Dog"}, // 🐕 - {"\U0001F431", "Cat Face"}, // 🐱 - {"\U0001F435", "Monkey Face"}, // 🐵 - {"\U0001F408", "Black Cat"}, // 🐈 - {"\U0001F98C", "Deer"}, // 🦌 - {"\U0001F344", "Mushroom"}, // 🍄 - {"\U0001F333", "Tree"}, // 🌳 - - // Weather and Space Symbols - {"\U0001F308", "Rainbow"}, // 🌈 - {"\U0001F320", "Shooting Star"}, // 🌠 - {"\U00002600", "Sun"}, // ☀️ - {"\U00002601", "Cloud"}, // ☁️ - {"\U000026A1", "High Voltage"}, // ⚡ - {"\U0001F525", "Fire"}, // 🔥 - {"\U000026C4", "Snowman"}, // ⛄ - {"\U0001F30A", "Water Wave"}, // 🌊 - - // Transport and Map Symbols - {"\U0001F68C", "Bus"}, // 🚌 - {"\U0001F697", "Car"}, // 🚗 - {"\U0001F6B2", "Bicycle"}, // 🚲 - {"\U0001F6A2", "Ship"}, // 🚢 - {"\U0001F681", "Helicopter"}, // 🚁 - {"\U0001F680", "Rocket"}, // 🚀 - {"\U0001F6EB", "Airplane"}, // 🛫 - - // Currency Symbols - {"\U00000024", "Dollar Sign"}, // $ - {"\U000000A3", "Pound Sign"}, // £ - {"\U000000A5", "Yen Sign"}, // ¥ - {"\U000020AC", "Euro Sign"}, // € - {"\U0001F4B5", "Dollar Banknote"}, // 💵 - {"\U0001F4B4", "Yen Banknote"}, // 💴 - - // Card Suits - {"\U00002660", "Black Spade Suit"}, // ♠️ - {"\U00002663", "Black Club Suit"}, // ♣️ - {"\U00002665", "Black Heart Suit"}, // ♥️ - {"\U00002666", "Black Diamond Suit"}, // ♦️ - {"\U0001F0CF", "Joker Card"}, // 🃏 - - // Office Supplies and Objects - {"\U0001F4DA", "Books"}, // 📚 - {"\U0001F4D7", "Green Book"}, // 📗 - {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 - {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 - {"\U0001F4B0", "Money Bag"}, // 💰 - {"\U0001F4B8", "Money with Wings"}, // 💸 - {"\U0001F4E6", "Package"}, // 📦 - - // Miscellaneous Symbols - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U00002714", "Check Mark"}, // ✔️ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002705", "Check Mark Button"}, // ✅ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U0001F4A1", "Light Bulb"}, // 💡 - {"\U0001F4A3", "Bomb"}, // 💣 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - // Musical Symbols - {"\U0001F3B5", "Musical Note"}, // 🎵 - {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 - {"\U0001F3BC", "Musical Score"}, // 🎼 - {"\U0001F399", "Studio Microphone"}, // 🎙️ - {"\U0001F3A4", "Microphone"}, // 🎤 - - // Food and Drink - {"\U0001F35F", "Cheese Wedge"}, // 🧀 - {"\U0001F355", "Slice of Pizza"}, // 🍕 - {"\U0001F32D", "Taco"}, // 🌮 - {"\U0001F37D", "Beer Mug"}, // 🍻 - {"\U0001F96B", "Cup with Straw"}, // 🥤 - {"\U0001F32E", "Hot Pepper"}, // 🌶️ - {"\U0001F95A", "Potato"}, // 🥔 - - // Zodiac Signs - {"\U00002600", "Aries"}, // ♈ - {"\U00002601", "Taurus"}, // ♉ - {"\U00002602", "Gemini"}, // ♊ - {"\U00002603", "Cancer"}, // ♋ - {"\U00002604", "Leo"}, // ♌ - {"\U00002605", "Virgo"}, // ♍ - {"\U00002606", "Libra"}, // ♎ - {"\U00002607", "Scorpio"}, // ♏ - {"\U00002608", "Sagittarius"}, // ♐ - {"\U00002609", "Capricorn"}, // ♑ - {"\U0000260A", "Aquarius"}, // ♒ - {"\U0000260B", "Pisces"}, // ♓ - - // Miscellaneous Shapes - {"\U0001F4C8", "Chart Increasing"}, // 📈 - {"\U0001F4C9", "Chart Decreasing"}, // 📉 - {"\U0001F4CA", "Bar Chart"}, // 📊 - {"\U0001F7E6", "Orange Circle"}, // 🟠 - {"\U0001F7E7", "Yellow Circle"}, // 🟡 - {"\U0001F7E8", "Green Circle"}, // 🟢 - {"\U0001F7E9", "Blue Circle"}, // 🔵 - {"\U0001F7EA", "Purple Circle"}, // 🟣 - - // Flags - {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 - {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 - {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 - {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 - {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 - {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 - {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 - - // Additional Miscellaneous Symbols - {"\U0001F4A5", "Collision"}, // 💥 - {"\U0001F4A6", "Sweat Droplets"}, // 💦 - {"\U0001F4A8", "Dashing Away"}, // 💨 - {"\U0001F50B", "Battery"}, // 🔋 - {"\U0001F4BB", "Laptop Computer"}, // 💻 - {"\U0001F4DE", "Telephone"}, // 📞 - {"\U0001F4E7", "Incoming Envelope"}, // 📧 -}; +remo_t remo[] = {{"\U0001F600", "Grinning Face"}, + {"\U0001F601", "Beaming Face with Smiling Eyes"}, + {"\U0001F602", "Face with Tears of Joy"}, + {"\U0001F923", "Rolling on the Floor Laughing"}, + {"\U0001F603", "Grinning Face with Big Eyes"}, + {"\U0001F604", "Grinning Face with Smiling Eyes"}, + {"\U0001F609", "Winking Face"}, + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, + {"\U0001F618", "Face Blowing a Kiss"}, + {"\U0001F617", "Kissing Face"}, + {"\U0001F61A", "Kissing Face with Closed Eyes"}, + {"\U0001F642", "Slightly Smiling Face"}, + {"\U0001F643", "Upside-Down Face"}, + {"\U0001F970", "Smiling Face with Hearts"}, + {"\U0001F60B", "Face Savoring Food"}, + {"\U0001F61B", "Face with Tongue"}, + {"\U0001F61C", "Winking Face with Tongue"}, + {"\U0001F92A", "Zany Face"}, + {"\U0001F929", "Star-Struck"}, + {"\U0001F631", "Face Screaming in Fear"}, + {"\U0001F62D", "Loudly Crying Face"}, + {"\U0001F624", "Face with Steam From Nose"}, + {"\U0001F620", "Angry Face"}, + {"\U0001F621", "Pouting Face"}, + {"\U0001F47B", "Ghost"}, + {"\U0001F480", "Skull"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F47D", "Alien"}, + {"\U000025A0", "Black Square"}, + {"\U000025B2", "Upward Triangle"}, + {"\U000025CF", "Black Circle"}, + {"\U000025CB", "White Circle"}, + {"\U00002B1B", "Large Black Square"}, + {"\U00002B1C", "Large White Square"}, + {"\U00002200", "For All"}, + {"\U00002203", "Exists"}, + {"\U00002205", "Empty Set"}, + {"\U00002207", "Nabla"}, + {"\U0000220F", "N-Ary Product"}, + {"\U00002212", "Minus Sign"}, + {"\U0000221E", "Infinity"}, + {"\U00002190", "Left Arrow"}, + {"\U00002191", "Up Arrow"}, + {"\U00002192", "Right Arrow"}, + {"\U00002193", "Down Arrow"}, + {"\U00002195", "Up Down Arrow"}, + {"\U00002197", "Up Right Arrow"}, + {"\U00002198", "Down Right Arrow"}, + {"\U000027A1", "Black Right Arrow"}, + {"\U00002714", "Check Mark"}, + {"\U00002716", "Heavy Multiplication X"}, + {"\U00002728", "Sparkles"}, + {"\U00002757", "Exclamation Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002795", "Heavy Plus Sign"}, + {"\U00002600", "Sun"}, + {"\U00002614", "Umbrella with Rain Drops"}, + {"\U00002620", "Skull and Crossbones"}, + {"\U000026A0", "Warning Sign"}, + {"\U000026BD", "Soccer Ball"}, + {"\U000026C4", "Snowman"}, + {"\U00002733", "Eight Pointed Black Star"}, + {"\U00002734", "Eight Spoked Asterisk"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U00002728", "Sparkles"}, + {"\U0001F98A", "Fox"}, + {"\U0001F415", "Dog"}, + {"\U0001F431", "Cat Face"}, + {"\U0001F435", "Monkey Face"}, + {"\U0001F408", "Black Cat"}, + {"\U0001F98C", "Deer"}, + {"\U0001F344", "Mushroom"}, + {"\U0001F333", "Tree"}, + {"\U0001F308", "Rainbow"}, + {"\U0001F320", "Shooting Star"}, + {"\U00002600", "Sun"}, + {"\U00002601", "Cloud"}, + {"\U000026A1", "High Voltage"}, + {"\U0001F525", "Fire"}, + {"\U000026C4", "Snowman"}, + {"\U0001F30A", "Water Wave"}, + {"\U0001F68C", "Bus"}, + {"\U0001F697", "Car"}, + {"\U0001F6B2", "Bicycle"}, + {"\U0001F6A2", "Ship"}, + {"\U0001F681", "Helicopter"}, + {"\U0001F680", "Rocket"}, + {"\U0001F6EB", "Airplane"}, + {"\U00000024", "Dollar Sign"}, + {"\U000000A3", "Pound Sign"}, + {"\U000000A5", "Yen Sign"}, + {"\U000020AC", "Euro Sign"}, + {"\U0001F4B5", "Dollar Banknote"}, + {"\U0001F4B4", "Yen Banknote"}, + {"\U00002660", "Black Spade Suit"}, + {"\U00002663", "Black Club Suit"}, + {"\U00002665", "Black Heart Suit"}, + {"\U00002666", "Black Diamond Suit"}, + {"\U0001F0CF", "Joker Card"}, + {"\U0001F4DA", "Books"}, + {"\U0001F4D7", "Green Book"}, + {"\U0001F4C8", "Chart with Upwards Trend"}, + {"\U0001F4C9", "Chart with Downwards Trend"}, + {"\U0001F4B0", "Money Bag"}, + {"\U0001F4B8", "Money with Wings"}, + {"\U0001F4E6", "Package"}, + {"\U00002757", "Exclamation Mark"}, + {"\U00002714", "Check Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002705", "Check Mark Button"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U0001F4A1", "Light Bulb"}, + {"\U0001F4A3", "Bomb"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F3B5", "Musical Note"}, + {"\U0001F3B6", "Multiple Musical Notes"}, + {"\U0001F3BC", "Musical Score"}, + {"\U0001F399", "Studio Microphone"}, + {"\U0001F3A4", "Microphone"}, + {"\U0001F35F", "Cheese Wedge"}, + {"\U0001F355", "Slice of Pizza"}, + {"\U0001F32D", "Taco"}, + {"\U0001F37D", "Beer Mug"}, + {"\U0001F96B", "Cup with Straw"}, + {"\U0001F32E", "Hot Pepper"}, + {"\U0001F95A", "Potato"}, + {"\U00002600", "Aries"}, + {"\U00002601", "Taurus"}, + {"\U00002602", "Gemini"}, + {"\U00002603", "Cancer"}, + {"\U00002604", "Leo"}, + {"\U00002605", "Virgo"}, + {"\U00002606", "Libra"}, + {"\U00002607", "Scorpio"}, + {"\U00002608", "Sagittarius"}, + {"\U00002609", "Capricorn"}, + {"\U0000260A", "Aquarius"}, + {"\U0000260B", "Pisces"}, + {"\U0001F4C8", "Chart Increasing"}, + {"\U0001F4C9", "Chart Decreasing"}, + {"\U0001F4CA", "Bar Chart"}, + {"\U0001F7E6", "Orange Circle"}, + {"\U0001F7E7", "Yellow Circle"}, + {"\U0001F7E8", "Green Circle"}, + {"\U0001F7E9", "Blue Circle"}, + {"\U0001F7EA", "Purple Circle"}, + {"\U0001F1E6\U0001F1E9", "Flag of France"}, + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, + {"\U0001F4A5", "Collision"}, + {"\U0001F4A6", "Sweat Droplets"}, + {"\U0001F4A8", "Dashing Away"}, + {"\U0001F50B", "Battery"}, + {"\U0001F4BB", "Laptop Computer"}, + {"\U0001F4DE", "Telephone"}, + {"\U0001F4E7", "Incoming Envelope"}}; size_t remo_count = sizeof(remo) / sizeof(remo[0]); void rstrtolower(const char *input, char *output) { @@ -220,16 +193,16 @@ void rstrtolower(const char *input, char *output) { } *output = 0; } + bool rstrinstr(const char *haystack, const char *needle) { char lower1[strlen(haystack) + 1]; char lower2[strlen(needle) + 1]; rstrtolower(haystack, lower1); rstrtolower(needle, lower2); - return strstr(lower1, lower2) ? true : false; + return strstr(lower1, lower2) != NULL; } void remo_print() { - for (size_t i = 0; i < remo_count; i++) { printf("%s - %s\n", remo[i].str, remo[i].description); } diff --git a/rhashtable.h b/rhashtable.h index 193b31d..e38907d 100644 --- a/rhashtable.h +++ b/rhashtable.h @@ -1,8 +1,30 @@ +// Written by retoor@molodetz.nl + +// This source code provides the implementation of a simple hash table using separate chaining for collision resolution. It contains +// functions to hash, retrieve, and insert entries into the hash table. + +// Imported library: The code uses the non-standard library "rmalloc.h". + +/* MIT License +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 RHASHTABLE_H #define RHASHTABLE_H -/* - ORIGINAL SOURCE IS FROM K&R - */ #include "rmalloc.h" #include <stdio.h> @@ -11,44 +33,42 @@ #define HASHSIZE 101 -// Structure for the table entries typedef struct rnlist { struct rnlist *next; char *name; char *defn; } rnlist; -// Hash table array static rnlist *rhashtab[HASHSIZE]; -// Hash function unsigned rhash(char *s) { - unsigned hashval; - for (hashval = 0; *s != '\0'; s++) + unsigned hashval = 0; + while (*s != '\0') { hashval = *s + 31 * hashval; + s++; + } return hashval % HASHSIZE; } rnlist *rlget(char *s) { rnlist *np; - for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) { if (strcmp(s, np->name) == 0) - return np; // Found - return NULL; // Not found + return np; + } + return NULL; } -// Lookup function char *rget(char *s) { rnlist *np = rlget(s); return np ? np->defn : NULL; } -// Install function (adds a name and definition to the table) struct rnlist *rset(char *name, char *defn) { struct rnlist *np = NULL; unsigned hashval; - if ((rlget(name)) == NULL) { // Not found + if ((rlget(name)) == NULL) { np = (struct rnlist *)malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) return NULL; @@ -56,12 +76,13 @@ struct rnlist *rset(char *name, char *defn) { np->next = rhashtab[hashval]; rhashtab[hashval] = np; } else { - if (np->defn) - free((void *)np->defn); + if (np->defn) { + free(np->defn); + } np->defn = NULL; } if ((np->defn = strdup(defn)) == NULL) return NULL; return np; } -#endif +#endif \ No newline at end of file diff --git a/rhttp.h b/rhttp.h index 98d750c..faa702d 100644 --- a/rhttp.h +++ b/rhttp.h @@ -1,5 +1,36 @@ +// Written by retoor@molodetz.nl + +// This code implements an HTTP server that can handle multiple connections, parse HTTP requests, log request information, and respond to +// different request types (including file and counter requests). + +// Include summary: +// This code includes custom headers ("rio.h", "rmalloc.h", "rstring.h", "rtemp.h", "rtime.h") and libraries ("arpa/inet.h", "pthread.h", +// "signal.h", "stdarg.h", "stdbool.h", "stdio.h", "stdlib.h", "string.h", "time.h", "unistd.h") that provide functionality for networking, +// threading, signal handling, and I/O operations. + +// The MIT License (MIT) + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + #ifndef RHTTP_H #define RHTTP_H + #include "rio.h" #include "rmalloc.h" #include "rstring.h" @@ -72,6 +103,7 @@ void rhttp_logs(const char *prefix, const char *level, const char *format, va_li sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); vfprintf(stdout, buf, args); } + void rhttp_log_info(const char *format, ...) { if (!rhttp_opt_info) return; @@ -80,6 +112,7 @@ void rhttp_log_info(const char *format, ...) { rhttp_logs("\e[32m", "INFO ", format, args); va_end(args); } + void rhttp_log_debug(const char *format, ...) { if (!rhttp_opt_debug) return; @@ -90,6 +123,7 @@ void rhttp_log_debug(const char *format, ...) { va_end(args); } + void rhttp_log_warn(const char *format, ...) { if (!rhttp_opt_warn) return; @@ -99,6 +133,7 @@ void rhttp_log_warn(const char *format, ...) { va_end(args); } + void rhttp_log_error(const char *format, ...) { if (!rhttp_opt_error) return; @@ -132,6 +167,7 @@ void rhttp_free_header(rhttp_header_t *h) { if (next) rhttp_free_header(next); } + void rhttp_rhttp_free_headers(rhttp_request_t *r) { if (!r->headers) return; @@ -192,6 +228,7 @@ long rhttp_header_get_long(rhttp_request_t *r, const char *name) { } return -1; } + char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { rhttp_header_t *h = r->headers; while (h) { @@ -203,18 +240,22 @@ char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { } void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } + void rhttp_print_headers(rhttp_header_t *h) { while (h) { rhttp_print_header(h); h = h->next; } } + void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } + void rhttp_print_request(rhttp_request_t *r) { rhttp_print_request_line(r); if (rhttp_opt_debug) rhttp_print_headers(r->headers); } + void rhttp_close(rhttp_request_t *r) { if (!r) return; @@ -222,6 +263,7 @@ void rhttp_close(rhttp_request_t *r) { close(r->c); rhttp_free_request(r); } + rhttp_request_t *rhttp_parse_request(int s) { rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); http_request_init(request); @@ -289,7 +331,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { unsigned char *to_send_original = to_send; memcpy(to_send, tsend, to_send_len); - // to_send[to_send_len] = '\0'; long bytes_sent = 0; long bytes_sent_total = 0; while (1) { @@ -304,7 +345,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { break; } else if (!bytes_sent) { bytes_sent_total = 0; - // error break; } else { rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); @@ -351,7 +391,6 @@ void rhttp_serve(const char *host, int port, int backlog, int request_logging, i } if (!r->keep_alive && !r->closed) { rhttp_close(r); - } else if (r->keep_alive && !r->closed) { } if (r->closed) { break; @@ -404,7 +443,7 @@ int rhttp_file_response(rhttp_request_t *r, char *path) { close(r->c); fclose(f); return 1; -}; +} int rhttp_file_request_handler(rhttp_request_t *r) { char *path = r->path; @@ -414,9 +453,10 @@ int rhttp_file_request_handler(rhttp_request_t *r) { return 0; } return rhttp_file_response(r, path); -}; +} unsigned int counter = 100000000; + int rhttp_counter_request_handler(rhttp_request_t *r) { if (!strncmp(r->path, "/counter", strlen("/counter"))) { counter++; @@ -432,6 +472,7 @@ int rhttp_counter_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_root_request_handler(rhttp_request_t *r) { if (!strcmp(r->path, "/")) { char to_send[1024] = {0}; @@ -443,6 +484,7 @@ int rhttp_root_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_error_404_handler(rhttp_request_t *r) { char to_send[1024] = {0}; sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " @@ -456,17 +498,14 @@ int rhttp_default_request_handler(rhttp_request_t *r) { if (rhttp_opt_debug || rhttp_opt_request_logging) rhttp_print_request(r); if (rhttp_counter_request_handler(r)) { - // Counter handler rhttp_log_info("Counter handler found for: %s\n", r->path); } else if (rhttp_root_request_handler(r)) { - // Root handler rhttp_log_info("Root handler found for: %s\n", r->path); } else if (rhttp_file_request_handler(r)) { rhttp_log_info("File %s sent\n", r->path); } else if (rhttp_error_404_handler(r)) { rhttp_log_warn("Error 404 for: %s\n", r->path); - // Error handler } else { rhttp_log_warn("No handler found for: %s\n", r->path); close(rhttp_c); @@ -530,8 +569,6 @@ int rhttp_main(int argc, char *argv[]) { return 0; } -/* CLIENT CODE */ - typedef struct rhttp_client_request_t { char *host; int port; @@ -588,12 +625,14 @@ int rhttp_execute_request(rhttp_client_request_t *r) { close(s); return ret; } + void rhttp_reset_request(rhttp_client_request_t *r) { free(r->response); r->is_done = false; r->response = NULL; r->bytes_received = 0; } + void rhttp_free_client_request(rhttp_client_request_t *r) { if (r->request) free(r->request); @@ -609,7 +648,6 @@ void rhttp_free_client_request(rhttp_client_request_t *r) { void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { rhttp_client_request_t *requests[workers]; while (times > 0) { - for (int i = 0; i < workers && times; i++) { requests[i] = rhttp_create_request(host, port, path); rhttp_execute_request(requests[i]); @@ -617,6 +655,7 @@ void rhttp_client_bench(int workers, int times, const char *host, int port, cons } } } + char *rhttp_client_get(const char *host, int port, const char *path) { if (!rhttp_c_mutex_initialized) { rhttp_c_mutex_initialized = 1; @@ -631,7 +670,7 @@ char *rhttp_client_get(const char *host, int port, const char *path) { reconnects++; tick(); if (reconnects == reconnects_max) { - fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + fprintf(stderr, "Maximum reconnects exceeded for %s:%d\n", host, port); rhttp_free_client_request(r); return NULL; } @@ -649,5 +688,5 @@ char *rhttp_client_get(const char *host, int port, const char *path) { pthread_mutex_unlock(&rhttp_c_mutex); return result; } -/*END CLIENT CODE */ -#endif + +#endif \ No newline at end of file diff --git a/rio.h b/rio.h index bb15576..cf46cac 100644 --- a/rio.h +++ b/rio.h @@ -1,3 +1,31 @@ +// Written by retoor@molodetz.nl + +// This source code provides a set of utility functions for file handling and directory operations in C. + +// Includes for handling directories, system calls, and working with the file system. + +// MIT License +// +// Copyright (c) [Year] [Author] +// +// 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_RIO #define RLIB_RIO #include <stdbool.h> @@ -7,7 +35,6 @@ #include <sys/select.h> #include <dirent.h> #include <sys/dir.h> -#include <sys/stat.h> #include <unistd.h> #include "rstring_list.h" @@ -21,8 +48,7 @@ void rjoin_path(char *p1, char *p2, char *output) { strcpy(output, p1); if (output[strlen(output) - 1] != '/') { - char slash[] = "/"; - strcat(output, slash); + strcat(output, "/"); } if (p2[0] == '/') { p2++; @@ -32,33 +58,28 @@ void rjoin_path(char *p1, char *p2, char *output) { 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 1; } - return 0; } + bool risdir(const char *path) { return !risprivatedir(path); } void rforfile(char *path, void callback(char *)) { - if (!rfile_exists(path)) + 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; } @@ -76,22 +97,18 @@ void rforfile(char *path, void callback(char *)) { } bool rfd_wait(int fd, int ms) { - fd_set read_fds; struct timeval timeout; - FD_ZERO(&read_fds); FD_SET(fd, &read_fds); - timeout.tv_sec = 0; timeout.tv_usec = 1000 * ms; - int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); return ret > 0 && FD_ISSET(fd, &read_fds); } bool rfd_wait_forever(int fd) { - while ((!rfd_wait(fd, 10))) { + while (!rfd_wait(fd, 10)) { } return true; } @@ -108,7 +125,6 @@ size_t rfile_readb(char *path, void *data, size_t size) { return 0; } size_t bytes_read = fread(data, sizeof(char), size, fd); - fclose(fd); ((char *)data)[bytes_read] = 0; return bytes_read; diff --git a/rjson.h b/rjson.h index b8e23c6..14ef4fb 100644 --- a/rjson.h +++ b/rjson.h @@ -1,5 +1,17 @@ +// Written by retoor@molodetz.nl + +// A C library for creating and manipulating JSON structures. It provides functions to build JSON strings recursively, including starting +// and closing JSON objects and arrays, adding key-value pairs (for strings, integers, numbers, booleans, and durations), and freeing JSON +// objects. + +// Includes for memory management, string manipulation, time handling, and testing utilities: rmalloc.h, rtypes.h, rstring.h, rtemp.h, +// rtime.h, rtest.h + +// MIT License + #ifndef RJSON_H #define RJSON_H + #include "rmalloc.h" #include "rtypes.h" #include "rstring.h" @@ -17,7 +29,7 @@ rjson_t *rjson() { rjson_t *json = rmalloc(sizeof(rjson_t)); json->size = 1024; json->length = 0; - json->content = (char *)rmalloc(json->size); + json->content = rmalloc(json->size); json->content[0] = 0; return json; } @@ -33,10 +45,12 @@ void rjson_write(rjson_t *rjs, char *content) { } void rjson_object_start(rjson_t *rjs) { - if (rstrendswith(rjs->content, "}")) + if (rstrendswith(rjs->content, "}")) { rjson_write(rjs, ","); + } rjson_write(rjs, "{"); } + void rjson_object_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -44,11 +58,14 @@ void rjson_object_close(rjson_t *rjs) { } rjson_write(rjs, "}"); } + void rjson_array_start(rjson_t *rjs) { - if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) { rjson_write(rjs, ","); + } rjson_write(rjs, "["); } + void rjson_array_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -64,7 +81,7 @@ void rjson_kv_string(rjson_t *rjs, char *key, char *value) { rjson_write(rjs, "\""); rjson_write(rjs, key); rjson_write(rjs, "\":\""); - char *value_str = (char *)rmalloc(strlen(value) + 4096); + char *value_str = rmalloc(strlen(value) + 4096); rstraddslashes(value, value_str); rjson_write(rjs, value_str); free(value_str); @@ -82,15 +99,14 @@ void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { sprintf(value_str, "%lld", value); rjson_write(rjs, value_str); } + void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { rjson_write(rjs, ","); } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(rformat_number(value))); rjson_write(rjs, "\""); } @@ -111,12 +127,11 @@ void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(format_time(value))); rjson_write(rjs, "\""); } + void rjson_free(rjson_t *rsj) { free(rsj->content); free(rsj); @@ -127,4 +142,5 @@ void rjson_key(rjson_t *rsj, char *key) { rjson_write(rsj, key); rjson_write(rsj, "\":"); } + #endif \ No newline at end of file diff --git a/rlib.h b/rlib.h index 0c50255..f58d6a8 100644 --- a/rlib.h +++ b/rlib.h @@ -1,19 +1,38 @@ // RETOOR - Mar 16 2025 +// Written by retoor@molodetz.nl + +// This source code includes and uses multiple modules and libraries to provide comprehensive networking, +// memory management, mathematical functions, and additional functionalities for developing a variety of applications. + +// Includes not part of the core language: "license.h", "rtypes.h", "nsock.h", "rmalloc.h", "uuid.h", +// "rnet.h", "rargs.h", "rcat.h", "rliza.h", "rcov.h", "rtemp.h", "rhttp.h", "rjson.h", "rstring_list.h", +// "rautocomplete.h", "rrex4.h", "rprint.h", "rmath.h", "rtest.h", "rkeytable.h", "rhashtable.h", +// "rrex3.h", "rtime.h", "arena.h", "rio.h", "rstring.h", "rcase.h", "rterminal.h", "rterm.h", +// "rtree.h", "rlexer.h", "rbench.h", "main.h" + +// MIT License + +// Written by retoor@molodetz.nl + +// This source code provides the implementation and licensing information for software available under the MIT License. + +// No external libraries or frameworks are used in this source code. + // 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 @@ -23,13 +42,6 @@ // SOFTWARE. #ifndef RLIB_H #define RLIB_H -// BEGIN OF RLIB - -/* - * Line below will be filtered by rmerge -<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after -tag" /> -*/ #ifndef RTYPES_H #define RTYPES_H @@ -63,25 +75,85 @@ typedef unsigned char byte; #endif #endif +// Written by retoor@molodetz.nl + +// The code is an implementation for managing network sockets. It provides functionality to create, connect, and manage a server or client +// sockets, handle multiple connections, read and write data, and handle events such as connecting, receiving data, and closing a +// connection. + +// External import summary: +// This code uses external libraries such as rmalloc.h and rio.h for memory allocation and I/O operations. + +// MIT License: +// 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 NSOCK_H #define NSOCK_H #include <unistd.h> +// Written by retoor@molodetz.nl + +// This code overrides the default dynamic memory allocation functions in C, providing custom implementations for malloc, calloc, realloc, +// free, and strdup, with additional logging and memory usage statistics. + +// Dependence on an external header file "rtemp.h". + +// MIT License +// +// 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 RMALLOC_H #define RMALLOC_H + #ifndef RMALLOC_OVERRIDE #define RMALLOC_OVERRIDE 1 #endif + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #ifndef ulonglong #define ulonglong unsigned long long #endif + #include <locale.h> #include <stdio.h> #include <stdlib.h> @@ -138,6 +210,7 @@ char *rtempc(char *data) { #define sbuf(val) rtempc(val) #endif + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -145,6 +218,7 @@ char *rtempc(char *data) { #else #undef _POSIX_C_SOURCE #endif + ulonglong rmalloc_count = 0; ulonglong rmalloc_alloc_count = 0; ulonglong rmalloc_free_count = 0; @@ -163,6 +237,7 @@ void *rmalloc(size_t size) { rmalloc_total_bytes_allocated += size; return result; } + void *rcalloc(size_t count, size_t size) { void *result; while (!(result = calloc(count, size))) { @@ -173,6 +248,7 @@ void *rcalloc(size_t count, size_t size) { rmalloc_total_bytes_allocated += count * size; return result; } + void *rrealloc(void *obj, size_t size) { if (!obj) { rmalloc_count++; @@ -181,8 +257,7 @@ void *rrealloc(void *obj, size_t size) { rmalloc_alloc_count++; if (obj == _rmalloc_prev_realloc_obj) { rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; - _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; - + _rmalloc_prev_realloc_obj_size = size; } else { _rmalloc_prev_realloc_obj_size = size; } @@ -207,6 +282,7 @@ char *rstrdup(const char *s) { rmalloc_total_bytes_allocated += size; return result; } + void *rfree(void *obj) { rmalloc_count--; rmalloc_free_count++; @@ -223,7 +299,6 @@ void *rfree(void *obj) { #endif char *rmalloc_lld_format(ulonglong num) { - char res[100]; res[0] = 0; sprintf(res, "%'lld", num); @@ -249,20 +324,14 @@ char *rmalloc_bytes_format(int factor, ulonglong num) { char *rmalloc_stats() { static char res[200]; res[0] = 0; - // int original_locale = localeconv(); setlocale(LC_NUMERIC, "en_US.UTF-8"); - sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), - rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), - - rmalloc_lld_format(rmalloc_count)); - // setlocale(LC_NUMERIC, original_locale); - + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unique freeds, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), rmalloc_lld_format(rmalloc_count)); setlocale(LC_NUMERIC, ""); return res; } #endif - #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -274,6 +343,34 @@ char *rmalloc_stats() { #include <sys/select.h> #include <sys/socket.h> #include <unistd.h> +// Written by retoor@molodetz.nl + +// This source code provides a set of utility functions for file handling and directory operations in C. + +// Includes for handling directories, system calls, and working with the file system. + +// MIT License +// +// Copyright (c) [Year] [Author] +// +// 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_RIO #define RLIB_RIO #include <dirent.h> @@ -341,8 +438,7 @@ void rjoin_path(char *p1, char *p2, char *output) { strcpy(output, p1); if (output[strlen(output) - 1] != '/') { - char slash[] = "/"; - strcat(output, slash); + strcat(output, "/"); } if (p2[0] == '/') { p2++; @@ -352,33 +448,28 @@ void rjoin_path(char *p1, char *p2, char *output) { 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 1; } - return 0; } + bool risdir(const char *path) { return !risprivatedir(path); } void rforfile(char *path, void callback(char *)) { - if (!rfile_exists(path)) + 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; } @@ -396,22 +487,18 @@ void rforfile(char *path, void callback(char *)) { } bool rfd_wait(int fd, int ms) { - fd_set read_fds; struct timeval timeout; - FD_ZERO(&read_fds); FD_SET(fd, &read_fds); - timeout.tv_sec = 0; timeout.tv_usec = 1000 * ms; - int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); return ret > 0 && FD_ISSET(fd, &read_fds); } bool rfd_wait_forever(int fd) { - while ((!rfd_wait(fd, 10))) { + while (!rfd_wait(fd, 10)) { } return true; } @@ -428,7 +515,6 @@ size_t rfile_readb(char *path, void *data, size_t size) { return 0; } size_t bytes_read = fread(data, sizeof(char), size, fd); - fclose(fd); ((char *)data)[bytes_read] = 0; return bytes_read; @@ -468,8 +554,8 @@ nsock_t *nsock_get(int fd) { if (fd >= nsocks_count || nsocks[fd] == NULL) { if (fd >= nsocks_count) { nsocks_count = fd + 1; - nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); - nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + nsocks = realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * nsocks_count); + nsocks[fd] = calloc(1, sizeof(nsock_t)); } nsocks[fd]->upstreams = NULL; nsocks[fd]->fd = fd; @@ -518,12 +604,12 @@ int *nsock_init(int socket_count) { if (nsock_socks) { return nsock_socks; } - nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + nsock_socks = calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); if (nsock_data) { free(nsock_data); nsock_data = NULL; } - nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_data = malloc(sizeof(void **) * socket_count + 1); nsock_socks[socket_count] = -1; return nsock_socks; } @@ -548,13 +634,14 @@ void nsock_add_upstream(int source, int target, bool downstream) { nsock_t *sock = nsock_get(source); nsock_t *sock_target = nsock_get(target); sock_target->type = NSOCK_UPSTREAM; - sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->upstreams = realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); sock->downstream = downstream; sock->upstreams[sock->upstream_count] = target; sock->upstream_count++; } void *nsock_get_data(int socket) { return nsock_data[socket]; } + void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } int nsock_connect(const char *host, unsigned int port) { @@ -644,7 +731,6 @@ int *nsock_select(suseconds_t timeout) { for (int i = 0; socks[i] != -1; i++) { if (i == server_fd) continue; - ; if (!socks[i]) continue; if (socks[i] > nsock_max_socket_fd) { @@ -680,7 +766,7 @@ int *nsock_select(suseconds_t timeout) { if (nsock_readable) { free(nsock_readable); } - nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable = calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); nsock_readable[nsock_max_socket_fd + 1] = -1; nsock_readable[0] = 0; int readable_count = 0; @@ -707,7 +793,7 @@ int *nsock_select(suseconds_t timeout) { unsigned char *nsock_read(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = read(fd, buffer, length); if (bytes_read <= 0) { nsock_close(fd); @@ -720,7 +806,7 @@ unsigned char *nsock_read(int fd, int length) { unsigned char *nsock_read_all(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = 0; while (bytes_read < length) { int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); @@ -768,7 +854,7 @@ int nsock_execute_upstream(int source, size_t buffer_size) { nsock_close(sock->upstreams[i]); continue; } - if (sock->downstream && downstreamed == false) { + if (sock->downstream && !downstreamed) { downstreamed = true; unsigned char data[4096]; memset(data, 0, 4096); @@ -839,7 +925,6 @@ void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void ( } } #endif - #ifndef UUID_H #define UUID_H #include <stdbool.h> @@ -885,16 +970,28 @@ char *uuid4() { return sbuf(str); } #endif +// Written by retoor@molodetz.nl + +// This source code defines and implements a simple networking library that provides various functions and structures to manage network +// sockets and servers. It offers the ability to create, bind, listen, connect, and close sockets, along with socket selection and +// asynchronous behavior handling. + +// No non-standard imports or includes are used in this source code. + +// MIT License + #ifndef RNET_H #define RNET_H + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -905,11 +1002,10 @@ char *uuid4() { #include <stdlib.h> #include <string.h> #include <sys/select.h> - #include <sys/socket.h> #include <sys/types.h> - #include <unistd.h> + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -917,6 +1013,7 @@ char *uuid4() { #else #undef _POSIX_C_SOURCE #endif + #define NET_SOCKET_MAX_CONNECTIONS 50000 typedef struct rnet_socket_t { @@ -1007,29 +1104,27 @@ bool net_set_non_blocking(int sock) { perror("fcntl"); return false; } - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); return false; } - return true; } int net_socket_init() { - int socket_fd = -1; - memset(sockets, 0, sizeof(sockets)); - int opt = 1; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == 0) { perror("Socket failed.\n"); return false; } - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + int opt = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("Setsockopt failed.\n"); close(socket_fd); return false; } net_set_non_blocking(socket_fd); + memset(sockets, 0, sizeof(sockets)); return socket_fd; } @@ -1037,19 +1132,15 @@ char *net_socket_name(int fd) { rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); if (rnet_socket) { return rnet_socket->name; - ; } - - // If socket disconnected or is no client from server return NULL; } bool net_socket_bind(int socket_fd, unsigned int port) { struct sockaddr_in address; - - address.sin_family = AF_INET; // IPv4 - address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address - address.sin_port = htons(port); // Convert port to network byte order + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); @@ -1061,48 +1152,36 @@ bool net_socket_bind(int socket_fd, unsigned int port) { int net_socket_connect(const char *host, unsigned int port) { char port_str[10] = {0}; - sprintf(port_str, "%d", port); - int status; - int socket_fd = -1; - struct addrinfo hints; - struct addrinfo *res; - struct addrinfo *p; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - return false; - } - + snprintf(port_str, sizeof(port_str), "%d", port); + struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) { + return false; + } + int status = getaddrinfo(host, port_str, &hints, &res); + if (status != 0) { return -1; } - for (p = res; p != NULL; p = p->ai_next) { - if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (socket_fd == -1) { continue; } - if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { close(socket_fd); continue; } - break; } - - if (p == NULL) { - freeaddrinfo(res); - return -1; - } - freeaddrinfo(res); - return socket_fd; + return (p == NULL) ? -1 : socket_fd; } bool net_socket_listen(int socket_fd, unsigned int backlog) { - if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + if (listen(socket_fd, backlog) < 0) { perror("Listen failed"); close(socket_fd); return false; @@ -1113,59 +1192,27 @@ bool net_socket_listen(int socket_fd, unsigned int backlog) { rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { signal(SIGPIPE, SIG_IGN); int socket_fd = net_socket_init(); - net_socket_bind(socket_fd, port); - net_socket_listen(socket_fd, backlog); + if (!net_socket_bind(socket_fd, port) || !net_socket_listen(socket_fd, backlog)) { + return NULL; + } return rnet_server_new(socket_fd, port, backlog); } int net_socket_accept(int net_socket_server_fd) { struct sockaddr_in address; int addrlen = sizeof(address); - int new_socket = -1; - if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { - close(new_socket); + int new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { return -1; - } else { - - return new_socket; } + return new_socket; } -/* -static void net_socket_stats(WrenVM *vm) -{ - - wrenSetSlotNewList(vm, 0); - - wrenSetSlotString(vm, 1, "sockets_total"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_total); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_concurrent_record"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_connected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_connected); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_disconnected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); - wrenInsertInList(vm, 0, -1, 1); -}*/ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { ssize_t sent_total = 0; - ssize_t sent = 0; ssize_t to_send = size; - while ((sent = send(sock->fd, message, to_send, 0))) { + while (1) { + ssize_t sent = send(sock->fd, message, to_send, 0); if (sent == -1) { sockets_errors++; net_socket_close(sock); @@ -1179,8 +1226,9 @@ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size break; } sent_total += sent; - if (sent_total == to_send) + if (sent_total == to_send) { break; + } } return sent_total; } @@ -1201,47 +1249,43 @@ unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { return NULL; } } - buffer[received + 1] = 0; + buffer[received] = 0; sock->bytes_received = received; return buffer; } rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { - if (!sock) - return NULL; - if (sock->fd == -1) + if (!sock || sock->fd == -1) { return NULL; + } fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock->fd, &read_fds); - int max_socket_fd = sock->fd; int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { - // perror("Select error"); + if (activity < 0 && errno != EINTR) { net_socket_close(sock); return NULL; } - if (FD_ISSET(sock->fd, &read_fds)) { - return sock; - } - - return NULL; + return FD_ISSET(sock->fd, &read_fds) ? sock : NULL; } void rnet_safe_str(char *str, size_t length) { - if (!str || !length || !*str) + if (!str || !length || !*str) { return; + } for (unsigned int i = 0; i < length; i++) { - if (str[i] < 32 || str[i] > 126) - if (str[i] != 0) + if (str[i] < 32 || str[i] > 126) { + if (str[i] != 0) { str[i] = '.'; + } + } } str[length] = 0; } rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { - rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + rnet_select_result_t *result = malloc(sizeof(rnet_select_result_t)); memset(result, 0, sizeof(rnet_select_result_t)); result->server_fd = socket_fd; result->socket_count = 0; @@ -1254,14 +1298,15 @@ void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { result->sockets[result->socket_count] = sock; result->socket_count++; } + void rnet_select_result_free(rnet_select_result_t *result) { free(result); } + rnet_select_result_t *net_socket_select(rnet_server_t *server) { fd_set read_fds; FD_ZERO(&read_fds); FD_SET(server->socket_fd, &read_fds); - server->max_fd = server->socket_fd; - int socket_fd = -1; + int socket_fd; for (unsigned int i = 0; i < server->socket_count; i++) { socket_fd = server->sockets[i]->fd; if (!server->sockets[i]->connected) { @@ -1278,19 +1323,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { struct sockaddr_in address; int addrlen = sizeof(struct sockaddr_in); int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { + if (activity < 0 && errno != EINTR) { perror("Select error\n"); return NULL; } if (FD_ISSET(server->socket_fd, &read_fds)) { - if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { perror("Accept failed\n"); return NULL; } - - // net_set_non_blocking(new_socket); char name[50] = {0}; - sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + snprintf(name, sizeof(name), "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); rnet_socket_t *sock_obj = NULL; for (unsigned int i = 0; i < server->socket_count; i++) { if (server->sockets && server->sockets[i]->fd == -1) { @@ -1298,7 +1342,7 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { } } if (!sock_obj) { - sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + sock_obj = malloc(sizeof(rnet_socket_t)); rnet_server_add_socket(server, sock_obj); } sock_obj->fd = new_socket; @@ -1306,17 +1350,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { sockets_connected++; sockets_total++; sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; - if (new_socket > net_socket_max_fd) { - net_socket_max_fd = new_socket; - } + net_socket_max_fd = (new_socket > net_socket_max_fd) ? new_socket : net_socket_max_fd; sock_obj->connected = true; - sock_obj->on_connect(sock_obj); + if (sock_obj->on_connect) { + sock_obj->on_connect(sock_obj); + } } rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); unsigned int readable_count = 0; for (unsigned int i = 0; i < server->socket_count; i++) { - if (server->sockets[i]->fd == -1) + if (server->sockets[i]->fd == -1) { continue; + } if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { rnet_select_result_add(result, server->sockets[i]); readable_count++; @@ -1329,8 +1374,9 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { rnet_select_result_free(server->select_result); server->select_result = NULL; } - if (readable_count == 0) + if (readable_count == 0) { rnet_select_result_free(result); + } return readable_count ? result : NULL; } @@ -1347,35 +1393,43 @@ void _net_socket_close(int sock) { if (sock > 0) { sockets_connected--; sockets_disconnected++; - if (sock > 0) { - if (close(sock) == -1) { - perror("Error closing socket.\n"); - } + if (close(sock) == -1) { + perror("Error closing socket.\n"); } } } void net_socket_close(rnet_socket_t *sock) { sock->connected = false; - if (sock->on_close) + if (sock->on_close) { sock->on_close(sock); + } _net_socket_close(sock->fd); sock->fd = -1; } + #undef _POSIX_C_SOURCE #endif +// Written by retoor@molodetz.nl + +// This source code implements a simple argument parsing utility for C programs, +// facilitating the checking or retrieval of command line argument values. + +// This file uses the standard C libraries: <stdio.h>, <string.h>, <stdlib.h>, <stdbool.h> + +// MIT License -#include <stdio.h> #ifndef RLIB_RARGS_H #define RLIB_RARGS_H + #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> bool rargs_isset(int argc, char *argv[], char *key) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { return true; } } @@ -1383,9 +1437,8 @@ bool rargs_isset(int argc, char *argv[], char *key) { } char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return argv[i + 1]; } @@ -1395,9 +1448,8 @@ char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def } int rargs_get_option_int(int argc, char *argv[], char *key, int def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return atoi(argv[i + 1]); } @@ -1407,24 +1459,32 @@ int rargs_get_option_int(int argc, char *argv[], char *key, int def) { } bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { - if (!strcmp(argv[i + 1], "false")) - return false; - if (!strcmp(argv[i + 1], "0")) + if (strcmp(argv[i + 1], "false") == 0 || strcmp(argv[i + 1], "0") == 0) { return false; + } return true; } } } - return def; } + #endif +// Written by retoor@molodetz.nl + +// This code provides a simple implementation of a reverse cat (rcat) function, which attempts to read a file in binary mode and outputs its +// contents to the standard output. + +// No external libraries apart from the standard C library are used here. + +// MIT License + #ifndef RCAT_H #define RCAT_H + #include <stdio.h> #include <stdlib.h> @@ -1435,7 +1495,7 @@ void rcat(char *filename) { return; } unsigned char c; - while ((c = fgetc(f)) && !feof(f)) { + while ((c = fgetc(f)) != EOF) { printf("%c", c); } fclose(f); @@ -1452,9 +1512,47 @@ int rcat_main(int argc, char *argv[]) { } #endif +// Written by retoor@molodetz.nl + +// This code defines a data structure and set of functions for handling JSON-like data types in C, allowing for the creation, manipulation, +// serialization, and deserialization of these structures. + +// Includes utilized but not part of the C standard library: "rbuffer.h", "rmalloc.h", and "rstring.h". These files would provide auxiliary +// functionalities such as dynamic memory management, string handling, or buffer manipulation required by this source code. + +// MIT License #ifndef RLIZA_H #define RLIZA_H +// Written by retoor@molodetz.nl + +// A ring buffer implementation in C that provides functionalities such as +// creating a new buffer, freeing, resetting, writing data, pushing data, +// popping data, matching options and more. It efficiently manages dynamic +// memory to handle data of varying sizes and applies basic buffer manipulation techniques. + +// This code includes the utility "rmalloc.h". It is assumed that this file +// contains custom memory management functions which are not specified here. + +// MIT License +// 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 RBUFFER_H #define RBUFFER_H #include <assert.h> @@ -1462,6 +1560,7 @@ int rcat_main(int argc, char *argv[]) { #include <stdio.h> #include <stdlib.h> #include <string.h> + typedef struct rbuffer_t { unsigned char *data; unsigned char *_data; @@ -1474,7 +1573,7 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size); void rbuffer_free(rbuffer_t *rfb); void rbuffer_reset(rbuffer_t *rfb); void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); -size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data); unsigned char rbuffer_pop(rbuffer_t *rfb); unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); @@ -1511,42 +1610,42 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { rfb->data = rfb->_data; return rfb; } + void rbuffer_free(rbuffer_t *rfb) { - if (rfb->_data) + if (rfb->_data) { free(rfb->_data); + } free(rfb); } -size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data) { if (rfb->pos < rfb->size) { - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; return 1; } rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; rfb->size++; return rfb->pos; } + void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { - unsigned char *data_ptr = (unsigned char *)data; for (size_t i = 0; i < size; i++) { - rbuffer_push(rfb, data_ptr[i]); + rbuffer_push(rfb, data[i]); } } unsigned char rbuffer_peek(rbuffer_t *rfb) { - unsigned char result = EOF; if (rfb->pos != rfb->size) { - result = rfb->_data[rfb->pos]; - return result; + return rfb->_data[rfb->pos]; } rfb->eof = true; return EOF; } + unsigned char rbuffer_pop(rbuffer_t *rfb) { - unsigned char result = EOF; - if (rfb->pos <= rfb->size) { - result = rfb->_data[rfb->pos]; + if (rfb->pos < rfb->size) { + unsigned char result = rfb->_data[rfb->pos]; rfb->pos++; rfb->data++; if (rfb->pos == rfb->size) { @@ -1555,23 +1654,19 @@ unsigned char rbuffer_pop(rbuffer_t *rfb) { return result; } rfb->eof = true; - return result; + return EOF; } + void rbuffer_reset(rbuffer_t *rfb) { rfb->data = rfb->_data; rfb->pos = 0; } unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { - return strncmp((char *)s1, (char *)s2, n); - while (n && *s1 == *s2) { - n--; - s1++; - s2++; - } - return *s1 != *s2; + return strncmp((const char *)s1, (const char *)s2, n); } -size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +size_t ustrlen(const unsigned char *s) { return strlen((const char *)s); } unsigned char *rbuffer_to_string(rbuffer_t *rfb) { unsigned char *result = rfb->_data; @@ -1587,7 +1682,6 @@ unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { strcpy(options_cpy, options); char *memory = options_cpy; while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { - size_t option_length = strlen(option); if (option_length > rfb->size - rfb->pos) { continue; @@ -1620,6 +1714,7 @@ unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { } return NULL; } + unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { unsigned char *result = NULL; if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { @@ -1627,11 +1722,37 @@ unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { } return result; } + #endif #ifndef RSTRING_H #define RSTRING_H +// Written by retoor@molodetz.nl + +// This code provides custom implementations of the `ceil`, `floor`, and `modf` functions for double precision numbers that mimic the +// behavior of those found in the C standard math library. + +// Summary of used imports: <math.h> for mathematical functions. + +// MIT License +// +// 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 RMATH_H #define RMATH_H + #include <math.h> #ifndef ceil @@ -1664,6 +1785,7 @@ double modf(double x, double *iptr) { return x - int_part; } #endif + #endif #include <ctype.h> #include <stdbool.h> @@ -2153,22 +2275,12 @@ void rliza_free(rliza_t *rliza) { rliza_free(rliza->value); rliza->value = NULL; } - // if (rliza->content.array) { - // printf("JAAAA\n"); - // } - // if (rliza->content.object) { - // rliza_free(rliza->content.object); - // rliza->content.object = NULL; - //} if (rliza->type == RLIZA_STRING) { if (rliza->content.string) { free(rliza->content.string); rliza->content.string = NULL; - // else if (rliza->type == RLIZA_NUMBER) { - // printf("STDring freed\n"); } } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { - if (rliza->content.map) { for (unsigned int i = 0; i < rliza->count; i++) { rliza_free(rliza->content.map[i]); @@ -2176,9 +2288,6 @@ void rliza_free(rliza_t *rliza) { free(rliza->content.map); } } - // free(rliza->content.array); - //} - free(rliza); } @@ -2342,7 +2451,6 @@ void rliza_set_null(rliza_t *self, char *key) { rliza_push_object(self, obj); } if (obj->type == RLIZA_OBJECT) { - rliza_free(obj->value); obj->value = NULL; } else if (obj->type == RLIZA_STRING) { @@ -2539,11 +2647,8 @@ rliza_t *_rliza_loads(char **content) { rliza_free(rliza); return NULL; } - // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); - // rstraddslashes(extracted, extracted_with_slashes); rliza->type = RLIZA_STRING; - rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; - // free(extracted); + rliza->content.string = extracted; return rliza; } else if (**content == '{') { rliza->type = RLIZA_OBJECT; @@ -2604,7 +2709,6 @@ rliza_t *_rliza_loads(char **content) { } else if (**content == '}') { break; } else { - // Parse error rliza_free(rliza); return NULL; } @@ -2676,21 +2780,17 @@ rliza_t *_rliza_loads(char **content) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = true; *content += 4; - return rliza; } else if (!strncmp(*content, "false", 5)) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = false; *content += 5; - return rliza; } else if (!strncmp(*content, "null", 4)) { rliza->type = RLIZA_NULL; *content += 4; - return rliza; } - // Parsing error rliza_free(rliza); return NULL; } @@ -2717,10 +2817,7 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%lld", rliza->content.integer); } } else if (rliza->type == RLIZA_STRING) { - - // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); char *escaped_string = rliza->content.string; - // rstrstripslashes((char *)rliza->content.string, escaped_string); size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; if (size < min_size) { size = min_size + 1; @@ -2740,7 +2837,6 @@ char *rliza_dumps(rliza_t *rliza) { content = realloc(content, size); sprintf(content, "\"%s\"", escaped_string); } - // free(escaped_string); } else if (rliza->type == RLIZA_NUMBER) { if (rliza->key) { sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); @@ -2773,14 +2869,12 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); } } else if (rliza->type == RLIZA_OBJECT) { - strcat(content, "{"); if (rliza->key) { strcat(content, "\""); strcat(content, rliza->key); strcat(content, "\":{"); } - // bool add_braces = false; for (unsigned i = 0; i < rliza->count; i++) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; @@ -2799,7 +2893,6 @@ char *rliza_dumps(rliza_t *rliza) { } if (content[strlen(content) - 1] == ',') { content[strlen(content) - 1] = '\0'; - if (rliza->key) { strcat(content, "}"); } @@ -2821,8 +2914,6 @@ char *rliza_dumps(rliza_t *rliza) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; if (*content_chunk_stripped == '{') { - // content_chunk_stripped++; - // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; } if (strlen(content_chunk_stripped) + strlen(content) > size) { size += strlen(content_chunk_stripped) + 20; @@ -2836,7 +2927,6 @@ char *rliza_dumps(rliza_t *rliza) { content[strlen(content) - 1] = 0; strcat(content, "]"); } else if (rliza->type == RLIZA_NULL) { - if (rliza->key) { char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); rstraddslashes((char *)rliza->key, escaped_key); @@ -2871,15 +2961,65 @@ int rliza_validate(char *json_content) { #endif +// Written by retoor@molodetz.nl + +// This code provides a console utility for performing code coverage analysis on a specified C source file using lcov and genhtml. It checks +// for lcov installation, compiles the source file with coverage options, runs it, and generates an HTML report. + +// The code uses lcov and genhtml for coverage analysis and viewing, google-chrome for displaying the HTML report, and it requires gcc for +// compilation. + +// MIT License + #ifndef RCOV_H #define RCOV_H + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +/* Written by retoor@molodetz.nl */ + +/* This source code defines a benchmarking utility for measuring the execution time of functions in C. It provides functionalities for + * adding, resetting, and executing functions multiple times while tracking their execution time. The code also includes progress tracking + * and functions for executing with varying numbers of arguments. */ + +/* Dependencies not part of the language itself: + - These likely include custom headers such as "rprint.h", "rtime.h", "rstring.h", and "rterminal.h" +*/ + +/* +MIT License + +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 RBENCH_H #define RBENCH_H +// Written by retoor@molodetz.nl + +// This source code provides a custom printing library for formatted output with optional color effects. It implements functions to print +// strings with various color enhancements and control codes for terminal manipulation. + +// Includes: The code uses a custom header "rtime.h" to work with time-related functions. + +// MIT License: 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 RPRINT_H #define RPRINT_H @@ -3052,109 +3192,94 @@ bool rprint_is_color_enabled() { } 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; } 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 = false; bool press_any_key = false; char new_format[4096]; bool enable_color = rprint_is_color_enabled(); - memset(new_format, 0, 4096); + + memset(new_format, 0, sizeof(new_format)); 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); + memset(temp, 0, sizeof(temp)); + + if (enable_color && prefix[0]) { + strcat(new_format, prefix); + new_format_length += strlen(prefix); reset_color = true; } - while (true) { - if (pformat[0] == '\\' && pformat[1] == 'i') { + + while (*format) { + if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 'C') { press_any_key = true; rpline_number++; - pformat++; - pformat++; + format += 2; reset_color = false; - } else if (pformat[0] == '\\' && pformat[1] == 'k') { + } else if (format[0] == '\\' && format[1] == 'k') { press_any_key = true; rpline_number++; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'c') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 't') { rprtime = nsecs(); - pformat++; - pformat++; + format += 2; } else { - new_format[new_format_length] = *pformat; - new_format_length++; - if (!*pformat) - break; - - // printf("%c",*pformat); - pformat++; + new_format[new_format_length++] = *format++; } } + if (reset_color) { strcat(new_format, "\e[0m"); new_format_length += strlen("\e[0m"); } - new_format[new_format_length] = 0; + new_format[new_format_length] = '\0'; vfprintf(f, new_format, args); fflush(stdout); @@ -3178,21 +3303,23 @@ void rprintf(FILE *f, const char *format, ...) { rprintpf(f, "", format, args); va_end(args); } + void rprint(const 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, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\\l", format, args); va_end(args); } + void rprintl(const char *format, ...) { va_list args; va_start(args, format); @@ -3200,13 +3327,13 @@ void rprintl(const char *format, ...) { va_end(args); } -// Black void rprintkf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[30m", format, args); va_end(args); } + void rprintk(const char *format, ...) { va_list args; va_start(args, format); @@ -3214,13 +3341,13 @@ void rprintk(const char *format, ...) { va_end(args); } -// Red void rprintrf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[31m", format, args); va_end(args); } + void rprintr(const char *format, ...) { va_list args; va_start(args, format); @@ -3228,13 +3355,13 @@ void rprintr(const char *format, ...) { va_end(args); } -// Green void rprintgf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[32m", format, args); va_end(args); } + void rprintg(const char *format, ...) { va_list args; va_start(args, format); @@ -3242,13 +3369,13 @@ void rprintg(const char *format, ...) { va_end(args); } -// Yellow void rprintyf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[33m", format, args); va_end(args); } + void rprinty(const char *format, ...) { va_list args; va_start(args, format); @@ -3256,7 +3383,6 @@ void rprinty(const char *format, ...) { va_end(args); } -// Blue void rprintbf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); @@ -3271,13 +3397,13 @@ void rprintb(const char *format, ...) { va_end(args); } -// Magenta void rprintmf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[35m", format, args); va_end(args); } + void rprintm(const char *format, ...) { va_list args; va_start(args, format); @@ -3285,13 +3411,13 @@ void rprintm(const char *format, ...) { va_end(args); } -// Cyan void rprintcf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[36m", format, args); va_end(args); } + void rprintc(const char *format, ...) { va_list args; va_start(args, format); @@ -3299,13 +3425,13 @@ void rprintc(const char *format, ...) { va_end(args); } -// White void rprintwf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[37m", format, args); va_end(args); } + void rprintw(const char *format, ...) { va_list args; va_start(args, format); @@ -3313,6 +3439,7 @@ void rprintw(const char *format, ...) { va_end(args); } #endif + #include <errno.h> #include <stdbool.h> #include <stdint.h> @@ -3321,7 +3448,6 @@ void rprintw(const char *format, ...) { #include <string.h> #include <sys/time.h> #include <time.h> - #ifndef RLIB_TERMINAL_H #define RLIB_TERMINAL_H @@ -3331,6 +3457,16 @@ void rprintw(const char *format, ...) { #include <string.h> #ifndef RTEST_H #define RTEST_H +// Written by retoor@molodetz.nl + +// This header file defines a structure `remo_t` used to store emoji representations and their descriptions. It includes functions to +// convert strings to lowercase, search for substrings case insensitively, print all emojis with their descriptions, and retrieve an emoji +// by its description. + +// No third-party imports or includes are used outside the language's standard library. + +// MIT License + #ifndef REMO_H #define REMO_H #include <ctype.h> @@ -3343,206 +3479,169 @@ typedef struct { const char *description; } remo_t; -remo_t remo[] = { - {"\U0001F600", "Grinning Face"}, // 😀 - {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 - {"\U0001F602", "Face with Tears of Joy"}, // 😂 - {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 - {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 - {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 - {"\U0001F609", "Winking Face"}, // 😉 - {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 - {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 - {"\U0001F618", "Face Blowing a Kiss"}, // 😘 - {"\U0001F617", "Kissing Face"}, // 😗 - {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 - {"\U0001F642", "Slightly Smiling Face"}, // 🙂 - {"\U0001F643", "Upside-Down Face"}, // 🙃 - {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 - {"\U0001F60B", "Face Savoring Food"}, // 😋 - {"\U0001F61B", "Face with Tongue"}, // 😛 - {"\U0001F61C", "Winking Face with Tongue"}, // 😜 - {"\U0001F92A", "Zany Face"}, // 🤪 - {"\U0001F929", "Star-Struck"}, // 🤩 - {"\U0001F631", "Face Screaming in Fear"}, // 😱 - {"\U0001F62D", "Loudly Crying Face"}, // 😭 - {"\U0001F624", "Face with Steam From Nose"}, // 😤 - {"\U0001F620", "Angry Face"}, // 😠 - {"\U0001F621", "Pouting Face"}, // 😡 - {"\U0001F47B", "Ghost"}, // 👻 - {"\U0001F480", "Skull"}, // 💀 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - {"\U0001F47D", "Alien"}, // 👽 - // Geometric Shapes - {"\U000025A0", "Black Square"}, // ■ - {"\U000025B2", "Upward Triangle"}, // ▲ - {"\U000025CF", "Black Circle"}, // ● - {"\U000025CB", "White Circle"}, // ○ - {"\U00002B1B", "Large Black Square"}, // ⬛ - {"\U00002B1C", "Large White Square"}, // ⬜ - - // Mathematical Symbols - {"\U00002200", "For All"}, // ∀ - {"\U00002203", "Exists"}, // ∃ - {"\U00002205", "Empty Set"}, // ∅ - {"\U00002207", "Nabla"}, // ∇ - {"\U0000220F", "N-Ary Product"}, // ∏ - {"\U00002212", "Minus Sign"}, // − - {"\U0000221E", "Infinity"}, // ∞ - - // Arrows - {"\U00002190", "Left Arrow"}, // ← - {"\U00002191", "Up Arrow"}, // ↑ - {"\U00002192", "Right Arrow"}, // → - {"\U00002193", "Down Arrow"}, // ↓ - {"\U00002195", "Up Down Arrow"}, // ↕ - {"\U00002197", "Up Right Arrow"}, // ↗ - {"\U00002198", "Down Right Arrow"}, // ↘ - {"\U000027A1", "Black Right Arrow"}, // ➡️ - - // Dingbats - {"\U00002714", "Check Mark"}, // ✔️ - {"\U00002716", "Heavy Multiplication X"}, // ✖️ - {"\U00002728", "Sparkles"}, // ✨ - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002795", "Heavy Plus Sign"}, // ➕ - - // Miscellaneous Symbols - {"\U00002600", "Sun"}, // ☀️ - {"\U00002614", "Umbrella with Rain Drops"}, // ☔ - {"\U00002620", "Skull and Crossbones"}, // ☠️ - {"\U000026A0", "Warning Sign"}, // ⚠️ - {"\U000026BD", "Soccer Ball"}, // ⚽ - {"\U000026C4", "Snowman"}, // ⛄ - - // Stars and Asterisks - {"\U00002733", "Eight Pointed Black Star"}, // ✳️ - {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U00002728", "Sparkles"}, // ✨ - // Animals and Nature - {"\U0001F98A", "Fox"}, // 🦊 - {"\U0001F415", "Dog"}, // 🐕 - {"\U0001F431", "Cat Face"}, // 🐱 - {"\U0001F435", "Monkey Face"}, // 🐵 - {"\U0001F408", "Black Cat"}, // 🐈 - {"\U0001F98C", "Deer"}, // 🦌 - {"\U0001F344", "Mushroom"}, // 🍄 - {"\U0001F333", "Tree"}, // 🌳 - - // Weather and Space Symbols - {"\U0001F308", "Rainbow"}, // 🌈 - {"\U0001F320", "Shooting Star"}, // 🌠 - {"\U00002600", "Sun"}, // ☀️ - {"\U00002601", "Cloud"}, // ☁️ - {"\U000026A1", "High Voltage"}, // ⚡ - {"\U0001F525", "Fire"}, // 🔥 - {"\U000026C4", "Snowman"}, // ⛄ - {"\U0001F30A", "Water Wave"}, // 🌊 - - // Transport and Map Symbols - {"\U0001F68C", "Bus"}, // 🚌 - {"\U0001F697", "Car"}, // 🚗 - {"\U0001F6B2", "Bicycle"}, // 🚲 - {"\U0001F6A2", "Ship"}, // 🚢 - {"\U0001F681", "Helicopter"}, // 🚁 - {"\U0001F680", "Rocket"}, // 🚀 - {"\U0001F6EB", "Airplane"}, // 🛫 - - // Currency Symbols - {"\U00000024", "Dollar Sign"}, // $ - {"\U000000A3", "Pound Sign"}, // £ - {"\U000000A5", "Yen Sign"}, // ¥ - {"\U000020AC", "Euro Sign"}, // € - {"\U0001F4B5", "Dollar Banknote"}, // 💵 - {"\U0001F4B4", "Yen Banknote"}, // 💴 - - // Card Suits - {"\U00002660", "Black Spade Suit"}, // ♠️ - {"\U00002663", "Black Club Suit"}, // ♣️ - {"\U00002665", "Black Heart Suit"}, // ♥️ - {"\U00002666", "Black Diamond Suit"}, // ♦️ - {"\U0001F0CF", "Joker Card"}, // 🃏 - - // Office Supplies and Objects - {"\U0001F4DA", "Books"}, // 📚 - {"\U0001F4D7", "Green Book"}, // 📗 - {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 - {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 - {"\U0001F4B0", "Money Bag"}, // 💰 - {"\U0001F4B8", "Money with Wings"}, // 💸 - {"\U0001F4E6", "Package"}, // 📦 - - // Miscellaneous Symbols - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U00002714", "Check Mark"}, // ✔️ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002705", "Check Mark Button"}, // ✅ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U0001F4A1", "Light Bulb"}, // 💡 - {"\U0001F4A3", "Bomb"}, // 💣 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - // Musical Symbols - {"\U0001F3B5", "Musical Note"}, // 🎵 - {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 - {"\U0001F3BC", "Musical Score"}, // 🎼 - {"\U0001F399", "Studio Microphone"}, // 🎙️ - {"\U0001F3A4", "Microphone"}, // 🎤 - - // Food and Drink - {"\U0001F35F", "Cheese Wedge"}, // 🧀 - {"\U0001F355", "Slice of Pizza"}, // 🍕 - {"\U0001F32D", "Taco"}, // 🌮 - {"\U0001F37D", "Beer Mug"}, // 🍻 - {"\U0001F96B", "Cup with Straw"}, // 🥤 - {"\U0001F32E", "Hot Pepper"}, // 🌶️ - {"\U0001F95A", "Potato"}, // 🥔 - - // Zodiac Signs - {"\U00002600", "Aries"}, // ♈ - {"\U00002601", "Taurus"}, // ♉ - {"\U00002602", "Gemini"}, // ♊ - {"\U00002603", "Cancer"}, // ♋ - {"\U00002604", "Leo"}, // ♌ - {"\U00002605", "Virgo"}, // ♍ - {"\U00002606", "Libra"}, // ♎ - {"\U00002607", "Scorpio"}, // ♏ - {"\U00002608", "Sagittarius"}, // ♐ - {"\U00002609", "Capricorn"}, // ♑ - {"\U0000260A", "Aquarius"}, // ♒ - {"\U0000260B", "Pisces"}, // ♓ - - // Miscellaneous Shapes - {"\U0001F4C8", "Chart Increasing"}, // 📈 - {"\U0001F4C9", "Chart Decreasing"}, // 📉 - {"\U0001F4CA", "Bar Chart"}, // 📊 - {"\U0001F7E6", "Orange Circle"}, // 🟠 - {"\U0001F7E7", "Yellow Circle"}, // 🟡 - {"\U0001F7E8", "Green Circle"}, // 🟢 - {"\U0001F7E9", "Blue Circle"}, // 🔵 - {"\U0001F7EA", "Purple Circle"}, // 🟣 - - // Flags - {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 - {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 - {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 - {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 - {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 - {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 - {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 - - // Additional Miscellaneous Symbols - {"\U0001F4A5", "Collision"}, // 💥 - {"\U0001F4A6", "Sweat Droplets"}, // 💦 - {"\U0001F4A8", "Dashing Away"}, // 💨 - {"\U0001F50B", "Battery"}, // 🔋 - {"\U0001F4BB", "Laptop Computer"}, // 💻 - {"\U0001F4DE", "Telephone"}, // 📞 - {"\U0001F4E7", "Incoming Envelope"}, // 📧 -}; +remo_t remo[] = {{"\U0001F600", "Grinning Face"}, + {"\U0001F601", "Beaming Face with Smiling Eyes"}, + {"\U0001F602", "Face with Tears of Joy"}, + {"\U0001F923", "Rolling on the Floor Laughing"}, + {"\U0001F603", "Grinning Face with Big Eyes"}, + {"\U0001F604", "Grinning Face with Smiling Eyes"}, + {"\U0001F609", "Winking Face"}, + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, + {"\U0001F618", "Face Blowing a Kiss"}, + {"\U0001F617", "Kissing Face"}, + {"\U0001F61A", "Kissing Face with Closed Eyes"}, + {"\U0001F642", "Slightly Smiling Face"}, + {"\U0001F643", "Upside-Down Face"}, + {"\U0001F970", "Smiling Face with Hearts"}, + {"\U0001F60B", "Face Savoring Food"}, + {"\U0001F61B", "Face with Tongue"}, + {"\U0001F61C", "Winking Face with Tongue"}, + {"\U0001F92A", "Zany Face"}, + {"\U0001F929", "Star-Struck"}, + {"\U0001F631", "Face Screaming in Fear"}, + {"\U0001F62D", "Loudly Crying Face"}, + {"\U0001F624", "Face with Steam From Nose"}, + {"\U0001F620", "Angry Face"}, + {"\U0001F621", "Pouting Face"}, + {"\U0001F47B", "Ghost"}, + {"\U0001F480", "Skull"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F47D", "Alien"}, + {"\U000025A0", "Black Square"}, + {"\U000025B2", "Upward Triangle"}, + {"\U000025CF", "Black Circle"}, + {"\U000025CB", "White Circle"}, + {"\U00002B1B", "Large Black Square"}, + {"\U00002B1C", "Large White Square"}, + {"\U00002200", "For All"}, + {"\U00002203", "Exists"}, + {"\U00002205", "Empty Set"}, + {"\U00002207", "Nabla"}, + {"\U0000220F", "N-Ary Product"}, + {"\U00002212", "Minus Sign"}, + {"\U0000221E", "Infinity"}, + {"\U00002190", "Left Arrow"}, + {"\U00002191", "Up Arrow"}, + {"\U00002192", "Right Arrow"}, + {"\U00002193", "Down Arrow"}, + {"\U00002195", "Up Down Arrow"}, + {"\U00002197", "Up Right Arrow"}, + {"\U00002198", "Down Right Arrow"}, + {"\U000027A1", "Black Right Arrow"}, + {"\U00002714", "Check Mark"}, + {"\U00002716", "Heavy Multiplication X"}, + {"\U00002728", "Sparkles"}, + {"\U00002757", "Exclamation Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002795", "Heavy Plus Sign"}, + {"\U00002600", "Sun"}, + {"\U00002614", "Umbrella with Rain Drops"}, + {"\U00002620", "Skull and Crossbones"}, + {"\U000026A0", "Warning Sign"}, + {"\U000026BD", "Soccer Ball"}, + {"\U000026C4", "Snowman"}, + {"\U00002733", "Eight Pointed Black Star"}, + {"\U00002734", "Eight Spoked Asterisk"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U00002728", "Sparkles"}, + {"\U0001F98A", "Fox"}, + {"\U0001F415", "Dog"}, + {"\U0001F431", "Cat Face"}, + {"\U0001F435", "Monkey Face"}, + {"\U0001F408", "Black Cat"}, + {"\U0001F98C", "Deer"}, + {"\U0001F344", "Mushroom"}, + {"\U0001F333", "Tree"}, + {"\U0001F308", "Rainbow"}, + {"\U0001F320", "Shooting Star"}, + {"\U00002600", "Sun"}, + {"\U00002601", "Cloud"}, + {"\U000026A1", "High Voltage"}, + {"\U0001F525", "Fire"}, + {"\U000026C4", "Snowman"}, + {"\U0001F30A", "Water Wave"}, + {"\U0001F68C", "Bus"}, + {"\U0001F697", "Car"}, + {"\U0001F6B2", "Bicycle"}, + {"\U0001F6A2", "Ship"}, + {"\U0001F681", "Helicopter"}, + {"\U0001F680", "Rocket"}, + {"\U0001F6EB", "Airplane"}, + {"\U00000024", "Dollar Sign"}, + {"\U000000A3", "Pound Sign"}, + {"\U000000A5", "Yen Sign"}, + {"\U000020AC", "Euro Sign"}, + {"\U0001F4B5", "Dollar Banknote"}, + {"\U0001F4B4", "Yen Banknote"}, + {"\U00002660", "Black Spade Suit"}, + {"\U00002663", "Black Club Suit"}, + {"\U00002665", "Black Heart Suit"}, + {"\U00002666", "Black Diamond Suit"}, + {"\U0001F0CF", "Joker Card"}, + {"\U0001F4DA", "Books"}, + {"\U0001F4D7", "Green Book"}, + {"\U0001F4C8", "Chart with Upwards Trend"}, + {"\U0001F4C9", "Chart with Downwards Trend"}, + {"\U0001F4B0", "Money Bag"}, + {"\U0001F4B8", "Money with Wings"}, + {"\U0001F4E6", "Package"}, + {"\U00002757", "Exclamation Mark"}, + {"\U00002714", "Check Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002705", "Check Mark Button"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U0001F4A1", "Light Bulb"}, + {"\U0001F4A3", "Bomb"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F3B5", "Musical Note"}, + {"\U0001F3B6", "Multiple Musical Notes"}, + {"\U0001F3BC", "Musical Score"}, + {"\U0001F399", "Studio Microphone"}, + {"\U0001F3A4", "Microphone"}, + {"\U0001F35F", "Cheese Wedge"}, + {"\U0001F355", "Slice of Pizza"}, + {"\U0001F32D", "Taco"}, + {"\U0001F37D", "Beer Mug"}, + {"\U0001F96B", "Cup with Straw"}, + {"\U0001F32E", "Hot Pepper"}, + {"\U0001F95A", "Potato"}, + {"\U00002600", "Aries"}, + {"\U00002601", "Taurus"}, + {"\U00002602", "Gemini"}, + {"\U00002603", "Cancer"}, + {"\U00002604", "Leo"}, + {"\U00002605", "Virgo"}, + {"\U00002606", "Libra"}, + {"\U00002607", "Scorpio"}, + {"\U00002608", "Sagittarius"}, + {"\U00002609", "Capricorn"}, + {"\U0000260A", "Aquarius"}, + {"\U0000260B", "Pisces"}, + {"\U0001F4C8", "Chart Increasing"}, + {"\U0001F4C9", "Chart Decreasing"}, + {"\U0001F4CA", "Bar Chart"}, + {"\U0001F7E6", "Orange Circle"}, + {"\U0001F7E7", "Yellow Circle"}, + {"\U0001F7E8", "Green Circle"}, + {"\U0001F7E9", "Blue Circle"}, + {"\U0001F7EA", "Purple Circle"}, + {"\U0001F1E6\U0001F1E9", "Flag of France"}, + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, + {"\U0001F4A5", "Collision"}, + {"\U0001F4A6", "Sweat Droplets"}, + {"\U0001F4A8", "Dashing Away"}, + {"\U0001F50B", "Battery"}, + {"\U0001F4BB", "Laptop Computer"}, + {"\U0001F4DE", "Telephone"}, + {"\U0001F4E7", "Incoming Envelope"}}; size_t remo_count = sizeof(remo) / sizeof(remo[0]); void rstrtolower(const char *input, char *output) { @@ -3553,16 +3652,16 @@ void rstrtolower(const char *input, char *output) { } *output = 0; } + bool rstrinstr(const char *haystack, const char *needle) { char lower1[strlen(haystack) + 1]; char lower2[strlen(needle) + 1]; rstrtolower(haystack, lower1); rstrtolower(needle, lower2); - return strstr(lower1, lower2) ? true : false; + return strstr(lower1, lower2) != NULL; } void remo_print() { - for (size_t i = 0; i < remo_count; i++) { printf("%s - %s\n", remo[i].str, remo[i].description); } @@ -3905,7 +4004,6 @@ void rlib_test_progressbar() { if (percentage_changed) { \ printf("\r%d%%", percentage); \ fflush(stdout); \ - \ prev_percentage = percentage; \ } \ } \ @@ -3929,7 +4027,6 @@ typedef struct rbench_function_t { bool last; int argc; unsigned long times_executed; - nsecs_t average_execution_time; nsecs_t total_execution_time; } rbench_function_t; @@ -3955,7 +4052,6 @@ typedef struct rbench_t { 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; @@ -3963,23 +4059,18 @@ FILE *_rbench_stdnull = NULL; void rbench_toggle_stdout(rbench_t *r) { if (!r->stdout) { - if (_rbench_stdout == NULL) { + if (!_rbench_stdout) { _rbench_stdout = stdout; } - if (_rbench_stdnull == NULL) { + if (!_rbench_stdnull) { _rbench_stdnull = fopen("/dev/null", "wb"); } - if (stdout == _rbench_stdout) { - stdout = _rbench_stdnull; - } else { - stdout = _rbench_stdout; - } + stdout = (stdout == _rbench_stdout) ? _rbench_stdnull : _rbench_stdout; } } + void rbench_restore_stdout(rbench_t *r) { - if (r->stdout) - return; - if (_rbench_stdout) { + if (!r->stdout && _rbench_stdout) { stdout = _rbench_stdout; } if (_rbench_stdnull) { @@ -3992,8 +4083,9 @@ rbench_t *rbench_new(); rbench_t *_rbench = NULL; rbench_function_t *rbf; + rbench_t *rbench() { - if (_rbench == NULL) { + if (!_rbench) { _rbench = rbench_new(); } return _rbench; @@ -4009,8 +4101,7 @@ void rbench_add_function(rbench_t *rp, const char *name, const char *group, void #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++; + rbench_function_t *f = &rp->functions[rp->function_count++]; f->average_execution_time = 0; f->total_execution_time = 0; f->times_executed = 0; @@ -4026,47 +4117,42 @@ void rbench_reset_function(rbench_function_t *f) { } void rbench_reset(rbench_t *rp) { - for (unsigned int i = 0; i < rp->function_count; i++) { + for (unsigned int i = 0; i < rp->function_count; ++i) { rbench_reset_function(&rp->functions[i]); } } + 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) { + for (unsigned int i = 0; i < r->function_count; ++i) { + if (!time || 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; -} + +bool rbench_was_last_function(rbench_t *r) { return r->current == &r->functions[r->function_count - 1]; } rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, int argc) { rbench_toggle_stdout(r); - if (findex == 0) { + if (!findex) { r->execution_time = 0; } rbench_function_t *rf = &r->functions[findex]; rf->argc = argc; rbf = rf; r->current = rf; - if (r->show_progress) + 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); if (r->progress_bar) { @@ -4074,42 +4160,35 @@ void rbench_execute_finish(rbench_t *r) { 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) + if (!r->silent) { rprintgf(stderr, "Benchmark results:\n"); + } nsecs_t total_time = 0; - - for (unsigned int i = 0; i < r->function_count; i++) { + 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 (is_winner && !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) + if (!r->silent) { rprintgf(stderr, "Total execution time: %s\n", format_time(total_time)); + } } rbench_restore_stdout(r); rbf = NULL; r->current = NULL; } + struct rbench_t *rbench_execute(rbench_t *r, long times) { - - for (unsigned int i = 0; i < r->function_count; i++) { - + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); rbench_call c = (rbench_call)f->call; nsecs_t start = nsecs(); @@ -4118,7 +4197,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4134,8 +4213,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { } struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -4144,7 +4222,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4160,8 +4238,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { } struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -4170,7 +4247,7 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4186,10 +4263,8 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 } struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { - - for (unsigned int i = 0; i < r->function_count; i++) { + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); - rbench_call3 c = (rbench_call3)f->call; nsecs_t start = nsecs(); f->first = true; @@ -4197,7 +4272,7 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2, arg3); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4212,7 +4287,6 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 } 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; @@ -4227,13 +4301,14 @@ rbench_t *rbench_new() { r->show_progress = true; return r; } + void rbench_free(rbench_t *r) { free(r); } #endif + bool check_lcov() { char buffer[1024 * 64]; - FILE *fp; - fp = popen("lcov --help", "r"); + FILE *fp = popen("lcov --help", "r"); if (fp == NULL) { return false; } @@ -4255,7 +4330,6 @@ int rcov_main(int argc, char *argv[]) { strcat(argstr, " "); } if (!check_lcov()) { - printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); return 1; } @@ -4269,22 +4343,19 @@ int rcov_main(int argc, char *argv[]) { "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", "rm -f *.gcda 2>/dev/null", "rm -f *.gcno 2>/dev/null", - "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", - + "rm -f %s.coverage.info 2>/dev/null", "gprof %s_coverage.o gmon.out > output.rcov_analysis", - "rm -f gmon.out", "cat output.rcov_analysis", "rm output.rcov_analysis", "rm -f %s_coverage.o", - "google-chrome /tmp/%s.coverage/index.html"}; uint command_count = sizeof(commands) / sizeof(commands[0]); - RBENCH(1,{ + RBENCH(1, { for (uint i = 0; i < command_count; i++) { char *formatted_command = sbuf(""); sprintf(formatted_command, commands[i], source_file, source_file); - // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { strcat(formatted_command, " "); strcat(formatted_command, argstr); @@ -4293,14 +4364,45 @@ int rcov_main(int argc, char *argv[]) { if (system(formatted_command)) { printf("`%s` returned non-zero code.\n", formatted_command); } - }); - } + } + }); return 0; } + #endif +// Written by retoor@molodetz.nl + +// This code implements an HTTP server that can handle multiple connections, parse HTTP requests, log request information, and respond to +// different request types (including file and counter requests). + +// Include summary: +// This code includes custom headers ("rio.h", "rmalloc.h", "rstring.h", "rtemp.h", "rtime.h") and libraries ("arpa/inet.h", "pthread.h", +// "signal.h", "stdarg.h", "stdbool.h", "stdio.h", "stdlib.h", "string.h", "time.h", "unistd.h") that provide functionality for networking, +// threading, signal handling, and I/O operations. + +// The MIT License (MIT) + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. #ifndef RHTTP_H #define RHTTP_H + #include <arpa/inet.h> #include <pthread.h> #include <signal.h> @@ -4368,6 +4470,7 @@ void rhttp_logs(const char *prefix, const char *level, const char *format, va_li sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); vfprintf(stdout, buf, args); } + void rhttp_log_info(const char *format, ...) { if (!rhttp_opt_info) return; @@ -4376,6 +4479,7 @@ void rhttp_log_info(const char *format, ...) { rhttp_logs("\e[32m", "INFO ", format, args); va_end(args); } + void rhttp_log_debug(const char *format, ...) { if (!rhttp_opt_debug) return; @@ -4386,6 +4490,7 @@ void rhttp_log_debug(const char *format, ...) { va_end(args); } + void rhttp_log_warn(const char *format, ...) { if (!rhttp_opt_warn) return; @@ -4395,6 +4500,7 @@ void rhttp_log_warn(const char *format, ...) { va_end(args); } + void rhttp_log_error(const char *format, ...) { if (!rhttp_opt_error) return; @@ -4428,6 +4534,7 @@ void rhttp_free_header(rhttp_header_t *h) { if (next) rhttp_free_header(next); } + void rhttp_rhttp_free_headers(rhttp_request_t *r) { if (!r->headers) return; @@ -4488,6 +4595,7 @@ long rhttp_header_get_long(rhttp_request_t *r, const char *name) { } return -1; } + char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { rhttp_header_t *h = r->headers; while (h) { @@ -4499,18 +4607,22 @@ char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { } void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } + void rhttp_print_headers(rhttp_header_t *h) { while (h) { rhttp_print_header(h); h = h->next; } } + void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } + void rhttp_print_request(rhttp_request_t *r) { rhttp_print_request_line(r); if (rhttp_opt_debug) rhttp_print_headers(r->headers); } + void rhttp_close(rhttp_request_t *r) { if (!r) return; @@ -4518,6 +4630,7 @@ void rhttp_close(rhttp_request_t *r) { close(r->c); rhttp_free_request(r); } + rhttp_request_t *rhttp_parse_request(int s) { rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); http_request_init(request); @@ -4585,7 +4698,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { unsigned char *to_send_original = to_send; memcpy(to_send, tsend, to_send_len); - // to_send[to_send_len] = '\0'; long bytes_sent = 0; long bytes_sent_total = 0; while (1) { @@ -4600,7 +4712,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { break; } else if (!bytes_sent) { bytes_sent_total = 0; - // error break; } else { rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); @@ -4647,7 +4758,6 @@ void rhttp_serve(const char *host, int port, int backlog, int request_logging, i } if (!r->keep_alive && !r->closed) { rhttp_close(r); - } else if (r->keep_alive && !r->closed) { } if (r->closed) { break; @@ -4700,7 +4810,7 @@ int rhttp_file_response(rhttp_request_t *r, char *path) { close(r->c); fclose(f); return 1; -}; +} int rhttp_file_request_handler(rhttp_request_t *r) { char *path = r->path; @@ -4710,9 +4820,10 @@ int rhttp_file_request_handler(rhttp_request_t *r) { return 0; } return rhttp_file_response(r, path); -}; +} unsigned int counter = 100000000; + int rhttp_counter_request_handler(rhttp_request_t *r) { if (!strncmp(r->path, "/counter", strlen("/counter"))) { counter++; @@ -4728,6 +4839,7 @@ int rhttp_counter_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_root_request_handler(rhttp_request_t *r) { if (!strcmp(r->path, "/")) { char to_send[1024] = {0}; @@ -4739,6 +4851,7 @@ int rhttp_root_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_error_404_handler(rhttp_request_t *r) { char to_send[1024] = {0}; sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " @@ -4752,17 +4865,14 @@ int rhttp_default_request_handler(rhttp_request_t *r) { if (rhttp_opt_debug || rhttp_opt_request_logging) rhttp_print_request(r); if (rhttp_counter_request_handler(r)) { - // Counter handler rhttp_log_info("Counter handler found for: %s\n", r->path); } else if (rhttp_root_request_handler(r)) { - // Root handler rhttp_log_info("Root handler found for: %s\n", r->path); } else if (rhttp_file_request_handler(r)) { rhttp_log_info("File %s sent\n", r->path); } else if (rhttp_error_404_handler(r)) { rhttp_log_warn("Error 404 for: %s\n", r->path); - // Error handler } else { rhttp_log_warn("No handler found for: %s\n", r->path); close(rhttp_c); @@ -4826,8 +4936,6 @@ int rhttp_main(int argc, char *argv[]) { return 0; } -/* CLIENT CODE */ - typedef struct rhttp_client_request_t { char *host; int port; @@ -4884,12 +4992,14 @@ int rhttp_execute_request(rhttp_client_request_t *r) { close(s); return ret; } + void rhttp_reset_request(rhttp_client_request_t *r) { free(r->response); r->is_done = false; r->response = NULL; r->bytes_received = 0; } + void rhttp_free_client_request(rhttp_client_request_t *r) { if (r->request) free(r->request); @@ -4905,7 +5015,6 @@ void rhttp_free_client_request(rhttp_client_request_t *r) { void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { rhttp_client_request_t *requests[workers]; while (times > 0) { - for (int i = 0; i < workers && times; i++) { requests[i] = rhttp_create_request(host, port, path); rhttp_execute_request(requests[i]); @@ -4913,6 +5022,7 @@ void rhttp_client_bench(int workers, int times, const char *host, int port, cons } } } + char *rhttp_client_get(const char *host, int port, const char *path) { if (!rhttp_c_mutex_initialized) { rhttp_c_mutex_initialized = 1; @@ -4927,7 +5037,7 @@ char *rhttp_client_get(const char *host, int port, const char *path) { reconnects++; tick(); if (reconnects == reconnects_max) { - fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + fprintf(stderr, "Maximum reconnects exceeded for %s:%d\n", host, port); rhttp_free_client_request(r); return NULL; } @@ -4945,8 +5055,18 @@ char *rhttp_client_get(const char *host, int port, const char *path) { pthread_mutex_unlock(&rhttp_c_mutex); return result; } -/*END CLIENT CODE */ + #endif +// Written by retoor@molodetz.nl + +// A C library for creating and manipulating JSON structures. It provides functions to build JSON strings recursively, including starting +// and closing JSON objects and arrays, adding key-value pairs (for strings, integers, numbers, booleans, and durations), and freeing JSON +// objects. + +// Includes for memory management, string manipulation, time handling, and testing utilities: rmalloc.h, rtypes.h, rstring.h, rtemp.h, +// rtime.h, rtest.h + +// MIT License #ifndef RJSON_H #define RJSON_H @@ -4961,7 +5081,7 @@ rjson_t *rjson() { rjson_t *json = rmalloc(sizeof(rjson_t)); json->size = 1024; json->length = 0; - json->content = (char *)rmalloc(json->size); + json->content = rmalloc(json->size); json->content[0] = 0; return json; } @@ -4977,10 +5097,12 @@ void rjson_write(rjson_t *rjs, char *content) { } void rjson_object_start(rjson_t *rjs) { - if (rstrendswith(rjs->content, "}")) + if (rstrendswith(rjs->content, "}")) { rjson_write(rjs, ","); + } rjson_write(rjs, "{"); } + void rjson_object_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -4988,11 +5110,14 @@ void rjson_object_close(rjson_t *rjs) { } rjson_write(rjs, "}"); } + void rjson_array_start(rjson_t *rjs) { - if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) { rjson_write(rjs, ","); + } rjson_write(rjs, "["); } + void rjson_array_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -5008,7 +5133,7 @@ void rjson_kv_string(rjson_t *rjs, char *key, char *value) { rjson_write(rjs, "\""); rjson_write(rjs, key); rjson_write(rjs, "\":\""); - char *value_str = (char *)rmalloc(strlen(value) + 4096); + char *value_str = rmalloc(strlen(value) + 4096); rstraddslashes(value, value_str); rjson_write(rjs, value_str); free(value_str); @@ -5026,15 +5151,14 @@ void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { sprintf(value_str, "%lld", value); rjson_write(rjs, value_str); } + void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { rjson_write(rjs, ","); } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(rformat_number(value))); rjson_write(rjs, "\""); } @@ -5055,12 +5179,11 @@ void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(format_time(value))); rjson_write(rjs, "\""); } + void rjson_free(rjson_t *rsj) { free(rsj->content); free(rsj); @@ -5071,10 +5194,38 @@ void rjson_key(rjson_t *rsj, char *key) { rjson_write(rsj, key); rjson_write(rsj, "\":"); } + #endif +// Written by retoor@molodetz.nl + +// This source code provides a simple autocomplete functionality by leveraging string list management and pattern matching with escaping +// characters where necessary. + +// No external imports or includes other than basic string operations and standard library functions are used in the source code. + +// MIT License +// +// 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 RAUTOCOMPLETE_H #define RAUTOCOMPLETE_H -#define R4_DEBUG + #ifndef RREX4_H #define RREX4_H #include <assert.h> @@ -5842,7 +5993,7 @@ bool r4_match(char *str, char *expr) { char *r4_escape(char *content) { size_t size = strlen(content) * 2 + 1; - char *escaped = (char *)calloc(size, sizeof(char)); + char *escaped = calloc(size, sizeof(char)); char *espr = escaped; char *to_escape = "?*+()[]{}^$\\"; *espr = '('; @@ -5867,22 +6018,19 @@ char *r4_escape(char *content) { } char *rautocomplete_find(rstring_list_t *list, char *expr) { - if (!list->count) - return NULL; - if (!expr || !strlen(expr)) + if (!list->count || !expr || !strlen(expr)) return NULL; char *escaped = r4_escape(expr); - for (unsigned int i = list->count - 1; i == 0; i--) { - char *match; + for (unsigned int i = list->count - 1; i >= 0; i--) { + char *match = NULL; r4_t *r = r4(list->strings[i], escaped); if (r->valid && r->match_count == 1) { match = strdup(r->matches[0]); } r4_free(r); if (match) { - free(escaped); return match; } @@ -5890,6 +6038,7 @@ char *rautocomplete_find(rstring_list_t *list, char *expr) { free(escaped); return NULL; } + #endif #ifndef RKEYTABLE_H #define RKEYTABLE_H @@ -5959,11 +6108,33 @@ rnklist *rkset(char *name, char *defn) { } #endif +// Written by retoor@molodetz.nl + +// This source code provides the implementation of a simple hash table using separate chaining for collision resolution. It contains +// functions to hash, retrieve, and insert entries into the hash table. + +// Imported library: The code uses the non-standard library "rmalloc.h". + +/* MIT License +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 RHASHTABLE_H #define RHASHTABLE_H -/* - ORIGINAL SOURCE IS FROM K&R - */ #include <stdio.h> #include <stdlib.h> @@ -5971,44 +6142,42 @@ rnklist *rkset(char *name, char *defn) { #define HASHSIZE 101 -// Structure for the table entries typedef struct rnlist { struct rnlist *next; char *name; char *defn; } rnlist; -// Hash table array static rnlist *rhashtab[HASHSIZE]; -// Hash function unsigned rhash(char *s) { - unsigned hashval; - for (hashval = 0; *s != '\0'; s++) + unsigned hashval = 0; + while (*s != '\0') { hashval = *s + 31 * hashval; + s++; + } return hashval % HASHSIZE; } rnlist *rlget(char *s) { rnlist *np; - for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) { if (strcmp(s, np->name) == 0) - return np; // Found - return NULL; // Not found + return np; + } + return NULL; } -// Lookup function char *rget(char *s) { rnlist *np = rlget(s); return np ? np->defn : NULL; } -// Install function (adds a name and definition to the table) struct rnlist *rset(char *name, char *defn) { struct rnlist *np = NULL; unsigned hashval; - if ((rlget(name)) == NULL) { // Not found + if ((rlget(name)) == NULL) { np = (struct rnlist *)malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) return NULL; @@ -6016,8 +6185,9 @@ struct rnlist *rset(char *name, char *defn) { np->next = rhashtab[hashval]; rhashtab[hashval] = np; } else { - if (np->defn) - free((void *)np->defn); + if (np->defn) { + free(np->defn); + } np->defn = NULL; } if ((np->defn = strdup(defn)) == NULL) @@ -6025,7 +6195,6 @@ struct rnlist *rset(char *name, char *defn) { return np; } #endif - #ifndef RREX3_H #define RREX3_H #include <assert.h> @@ -7254,6 +7423,16 @@ void rrex3_test() { rrex3_free(rrex); } #endif +// Written by retoor@molodetz.nl + +// This code provides a simple memory arena implementation, which allows dynamic memory allocation within a predefined size. It includes +// functions for constructing a new arena, allocating memory within the arena, resetting, and freeing the arena. + +// The code utilizes rmalloc and rfree for custom memory allocation, which are likely part of another library not defined within the +// standard C library. + +// MIT License + #ifndef RARENA_H #define RARENA_H @@ -7291,7 +7470,6 @@ void *arena_alloc(arena_t *arena, size_t size) { } void arena_free(arena_t *arena) { - // Just constructed and unused arena memory is NULL so no free needed if (arena->memory) { rfree(arena->memory); } @@ -7299,9 +7477,20 @@ void arena_free(arena_t *arena) { } void arena_reset(arena_t *arena) { arena->pointer = 0; } + #endif +// Written by retoor@molodetz.nl + +// This code provides functions to determine and convert between snake_case and camelCase strings. It reads from files and processes string +// formats, outputting converted formats. + +// The source code includes custom headers: "rio.h", "rmalloc.h", "rprint.h", "rstring.h". + +// MIT License + #ifndef RCASE_H #define RCASE_H + #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -7311,47 +7500,42 @@ void arena_reset(arena_t *arena) { arena->pointer = 0; } #define RCAMEL_CASE 1 #define RSNAKE_CASE 2 #define RINVALID_CASE 0 -#define RCONST_TEST_T 4; +#define RCONST_TEST_T 4 int rdetermine_case(const char *str) { + char previousChar = 0; int length = strlen(str); - char p = 0; while (*str) { - if (p == '_' && islower(*str)) + if (previousChar == '_' && islower(*str)) return RSNAKE_CASE; - if (p != '_' && !isupper(p) && isupper(*str)) + if (previousChar != '_' && !isupper(previousChar) && isupper(*str)) return RCAMEL_CASE; - p = *str; + previousChar = *str; str++; } - return RINVALID_CASE; - if (length == 0) { + if (length == 0) return RINVALID_CASE; - } + if (strchr(str, '_')) { - if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) return RINVALID_CASE; - } + for (int i = 0; i < length; i++) { - if (!islower(str[i]) && str[i] != '_') { + if (!islower(str[i]) && str[i] != '_') return RINVALID_CASE; - } } return RSNAKE_CASE; } else { - - if (!islower(str[0])) { + if (!islower(str[0])) return RINVALID_CASE; - } + for (int i = 1; i < length; i++) { - if (str[i] == '_') { + if (str[i] == '_') return RINVALID_CASE; - } - if (isupper(str[i]) && isupper(str[i - 1])) { + if (isupper(str[i]) && isupper(str[i - 1])) return RINVALID_CASE; - } } return RCAMEL_CASE; } @@ -7364,37 +7548,24 @@ char *rsnake_to_camel(const char *snake_case) { int toUpper = 0; for (int i = 0; i < length; i++) { - if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { - toUpper = 1; - if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - - toUpper = 0; + if (snake_case[i] == '_') { + if (snake_case[i + 1] == 'T' || (snake_case[i + 1] == 't' && !isspace(snake_case[i + 2]))) { + toUpper = 1; } + continue; } - if (snake_case[i] == '_' && snake_case[i + 1] != 't') { - toUpper = 1; - if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - toUpper = 0; - } - } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { - toUpper = 1; - } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { - toUpper = 1; - camel_case[j++] = '_'; - j++; + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; } else { - if (toUpper) { - camel_case[j++] = toupper(snake_case[i]); - toUpper = 0; - } else { - camel_case[j++] = snake_case[i]; - } + camel_case[j++] = snake_case[i]; } } camel_case[j] = '\0'; return camel_case; } + char *rcamel_to_snake(const char *camelCase) { int length = strlen(camelCase); char *snake_case = (char *)malloc(2 * length + 1); @@ -7402,9 +7573,8 @@ char *rcamel_to_snake(const char *camelCase) { for (int i = 0; i < length; i++) { if (isupper(camelCase[i])) { - if (i != 0) { + if (i != 0) snake_case[j++] = '_'; - } snake_case[j++] = tolower(camelCase[i]); } else { snake_case[j++] = camelCase[i]; @@ -7416,11 +7586,12 @@ char *rcamel_to_snake(const char *camelCase) { } char *rflip_case(char *content) { - if (rdetermine_case(content) == RSNAKE_CASE) { + switch (rdetermine_case(content)) { + case RSNAKE_CASE: return rcamel_to_snake(content); - } else if (rdetermine_case(content) == RCAMEL_CASE) { + case RCAMEL_CASE: return rsnake_to_camel(content); - } else { + default: rprintr("Could not determine case\n"); return NULL; } @@ -7428,20 +7599,17 @@ char *rflip_case(char *content) { char *rflip_case_file(char *filepath) { size_t file_size = rfile_size(filepath); - if (file_size == 0) { + if (file_size == 0) return NULL; - } + char *content = (char *)malloc(file_size); char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { result = rflip_case(content); - if (result) { - free(content); - return result; - } else { - return content; - } + free(content); } + return result; } @@ -7450,6 +7618,7 @@ int rcase_main(int argc, char *argv[]) { printf("usage: rcase <file>\n"); return 1; } + for (int i = 1; i < argc; i++) { char *result = rflip_case_file(argv[i]); if (result) { @@ -7459,8 +7628,8 @@ int rcase_main(int argc, char *argv[]) { } return 0; } -#endif +#endif #ifndef RTERM_H #define RTERM_H #include <stdbool.h> @@ -8226,11 +8395,31 @@ char *rlex_format(char *content) { } #endif +Written by retoor@molodetz.nl + +This code provides an entry point for a library with command-line utilities. It forwards arguments to the corresponding tool based on the user's input. + +Includes used: +- rhttp.h: Provides functionality for an HTTP file server. +- rmerge.h: Includes a tool for merging C source files. +- rcov.h: Implements a code coverage tool based on lcov. +- rcase.h: Contains a utility to convert file naming conventions between camel case and snake case. + +MIT License + #ifndef RLIB_MAIN #define RLIB_MAIN -#ifndef RMERGE_H -#define RMERGE_H -// #include "../mrex/rmatch.h" +// Written by retoor@molodetz.nl + +// The code provides functionality to manage and merge files, particularly focusing on parsing and including scripts or C local includes. It +// implements functionality to read lines from files, extract local includes from script tags, and manage history to avoid duplicate merges. + +// The code utilizes several external libraries: "rlexer.h" for lexical analysis, "rmalloc.h" for memory management, "rprint.h" for printing +// utilities, "rrex3.h" for regular expression handling, and "remo.h" for additional utilities. It also uses standard libraries like +// stdio.h, stdlib.h, string.h, and stdbool.h for fundamental operations. + +// MIT License + #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -8239,9 +8428,8 @@ char *rlex_format(char *content) { bool has_error = false; char *extract_script_src_include(char *line, char *include_path) { - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -8251,18 +8439,8 @@ char *extract_script_src_include(char *line, char *include_path) { } char *extract_c_local_include(char *line, char *include_path) { - // - /* - char res; - res= rmatch_extract(line, "#include.*"\".*\""); - - - printf("%MATCH:%s\n", res); - */ - - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -8273,22 +8451,22 @@ char *extract_c_local_include(char *line, char *include_path) { char *rmerge_readline(FILE *f) { static char data[4096]; - data[0] = 0; + data[0] = '\0'; int index = 0; char c; while ((c = fgetc(f)) != EOF) { if (c != '\0') { - data[index] = c; - index++; + data[index++] = c; if (c == '\n') break; } } - data[index] = 0; - if (data[0] == 0) + data[index] = '\0'; + if (data[0] == '\0') return NULL; return data; } + void writestring(FILE *f, char *line) { char c; while ((c = *line) != '\0') { @@ -8296,15 +8474,16 @@ void writestring(FILE *f, char *line) { line++; } } + char files_history[8096]; char files_duplicate[8096]; bool is_merging = false; void merge_file(char *source, FILE *d) { - if (is_merging == false) { + if (!is_merging) { is_merging = true; - files_history[0] = 0; - files_duplicate[0] = 0; + files_history[0] = '\0'; + files_duplicate[0] = '\0'; } if (strstr(files_history, source)) { if (strstr(files_duplicate, source)) { @@ -8330,37 +8509,12 @@ void merge_file(char *source, FILE *d) { char *line; char include_path[4096]; while ((line = rmerge_readline(fd))) { - - include_path[0] = 0; + include_path[0] = '\0'; if (!*line) break; - - // char *inc = extract_c_local_include(line, include_path); if (!inc) inc = extract_script_src_include(line, include_path); - - /* - if (!strncmp(line, "#include ", 9)) { - int index = 0; - while (line[index] != '"' && line[index] != 0) { - index++; - } - if (line[index] == '"') { - int pindex = 0; - index++; - while (line[index] != '"') { - include_path[pindex] = line[index]; - pindex++; - index++; - } - if (line[index] != '"') { - include_path[0] = 0; - } else { - include_path[pindex] = '\0'; - } - } - }*/ if (inc) { merge_file(inc, d); } else { @@ -8377,7 +8531,6 @@ int rmerge_main(int argc, char *argv[]) { printf("Usage: <input-file>\n"); } else { file_input = argv[1]; - // file_output = argv[2]; } FILE *f = tmpfile(); printf("// RETOOR - %s\n", __DATE__); @@ -8396,30 +8549,27 @@ int rmerge_main(int argc, char *argv[]) { if (has_error) { rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); } else { - rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + rprintgf(stderr, "\\l Merge successful without error(s).%s\n", remo_get("fire")); } return 0; } -#endif void forward_argument(int *argcc, char *argv[]) { int argc = *argcc; for (int i = 0; i < argc; i++) { argv[i] = argv[i + 1]; } - argc--; - *argcc = argc; + (*argcc)--; } int rlib_main(int argc, char *argv[]) { - if (argc == 1) { printf("rlib\n\n"); printf("options:\n"); - printf(" httpd - a http file server. Accepts port as argument.\n"); - printf(" rmerge - a merge tool. Converts c source files to one file \n" + printf(" httpd - a HTTP file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts C source files to one file \n" " with local includes by giving main file as argument.\n"); - printf(" rcov - coverage tool theat cleans up after himself. Based on " + printf(" rcov - coverage tool that cleans up after itself. Based on " "lcov.\n"); printf(" rcase - tool to swap input file automatically between" " camel case and snake case.\n"); @@ -8429,7 +8579,6 @@ int rlib_main(int argc, char *argv[]) { forward_argument(&argc, argv); if (!strcmp(argv[0], "httpd")) { - return rhttp_main(argc, argv); } if (!strcmp(argv[0], "rmerge")) { @@ -8447,5 +8596,4 @@ int rlib_main(int argc, char *argv[]) { #endif -// END OF RLIB #endif diff --git a/rlibrlibso.c b/rlibrlibso.c index 0c50255..f58d6a8 100644 --- a/rlibrlibso.c +++ b/rlibrlibso.c @@ -1,19 +1,38 @@ // RETOOR - Mar 16 2025 +// Written by retoor@molodetz.nl + +// This source code includes and uses multiple modules and libraries to provide comprehensive networking, +// memory management, mathematical functions, and additional functionalities for developing a variety of applications. + +// Includes not part of the core language: "license.h", "rtypes.h", "nsock.h", "rmalloc.h", "uuid.h", +// "rnet.h", "rargs.h", "rcat.h", "rliza.h", "rcov.h", "rtemp.h", "rhttp.h", "rjson.h", "rstring_list.h", +// "rautocomplete.h", "rrex4.h", "rprint.h", "rmath.h", "rtest.h", "rkeytable.h", "rhashtable.h", +// "rrex3.h", "rtime.h", "arena.h", "rio.h", "rstring.h", "rcase.h", "rterminal.h", "rterm.h", +// "rtree.h", "rlexer.h", "rbench.h", "main.h" + +// MIT License + +// Written by retoor@molodetz.nl + +// This source code provides the implementation and licensing information for software available under the MIT License. + +// No external libraries or frameworks are used in this source code. + // 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 @@ -23,13 +42,6 @@ // SOFTWARE. #ifndef RLIB_H #define RLIB_H -// BEGIN OF RLIB - -/* - * Line below will be filtered by rmerge -<script language="Javva script" type="woeiii" src="Pony.html" after-tag="after -tag" /> -*/ #ifndef RTYPES_H #define RTYPES_H @@ -63,25 +75,85 @@ typedef unsigned char byte; #endif #endif +// Written by retoor@molodetz.nl + +// The code is an implementation for managing network sockets. It provides functionality to create, connect, and manage a server or client +// sockets, handle multiple connections, read and write data, and handle events such as connecting, receiving data, and closing a +// connection. + +// External import summary: +// This code uses external libraries such as rmalloc.h and rio.h for memory allocation and I/O operations. + +// MIT License: +// 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 NSOCK_H #define NSOCK_H #include <unistd.h> +// Written by retoor@molodetz.nl + +// This code overrides the default dynamic memory allocation functions in C, providing custom implementations for malloc, calloc, realloc, +// free, and strdup, with additional logging and memory usage statistics. + +// Dependence on an external header file "rtemp.h". + +// MIT License +// +// 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 RMALLOC_H #define RMALLOC_H + #ifndef RMALLOC_OVERRIDE #define RMALLOC_OVERRIDE 1 #endif + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #ifndef ulonglong #define ulonglong unsigned long long #endif + #include <locale.h> #include <stdio.h> #include <stdlib.h> @@ -138,6 +210,7 @@ char *rtempc(char *data) { #define sbuf(val) rtempc(val) #endif + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -145,6 +218,7 @@ char *rtempc(char *data) { #else #undef _POSIX_C_SOURCE #endif + ulonglong rmalloc_count = 0; ulonglong rmalloc_alloc_count = 0; ulonglong rmalloc_free_count = 0; @@ -163,6 +237,7 @@ void *rmalloc(size_t size) { rmalloc_total_bytes_allocated += size; return result; } + void *rcalloc(size_t count, size_t size) { void *result; while (!(result = calloc(count, size))) { @@ -173,6 +248,7 @@ void *rcalloc(size_t count, size_t size) { rmalloc_total_bytes_allocated += count * size; return result; } + void *rrealloc(void *obj, size_t size) { if (!obj) { rmalloc_count++; @@ -181,8 +257,7 @@ void *rrealloc(void *obj, size_t size) { rmalloc_alloc_count++; if (obj == _rmalloc_prev_realloc_obj) { rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; - _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; - + _rmalloc_prev_realloc_obj_size = size; } else { _rmalloc_prev_realloc_obj_size = size; } @@ -207,6 +282,7 @@ char *rstrdup(const char *s) { rmalloc_total_bytes_allocated += size; return result; } + void *rfree(void *obj) { rmalloc_count--; rmalloc_free_count++; @@ -223,7 +299,6 @@ void *rfree(void *obj) { #endif char *rmalloc_lld_format(ulonglong num) { - char res[100]; res[0] = 0; sprintf(res, "%'lld", num); @@ -249,20 +324,14 @@ char *rmalloc_bytes_format(int factor, ulonglong num) { char *rmalloc_stats() { static char res[200]; res[0] = 0; - // int original_locale = localeconv(); setlocale(LC_NUMERIC, "en_US.UTF-8"); - sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), - rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), - - rmalloc_lld_format(rmalloc_count)); - // setlocale(LC_NUMERIC, original_locale); - + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unique freeds, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), rmalloc_lld_format(rmalloc_count)); setlocale(LC_NUMERIC, ""); return res; } #endif - #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -274,6 +343,34 @@ char *rmalloc_stats() { #include <sys/select.h> #include <sys/socket.h> #include <unistd.h> +// Written by retoor@molodetz.nl + +// This source code provides a set of utility functions for file handling and directory operations in C. + +// Includes for handling directories, system calls, and working with the file system. + +// MIT License +// +// Copyright (c) [Year] [Author] +// +// 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_RIO #define RLIB_RIO #include <dirent.h> @@ -341,8 +438,7 @@ void rjoin_path(char *p1, char *p2, char *output) { strcpy(output, p1); if (output[strlen(output) - 1] != '/') { - char slash[] = "/"; - strcat(output, slash); + strcat(output, "/"); } if (p2[0] == '/') { p2++; @@ -352,33 +448,28 @@ void rjoin_path(char *p1, char *p2, char *output) { 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 1; } - return 0; } + bool risdir(const char *path) { return !risprivatedir(path); } void rforfile(char *path, void callback(char *)) { - if (!rfile_exists(path)) + 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; } @@ -396,22 +487,18 @@ void rforfile(char *path, void callback(char *)) { } bool rfd_wait(int fd, int ms) { - fd_set read_fds; struct timeval timeout; - FD_ZERO(&read_fds); FD_SET(fd, &read_fds); - timeout.tv_sec = 0; timeout.tv_usec = 1000 * ms; - int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); return ret > 0 && FD_ISSET(fd, &read_fds); } bool rfd_wait_forever(int fd) { - while ((!rfd_wait(fd, 10))) { + while (!rfd_wait(fd, 10)) { } return true; } @@ -428,7 +515,6 @@ size_t rfile_readb(char *path, void *data, size_t size) { return 0; } size_t bytes_read = fread(data, sizeof(char), size, fd); - fclose(fd); ((char *)data)[bytes_read] = 0; return bytes_read; @@ -468,8 +554,8 @@ nsock_t *nsock_get(int fd) { if (fd >= nsocks_count || nsocks[fd] == NULL) { if (fd >= nsocks_count) { nsocks_count = fd + 1; - nsocks = (nsock_t **)realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * (nsocks_count)); - nsocks[fd] = (nsock_t *)calloc(1, sizeof(nsock_t)); + nsocks = realloc(nsocks, sizeof(nsock_t *) * sizeof(nsock_t) * nsocks_count); + nsocks[fd] = calloc(1, sizeof(nsock_t)); } nsocks[fd]->upstreams = NULL; nsocks[fd]->fd = fd; @@ -518,12 +604,12 @@ int *nsock_init(int socket_count) { if (nsock_socks) { return nsock_socks; } - nsock_socks = (int *)calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); + nsock_socks = calloc(1, sizeof(int) * sizeof(int *) * socket_count + 1); if (nsock_data) { free(nsock_data); nsock_data = NULL; } - nsock_data = (void **)malloc(sizeof(void **) * socket_count + 1); + nsock_data = malloc(sizeof(void **) * socket_count + 1); nsock_socks[socket_count] = -1; return nsock_socks; } @@ -548,13 +634,14 @@ void nsock_add_upstream(int source, int target, bool downstream) { nsock_t *sock = nsock_get(source); nsock_t *sock_target = nsock_get(target); sock_target->type = NSOCK_UPSTREAM; - sock->upstreams = (int *)realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); + sock->upstreams = realloc(sock->upstreams, sizeof(int) * (sock->upstream_count + 1)); sock->downstream = downstream; sock->upstreams[sock->upstream_count] = target; sock->upstream_count++; } void *nsock_get_data(int socket) { return nsock_data[socket]; } + void nsock_set_data(int socket, void *data) { nsock_data[socket] = data; } int nsock_connect(const char *host, unsigned int port) { @@ -644,7 +731,6 @@ int *nsock_select(suseconds_t timeout) { for (int i = 0; socks[i] != -1; i++) { if (i == server_fd) continue; - ; if (!socks[i]) continue; if (socks[i] > nsock_max_socket_fd) { @@ -680,7 +766,7 @@ int *nsock_select(suseconds_t timeout) { if (nsock_readable) { free(nsock_readable); } - nsock_readable = (int *)calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); + nsock_readable = calloc(1, sizeof(int *) + sizeof(int) * (nsock_max_socket_fd + 2)); nsock_readable[nsock_max_socket_fd + 1] = -1; nsock_readable[0] = 0; int readable_count = 0; @@ -707,7 +793,7 @@ int *nsock_select(suseconds_t timeout) { unsigned char *nsock_read(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = read(fd, buffer, length); if (bytes_read <= 0) { nsock_close(fd); @@ -720,7 +806,7 @@ unsigned char *nsock_read(int fd, int length) { unsigned char *nsock_read_all(int fd, int length) { if (!nsock_socks[fd]) return NULL; - unsigned char *buffer = (unsigned char *)malloc(length + 1); + unsigned char *buffer = malloc(length + 1); int bytes_read = 0; while (bytes_read < length) { int bytes_chunk = read(fd, buffer + bytes_read, length - bytes_read); @@ -768,7 +854,7 @@ int nsock_execute_upstream(int source, size_t buffer_size) { nsock_close(sock->upstreams[i]); continue; } - if (sock->downstream && downstreamed == false) { + if (sock->downstream && !downstreamed) { downstreamed = true; unsigned char data[4096]; memset(data, 0, 4096); @@ -839,7 +925,6 @@ void nsock(int port, void (*on_connect)(int fd), void (*on_data)(int fd), void ( } } #endif - #ifndef UUID_H #define UUID_H #include <stdbool.h> @@ -885,16 +970,28 @@ char *uuid4() { return sbuf(str); } #endif +// Written by retoor@molodetz.nl + +// This source code defines and implements a simple networking library that provides various functions and structures to manage network +// sockets and servers. It offers the ability to create, bind, listen, connect, and close sockets, along with socket selection and +// asynchronous behavior handling. + +// No non-standard imports or includes are used in this source code. + +// MIT License + #ifndef RNET_H #define RNET_H + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -905,11 +1002,10 @@ char *uuid4() { #include <stdlib.h> #include <string.h> #include <sys/select.h> - #include <sys/socket.h> #include <sys/types.h> - #include <unistd.h> + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -917,6 +1013,7 @@ char *uuid4() { #else #undef _POSIX_C_SOURCE #endif + #define NET_SOCKET_MAX_CONNECTIONS 50000 typedef struct rnet_socket_t { @@ -1007,29 +1104,27 @@ bool net_set_non_blocking(int sock) { perror("fcntl"); return false; } - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); return false; } - return true; } int net_socket_init() { - int socket_fd = -1; - memset(sockets, 0, sizeof(sockets)); - int opt = 1; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == 0) { perror("Socket failed.\n"); return false; } - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + int opt = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("Setsockopt failed.\n"); close(socket_fd); return false; } net_set_non_blocking(socket_fd); + memset(sockets, 0, sizeof(sockets)); return socket_fd; } @@ -1037,19 +1132,15 @@ char *net_socket_name(int fd) { rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); if (rnet_socket) { return rnet_socket->name; - ; } - - // If socket disconnected or is no client from server return NULL; } bool net_socket_bind(int socket_fd, unsigned int port) { struct sockaddr_in address; - - address.sin_family = AF_INET; // IPv4 - address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address - address.sin_port = htons(port); // Convert port to network byte order + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); @@ -1061,48 +1152,36 @@ bool net_socket_bind(int socket_fd, unsigned int port) { int net_socket_connect(const char *host, unsigned int port) { char port_str[10] = {0}; - sprintf(port_str, "%d", port); - int status; - int socket_fd = -1; - struct addrinfo hints; - struct addrinfo *res; - struct addrinfo *p; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - return false; - } - + snprintf(port_str, sizeof(port_str), "%d", port); + struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) { + return false; + } + int status = getaddrinfo(host, port_str, &hints, &res); + if (status != 0) { return -1; } - for (p = res; p != NULL; p = p->ai_next) { - if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (socket_fd == -1) { continue; } - if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { close(socket_fd); continue; } - break; } - - if (p == NULL) { - freeaddrinfo(res); - return -1; - } - freeaddrinfo(res); - return socket_fd; + return (p == NULL) ? -1 : socket_fd; } bool net_socket_listen(int socket_fd, unsigned int backlog) { - if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + if (listen(socket_fd, backlog) < 0) { perror("Listen failed"); close(socket_fd); return false; @@ -1113,59 +1192,27 @@ bool net_socket_listen(int socket_fd, unsigned int backlog) { rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { signal(SIGPIPE, SIG_IGN); int socket_fd = net_socket_init(); - net_socket_bind(socket_fd, port); - net_socket_listen(socket_fd, backlog); + if (!net_socket_bind(socket_fd, port) || !net_socket_listen(socket_fd, backlog)) { + return NULL; + } return rnet_server_new(socket_fd, port, backlog); } int net_socket_accept(int net_socket_server_fd) { struct sockaddr_in address; int addrlen = sizeof(address); - int new_socket = -1; - if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { - close(new_socket); + int new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { return -1; - } else { - - return new_socket; } + return new_socket; } -/* -static void net_socket_stats(WrenVM *vm) -{ - - wrenSetSlotNewList(vm, 0); - - wrenSetSlotString(vm, 1, "sockets_total"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_total); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_concurrent_record"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_connected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_connected); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_disconnected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); - wrenInsertInList(vm, 0, -1, 1); -}*/ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { ssize_t sent_total = 0; - ssize_t sent = 0; ssize_t to_send = size; - while ((sent = send(sock->fd, message, to_send, 0))) { + while (1) { + ssize_t sent = send(sock->fd, message, to_send, 0); if (sent == -1) { sockets_errors++; net_socket_close(sock); @@ -1179,8 +1226,9 @@ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size break; } sent_total += sent; - if (sent_total == to_send) + if (sent_total == to_send) { break; + } } return sent_total; } @@ -1201,47 +1249,43 @@ unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { return NULL; } } - buffer[received + 1] = 0; + buffer[received] = 0; sock->bytes_received = received; return buffer; } rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { - if (!sock) - return NULL; - if (sock->fd == -1) + if (!sock || sock->fd == -1) { return NULL; + } fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock->fd, &read_fds); - int max_socket_fd = sock->fd; int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { - // perror("Select error"); + if (activity < 0 && errno != EINTR) { net_socket_close(sock); return NULL; } - if (FD_ISSET(sock->fd, &read_fds)) { - return sock; - } - - return NULL; + return FD_ISSET(sock->fd, &read_fds) ? sock : NULL; } void rnet_safe_str(char *str, size_t length) { - if (!str || !length || !*str) + if (!str || !length || !*str) { return; + } for (unsigned int i = 0; i < length; i++) { - if (str[i] < 32 || str[i] > 126) - if (str[i] != 0) + if (str[i] < 32 || str[i] > 126) { + if (str[i] != 0) { str[i] = '.'; + } + } } str[length] = 0; } rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { - rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + rnet_select_result_t *result = malloc(sizeof(rnet_select_result_t)); memset(result, 0, sizeof(rnet_select_result_t)); result->server_fd = socket_fd; result->socket_count = 0; @@ -1254,14 +1298,15 @@ void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { result->sockets[result->socket_count] = sock; result->socket_count++; } + void rnet_select_result_free(rnet_select_result_t *result) { free(result); } + rnet_select_result_t *net_socket_select(rnet_server_t *server) { fd_set read_fds; FD_ZERO(&read_fds); FD_SET(server->socket_fd, &read_fds); - server->max_fd = server->socket_fd; - int socket_fd = -1; + int socket_fd; for (unsigned int i = 0; i < server->socket_count; i++) { socket_fd = server->sockets[i]->fd; if (!server->sockets[i]->connected) { @@ -1278,19 +1323,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { struct sockaddr_in address; int addrlen = sizeof(struct sockaddr_in); int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { + if (activity < 0 && errno != EINTR) { perror("Select error\n"); return NULL; } if (FD_ISSET(server->socket_fd, &read_fds)) { - if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { perror("Accept failed\n"); return NULL; } - - // net_set_non_blocking(new_socket); char name[50] = {0}; - sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + snprintf(name, sizeof(name), "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); rnet_socket_t *sock_obj = NULL; for (unsigned int i = 0; i < server->socket_count; i++) { if (server->sockets && server->sockets[i]->fd == -1) { @@ -1298,7 +1342,7 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { } } if (!sock_obj) { - sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + sock_obj = malloc(sizeof(rnet_socket_t)); rnet_server_add_socket(server, sock_obj); } sock_obj->fd = new_socket; @@ -1306,17 +1350,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { sockets_connected++; sockets_total++; sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; - if (new_socket > net_socket_max_fd) { - net_socket_max_fd = new_socket; - } + net_socket_max_fd = (new_socket > net_socket_max_fd) ? new_socket : net_socket_max_fd; sock_obj->connected = true; - sock_obj->on_connect(sock_obj); + if (sock_obj->on_connect) { + sock_obj->on_connect(sock_obj); + } } rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); unsigned int readable_count = 0; for (unsigned int i = 0; i < server->socket_count; i++) { - if (server->sockets[i]->fd == -1) + if (server->sockets[i]->fd == -1) { continue; + } if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { rnet_select_result_add(result, server->sockets[i]); readable_count++; @@ -1329,8 +1374,9 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { rnet_select_result_free(server->select_result); server->select_result = NULL; } - if (readable_count == 0) + if (readable_count == 0) { rnet_select_result_free(result); + } return readable_count ? result : NULL; } @@ -1347,35 +1393,43 @@ void _net_socket_close(int sock) { if (sock > 0) { sockets_connected--; sockets_disconnected++; - if (sock > 0) { - if (close(sock) == -1) { - perror("Error closing socket.\n"); - } + if (close(sock) == -1) { + perror("Error closing socket.\n"); } } } void net_socket_close(rnet_socket_t *sock) { sock->connected = false; - if (sock->on_close) + if (sock->on_close) { sock->on_close(sock); + } _net_socket_close(sock->fd); sock->fd = -1; } + #undef _POSIX_C_SOURCE #endif +// Written by retoor@molodetz.nl + +// This source code implements a simple argument parsing utility for C programs, +// facilitating the checking or retrieval of command line argument values. + +// This file uses the standard C libraries: <stdio.h>, <string.h>, <stdlib.h>, <stdbool.h> + +// MIT License -#include <stdio.h> #ifndef RLIB_RARGS_H #define RLIB_RARGS_H + #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> bool rargs_isset(int argc, char *argv[], char *key) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { return true; } } @@ -1383,9 +1437,8 @@ bool rargs_isset(int argc, char *argv[], char *key) { } char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return argv[i + 1]; } @@ -1395,9 +1448,8 @@ char *rargs_get_option_string(int argc, char *argv[], char *key, const char *def } int rargs_get_option_int(int argc, char *argv[], char *key, int def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { return atoi(argv[i + 1]); } @@ -1407,24 +1459,32 @@ int rargs_get_option_int(int argc, char *argv[], char *key, int def) { } bool rargs_get_option_bool(int argc, char *argv[], char *key, bool def) { - for (int i = 0; i < argc; i++) { - if (!strcmp(argv[i], key)) { + if (strcmp(argv[i], key) == 0) { if (i < argc - 1) { - if (!strcmp(argv[i + 1], "false")) - return false; - if (!strcmp(argv[i + 1], "0")) + if (strcmp(argv[i + 1], "false") == 0 || strcmp(argv[i + 1], "0") == 0) { return false; + } return true; } } } - return def; } + #endif +// Written by retoor@molodetz.nl + +// This code provides a simple implementation of a reverse cat (rcat) function, which attempts to read a file in binary mode and outputs its +// contents to the standard output. + +// No external libraries apart from the standard C library are used here. + +// MIT License + #ifndef RCAT_H #define RCAT_H + #include <stdio.h> #include <stdlib.h> @@ -1435,7 +1495,7 @@ void rcat(char *filename) { return; } unsigned char c; - while ((c = fgetc(f)) && !feof(f)) { + while ((c = fgetc(f)) != EOF) { printf("%c", c); } fclose(f); @@ -1452,9 +1512,47 @@ int rcat_main(int argc, char *argv[]) { } #endif +// Written by retoor@molodetz.nl + +// This code defines a data structure and set of functions for handling JSON-like data types in C, allowing for the creation, manipulation, +// serialization, and deserialization of these structures. + +// Includes utilized but not part of the C standard library: "rbuffer.h", "rmalloc.h", and "rstring.h". These files would provide auxiliary +// functionalities such as dynamic memory management, string handling, or buffer manipulation required by this source code. + +// MIT License #ifndef RLIZA_H #define RLIZA_H +// Written by retoor@molodetz.nl + +// A ring buffer implementation in C that provides functionalities such as +// creating a new buffer, freeing, resetting, writing data, pushing data, +// popping data, matching options and more. It efficiently manages dynamic +// memory to handle data of varying sizes and applies basic buffer manipulation techniques. + +// This code includes the utility "rmalloc.h". It is assumed that this file +// contains custom memory management functions which are not specified here. + +// MIT License +// 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 RBUFFER_H #define RBUFFER_H #include <assert.h> @@ -1462,6 +1560,7 @@ int rcat_main(int argc, char *argv[]) { #include <stdio.h> #include <stdlib.h> #include <string.h> + typedef struct rbuffer_t { unsigned char *data; unsigned char *_data; @@ -1474,7 +1573,7 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size); void rbuffer_free(rbuffer_t *rfb); void rbuffer_reset(rbuffer_t *rfb); void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); -size_t rbuffer_push(rbuffer_t *rfb, unsigned char); +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data); unsigned char rbuffer_pop(rbuffer_t *rfb); unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); @@ -1511,42 +1610,42 @@ rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { rfb->data = rfb->_data; return rfb; } + void rbuffer_free(rbuffer_t *rfb) { - if (rfb->_data) + if (rfb->_data) { free(rfb->_data); + } free(rfb); } -size_t rbuffer_push(rbuffer_t *rfb, unsigned char c) { +size_t rbuffer_push(rbuffer_t *rfb, unsigned char data) { if (rfb->pos < rfb->size) { - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; return 1; } rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); - rfb->_data[rfb->pos++] = c; + rfb->_data[rfb->pos++] = data; rfb->size++; return rfb->pos; } + void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { - unsigned char *data_ptr = (unsigned char *)data; for (size_t i = 0; i < size; i++) { - rbuffer_push(rfb, data_ptr[i]); + rbuffer_push(rfb, data[i]); } } unsigned char rbuffer_peek(rbuffer_t *rfb) { - unsigned char result = EOF; if (rfb->pos != rfb->size) { - result = rfb->_data[rfb->pos]; - return result; + return rfb->_data[rfb->pos]; } rfb->eof = true; return EOF; } + unsigned char rbuffer_pop(rbuffer_t *rfb) { - unsigned char result = EOF; - if (rfb->pos <= rfb->size) { - result = rfb->_data[rfb->pos]; + if (rfb->pos < rfb->size) { + unsigned char result = rfb->_data[rfb->pos]; rfb->pos++; rfb->data++; if (rfb->pos == rfb->size) { @@ -1555,23 +1654,19 @@ unsigned char rbuffer_pop(rbuffer_t *rfb) { return result; } rfb->eof = true; - return result; + return EOF; } + void rbuffer_reset(rbuffer_t *rfb) { rfb->data = rfb->_data; rfb->pos = 0; } unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { - return strncmp((char *)s1, (char *)s2, n); - while (n && *s1 == *s2) { - n--; - s1++; - s2++; - } - return *s1 != *s2; + return strncmp((const char *)s1, (const char *)s2, n); } -size_t ustrlen(const unsigned char *s) { return strlen((char *)s); } + +size_t ustrlen(const unsigned char *s) { return strlen((const char *)s); } unsigned char *rbuffer_to_string(rbuffer_t *rfb) { unsigned char *result = rfb->_data; @@ -1587,7 +1682,6 @@ unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { strcpy(options_cpy, options); char *memory = options_cpy; while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { - size_t option_length = strlen(option); if (option_length > rfb->size - rfb->pos) { continue; @@ -1620,6 +1714,7 @@ unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { } return NULL; } + unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { unsigned char *result = NULL; if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { @@ -1627,11 +1722,37 @@ unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { } return result; } + #endif #ifndef RSTRING_H #define RSTRING_H +// Written by retoor@molodetz.nl + +// This code provides custom implementations of the `ceil`, `floor`, and `modf` functions for double precision numbers that mimic the +// behavior of those found in the C standard math library. + +// Summary of used imports: <math.h> for mathematical functions. + +// MIT License +// +// 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 RMATH_H #define RMATH_H + #include <math.h> #ifndef ceil @@ -1664,6 +1785,7 @@ double modf(double x, double *iptr) { return x - int_part; } #endif + #endif #include <ctype.h> #include <stdbool.h> @@ -2153,22 +2275,12 @@ void rliza_free(rliza_t *rliza) { rliza_free(rliza->value); rliza->value = NULL; } - // if (rliza->content.array) { - // printf("JAAAA\n"); - // } - // if (rliza->content.object) { - // rliza_free(rliza->content.object); - // rliza->content.object = NULL; - //} if (rliza->type == RLIZA_STRING) { if (rliza->content.string) { free(rliza->content.string); rliza->content.string = NULL; - // else if (rliza->type == RLIZA_NUMBER) { - // printf("STDring freed\n"); } } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { - if (rliza->content.map) { for (unsigned int i = 0; i < rliza->count; i++) { rliza_free(rliza->content.map[i]); @@ -2176,9 +2288,6 @@ void rliza_free(rliza_t *rliza) { free(rliza->content.map); } } - // free(rliza->content.array); - //} - free(rliza); } @@ -2342,7 +2451,6 @@ void rliza_set_null(rliza_t *self, char *key) { rliza_push_object(self, obj); } if (obj->type == RLIZA_OBJECT) { - rliza_free(obj->value); obj->value = NULL; } else if (obj->type == RLIZA_STRING) { @@ -2539,11 +2647,8 @@ rliza_t *_rliza_loads(char **content) { rliza_free(rliza); return NULL; } - // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); - // rstraddslashes(extracted, extracted_with_slashes); rliza->type = RLIZA_STRING; - rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; - // free(extracted); + rliza->content.string = extracted; return rliza; } else if (**content == '{') { rliza->type = RLIZA_OBJECT; @@ -2604,7 +2709,6 @@ rliza_t *_rliza_loads(char **content) { } else if (**content == '}') { break; } else { - // Parse error rliza_free(rliza); return NULL; } @@ -2676,21 +2780,17 @@ rliza_t *_rliza_loads(char **content) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = true; *content += 4; - return rliza; } else if (!strncmp(*content, "false", 5)) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = false; *content += 5; - return rliza; } else if (!strncmp(*content, "null", 4)) { rliza->type = RLIZA_NULL; *content += 4; - return rliza; } - // Parsing error rliza_free(rliza); return NULL; } @@ -2717,10 +2817,7 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%lld", rliza->content.integer); } } else if (rliza->type == RLIZA_STRING) { - - // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); char *escaped_string = rliza->content.string; - // rstrstripslashes((char *)rliza->content.string, escaped_string); size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; if (size < min_size) { size = min_size + 1; @@ -2740,7 +2837,6 @@ char *rliza_dumps(rliza_t *rliza) { content = realloc(content, size); sprintf(content, "\"%s\"", escaped_string); } - // free(escaped_string); } else if (rliza->type == RLIZA_NUMBER) { if (rliza->key) { sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); @@ -2773,14 +2869,12 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); } } else if (rliza->type == RLIZA_OBJECT) { - strcat(content, "{"); if (rliza->key) { strcat(content, "\""); strcat(content, rliza->key); strcat(content, "\":{"); } - // bool add_braces = false; for (unsigned i = 0; i < rliza->count; i++) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; @@ -2799,7 +2893,6 @@ char *rliza_dumps(rliza_t *rliza) { } if (content[strlen(content) - 1] == ',') { content[strlen(content) - 1] = '\0'; - if (rliza->key) { strcat(content, "}"); } @@ -2821,8 +2914,6 @@ char *rliza_dumps(rliza_t *rliza) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; if (*content_chunk_stripped == '{') { - // content_chunk_stripped++; - // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; } if (strlen(content_chunk_stripped) + strlen(content) > size) { size += strlen(content_chunk_stripped) + 20; @@ -2836,7 +2927,6 @@ char *rliza_dumps(rliza_t *rliza) { content[strlen(content) - 1] = 0; strcat(content, "]"); } else if (rliza->type == RLIZA_NULL) { - if (rliza->key) { char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); rstraddslashes((char *)rliza->key, escaped_key); @@ -2871,15 +2961,65 @@ int rliza_validate(char *json_content) { #endif +// Written by retoor@molodetz.nl + +// This code provides a console utility for performing code coverage analysis on a specified C source file using lcov and genhtml. It checks +// for lcov installation, compiles the source file with coverage options, runs it, and generates an HTML report. + +// The code uses lcov and genhtml for coverage analysis and viewing, google-chrome for displaying the HTML report, and it requires gcc for +// compilation. + +// MIT License + #ifndef RCOV_H #define RCOV_H + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +/* Written by retoor@molodetz.nl */ + +/* This source code defines a benchmarking utility for measuring the execution time of functions in C. It provides functionalities for + * adding, resetting, and executing functions multiple times while tracking their execution time. The code also includes progress tracking + * and functions for executing with varying numbers of arguments. */ + +/* Dependencies not part of the language itself: + - These likely include custom headers such as "rprint.h", "rtime.h", "rstring.h", and "rterminal.h" +*/ + +/* +MIT License + +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 RBENCH_H #define RBENCH_H +// Written by retoor@molodetz.nl + +// This source code provides a custom printing library for formatted output with optional color effects. It implements functions to print +// strings with various color enhancements and control codes for terminal manipulation. + +// Includes: The code uses a custom header "rtime.h" to work with time-related functions. + +// MIT License: 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 RPRINT_H #define RPRINT_H @@ -3052,109 +3192,94 @@ bool rprint_is_color_enabled() { } 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; } 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 = false; bool press_any_key = false; char new_format[4096]; bool enable_color = rprint_is_color_enabled(); - memset(new_format, 0, 4096); + + memset(new_format, 0, sizeof(new_format)); 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); + memset(temp, 0, sizeof(temp)); + + if (enable_color && prefix[0]) { + strcat(new_format, prefix); + new_format_length += strlen(prefix); reset_color = true; } - while (true) { - if (pformat[0] == '\\' && pformat[1] == 'i') { + + while (*format) { + if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 'C') { press_any_key = true; rpline_number++; - pformat++; - pformat++; + format += 2; reset_color = false; - } else if (pformat[0] == '\\' && pformat[1] == 'k') { + } else if (format[0] == '\\' && format[1] == 'k') { press_any_key = true; rpline_number++; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'c') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 't') { rprtime = nsecs(); - pformat++; - pformat++; + format += 2; } else { - new_format[new_format_length] = *pformat; - new_format_length++; - if (!*pformat) - break; - - // printf("%c",*pformat); - pformat++; + new_format[new_format_length++] = *format++; } } + if (reset_color) { strcat(new_format, "\e[0m"); new_format_length += strlen("\e[0m"); } - new_format[new_format_length] = 0; + new_format[new_format_length] = '\0'; vfprintf(f, new_format, args); fflush(stdout); @@ -3178,21 +3303,23 @@ void rprintf(FILE *f, const char *format, ...) { rprintpf(f, "", format, args); va_end(args); } + void rprint(const 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, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\\l", format, args); va_end(args); } + void rprintl(const char *format, ...) { va_list args; va_start(args, format); @@ -3200,13 +3327,13 @@ void rprintl(const char *format, ...) { va_end(args); } -// Black void rprintkf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[30m", format, args); va_end(args); } + void rprintk(const char *format, ...) { va_list args; va_start(args, format); @@ -3214,13 +3341,13 @@ void rprintk(const char *format, ...) { va_end(args); } -// Red void rprintrf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[31m", format, args); va_end(args); } + void rprintr(const char *format, ...) { va_list args; va_start(args, format); @@ -3228,13 +3355,13 @@ void rprintr(const char *format, ...) { va_end(args); } -// Green void rprintgf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[32m", format, args); va_end(args); } + void rprintg(const char *format, ...) { va_list args; va_start(args, format); @@ -3242,13 +3369,13 @@ void rprintg(const char *format, ...) { va_end(args); } -// Yellow void rprintyf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[33m", format, args); va_end(args); } + void rprinty(const char *format, ...) { va_list args; va_start(args, format); @@ -3256,7 +3383,6 @@ void rprinty(const char *format, ...) { va_end(args); } -// Blue void rprintbf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); @@ -3271,13 +3397,13 @@ void rprintb(const char *format, ...) { va_end(args); } -// Magenta void rprintmf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[35m", format, args); va_end(args); } + void rprintm(const char *format, ...) { va_list args; va_start(args, format); @@ -3285,13 +3411,13 @@ void rprintm(const char *format, ...) { va_end(args); } -// Cyan void rprintcf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[36m", format, args); va_end(args); } + void rprintc(const char *format, ...) { va_list args; va_start(args, format); @@ -3299,13 +3425,13 @@ void rprintc(const char *format, ...) { va_end(args); } -// White void rprintwf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[37m", format, args); va_end(args); } + void rprintw(const char *format, ...) { va_list args; va_start(args, format); @@ -3313,6 +3439,7 @@ void rprintw(const char *format, ...) { va_end(args); } #endif + #include <errno.h> #include <stdbool.h> #include <stdint.h> @@ -3321,7 +3448,6 @@ void rprintw(const char *format, ...) { #include <string.h> #include <sys/time.h> #include <time.h> - #ifndef RLIB_TERMINAL_H #define RLIB_TERMINAL_H @@ -3331,6 +3457,16 @@ void rprintw(const char *format, ...) { #include <string.h> #ifndef RTEST_H #define RTEST_H +// Written by retoor@molodetz.nl + +// This header file defines a structure `remo_t` used to store emoji representations and their descriptions. It includes functions to +// convert strings to lowercase, search for substrings case insensitively, print all emojis with their descriptions, and retrieve an emoji +// by its description. + +// No third-party imports or includes are used outside the language's standard library. + +// MIT License + #ifndef REMO_H #define REMO_H #include <ctype.h> @@ -3343,206 +3479,169 @@ typedef struct { const char *description; } remo_t; -remo_t remo[] = { - {"\U0001F600", "Grinning Face"}, // 😀 - {"\U0001F601", "Beaming Face with Smiling Eyes"}, // 😁 - {"\U0001F602", "Face with Tears of Joy"}, // 😂 - {"\U0001F923", "Rolling on the Floor Laughing"}, // 🤣 - {"\U0001F603", "Grinning Face with Big Eyes"}, // 😃 - {"\U0001F604", "Grinning Face with Smiling Eyes"}, // 😄 - {"\U0001F609", "Winking Face"}, // 😉 - {"\U0001F60A", "Smiling Face with Smiling Eyes"}, // 😊 - {"\U0001F60D", "Smiling Face with Heart-Eyes"}, // 😍 - {"\U0001F618", "Face Blowing a Kiss"}, // 😘 - {"\U0001F617", "Kissing Face"}, // 😗 - {"\U0001F61A", "Kissing Face with Closed Eyes"}, // 😚 - {"\U0001F642", "Slightly Smiling Face"}, // 🙂 - {"\U0001F643", "Upside-Down Face"}, // 🙃 - {"\U0001F970", "Smiling Face with Hearts"}, // 🥰 - {"\U0001F60B", "Face Savoring Food"}, // 😋 - {"\U0001F61B", "Face with Tongue"}, // 😛 - {"\U0001F61C", "Winking Face with Tongue"}, // 😜 - {"\U0001F92A", "Zany Face"}, // 🤪 - {"\U0001F929", "Star-Struck"}, // 🤩 - {"\U0001F631", "Face Screaming in Fear"}, // 😱 - {"\U0001F62D", "Loudly Crying Face"}, // 😭 - {"\U0001F624", "Face with Steam From Nose"}, // 😤 - {"\U0001F620", "Angry Face"}, // 😠 - {"\U0001F621", "Pouting Face"}, // 😡 - {"\U0001F47B", "Ghost"}, // 👻 - {"\U0001F480", "Skull"}, // 💀 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - {"\U0001F47D", "Alien"}, // 👽 - // Geometric Shapes - {"\U000025A0", "Black Square"}, // ■ - {"\U000025B2", "Upward Triangle"}, // ▲ - {"\U000025CF", "Black Circle"}, // ● - {"\U000025CB", "White Circle"}, // ○ - {"\U00002B1B", "Large Black Square"}, // ⬛ - {"\U00002B1C", "Large White Square"}, // ⬜ - - // Mathematical Symbols - {"\U00002200", "For All"}, // ∀ - {"\U00002203", "Exists"}, // ∃ - {"\U00002205", "Empty Set"}, // ∅ - {"\U00002207", "Nabla"}, // ∇ - {"\U0000220F", "N-Ary Product"}, // ∏ - {"\U00002212", "Minus Sign"}, // − - {"\U0000221E", "Infinity"}, // ∞ - - // Arrows - {"\U00002190", "Left Arrow"}, // ← - {"\U00002191", "Up Arrow"}, // ↑ - {"\U00002192", "Right Arrow"}, // → - {"\U00002193", "Down Arrow"}, // ↓ - {"\U00002195", "Up Down Arrow"}, // ↕ - {"\U00002197", "Up Right Arrow"}, // ↗ - {"\U00002198", "Down Right Arrow"}, // ↘ - {"\U000027A1", "Black Right Arrow"}, // ➡️ - - // Dingbats - {"\U00002714", "Check Mark"}, // ✔️ - {"\U00002716", "Heavy Multiplication X"}, // ✖️ - {"\U00002728", "Sparkles"}, // ✨ - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002795", "Heavy Plus Sign"}, // ➕ - - // Miscellaneous Symbols - {"\U00002600", "Sun"}, // ☀️ - {"\U00002614", "Umbrella with Rain Drops"}, // ☔ - {"\U00002620", "Skull and Crossbones"}, // ☠️ - {"\U000026A0", "Warning Sign"}, // ⚠️ - {"\U000026BD", "Soccer Ball"}, // ⚽ - {"\U000026C4", "Snowman"}, // ⛄ - - // Stars and Asterisks - {"\U00002733", "Eight Pointed Black Star"}, // ✳️ - {"\U00002734", "Eight Spoked Asterisk"}, // ✴️ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U00002728", "Sparkles"}, // ✨ - // Animals and Nature - {"\U0001F98A", "Fox"}, // 🦊 - {"\U0001F415", "Dog"}, // 🐕 - {"\U0001F431", "Cat Face"}, // 🐱 - {"\U0001F435", "Monkey Face"}, // 🐵 - {"\U0001F408", "Black Cat"}, // 🐈 - {"\U0001F98C", "Deer"}, // 🦌 - {"\U0001F344", "Mushroom"}, // 🍄 - {"\U0001F333", "Tree"}, // 🌳 - - // Weather and Space Symbols - {"\U0001F308", "Rainbow"}, // 🌈 - {"\U0001F320", "Shooting Star"}, // 🌠 - {"\U00002600", "Sun"}, // ☀️ - {"\U00002601", "Cloud"}, // ☁️ - {"\U000026A1", "High Voltage"}, // ⚡ - {"\U0001F525", "Fire"}, // 🔥 - {"\U000026C4", "Snowman"}, // ⛄ - {"\U0001F30A", "Water Wave"}, // 🌊 - - // Transport and Map Symbols - {"\U0001F68C", "Bus"}, // 🚌 - {"\U0001F697", "Car"}, // 🚗 - {"\U0001F6B2", "Bicycle"}, // 🚲 - {"\U0001F6A2", "Ship"}, // 🚢 - {"\U0001F681", "Helicopter"}, // 🚁 - {"\U0001F680", "Rocket"}, // 🚀 - {"\U0001F6EB", "Airplane"}, // 🛫 - - // Currency Symbols - {"\U00000024", "Dollar Sign"}, // $ - {"\U000000A3", "Pound Sign"}, // £ - {"\U000000A5", "Yen Sign"}, // ¥ - {"\U000020AC", "Euro Sign"}, // € - {"\U0001F4B5", "Dollar Banknote"}, // 💵 - {"\U0001F4B4", "Yen Banknote"}, // 💴 - - // Card Suits - {"\U00002660", "Black Spade Suit"}, // ♠️ - {"\U00002663", "Black Club Suit"}, // ♣️ - {"\U00002665", "Black Heart Suit"}, // ♥️ - {"\U00002666", "Black Diamond Suit"}, // ♦️ - {"\U0001F0CF", "Joker Card"}, // 🃏 - - // Office Supplies and Objects - {"\U0001F4DA", "Books"}, // 📚 - {"\U0001F4D7", "Green Book"}, // 📗 - {"\U0001F4C8", "Chart with Upwards Trend"}, // 📈 - {"\U0001F4C9", "Chart with Downwards Trend"}, // 📉 - {"\U0001F4B0", "Money Bag"}, // 💰 - {"\U0001F4B8", "Money with Wings"}, // 💸 - {"\U0001F4E6", "Package"}, // 📦 - - // Miscellaneous Symbols - {"\U00002757", "Exclamation Mark"}, // ❗ - {"\U00002714", "Check Mark"}, // ✔️ - {"\U0000274C", "Cross Mark"}, // ❌ - {"\U00002705", "Check Mark Button"}, // ✅ - {"\U00002B50", "White Star"}, // ⭐ - {"\U0001F31F", "Glowing Star"}, // 🌟 - {"\U0001F4A1", "Light Bulb"}, // 💡 - {"\U0001F4A3", "Bomb"}, // 💣 - {"\U0001F4A9", "Pile of Poo"}, // 💩 - // Musical Symbols - {"\U0001F3B5", "Musical Note"}, // 🎵 - {"\U0001F3B6", "Multiple Musical Notes"}, // 🎶 - {"\U0001F3BC", "Musical Score"}, // 🎼 - {"\U0001F399", "Studio Microphone"}, // 🎙️ - {"\U0001F3A4", "Microphone"}, // 🎤 - - // Food and Drink - {"\U0001F35F", "Cheese Wedge"}, // 🧀 - {"\U0001F355", "Slice of Pizza"}, // 🍕 - {"\U0001F32D", "Taco"}, // 🌮 - {"\U0001F37D", "Beer Mug"}, // 🍻 - {"\U0001F96B", "Cup with Straw"}, // 🥤 - {"\U0001F32E", "Hot Pepper"}, // 🌶️ - {"\U0001F95A", "Potato"}, // 🥔 - - // Zodiac Signs - {"\U00002600", "Aries"}, // ♈ - {"\U00002601", "Taurus"}, // ♉ - {"\U00002602", "Gemini"}, // ♊ - {"\U00002603", "Cancer"}, // ♋ - {"\U00002604", "Leo"}, // ♌ - {"\U00002605", "Virgo"}, // ♍ - {"\U00002606", "Libra"}, // ♎ - {"\U00002607", "Scorpio"}, // ♏ - {"\U00002608", "Sagittarius"}, // ♐ - {"\U00002609", "Capricorn"}, // ♑ - {"\U0000260A", "Aquarius"}, // ♒ - {"\U0000260B", "Pisces"}, // ♓ - - // Miscellaneous Shapes - {"\U0001F4C8", "Chart Increasing"}, // 📈 - {"\U0001F4C9", "Chart Decreasing"}, // 📉 - {"\U0001F4CA", "Bar Chart"}, // 📊 - {"\U0001F7E6", "Orange Circle"}, // 🟠 - {"\U0001F7E7", "Yellow Circle"}, // 🟡 - {"\U0001F7E8", "Green Circle"}, // 🟢 - {"\U0001F7E9", "Blue Circle"}, // 🔵 - {"\U0001F7EA", "Purple Circle"}, // 🟣 - - // Flags - {"\U0001F1E6\U0001F1E9", "Flag of France"}, // 🇫🇷 - {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, // 🇩🇪 - {"\U0001F1FA\U0001F1F8", "Flag of United States"}, // 🇺🇸 - {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, // 🇨🇦 - {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, // 🇮🇹 - {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, // 🇦🇺 - {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, // 🇪🇸 - - // Additional Miscellaneous Symbols - {"\U0001F4A5", "Collision"}, // 💥 - {"\U0001F4A6", "Sweat Droplets"}, // 💦 - {"\U0001F4A8", "Dashing Away"}, // 💨 - {"\U0001F50B", "Battery"}, // 🔋 - {"\U0001F4BB", "Laptop Computer"}, // 💻 - {"\U0001F4DE", "Telephone"}, // 📞 - {"\U0001F4E7", "Incoming Envelope"}, // 📧 -}; +remo_t remo[] = {{"\U0001F600", "Grinning Face"}, + {"\U0001F601", "Beaming Face with Smiling Eyes"}, + {"\U0001F602", "Face with Tears of Joy"}, + {"\U0001F923", "Rolling on the Floor Laughing"}, + {"\U0001F603", "Grinning Face with Big Eyes"}, + {"\U0001F604", "Grinning Face with Smiling Eyes"}, + {"\U0001F609", "Winking Face"}, + {"\U0001F60A", "Smiling Face with Smiling Eyes"}, + {"\U0001F60D", "Smiling Face with Heart-Eyes"}, + {"\U0001F618", "Face Blowing a Kiss"}, + {"\U0001F617", "Kissing Face"}, + {"\U0001F61A", "Kissing Face with Closed Eyes"}, + {"\U0001F642", "Slightly Smiling Face"}, + {"\U0001F643", "Upside-Down Face"}, + {"\U0001F970", "Smiling Face with Hearts"}, + {"\U0001F60B", "Face Savoring Food"}, + {"\U0001F61B", "Face with Tongue"}, + {"\U0001F61C", "Winking Face with Tongue"}, + {"\U0001F92A", "Zany Face"}, + {"\U0001F929", "Star-Struck"}, + {"\U0001F631", "Face Screaming in Fear"}, + {"\U0001F62D", "Loudly Crying Face"}, + {"\U0001F624", "Face with Steam From Nose"}, + {"\U0001F620", "Angry Face"}, + {"\U0001F621", "Pouting Face"}, + {"\U0001F47B", "Ghost"}, + {"\U0001F480", "Skull"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F47D", "Alien"}, + {"\U000025A0", "Black Square"}, + {"\U000025B2", "Upward Triangle"}, + {"\U000025CF", "Black Circle"}, + {"\U000025CB", "White Circle"}, + {"\U00002B1B", "Large Black Square"}, + {"\U00002B1C", "Large White Square"}, + {"\U00002200", "For All"}, + {"\U00002203", "Exists"}, + {"\U00002205", "Empty Set"}, + {"\U00002207", "Nabla"}, + {"\U0000220F", "N-Ary Product"}, + {"\U00002212", "Minus Sign"}, + {"\U0000221E", "Infinity"}, + {"\U00002190", "Left Arrow"}, + {"\U00002191", "Up Arrow"}, + {"\U00002192", "Right Arrow"}, + {"\U00002193", "Down Arrow"}, + {"\U00002195", "Up Down Arrow"}, + {"\U00002197", "Up Right Arrow"}, + {"\U00002198", "Down Right Arrow"}, + {"\U000027A1", "Black Right Arrow"}, + {"\U00002714", "Check Mark"}, + {"\U00002716", "Heavy Multiplication X"}, + {"\U00002728", "Sparkles"}, + {"\U00002757", "Exclamation Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002795", "Heavy Plus Sign"}, + {"\U00002600", "Sun"}, + {"\U00002614", "Umbrella with Rain Drops"}, + {"\U00002620", "Skull and Crossbones"}, + {"\U000026A0", "Warning Sign"}, + {"\U000026BD", "Soccer Ball"}, + {"\U000026C4", "Snowman"}, + {"\U00002733", "Eight Pointed Black Star"}, + {"\U00002734", "Eight Spoked Asterisk"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U00002728", "Sparkles"}, + {"\U0001F98A", "Fox"}, + {"\U0001F415", "Dog"}, + {"\U0001F431", "Cat Face"}, + {"\U0001F435", "Monkey Face"}, + {"\U0001F408", "Black Cat"}, + {"\U0001F98C", "Deer"}, + {"\U0001F344", "Mushroom"}, + {"\U0001F333", "Tree"}, + {"\U0001F308", "Rainbow"}, + {"\U0001F320", "Shooting Star"}, + {"\U00002600", "Sun"}, + {"\U00002601", "Cloud"}, + {"\U000026A1", "High Voltage"}, + {"\U0001F525", "Fire"}, + {"\U000026C4", "Snowman"}, + {"\U0001F30A", "Water Wave"}, + {"\U0001F68C", "Bus"}, + {"\U0001F697", "Car"}, + {"\U0001F6B2", "Bicycle"}, + {"\U0001F6A2", "Ship"}, + {"\U0001F681", "Helicopter"}, + {"\U0001F680", "Rocket"}, + {"\U0001F6EB", "Airplane"}, + {"\U00000024", "Dollar Sign"}, + {"\U000000A3", "Pound Sign"}, + {"\U000000A5", "Yen Sign"}, + {"\U000020AC", "Euro Sign"}, + {"\U0001F4B5", "Dollar Banknote"}, + {"\U0001F4B4", "Yen Banknote"}, + {"\U00002660", "Black Spade Suit"}, + {"\U00002663", "Black Club Suit"}, + {"\U00002665", "Black Heart Suit"}, + {"\U00002666", "Black Diamond Suit"}, + {"\U0001F0CF", "Joker Card"}, + {"\U0001F4DA", "Books"}, + {"\U0001F4D7", "Green Book"}, + {"\U0001F4C8", "Chart with Upwards Trend"}, + {"\U0001F4C9", "Chart with Downwards Trend"}, + {"\U0001F4B0", "Money Bag"}, + {"\U0001F4B8", "Money with Wings"}, + {"\U0001F4E6", "Package"}, + {"\U00002757", "Exclamation Mark"}, + {"\U00002714", "Check Mark"}, + {"\U0000274C", "Cross Mark"}, + {"\U00002705", "Check Mark Button"}, + {"\U00002B50", "White Star"}, + {"\U0001F31F", "Glowing Star"}, + {"\U0001F4A1", "Light Bulb"}, + {"\U0001F4A3", "Bomb"}, + {"\U0001F4A9", "Pile of Poo"}, + {"\U0001F3B5", "Musical Note"}, + {"\U0001F3B6", "Multiple Musical Notes"}, + {"\U0001F3BC", "Musical Score"}, + {"\U0001F399", "Studio Microphone"}, + {"\U0001F3A4", "Microphone"}, + {"\U0001F35F", "Cheese Wedge"}, + {"\U0001F355", "Slice of Pizza"}, + {"\U0001F32D", "Taco"}, + {"\U0001F37D", "Beer Mug"}, + {"\U0001F96B", "Cup with Straw"}, + {"\U0001F32E", "Hot Pepper"}, + {"\U0001F95A", "Potato"}, + {"\U00002600", "Aries"}, + {"\U00002601", "Taurus"}, + {"\U00002602", "Gemini"}, + {"\U00002603", "Cancer"}, + {"\U00002604", "Leo"}, + {"\U00002605", "Virgo"}, + {"\U00002606", "Libra"}, + {"\U00002607", "Scorpio"}, + {"\U00002608", "Sagittarius"}, + {"\U00002609", "Capricorn"}, + {"\U0000260A", "Aquarius"}, + {"\U0000260B", "Pisces"}, + {"\U0001F4C8", "Chart Increasing"}, + {"\U0001F4C9", "Chart Decreasing"}, + {"\U0001F4CA", "Bar Chart"}, + {"\U0001F7E6", "Orange Circle"}, + {"\U0001F7E7", "Yellow Circle"}, + {"\U0001F7E8", "Green Circle"}, + {"\U0001F7E9", "Blue Circle"}, + {"\U0001F7EA", "Purple Circle"}, + {"\U0001F1E6\U0001F1E9", "Flag of France"}, + {"\U0001F1E8\U0001F1E6", "Flag of Germany"}, + {"\U0001F1FA\U0001F1F8", "Flag of United States"}, + {"\U0001F1E7\U0001F1F7", "Flag of Canada"}, + {"\U0001F1EE\U0001F1F2", "Flag of Italy"}, + {"\U0001F1F8\U0001F1EC", "Flag of Australia"}, + {"\U0001F1F3\U0001F1F4", "Flag of Spain"}, + {"\U0001F4A5", "Collision"}, + {"\U0001F4A6", "Sweat Droplets"}, + {"\U0001F4A8", "Dashing Away"}, + {"\U0001F50B", "Battery"}, + {"\U0001F4BB", "Laptop Computer"}, + {"\U0001F4DE", "Telephone"}, + {"\U0001F4E7", "Incoming Envelope"}}; size_t remo_count = sizeof(remo) / sizeof(remo[0]); void rstrtolower(const char *input, char *output) { @@ -3553,16 +3652,16 @@ void rstrtolower(const char *input, char *output) { } *output = 0; } + bool rstrinstr(const char *haystack, const char *needle) { char lower1[strlen(haystack) + 1]; char lower2[strlen(needle) + 1]; rstrtolower(haystack, lower1); rstrtolower(needle, lower2); - return strstr(lower1, lower2) ? true : false; + return strstr(lower1, lower2) != NULL; } void remo_print() { - for (size_t i = 0; i < remo_count; i++) { printf("%s - %s\n", remo[i].str, remo[i].description); } @@ -3905,7 +4004,6 @@ void rlib_test_progressbar() { if (percentage_changed) { \ printf("\r%d%%", percentage); \ fflush(stdout); \ - \ prev_percentage = percentage; \ } \ } \ @@ -3929,7 +4027,6 @@ typedef struct rbench_function_t { bool last; int argc; unsigned long times_executed; - nsecs_t average_execution_time; nsecs_t total_execution_time; } rbench_function_t; @@ -3955,7 +4052,6 @@ typedef struct rbench_t { 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; @@ -3963,23 +4059,18 @@ FILE *_rbench_stdnull = NULL; void rbench_toggle_stdout(rbench_t *r) { if (!r->stdout) { - if (_rbench_stdout == NULL) { + if (!_rbench_stdout) { _rbench_stdout = stdout; } - if (_rbench_stdnull == NULL) { + if (!_rbench_stdnull) { _rbench_stdnull = fopen("/dev/null", "wb"); } - if (stdout == _rbench_stdout) { - stdout = _rbench_stdnull; - } else { - stdout = _rbench_stdout; - } + stdout = (stdout == _rbench_stdout) ? _rbench_stdnull : _rbench_stdout; } } + void rbench_restore_stdout(rbench_t *r) { - if (r->stdout) - return; - if (_rbench_stdout) { + if (!r->stdout && _rbench_stdout) { stdout = _rbench_stdout; } if (_rbench_stdnull) { @@ -3992,8 +4083,9 @@ rbench_t *rbench_new(); rbench_t *_rbench = NULL; rbench_function_t *rbf; + rbench_t *rbench() { - if (_rbench == NULL) { + if (!_rbench) { _rbench = rbench_new(); } return _rbench; @@ -4009,8 +4101,7 @@ void rbench_add_function(rbench_t *rp, const char *name, const char *group, void #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++; + rbench_function_t *f = &rp->functions[rp->function_count++]; f->average_execution_time = 0; f->total_execution_time = 0; f->times_executed = 0; @@ -4026,47 +4117,42 @@ void rbench_reset_function(rbench_function_t *f) { } void rbench_reset(rbench_t *rp) { - for (unsigned int i = 0; i < rp->function_count; i++) { + for (unsigned int i = 0; i < rp->function_count; ++i) { rbench_reset_function(&rp->functions[i]); } } + 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) { + for (unsigned int i = 0; i < r->function_count; ++i) { + if (!time || 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; -} + +bool rbench_was_last_function(rbench_t *r) { return r->current == &r->functions[r->function_count - 1]; } rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, int argc) { rbench_toggle_stdout(r); - if (findex == 0) { + if (!findex) { r->execution_time = 0; } rbench_function_t *rf = &r->functions[findex]; rf->argc = argc; rbf = rf; r->current = rf; - if (r->show_progress) + 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); if (r->progress_bar) { @@ -4074,42 +4160,35 @@ void rbench_execute_finish(rbench_t *r) { 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) + if (!r->silent) { rprintgf(stderr, "Benchmark results:\n"); + } nsecs_t total_time = 0; - - for (unsigned int i = 0; i < r->function_count; i++) { + 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 (is_winner && !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) + if (!r->silent) { rprintgf(stderr, "Total execution time: %s\n", format_time(total_time)); + } } rbench_restore_stdout(r); rbf = NULL; r->current = NULL; } + struct rbench_t *rbench_execute(rbench_t *r, long times) { - - for (unsigned int i = 0; i < r->function_count; i++) { - + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); rbench_call c = (rbench_call)f->call; nsecs_t start = nsecs(); @@ -4118,7 +4197,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4134,8 +4213,7 @@ struct rbench_t *rbench_execute(rbench_t *r, long times) { } struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -4144,7 +4222,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4160,8 +4238,7 @@ struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { } struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2) { - - for (unsigned int i = 0; i < r->function_count; i++) { + 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(); @@ -4170,7 +4247,7 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4186,10 +4263,8 @@ struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2 } struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { - - for (unsigned int i = 0; i < r->function_count; i++) { + for (unsigned int i = 0; i < r->function_count; ++i) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); - rbench_call3 c = (rbench_call3)f->call; nsecs_t start = nsecs(); f->first = true; @@ -4197,7 +4272,7 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 f->first = false; f->last = false; f->times_executed++; - for (int j = 1; j < times; j++) { + for (int j = 1; j < times; ++j) { c(arg1, arg2, arg3); f->times_executed++; f->last = f->times_executed == r->times - 1; @@ -4212,7 +4287,6 @@ struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2 } 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; @@ -4227,13 +4301,14 @@ rbench_t *rbench_new() { r->show_progress = true; return r; } + void rbench_free(rbench_t *r) { free(r); } #endif + bool check_lcov() { char buffer[1024 * 64]; - FILE *fp; - fp = popen("lcov --help", "r"); + FILE *fp = popen("lcov --help", "r"); if (fp == NULL) { return false; } @@ -4255,7 +4330,6 @@ int rcov_main(int argc, char *argv[]) { strcat(argstr, " "); } if (!check_lcov()) { - printf("lcov is not installed. Please execute `sudo apt install lcov`.\n"); return 1; } @@ -4269,22 +4343,19 @@ int rcov_main(int argc, char *argv[]) { "genhtml %s.coverage.info --output-directory /tmp/%s.coverage", "rm -f *.gcda 2>/dev/null", "rm -f *.gcno 2>/dev/null", - "rm -f %s.coverage.info 2>/dev/null", //"cat gmon.out", - + "rm -f %s.coverage.info 2>/dev/null", "gprof %s_coverage.o gmon.out > output.rcov_analysis", - "rm -f gmon.out", "cat output.rcov_analysis", "rm output.rcov_analysis", "rm -f %s_coverage.o", - "google-chrome /tmp/%s.coverage/index.html"}; uint command_count = sizeof(commands) / sizeof(commands[0]); - RBENCH(1,{ + RBENCH(1, { for (uint i = 0; i < command_count; i++) { char *formatted_command = sbuf(""); sprintf(formatted_command, commands[i], source_file, source_file); - // printf("%s\n", formatted_command); + if (formatted_command[0] == '.' && formatted_command[1] == '/') { strcat(formatted_command, " "); strcat(formatted_command, argstr); @@ -4293,14 +4364,45 @@ int rcov_main(int argc, char *argv[]) { if (system(formatted_command)) { printf("`%s` returned non-zero code.\n", formatted_command); } - }); - } + } + }); return 0; } + #endif +// Written by retoor@molodetz.nl + +// This code implements an HTTP server that can handle multiple connections, parse HTTP requests, log request information, and respond to +// different request types (including file and counter requests). + +// Include summary: +// This code includes custom headers ("rio.h", "rmalloc.h", "rstring.h", "rtemp.h", "rtime.h") and libraries ("arpa/inet.h", "pthread.h", +// "signal.h", "stdarg.h", "stdbool.h", "stdio.h", "stdlib.h", "string.h", "time.h", "unistd.h") that provide functionality for networking, +// threading, signal handling, and I/O operations. + +// The MIT License (MIT) + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. #ifndef RHTTP_H #define RHTTP_H + #include <arpa/inet.h> #include <pthread.h> #include <signal.h> @@ -4368,6 +4470,7 @@ void rhttp_logs(const char *prefix, const char *level, const char *format, va_li sprintf(buf, "%s%s %s %s\e[0m", prefix, rhttp_current_timestamp(), level, format); vfprintf(stdout, buf, args); } + void rhttp_log_info(const char *format, ...) { if (!rhttp_opt_info) return; @@ -4376,6 +4479,7 @@ void rhttp_log_info(const char *format, ...) { rhttp_logs("\e[32m", "INFO ", format, args); va_end(args); } + void rhttp_log_debug(const char *format, ...) { if (!rhttp_opt_debug) return; @@ -4386,6 +4490,7 @@ void rhttp_log_debug(const char *format, ...) { va_end(args); } + void rhttp_log_warn(const char *format, ...) { if (!rhttp_opt_warn) return; @@ -4395,6 +4500,7 @@ void rhttp_log_warn(const char *format, ...) { va_end(args); } + void rhttp_log_error(const char *format, ...) { if (!rhttp_opt_error) return; @@ -4428,6 +4534,7 @@ void rhttp_free_header(rhttp_header_t *h) { if (next) rhttp_free_header(next); } + void rhttp_rhttp_free_headers(rhttp_request_t *r) { if (!r->headers) return; @@ -4488,6 +4595,7 @@ long rhttp_header_get_long(rhttp_request_t *r, const char *name) { } return -1; } + char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { rhttp_header_t *h = r->headers; while (h) { @@ -4499,18 +4607,22 @@ char *rhttp_header_get_string(rhttp_request_t *r, const char *name) { } void rhttp_print_header(rhttp_header_t *h) { rhttp_log_debug("Header: <%s> \"%s\"\n", h->name, h->value); } + void rhttp_print_headers(rhttp_header_t *h) { while (h) { rhttp_print_header(h); h = h->next; } } + void rhttp_print_request_line(rhttp_request_t *r) { rhttp_log_info("%s %s %s\n", r->method, r->path, r->version); } + void rhttp_print_request(rhttp_request_t *r) { rhttp_print_request_line(r); if (rhttp_opt_debug) rhttp_print_headers(r->headers); } + void rhttp_close(rhttp_request_t *r) { if (!r) return; @@ -4518,6 +4630,7 @@ void rhttp_close(rhttp_request_t *r) { close(r->c); rhttp_free_request(r); } + rhttp_request_t *rhttp_parse_request(int s) { rhttp_request_t *request = (rhttp_request_t *)malloc(sizeof(rhttp_request_t)); http_request_init(request); @@ -4585,7 +4698,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { unsigned char *to_send_original = to_send; memcpy(to_send, tsend, to_send_len); - // to_send[to_send_len] = '\0'; long bytes_sent = 0; long bytes_sent_total = 0; while (1) { @@ -4600,7 +4712,6 @@ size_t rhttp_send_drain(int s, void *tsend, size_t to_send_len) { break; } else if (!bytes_sent) { bytes_sent_total = 0; - // error break; } else { rhttp_log_info("Extra send of %d/%d bytes.\n", bytes_sent_total, to_send_len); @@ -4647,7 +4758,6 @@ void rhttp_serve(const char *host, int port, int backlog, int request_logging, i } if (!r->keep_alive && !r->closed) { rhttp_close(r); - } else if (r->keep_alive && !r->closed) { } if (r->closed) { break; @@ -4700,7 +4810,7 @@ int rhttp_file_response(rhttp_request_t *r, char *path) { close(r->c); fclose(f); return 1; -}; +} int rhttp_file_request_handler(rhttp_request_t *r) { char *path = r->path; @@ -4710,9 +4820,10 @@ int rhttp_file_request_handler(rhttp_request_t *r) { return 0; } return rhttp_file_response(r, path); -}; +} unsigned int counter = 100000000; + int rhttp_counter_request_handler(rhttp_request_t *r) { if (!strncmp(r->path, "/counter", strlen("/counter"))) { counter++; @@ -4728,6 +4839,7 @@ int rhttp_counter_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_root_request_handler(rhttp_request_t *r) { if (!strcmp(r->path, "/")) { char to_send[1024] = {0}; @@ -4739,6 +4851,7 @@ int rhttp_root_request_handler(rhttp_request_t *r) { } return 0; } + int rhttp_error_404_handler(rhttp_request_t *r) { char to_send[1024] = {0}; sprintf(to_send, "HTTP/1.1 404 Document not found\r\nContent-Length: " @@ -4752,17 +4865,14 @@ int rhttp_default_request_handler(rhttp_request_t *r) { if (rhttp_opt_debug || rhttp_opt_request_logging) rhttp_print_request(r); if (rhttp_counter_request_handler(r)) { - // Counter handler rhttp_log_info("Counter handler found for: %s\n", r->path); } else if (rhttp_root_request_handler(r)) { - // Root handler rhttp_log_info("Root handler found for: %s\n", r->path); } else if (rhttp_file_request_handler(r)) { rhttp_log_info("File %s sent\n", r->path); } else if (rhttp_error_404_handler(r)) { rhttp_log_warn("Error 404 for: %s\n", r->path); - // Error handler } else { rhttp_log_warn("No handler found for: %s\n", r->path); close(rhttp_c); @@ -4826,8 +4936,6 @@ int rhttp_main(int argc, char *argv[]) { return 0; } -/* CLIENT CODE */ - typedef struct rhttp_client_request_t { char *host; int port; @@ -4884,12 +4992,14 @@ int rhttp_execute_request(rhttp_client_request_t *r) { close(s); return ret; } + void rhttp_reset_request(rhttp_client_request_t *r) { free(r->response); r->is_done = false; r->response = NULL; r->bytes_received = 0; } + void rhttp_free_client_request(rhttp_client_request_t *r) { if (r->request) free(r->request); @@ -4905,7 +5015,6 @@ void rhttp_free_client_request(rhttp_client_request_t *r) { void rhttp_client_bench(int workers, int times, const char *host, int port, const char *path) { rhttp_client_request_t *requests[workers]; while (times > 0) { - for (int i = 0; i < workers && times; i++) { requests[i] = rhttp_create_request(host, port, path); rhttp_execute_request(requests[i]); @@ -4913,6 +5022,7 @@ void rhttp_client_bench(int workers, int times, const char *host, int port, cons } } } + char *rhttp_client_get(const char *host, int port, const char *path) { if (!rhttp_c_mutex_initialized) { rhttp_c_mutex_initialized = 1; @@ -4927,7 +5037,7 @@ char *rhttp_client_get(const char *host, int port, const char *path) { reconnects++; tick(); if (reconnects == reconnects_max) { - fprintf(stderr, "Maxium reconnects exceeded for %s:%d\n", host, port); + fprintf(stderr, "Maximum reconnects exceeded for %s:%d\n", host, port); rhttp_free_client_request(r); return NULL; } @@ -4945,8 +5055,18 @@ char *rhttp_client_get(const char *host, int port, const char *path) { pthread_mutex_unlock(&rhttp_c_mutex); return result; } -/*END CLIENT CODE */ + #endif +// Written by retoor@molodetz.nl + +// A C library for creating and manipulating JSON structures. It provides functions to build JSON strings recursively, including starting +// and closing JSON objects and arrays, adding key-value pairs (for strings, integers, numbers, booleans, and durations), and freeing JSON +// objects. + +// Includes for memory management, string manipulation, time handling, and testing utilities: rmalloc.h, rtypes.h, rstring.h, rtemp.h, +// rtime.h, rtest.h + +// MIT License #ifndef RJSON_H #define RJSON_H @@ -4961,7 +5081,7 @@ rjson_t *rjson() { rjson_t *json = rmalloc(sizeof(rjson_t)); json->size = 1024; json->length = 0; - json->content = (char *)rmalloc(json->size); + json->content = rmalloc(json->size); json->content[0] = 0; return json; } @@ -4977,10 +5097,12 @@ void rjson_write(rjson_t *rjs, char *content) { } void rjson_object_start(rjson_t *rjs) { - if (rstrendswith(rjs->content, "}")) + if (rstrendswith(rjs->content, "}")) { rjson_write(rjs, ","); + } rjson_write(rjs, "{"); } + void rjson_object_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -4988,11 +5110,14 @@ void rjson_object_close(rjson_t *rjs) { } rjson_write(rjs, "}"); } + void rjson_array_start(rjson_t *rjs) { - if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) + if (rjs->length && (rstrendswith(rjs->content, "}") || rstrendswith(rjs->content, "]"))) { rjson_write(rjs, ","); + } rjson_write(rjs, "["); } + void rjson_array_close(rjson_t *rjs) { if (rstrendswith(rjs->content, ",")) { rjs->content[rjs->length - 1] = 0; @@ -5008,7 +5133,7 @@ void rjson_kv_string(rjson_t *rjs, char *key, char *value) { rjson_write(rjs, "\""); rjson_write(rjs, key); rjson_write(rjs, "\":\""); - char *value_str = (char *)rmalloc(strlen(value) + 4096); + char *value_str = rmalloc(strlen(value) + 4096); rstraddslashes(value, value_str); rjson_write(rjs, value_str); free(value_str); @@ -5026,15 +5151,14 @@ void rjson_kv_int(rjson_t *rjs, char *key, ulonglong value) { sprintf(value_str, "%lld", value); rjson_write(rjs, value_str); } + void rjson_kv_number(rjson_t *rjs, char *key, ulonglong value) { if (rjs->length && !rstrendswith(rjs->content, "{") && !rstrendswith(rjs->content, "[")) { rjson_write(rjs, ","); } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(rformat_number(value))); rjson_write(rjs, "\""); } @@ -5055,12 +5179,11 @@ void rjson_kv_duration(rjson_t *rjs, char *key, nsecs_t value) { } rjson_write(rjs, "\""); rjson_write(rjs, key); - rjson_write(rjs, "\":"); - rjson_write(rjs, "\""); - + rjson_write(rjs, "\":\""); rjson_write(rjs, sbuf(format_time(value))); rjson_write(rjs, "\""); } + void rjson_free(rjson_t *rsj) { free(rsj->content); free(rsj); @@ -5071,10 +5194,38 @@ void rjson_key(rjson_t *rsj, char *key) { rjson_write(rsj, key); rjson_write(rsj, "\":"); } + #endif +// Written by retoor@molodetz.nl + +// This source code provides a simple autocomplete functionality by leveraging string list management and pattern matching with escaping +// characters where necessary. + +// No external imports or includes other than basic string operations and standard library functions are used in the source code. + +// MIT License +// +// 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 RAUTOCOMPLETE_H #define RAUTOCOMPLETE_H -#define R4_DEBUG + #ifndef RREX4_H #define RREX4_H #include <assert.h> @@ -5842,7 +5993,7 @@ bool r4_match(char *str, char *expr) { char *r4_escape(char *content) { size_t size = strlen(content) * 2 + 1; - char *escaped = (char *)calloc(size, sizeof(char)); + char *escaped = calloc(size, sizeof(char)); char *espr = escaped; char *to_escape = "?*+()[]{}^$\\"; *espr = '('; @@ -5867,22 +6018,19 @@ char *r4_escape(char *content) { } char *rautocomplete_find(rstring_list_t *list, char *expr) { - if (!list->count) - return NULL; - if (!expr || !strlen(expr)) + if (!list->count || !expr || !strlen(expr)) return NULL; char *escaped = r4_escape(expr); - for (unsigned int i = list->count - 1; i == 0; i--) { - char *match; + for (unsigned int i = list->count - 1; i >= 0; i--) { + char *match = NULL; r4_t *r = r4(list->strings[i], escaped); if (r->valid && r->match_count == 1) { match = strdup(r->matches[0]); } r4_free(r); if (match) { - free(escaped); return match; } @@ -5890,6 +6038,7 @@ char *rautocomplete_find(rstring_list_t *list, char *expr) { free(escaped); return NULL; } + #endif #ifndef RKEYTABLE_H #define RKEYTABLE_H @@ -5959,11 +6108,33 @@ rnklist *rkset(char *name, char *defn) { } #endif +// Written by retoor@molodetz.nl + +// This source code provides the implementation of a simple hash table using separate chaining for collision resolution. It contains +// functions to hash, retrieve, and insert entries into the hash table. + +// Imported library: The code uses the non-standard library "rmalloc.h". + +/* MIT License +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 RHASHTABLE_H #define RHASHTABLE_H -/* - ORIGINAL SOURCE IS FROM K&R - */ #include <stdio.h> #include <stdlib.h> @@ -5971,44 +6142,42 @@ rnklist *rkset(char *name, char *defn) { #define HASHSIZE 101 -// Structure for the table entries typedef struct rnlist { struct rnlist *next; char *name; char *defn; } rnlist; -// Hash table array static rnlist *rhashtab[HASHSIZE]; -// Hash function unsigned rhash(char *s) { - unsigned hashval; - for (hashval = 0; *s != '\0'; s++) + unsigned hashval = 0; + while (*s != '\0') { hashval = *s + 31 * hashval; + s++; + } return hashval % HASHSIZE; } rnlist *rlget(char *s) { rnlist *np; - for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) + for (np = rhashtab[rhash(s)]; np != NULL; np = np->next) { if (strcmp(s, np->name) == 0) - return np; // Found - return NULL; // Not found + return np; + } + return NULL; } -// Lookup function char *rget(char *s) { rnlist *np = rlget(s); return np ? np->defn : NULL; } -// Install function (adds a name and definition to the table) struct rnlist *rset(char *name, char *defn) { struct rnlist *np = NULL; unsigned hashval; - if ((rlget(name)) == NULL) { // Not found + if ((rlget(name)) == NULL) { np = (struct rnlist *)malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) return NULL; @@ -6016,8 +6185,9 @@ struct rnlist *rset(char *name, char *defn) { np->next = rhashtab[hashval]; rhashtab[hashval] = np; } else { - if (np->defn) - free((void *)np->defn); + if (np->defn) { + free(np->defn); + } np->defn = NULL; } if ((np->defn = strdup(defn)) == NULL) @@ -6025,7 +6195,6 @@ struct rnlist *rset(char *name, char *defn) { return np; } #endif - #ifndef RREX3_H #define RREX3_H #include <assert.h> @@ -7254,6 +7423,16 @@ void rrex3_test() { rrex3_free(rrex); } #endif +// Written by retoor@molodetz.nl + +// This code provides a simple memory arena implementation, which allows dynamic memory allocation within a predefined size. It includes +// functions for constructing a new arena, allocating memory within the arena, resetting, and freeing the arena. + +// The code utilizes rmalloc and rfree for custom memory allocation, which are likely part of another library not defined within the +// standard C library. + +// MIT License + #ifndef RARENA_H #define RARENA_H @@ -7291,7 +7470,6 @@ void *arena_alloc(arena_t *arena, size_t size) { } void arena_free(arena_t *arena) { - // Just constructed and unused arena memory is NULL so no free needed if (arena->memory) { rfree(arena->memory); } @@ -7299,9 +7477,20 @@ void arena_free(arena_t *arena) { } void arena_reset(arena_t *arena) { arena->pointer = 0; } + #endif +// Written by retoor@molodetz.nl + +// This code provides functions to determine and convert between snake_case and camelCase strings. It reads from files and processes string +// formats, outputting converted formats. + +// The source code includes custom headers: "rio.h", "rmalloc.h", "rprint.h", "rstring.h". + +// MIT License + #ifndef RCASE_H #define RCASE_H + #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -7311,47 +7500,42 @@ void arena_reset(arena_t *arena) { arena->pointer = 0; } #define RCAMEL_CASE 1 #define RSNAKE_CASE 2 #define RINVALID_CASE 0 -#define RCONST_TEST_T 4; +#define RCONST_TEST_T 4 int rdetermine_case(const char *str) { + char previousChar = 0; int length = strlen(str); - char p = 0; while (*str) { - if (p == '_' && islower(*str)) + if (previousChar == '_' && islower(*str)) return RSNAKE_CASE; - if (p != '_' && !isupper(p) && isupper(*str)) + if (previousChar != '_' && !isupper(previousChar) && isupper(*str)) return RCAMEL_CASE; - p = *str; + previousChar = *str; str++; } - return RINVALID_CASE; - if (length == 0) { + if (length == 0) return RINVALID_CASE; - } + if (strchr(str, '_')) { - if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) { + if (str[0] == '_' || str[length - 1] == '_' || strstr(str, "__")) return RINVALID_CASE; - } + for (int i = 0; i < length; i++) { - if (!islower(str[i]) && str[i] != '_') { + if (!islower(str[i]) && str[i] != '_') return RINVALID_CASE; - } } return RSNAKE_CASE; } else { - - if (!islower(str[0])) { + if (!islower(str[0])) return RINVALID_CASE; - } + for (int i = 1; i < length; i++) { - if (str[i] == '_') { + if (str[i] == '_') return RINVALID_CASE; - } - if (isupper(str[i]) && isupper(str[i - 1])) { + if (isupper(str[i]) && isupper(str[i - 1])) return RINVALID_CASE; - } } return RCAMEL_CASE; } @@ -7364,37 +7548,24 @@ char *rsnake_to_camel(const char *snake_case) { int toUpper = 0; for (int i = 0; i < length; i++) { - if (i > 0 && snake_case[i] == '_' && snake_case[i + 1] == 'T') { - toUpper = 1; - if (snake_case[i + 1] == 'T' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - - toUpper = 0; + if (snake_case[i] == '_') { + if (snake_case[i + 1] == 'T' || (snake_case[i + 1] == 't' && !isspace(snake_case[i + 2]))) { + toUpper = 1; } + continue; } - if (snake_case[i] == '_' && snake_case[i + 1] != 't') { - toUpper = 1; - if (snake_case[i + 1] == 't' && (snake_case[i + 2] != '\n' || snake_case[i + 2] != '\0' || snake_case[i + 2] != ' ')) { - toUpper = 0; - } - } else if (snake_case[i] == '_' && snake_case[i + 1] == 't' && !isspace(snake_case[i + 2])) { - toUpper = 1; - } else if (snake_case[i] == '_' && snake_case[i + 1] == 'T' && !isspace(snake_case[i + 2])) { - toUpper = 1; - camel_case[j++] = '_'; - j++; + if (toUpper) { + camel_case[j++] = toupper(snake_case[i]); + toUpper = 0; } else { - if (toUpper) { - camel_case[j++] = toupper(snake_case[i]); - toUpper = 0; - } else { - camel_case[j++] = snake_case[i]; - } + camel_case[j++] = snake_case[i]; } } camel_case[j] = '\0'; return camel_case; } + char *rcamel_to_snake(const char *camelCase) { int length = strlen(camelCase); char *snake_case = (char *)malloc(2 * length + 1); @@ -7402,9 +7573,8 @@ char *rcamel_to_snake(const char *camelCase) { for (int i = 0; i < length; i++) { if (isupper(camelCase[i])) { - if (i != 0) { + if (i != 0) snake_case[j++] = '_'; - } snake_case[j++] = tolower(camelCase[i]); } else { snake_case[j++] = camelCase[i]; @@ -7416,11 +7586,12 @@ char *rcamel_to_snake(const char *camelCase) { } char *rflip_case(char *content) { - if (rdetermine_case(content) == RSNAKE_CASE) { + switch (rdetermine_case(content)) { + case RSNAKE_CASE: return rcamel_to_snake(content); - } else if (rdetermine_case(content) == RCAMEL_CASE) { + case RCAMEL_CASE: return rsnake_to_camel(content); - } else { + default: rprintr("Could not determine case\n"); return NULL; } @@ -7428,20 +7599,17 @@ char *rflip_case(char *content) { char *rflip_case_file(char *filepath) { size_t file_size = rfile_size(filepath); - if (file_size == 0) { + if (file_size == 0) return NULL; - } + char *content = (char *)malloc(file_size); char *result = NULL; + if (rfile_readb(filepath, content, file_size)) { result = rflip_case(content); - if (result) { - free(content); - return result; - } else { - return content; - } + free(content); } + return result; } @@ -7450,6 +7618,7 @@ int rcase_main(int argc, char *argv[]) { printf("usage: rcase <file>\n"); return 1; } + for (int i = 1; i < argc; i++) { char *result = rflip_case_file(argv[i]); if (result) { @@ -7459,8 +7628,8 @@ int rcase_main(int argc, char *argv[]) { } return 0; } -#endif +#endif #ifndef RTERM_H #define RTERM_H #include <stdbool.h> @@ -8226,11 +8395,31 @@ char *rlex_format(char *content) { } #endif +Written by retoor@molodetz.nl + +This code provides an entry point for a library with command-line utilities. It forwards arguments to the corresponding tool based on the user's input. + +Includes used: +- rhttp.h: Provides functionality for an HTTP file server. +- rmerge.h: Includes a tool for merging C source files. +- rcov.h: Implements a code coverage tool based on lcov. +- rcase.h: Contains a utility to convert file naming conventions between camel case and snake case. + +MIT License + #ifndef RLIB_MAIN #define RLIB_MAIN -#ifndef RMERGE_H -#define RMERGE_H -// #include "../mrex/rmatch.h" +// Written by retoor@molodetz.nl + +// The code provides functionality to manage and merge files, particularly focusing on parsing and including scripts or C local includes. It +// implements functionality to read lines from files, extract local includes from script tags, and manage history to avoid duplicate merges. + +// The code utilizes several external libraries: "rlexer.h" for lexical analysis, "rmalloc.h" for memory management, "rprint.h" for printing +// utilities, "rrex3.h" for regular expression handling, and "remo.h" for additional utilities. It also uses standard libraries like +// stdio.h, stdlib.h, string.h, and stdbool.h for fundamental operations. + +// MIT License + #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -8239,9 +8428,8 @@ char *rlex_format(char *content) { bool has_error = false; char *extract_script_src_include(char *line, char *include_path) { - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -8251,18 +8439,8 @@ char *extract_script_src_include(char *line, char *include_path) { } char *extract_c_local_include(char *line, char *include_path) { - // - /* - char res; - res= rmatch_extract(line, "#include.*"\".*\""); - - - printf("%MATCH:%s\n", res); - */ - - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -8273,22 +8451,22 @@ char *extract_c_local_include(char *line, char *include_path) { char *rmerge_readline(FILE *f) { static char data[4096]; - data[0] = 0; + data[0] = '\0'; int index = 0; char c; while ((c = fgetc(f)) != EOF) { if (c != '\0') { - data[index] = c; - index++; + data[index++] = c; if (c == '\n') break; } } - data[index] = 0; - if (data[0] == 0) + data[index] = '\0'; + if (data[0] == '\0') return NULL; return data; } + void writestring(FILE *f, char *line) { char c; while ((c = *line) != '\0') { @@ -8296,15 +8474,16 @@ void writestring(FILE *f, char *line) { line++; } } + char files_history[8096]; char files_duplicate[8096]; bool is_merging = false; void merge_file(char *source, FILE *d) { - if (is_merging == false) { + if (!is_merging) { is_merging = true; - files_history[0] = 0; - files_duplicate[0] = 0; + files_history[0] = '\0'; + files_duplicate[0] = '\0'; } if (strstr(files_history, source)) { if (strstr(files_duplicate, source)) { @@ -8330,37 +8509,12 @@ void merge_file(char *source, FILE *d) { char *line; char include_path[4096]; while ((line = rmerge_readline(fd))) { - - include_path[0] = 0; + include_path[0] = '\0'; if (!*line) break; - - // char *inc = extract_c_local_include(line, include_path); if (!inc) inc = extract_script_src_include(line, include_path); - - /* - if (!strncmp(line, "#include ", 9)) { - int index = 0; - while (line[index] != '"' && line[index] != 0) { - index++; - } - if (line[index] == '"') { - int pindex = 0; - index++; - while (line[index] != '"') { - include_path[pindex] = line[index]; - pindex++; - index++; - } - if (line[index] != '"') { - include_path[0] = 0; - } else { - include_path[pindex] = '\0'; - } - } - }*/ if (inc) { merge_file(inc, d); } else { @@ -8377,7 +8531,6 @@ int rmerge_main(int argc, char *argv[]) { printf("Usage: <input-file>\n"); } else { file_input = argv[1]; - // file_output = argv[2]; } FILE *f = tmpfile(); printf("// RETOOR - %s\n", __DATE__); @@ -8396,30 +8549,27 @@ int rmerge_main(int argc, char *argv[]) { if (has_error) { rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); } else { - rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + rprintgf(stderr, "\\l Merge successful without error(s).%s\n", remo_get("fire")); } return 0; } -#endif void forward_argument(int *argcc, char *argv[]) { int argc = *argcc; for (int i = 0; i < argc; i++) { argv[i] = argv[i + 1]; } - argc--; - *argcc = argc; + (*argcc)--; } int rlib_main(int argc, char *argv[]) { - if (argc == 1) { printf("rlib\n\n"); printf("options:\n"); - printf(" httpd - a http file server. Accepts port as argument.\n"); - printf(" rmerge - a merge tool. Converts c source files to one file \n" + printf(" httpd - a HTTP file server. Accepts port as argument.\n"); + printf(" rmerge - a merge tool. Converts C source files to one file \n" " with local includes by giving main file as argument.\n"); - printf(" rcov - coverage tool theat cleans up after himself. Based on " + printf(" rcov - coverage tool that cleans up after itself. Based on " "lcov.\n"); printf(" rcase - tool to swap input file automatically between" " camel case and snake case.\n"); @@ -8429,7 +8579,6 @@ int rlib_main(int argc, char *argv[]) { forward_argument(&argc, argv); if (!strcmp(argv[0], "httpd")) { - return rhttp_main(argc, argv); } if (!strcmp(argv[0], "rmerge")) { @@ -8447,5 +8596,4 @@ int rlib_main(int argc, char *argv[]) { #endif -// END OF RLIB #endif diff --git a/rliza.h b/rliza.h index c742729..4b311a5 100644 --- a/rliza.h +++ b/rliza.h @@ -1,3 +1,13 @@ +// Written by retoor@molodetz.nl + +// This code defines a data structure and set of functions for handling JSON-like data types in C, allowing for the creation, manipulation, +// serialization, and deserialization of these structures. + +// Includes utilized but not part of the C standard library: "rbuffer.h", "rmalloc.h", and "rstring.h". These files would provide auxiliary +// functionalities such as dynamic memory management, string handling, or buffer manipulation required by this source code. + +// MIT License + #ifndef RLIZA_H #define RLIZA_H #include "rbuffer.h" @@ -56,22 +66,12 @@ void rliza_free(rliza_t *rliza) { rliza_free(rliza->value); rliza->value = NULL; } - // if (rliza->content.array) { - // printf("JAAAA\n"); - // } - // if (rliza->content.object) { - // rliza_free(rliza->content.object); - // rliza->content.object = NULL; - //} if (rliza->type == RLIZA_STRING) { if (rliza->content.string) { free(rliza->content.string); rliza->content.string = NULL; - // else if (rliza->type == RLIZA_NUMBER) { - // printf("STDring freed\n"); } } else if (rliza->type == RLIZA_OBJECT || rliza->type == RLIZA_ARRAY) { - if (rliza->content.map) { for (unsigned int i = 0; i < rliza->count; i++) { rliza_free(rliza->content.map[i]); @@ -79,9 +79,6 @@ void rliza_free(rliza_t *rliza) { free(rliza->content.map); } } - // free(rliza->content.array); - //} - free(rliza); } @@ -245,7 +242,6 @@ void rliza_set_null(rliza_t *self, char *key) { rliza_push_object(self, obj); } if (obj->type == RLIZA_OBJECT) { - rliza_free(obj->value); obj->value = NULL; } else if (obj->type == RLIZA_STRING) { @@ -442,11 +438,8 @@ rliza_t *_rliza_loads(char **content) { rliza_free(rliza); return NULL; } - // char *extracted_with_slashes = (char *)malloc(strlen((char *)extracted) * 2 + 1); - // rstraddslashes(extracted, extracted_with_slashes); rliza->type = RLIZA_STRING; - rliza->content.string = extracted; // extracted_with_slashes; // extracted_without_slashes; - // free(extracted); + rliza->content.string = extracted; return rliza; } else if (**content == '{') { rliza->type = RLIZA_OBJECT; @@ -507,7 +500,6 @@ rliza_t *_rliza_loads(char **content) { } else if (**content == '}') { break; } else { - // Parse error rliza_free(rliza); return NULL; } @@ -579,21 +571,17 @@ rliza_t *_rliza_loads(char **content) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = true; *content += 4; - return rliza; } else if (!strncmp(*content, "false", 5)) { rliza->type = RLIZA_BOOLEAN; rliza->content.boolean = false; *content += 5; - return rliza; } else if (!strncmp(*content, "null", 4)) { rliza->type = RLIZA_NULL; *content += 4; - return rliza; } - // Parsing error rliza_free(rliza); return NULL; } @@ -620,10 +608,7 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%lld", rliza->content.integer); } } else if (rliza->type == RLIZA_STRING) { - - // char *escaped_string = (char *)calloc(strlen((char *)rliza->content.string) * 2 + 1024,sizeof(char)); char *escaped_string = rliza->content.string; - // rstrstripslashes((char *)rliza->content.string, escaped_string); size_t min_size = strlen((char *)escaped_string) + (rliza->key ? strlen(rliza->key) : 0) + 1024; if (size < min_size) { size = min_size + 1; @@ -643,7 +628,6 @@ char *rliza_dumps(rliza_t *rliza) { content = realloc(content, size); sprintf(content, "\"%s\"", escaped_string); } - // free(escaped_string); } else if (rliza->type == RLIZA_NUMBER) { if (rliza->key) { sprintf(content, "\"%s\":%f", rliza->key, rliza->content.number); @@ -676,14 +660,12 @@ char *rliza_dumps(rliza_t *rliza) { sprintf(content, "%s", rliza->content.boolean ? "true" : "false"); } } else if (rliza->type == RLIZA_OBJECT) { - strcat(content, "{"); if (rliza->key) { strcat(content, "\""); strcat(content, rliza->key); strcat(content, "\":{"); } - // bool add_braces = false; for (unsigned i = 0; i < rliza->count; i++) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; @@ -702,7 +684,6 @@ char *rliza_dumps(rliza_t *rliza) { } if (content[strlen(content) - 1] == ',') { content[strlen(content) - 1] = '\0'; - if (rliza->key) { strcat(content, "}"); } @@ -724,8 +705,6 @@ char *rliza_dumps(rliza_t *rliza) { char *content_chunk = rliza_dumps(rliza->content.map[i]); char *content_chunk_stripped = content_chunk; if (*content_chunk_stripped == '{') { - // content_chunk_stripped++; - // content_chunk_stripped[strlen(content_chunk_stripped) - 1] = 0; } if (strlen(content_chunk_stripped) + strlen(content) > size) { size += strlen(content_chunk_stripped) + 20; @@ -739,7 +718,6 @@ char *rliza_dumps(rliza_t *rliza) { content[strlen(content) - 1] = 0; strcat(content, "]"); } else if (rliza->type == RLIZA_NULL) { - if (rliza->key) { char *escaped_key = (char *)malloc(strlen((char *)rliza->key) * 2 + 1); rstraddslashes((char *)rliza->key, escaped_key); diff --git a/rmalloc.h b/rmalloc.h index 444b155..2d0f586 100644 --- a/rmalloc.h +++ b/rmalloc.h @@ -1,24 +1,57 @@ +// Written by retoor@molodetz.nl + +// This code overrides the default dynamic memory allocation functions in C, providing custom implementations for malloc, calloc, realloc, +// free, and strdup, with additional logging and memory usage statistics. + +// Dependence on an external header file "rtemp.h". + +// MIT License +// +// 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 RMALLOC_H #define RMALLOC_H + #ifndef RMALLOC_OVERRIDE #define RMALLOC_OVERRIDE 1 #endif + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #ifndef ulonglong #define ulonglong unsigned long long #endif + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <locale.h> #include "rtemp.h" + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -26,6 +59,7 @@ #else #undef _POSIX_C_SOURCE #endif + ulonglong rmalloc_count = 0; ulonglong rmalloc_alloc_count = 0; ulonglong rmalloc_free_count = 0; @@ -44,6 +78,7 @@ void *rmalloc(size_t size) { rmalloc_total_bytes_allocated += size; return result; } + void *rcalloc(size_t count, size_t size) { void *result; while (!(result = calloc(count, size))) { @@ -54,6 +89,7 @@ void *rcalloc(size_t count, size_t size) { rmalloc_total_bytes_allocated += count * size; return result; } + void *rrealloc(void *obj, size_t size) { if (!obj) { rmalloc_count++; @@ -62,8 +98,7 @@ void *rrealloc(void *obj, size_t size) { rmalloc_alloc_count++; if (obj == _rmalloc_prev_realloc_obj) { rmalloc_total_bytes_allocated += size - _rmalloc_prev_realloc_obj_size; - _rmalloc_prev_realloc_obj_size = size - _rmalloc_prev_realloc_obj_size; - + _rmalloc_prev_realloc_obj_size = size; } else { _rmalloc_prev_realloc_obj_size = size; } @@ -88,6 +123,7 @@ char *rstrdup(const char *s) { rmalloc_total_bytes_allocated += size; return result; } + void *rfree(void *obj) { rmalloc_count--; rmalloc_free_count++; @@ -104,7 +140,6 @@ void *rfree(void *obj) { #endif char *rmalloc_lld_format(ulonglong num) { - char res[100]; res[0] = 0; sprintf(res, "%'lld", num); @@ -130,16 +165,11 @@ char *rmalloc_bytes_format(int factor, ulonglong num) { char *rmalloc_stats() { static char res[200]; res[0] = 0; - // int original_locale = localeconv(); setlocale(LC_NUMERIC, "en_US.UTF-8"); - sprintf(res, "Memory usage: %s, %s (re)allocated, %s unqiue free'd, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), - rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), - - rmalloc_lld_format(rmalloc_count)); - // setlocale(LC_NUMERIC, original_locale); - + sprintf(res, "Memory usage: %s, %s (re)allocated, %s unique freeds, %s in use.", rmalloc_bytes_format(0, rmalloc_total_bytes_allocated), + rmalloc_lld_format(rmalloc_alloc_count), rmalloc_lld_format(rmalloc_free_count), rmalloc_lld_format(rmalloc_count)); setlocale(LC_NUMERIC, ""); return res; } -#endif +#endif \ No newline at end of file diff --git a/rmath.h b/rmath.h index 454dae4..1ed0792 100644 --- a/rmath.h +++ b/rmath.h @@ -1,5 +1,30 @@ +// Written by retoor@molodetz.nl + +// This code provides custom implementations of the `ceil`, `floor`, and `modf` functions for double precision numbers that mimic the +// behavior of those found in the C standard math library. + +// Summary of used imports: <math.h> for mathematical functions. + +// MIT License +// +// 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 RMATH_H #define RMATH_H + #include <math.h> #ifndef ceil @@ -32,4 +57,5 @@ double modf(double x, double *iptr) { return x - int_part; } #endif + #endif \ No newline at end of file diff --git a/rmerge.h b/rmerge.h index be5852e..c8b2dc4 100644 --- a/rmerge.h +++ b/rmerge.h @@ -1,6 +1,14 @@ -#ifndef RMERGE_H -#define RMERGE_H -// #include "../mrex/rmatch.h" +// Written by retoor@molodetz.nl + +// The code provides functionality to manage and merge files, particularly focusing on parsing and including scripts or C local includes. It +// implements functionality to read lines from files, extract local includes from script tags, and manage history to avoid duplicate merges. + +// The code utilizes several external libraries: "rlexer.h" for lexical analysis, "rmalloc.h" for memory management, "rprint.h" for printing +// utilities, "rrex3.h" for regular expression handling, and "remo.h" for additional utilities. It also uses standard libraries like +// stdio.h, stdlib.h, string.h, and stdbool.h for fundamental operations. + +// MIT License + #include "rlexer.h" #include "rmalloc.h" #include "rprint.h" @@ -14,9 +22,8 @@ bool has_error = false; char *extract_script_src_include(char *line, char *include_path) { - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "<script.*src=\"(.*)\".*<.*script.*>"); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -26,18 +33,8 @@ char *extract_script_src_include(char *line, char *include_path) { } char *extract_c_local_include(char *line, char *include_path) { - // - /* - char res; - res= rmatch_extract(line, "#include.*"\".*\""); - - - printf("%MATCH:%s\n", res); - */ - - include_path[0] = 0; - rrex3_t *rrex; - rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); + include_path[0] = '\0'; + rrex3_t *rrex = rrex3(NULL, line, "[^\\\\*]^#include .*\"(.*)\""); if (rrex) { strcpy(include_path, rrex->matches[0]); rrex3_free(rrex); @@ -48,22 +45,22 @@ char *extract_c_local_include(char *line, char *include_path) { char *rmerge_readline(FILE *f) { static char data[4096]; - data[0] = 0; + data[0] = '\0'; int index = 0; char c; while ((c = fgetc(f)) != EOF) { if (c != '\0') { - data[index] = c; - index++; + data[index++] = c; if (c == '\n') break; } } - data[index] = 0; - if (data[0] == 0) + data[index] = '\0'; + if (data[0] == '\0') return NULL; return data; } + void writestring(FILE *f, char *line) { char c; while ((c = *line) != '\0') { @@ -71,15 +68,16 @@ void writestring(FILE *f, char *line) { line++; } } + char files_history[8096]; char files_duplicate[8096]; bool is_merging = false; void merge_file(char *source, FILE *d) { - if (is_merging == false) { + if (!is_merging) { is_merging = true; - files_history[0] = 0; - files_duplicate[0] = 0; + files_history[0] = '\0'; + files_duplicate[0] = '\0'; } if (strstr(files_history, source)) { if (strstr(files_duplicate, source)) { @@ -105,37 +103,12 @@ void merge_file(char *source, FILE *d) { char *line; char include_path[4096]; while ((line = rmerge_readline(fd))) { - - include_path[0] = 0; + include_path[0] = '\0'; if (!*line) break; - - // char *inc = extract_c_local_include(line, include_path); if (!inc) inc = extract_script_src_include(line, include_path); - - /* - if (!strncmp(line, "#include ", 9)) { - int index = 0; - while (line[index] != '"' && line[index] != 0) { - index++; - } - if (line[index] == '"') { - int pindex = 0; - index++; - while (line[index] != '"') { - include_path[pindex] = line[index]; - pindex++; - index++; - } - if (line[index] != '"') { - include_path[0] = 0; - } else { - include_path[pindex] = '\0'; - } - } - }*/ if (inc) { merge_file(inc, d); } else { @@ -152,7 +125,6 @@ int rmerge_main(int argc, char *argv[]) { printf("Usage: <input-file>\n"); } else { file_input = argv[1]; - // file_output = argv[2]; } FILE *f = tmpfile(); printf("// RETOOR - %s\n", __DATE__); @@ -171,8 +143,7 @@ int rmerge_main(int argc, char *argv[]) { if (has_error) { rprintrf(stderr, "\\l Warning: there are errors while merging this file.\n"); } else { - rprintgf(stderr, "\\l Merge succesful without error(s).%s\n", remo_get("fire")); + rprintgf(stderr, "\\l Merge successful without error(s).%s\n", remo_get("fire")); } return 0; -} -#endif +} \ No newline at end of file diff --git a/rnet.h b/rnet.h index 83ea58f..0736760 100644 --- a/rnet.h +++ b/rnet.h @@ -1,29 +1,39 @@ +// Written by retoor@molodetz.nl + +// This source code defines and implements a simple networking library that provides various functions and structures to manage network +// sockets and servers. It offers the ability to create, bind, listen, connect, and close sockets, along with socket selection and +// asynchronous behavior handling. + +// No non-standard imports or includes are used in this source code. + +// MIT License + #ifndef RNET_H #define RNET_H + #ifdef _POSIX_C_SOURCE #define _POSIX_C_SOURCE_TEMP _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif + #ifndef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif + #include <arpa/inet.h> #include <netdb.h> #include <errno.h> #include <fcntl.h> -#include <netdb.h> #include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> - #include <sys/types.h> #include <sys/socket.h> - #include <unistd.h> + #ifdef _POSIX_C_SOURCE_TEMP #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE _POSIX_C_SOURCE_TEMP @@ -31,6 +41,7 @@ #else #undef _POSIX_C_SOURCE #endif + #define NET_SOCKET_MAX_CONNECTIONS 50000 typedef struct rnet_socket_t { @@ -121,29 +132,27 @@ bool net_set_non_blocking(int sock) { perror("fcntl"); return false; } - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); return false; } - return true; } int net_socket_init() { - int socket_fd = -1; - memset(sockets, 0, sizeof(sockets)); - int opt = 1; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == 0) { perror("Socket failed.\n"); return false; } - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + int opt = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("Setsockopt failed.\n"); close(socket_fd); return false; } net_set_non_blocking(socket_fd); + memset(sockets, 0, sizeof(sockets)); return socket_fd; } @@ -151,19 +160,15 @@ char *net_socket_name(int fd) { rnet_socket_t *rnet_socket = get_net_socket_by_fd(fd); if (rnet_socket) { return rnet_socket->name; - ; } - - // If socket disconnected or is no client from server return NULL; } bool net_socket_bind(int socket_fd, unsigned int port) { struct sockaddr_in address; - - address.sin_family = AF_INET; // IPv4 - address.sin_addr.s_addr = INADDR_ANY; // Bind to any available address - address.sin_port = htons(port); // Convert port to network byte order + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); if (bind(socket_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); @@ -175,48 +180,36 @@ bool net_socket_bind(int socket_fd, unsigned int port) { int net_socket_connect(const char *host, unsigned int port) { char port_str[10] = {0}; - sprintf(port_str, "%d", port); - int status; - int socket_fd = -1; - struct addrinfo hints; - struct addrinfo *res; - struct addrinfo *p; - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - return false; - } - + snprintf(port_str, sizeof(port_str), "%d", port); + struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) { + return false; + } + int status = getaddrinfo(host, port_str, &hints, &res); + if (status != 0) { return -1; } - for (p = res; p != NULL; p = p->ai_next) { - if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (socket_fd == -1) { continue; } - if (connect(socket_fd, p->ai_addr, p->ai_addrlen) == -1) { close(socket_fd); continue; } - break; } - - if (p == NULL) { - freeaddrinfo(res); - return -1; - } - freeaddrinfo(res); - return socket_fd; + return (p == NULL) ? -1 : socket_fd; } bool net_socket_listen(int socket_fd, unsigned int backlog) { - if (listen(socket_fd, backlog) < 0) { // '3' is the backlog size + if (listen(socket_fd, backlog) < 0) { perror("Listen failed"); close(socket_fd); return false; @@ -227,59 +220,27 @@ bool net_socket_listen(int socket_fd, unsigned int backlog) { rnet_server_t *net_socket_serve(unsigned int port, unsigned int backlog) { signal(SIGPIPE, SIG_IGN); int socket_fd = net_socket_init(); - net_socket_bind(socket_fd, port); - net_socket_listen(socket_fd, backlog); + if (!net_socket_bind(socket_fd, port) || !net_socket_listen(socket_fd, backlog)) { + return NULL; + } return rnet_server_new(socket_fd, port, backlog); } int net_socket_accept(int net_socket_server_fd) { struct sockaddr_in address; int addrlen = sizeof(address); - int new_socket = -1; - if ((new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { - close(new_socket); + int new_socket = accept(net_socket_server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { return -1; - } else { - - return new_socket; } + return new_socket; } -/* -static void net_socket_stats(WrenVM *vm) -{ - - wrenSetSlotNewList(vm, 0); - - wrenSetSlotString(vm, 1, "sockets_total"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_total); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_concurrent_record"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_concurrent_record); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_connected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_connected); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotString(vm, 1, "sockets_disconnected"); - wrenInsertInList(vm, 0, -1, 1); - - wrenSetSlotDouble(vm, 1, (double)sockets_disconnected); - wrenInsertInList(vm, 0, -1, 1); -}*/ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size) { ssize_t sent_total = 0; - ssize_t sent = 0; ssize_t to_send = size; - while ((sent = send(sock->fd, message, to_send, 0))) { + while (1) { + ssize_t sent = send(sock->fd, message, to_send, 0); if (sent == -1) { sockets_errors++; net_socket_close(sock); @@ -293,8 +254,9 @@ size_t net_socket_write(rnet_socket_t *sock, unsigned char *message, size_t size break; } sent_total += sent; - if (sent_total == to_send) + if (sent_total == to_send) { break; + } } return sent_total; } @@ -315,47 +277,43 @@ unsigned char *net_socket_read(rnet_socket_t *sock, unsigned int buff_size) { return NULL; } } - buffer[received + 1] = 0; + buffer[received] = 0; sock->bytes_received = received; return buffer; } rnet_socket_t *net_socket_wait(rnet_socket_t *sock) { - if (!sock) - return NULL; - if (sock->fd == -1) + if (!sock || sock->fd == -1) { return NULL; + } fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock->fd, &read_fds); - int max_socket_fd = sock->fd; int activity = select(max_socket_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { - // perror("Select error"); + if (activity < 0 && errno != EINTR) { net_socket_close(sock); return NULL; } - if (FD_ISSET(sock->fd, &read_fds)) { - return sock; - } - - return NULL; + return FD_ISSET(sock->fd, &read_fds) ? sock : NULL; } void rnet_safe_str(char *str, size_t length) { - if (!str || !length || !*str) + if (!str || !length || !*str) { return; + } for (unsigned int i = 0; i < length; i++) { - if (str[i] < 32 || str[i] > 126) - if (str[i] != 0) + if (str[i] < 32 || str[i] > 126) { + if (str[i] != 0) { str[i] = '.'; + } + } } str[length] = 0; } rnet_select_result_t *rnet_new_socket_select_result(int socket_fd) { - rnet_select_result_t *result = (rnet_select_result_t *)malloc(sizeof(rnet_select_result_t)); + rnet_select_result_t *result = malloc(sizeof(rnet_select_result_t)); memset(result, 0, sizeof(rnet_select_result_t)); result->server_fd = socket_fd; result->socket_count = 0; @@ -368,14 +326,15 @@ void rnet_select_result_add(rnet_select_result_t *result, rnet_socket_t *sock) { result->sockets[result->socket_count] = sock; result->socket_count++; } + void rnet_select_result_free(rnet_select_result_t *result) { free(result); } + rnet_select_result_t *net_socket_select(rnet_server_t *server) { fd_set read_fds; FD_ZERO(&read_fds); FD_SET(server->socket_fd, &read_fds); - server->max_fd = server->socket_fd; - int socket_fd = -1; + int socket_fd; for (unsigned int i = 0; i < server->socket_count; i++) { socket_fd = server->sockets[i]->fd; if (!server->sockets[i]->connected) { @@ -392,19 +351,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { struct sockaddr_in address; int addrlen = sizeof(struct sockaddr_in); int activity = select(server->max_fd + 1, &read_fds, NULL, NULL, NULL); - if ((activity < 0) && (errno != EINTR)) { + if (activity < 0 && errno != EINTR) { perror("Select error\n"); return NULL; } if (FD_ISSET(server->socket_fd, &read_fds)) { - if ((new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + new_socket = accept(server->socket_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); + if (new_socket < 0) { perror("Accept failed\n"); return NULL; } - - // net_set_non_blocking(new_socket); char name[50] = {0}; - sprintf(name, "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); + snprintf(name, sizeof(name), "fd:%.4d:ip:%12s:port:%.6d", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); rnet_socket_t *sock_obj = NULL; for (unsigned int i = 0; i < server->socket_count; i++) { if (server->sockets && server->sockets[i]->fd == -1) { @@ -412,7 +370,7 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { } } if (!sock_obj) { - sock_obj = (rnet_socket_t *)malloc(sizeof(rnet_socket_t)); + sock_obj = malloc(sizeof(rnet_socket_t)); rnet_server_add_socket(server, sock_obj); } sock_obj->fd = new_socket; @@ -420,17 +378,18 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { sockets_connected++; sockets_total++; sockets_concurrent_record = sockets_connected > sockets_concurrent_record ? sockets_connected : sockets_concurrent_record; - if (new_socket > net_socket_max_fd) { - net_socket_max_fd = new_socket; - } + net_socket_max_fd = (new_socket > net_socket_max_fd) ? new_socket : net_socket_max_fd; sock_obj->connected = true; - sock_obj->on_connect(sock_obj); + if (sock_obj->on_connect) { + sock_obj->on_connect(sock_obj); + } } rnet_select_result_t *result = rnet_new_socket_select_result(server->socket_fd); unsigned int readable_count = 0; for (unsigned int i = 0; i < server->socket_count; i++) { - if (server->sockets[i]->fd == -1) + if (server->sockets[i]->fd == -1) { continue; + } if (FD_ISSET(server->sockets[i]->fd, &read_fds)) { rnet_select_result_add(result, server->sockets[i]); readable_count++; @@ -443,8 +402,9 @@ rnet_select_result_t *net_socket_select(rnet_server_t *server) { rnet_select_result_free(server->select_result); server->select_result = NULL; } - if (readable_count == 0) + if (readable_count == 0) { rnet_select_result_free(result); + } return readable_count ? result : NULL; } @@ -461,20 +421,20 @@ void _net_socket_close(int sock) { if (sock > 0) { sockets_connected--; sockets_disconnected++; - if (sock > 0) { - if (close(sock) == -1) { - perror("Error closing socket.\n"); - } + if (close(sock) == -1) { + perror("Error closing socket.\n"); } } } void net_socket_close(rnet_socket_t *sock) { sock->connected = false; - if (sock->on_close) + if (sock->on_close) { sock->on_close(sock); + } _net_socket_close(sock->fd); sock->fd = -1; } + #undef _POSIX_C_SOURCE -#endif +#endif \ No newline at end of file diff --git a/rprint.h b/rprint.h index 2b615ee..fade387 100644 --- a/rprint.h +++ b/rprint.h @@ -1,3 +1,19 @@ +// Written by retoor@molodetz.nl + +// This source code provides a custom printing library for formatted output with optional color effects. It implements functions to print +// strings with various color enhancements and control codes for terminal manipulation. + +// Includes: The code uses a custom header "rtime.h" to work with time-related functions. + +// MIT License: 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 RPRINT_H #define RPRINT_H #include "rtime.h" @@ -24,109 +40,94 @@ bool rprint_is_color_enabled() { } 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; } 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 = false; bool press_any_key = false; char new_format[4096]; bool enable_color = rprint_is_color_enabled(); - memset(new_format, 0, 4096); + + memset(new_format, 0, sizeof(new_format)); 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); + memset(temp, 0, sizeof(temp)); + + if (enable_color && prefix[0]) { + strcat(new_format, prefix); + new_format_length += strlen(prefix); reset_color = true; } - while (true) { - if (pformat[0] == '\\' && pformat[1] == 'i') { + + while (*format) { + if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 'C') { press_any_key = true; rpline_number++; - pformat++; - pformat++; + format += 2; reset_color = false; - } else if (pformat[0] == '\\' && pformat[1] == 'k') { + } else if (format[0] == '\\' && format[1] == 'k') { press_any_key = true; rpline_number++; - pformat++; - pformat++; - } else if (pformat[0] == '\\' && pformat[1] == 'c') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[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') { + format += 2; + } else if (format[0] == '\\' && format[1] == 't') { rprtime = nsecs(); - pformat++; - pformat++; + format += 2; } else { - new_format[new_format_length] = *pformat; - new_format_length++; - if (!*pformat) - break; - - // printf("%c",*pformat); - pformat++; + new_format[new_format_length++] = *format++; } } + if (reset_color) { strcat(new_format, "\e[0m"); new_format_length += strlen("\e[0m"); } - new_format[new_format_length] = 0; + new_format[new_format_length] = '\0'; vfprintf(f, new_format, args); fflush(stdout); @@ -150,21 +151,23 @@ void rprintf(FILE *f, const char *format, ...) { rprintpf(f, "", format, args); va_end(args); } + void rprint(const 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, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\\l", format, args); va_end(args); } + void rprintl(const char *format, ...) { va_list args; va_start(args, format); @@ -172,13 +175,13 @@ void rprintl(const char *format, ...) { va_end(args); } -// Black void rprintkf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[30m", format, args); va_end(args); } + void rprintk(const char *format, ...) { va_list args; va_start(args, format); @@ -186,13 +189,13 @@ void rprintk(const char *format, ...) { va_end(args); } -// Red void rprintrf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[31m", format, args); va_end(args); } + void rprintr(const char *format, ...) { va_list args; va_start(args, format); @@ -200,13 +203,13 @@ void rprintr(const char *format, ...) { va_end(args); } -// Green void rprintgf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[32m", format, args); va_end(args); } + void rprintg(const char *format, ...) { va_list args; va_start(args, format); @@ -214,13 +217,13 @@ void rprintg(const char *format, ...) { va_end(args); } -// Yellow void rprintyf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[33m", format, args); va_end(args); } + void rprinty(const char *format, ...) { va_list args; va_start(args, format); @@ -228,7 +231,6 @@ void rprinty(const char *format, ...) { va_end(args); } -// Blue void rprintbf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); @@ -243,13 +245,13 @@ void rprintb(const char *format, ...) { va_end(args); } -// Magenta void rprintmf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[35m", format, args); va_end(args); } + void rprintm(const char *format, ...) { va_list args; va_start(args, format); @@ -257,13 +259,13 @@ void rprintm(const char *format, ...) { va_end(args); } -// Cyan void rprintcf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[36m", format, args); va_end(args); } + void rprintc(const char *format, ...) { va_list args; va_start(args, format); @@ -271,17 +273,17 @@ void rprintc(const char *format, ...) { va_end(args); } -// White void rprintwf(FILE *f, const char *format, ...) { va_list args; va_start(args, format); rprintpf(f, "\e[37m", format, args); va_end(args); } + void rprintw(const char *format, ...) { va_list args; va_start(args, format); rprintpf(stdout, "\e[37m", format, args); va_end(args); } -#endif \ No newline at end of file +#endif