This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// RETOOR - Dec 5 2024
#ifndef SORM_H
#define SORM_H
#ifndef SORM_STR_H
#define SORM_STR_H
// RETOOR - Nov 28 2024
// MIT License
// ===========
// Copyright (c) 2024 Retoor
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef RLIB_H
#define RLIB_H
// BEGIN OF RLIB
/*
* 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
#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) {
for (unsigned int i = 0; i < sock->upstream_count; i++) {
nsock_close(sock->upstreams[i]);
sock->upstreams[i] = 0;
}
if (sock->upstream_count) {
free(sock->upstreams);
}
sock->upstream_count = 0;
sock->connected = false;
}
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(&current_time);
struct tm *local_time = localtime(&current_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