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