YREA-SLS/SLS_C/src/string.c

306 lines
9.5 KiB
C

// Kyler Olsen
// YREA SLS
// String Helpers
// November 2025
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <stdlib.h>
#include "sls/string.h"
#include "sls/lexer.h"
int isascii(unsigned char c) {
return c < 128;
}
size_t strnlen(const char *s, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++)
if (s[i] == '\0') break;
return i;
}
SlsStr malloc_str(const char *s, size_t maxlen) {
size_t length = strnlen(s, maxlen);
char *new_str = (char *)malloc(sizeof(char) * (length + 1));
strncpy(new_str, s, length + 1);
return (SlsStr){length, new_str, TRUE};
}
SlsStr new_str(size_t length) {
char *new_str = (char *)malloc(sizeof(char) * length);
for (size_t i = 0; i < length; i++) new_str[i] = '\0';
return (SlsStr){length, new_str, TRUE};
}
SlsStr copy_str(SlsStr s) {
return malloc_str(s.str, s.len);
}
int32_t compare_str(SlsStr a, SlsStr b) {
return strcmp(a.str, b.str);
}
void free_str(SlsStr *s) {
if (s->allocated) {
free((void *)s->str);
s->len = 0;
s->str = 0;
s->allocated = FALSE;
}
}
typedef enum {
FORMAT_C_STRINGS,
FORMAT_CHARACTER,
FORMAT_INTEGER_32,
FORMAT_INTEGER_64,
FORMAT_UNSIGNED_INTEGER_64,
FORMAT_SIZE_INTEGER,
FORMAT_FLOAT,
FORMAT_SLS_STR,
FORMAT_SLS_TOKEN_TYPE,
FORMAT_SLS_ARRAY_TYPE,
FORMAT_SLS_BUILTIN_INTEGER,
FORMAT_SLS_ERROR,
FORMAT_SLS_BOOLEAN,
} FormatStringTypes;
typedef struct {
FormatStringTypes type;
union {
const char *c_string;
char character;
int32_t integer_32;
int64_t integer_64;
uint64_t unsigned_integer_64;
size_t size_integer;
double ffloat;
SlsStr sls_str;
TokenType token_type;
ArrayType array_type;
IntegerBuiltInType builtin_integer;
SlsError error;
Boolean boolean;
};
size_t str_index;
size_t self_length;
} FormatStringItem;
static size_t number_length(int64_t i) {
if (i == 0) return 1;
else return (i < 0 ? 1 : 0) + (int)log10(llabs(i) + 1);
}
static size_t unsigned_number_length(uint64_t i) {
if (i == 0) return 1;
else return (int)log10(i + 1);
}
SlsStr format(const SlsStr s, ...) {
va_list args;
va_start(args, s);
size_t count = 0;
const char *current = strchr(s.str, '%');
do {
switch (current[1]) {
case 'y':
case 'c':
case 'd':
case 'l':
case 'u':
case 'z':
case 'f':
case 's':
case 't':
case 'a':
case 'i':
case 'e':
case 'b':
count++;
break;
}
current = strchr(current + 2, '%');
} while (current);
FormatStringItem *items = (FormatStringItem *)malloc(sizeof(FormatStringItem) * count);
size_t i = 0;
size_t last_index = (size_t)s.str;
current = strchr(s.str, '%');
do {
switch (current[1]) {
case 'y':
items[i].type = FORMAT_C_STRINGS;
items[i].c_string = va_arg(args, const char *);
break;
case 'c':
items[i].type = FORMAT_CHARACTER;
items[i].character = va_arg(args, int);
break;
case 'd':
items[i].type = FORMAT_INTEGER_32;
items[i].integer_32 = va_arg(args, int32_t);
break;
case 'l':
items[i].type = FORMAT_INTEGER_64;
items[i].integer_64 = va_arg(args, int64_t);
break;
case 'u':
items[i].type = FORMAT_UNSIGNED_INTEGER_64;
items[i].unsigned_integer_64 = va_arg(args, uint64_t);
break;
case 'z':
items[i].type = FORMAT_SIZE_INTEGER;
items[i].size_integer = va_arg(args, size_t);
break;
case 'f':
items[i].type = FORMAT_FLOAT;
items[i].ffloat = va_arg(args, double);
break;
case 's':
items[i].type = FORMAT_SLS_STR;
items[i].sls_str = va_arg(args, SlsStr);
break;
case 't':
items[i].type = FORMAT_SLS_TOKEN_TYPE;
items[i].token_type = va_arg(args, TokenType);
break;
case 'a':
items[i].type = FORMAT_SLS_ARRAY_TYPE;
items[i].array_type = va_arg(args, ArrayType);
break;
case 'i':
items[i].type = FORMAT_SLS_BUILTIN_INTEGER;
items[i].builtin_integer = va_arg(args, IntegerBuiltInType);
break;
case 'e':
items[i].type = FORMAT_SLS_ERROR;
items[i].error = va_arg(args, SlsError);
break;
case 'b':
items[i].type = FORMAT_SLS_BOOLEAN;
items[i].boolean = va_arg(args, Boolean);
break;
}
items[i].str_index = (size_t)current - last_index;
last_index = (size_t)current + 2;
i++;
current = strchr(current + 2, '%');
} while (current);
size_t length = s.len - (count * 2);
for (size_t i = 0; i < count; i++) {
switch (items[i].type) {
case FORMAT_C_STRINGS:
length += items[i].self_length = strlen(items[i].c_string);
break;
case FORMAT_CHARACTER:
length += items[i].self_length = 1;
break;
case FORMAT_INTEGER_32:
length += items[i].self_length = number_length(items[i].integer_32);
break;
case FORMAT_INTEGER_64:
length += items[i].self_length = number_length(items[i].integer_64);
break;
case FORMAT_UNSIGNED_INTEGER_64:
length += items[i].self_length = unsigned_number_length(items[i].unsigned_integer_64);
break;
case FORMAT_SIZE_INTEGER:
length += items[i].self_length = unsigned_number_length(items[i].size_integer);
break;
case FORMAT_FLOAT:
length += items[i].self_length = number_length(items[i].ffloat) + 3;
break;
case FORMAT_SLS_STR:
length += items[i].self_length = items[i].sls_str.len - 1;
break;
case FORMAT_SLS_TOKEN_TYPE:
length += items[i].self_length = strnlen(TOKEN_TYPES_NAMES[items[i].token_type], TYPE_NAMES_SAFE_LENGTH);
break;
case FORMAT_SLS_ARRAY_TYPE:
length += items[i].self_length = strnlen(ARRAY_TYPES_NAMES[items[i].array_type], TYPE_NAMES_SAFE_LENGTH);
break;
case FORMAT_SLS_BUILTIN_INTEGER:
length += items[i].self_length = strnlen(INTEGER_TYPES_NAMES[items[i].builtin_integer], TYPE_NAMES_SAFE_LENGTH);
break;
case FORMAT_SLS_ERROR:
length += items[i].self_length = items[i].error.message.len - 1;
break;
case FORMAT_SLS_BOOLEAN:
length += items[i].self_length = (items[i].boolean ? 4 : 5);
break;
}
}
char *temp = (char *)malloc(sizeof(char) * length);
SlsStr str_new = new_str(length);
char *str = (char *)str_new.str;
size_t item_i = 0;
size_t target_i = 0;
size_t source_i = 0;
while (item_i < count) {
memcpy(str + target_i, s.str + source_i, items[item_i].str_index);
target_i += items[item_i].str_index;
source_i += items[item_i].str_index + 2;
switch (items[item_i].type) {
case FORMAT_C_STRINGS:
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].c_string);
break;
case FORMAT_CHARACTER:
snprintf(temp, items[item_i].self_length + 1, "%c", items[item_i].character);
break;
case FORMAT_INTEGER_32:
snprintf(temp, items[item_i].self_length + 1, "%d", items[item_i].integer_32);
break;
case FORMAT_INTEGER_64:
snprintf(temp, items[item_i].self_length + 1, "%ld", items[item_i].integer_64);
break;
case FORMAT_UNSIGNED_INTEGER_64:
snprintf(temp, items[item_i].self_length + 1, "%lu", items[item_i].unsigned_integer_64);
break;
case FORMAT_SIZE_INTEGER:
snprintf(temp, items[item_i].self_length + 1, "%zu", items[item_i].size_integer);
break;
case FORMAT_FLOAT:
snprintf(temp, items[item_i].self_length + 1, "%.2f", items[item_i].ffloat);
break;
case FORMAT_SLS_STR:
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].sls_str.str);
break;
case FORMAT_SLS_TOKEN_TYPE:
snprintf(temp, items[item_i].self_length + 1, "%s", TOKEN_TYPES_NAMES[items[item_i].token_type]);
break;
case FORMAT_SLS_ARRAY_TYPE:
snprintf(temp, items[item_i].self_length + 1, "%s", ARRAY_TYPES_NAMES[items[item_i].array_type]);
break;
case FORMAT_SLS_BUILTIN_INTEGER:
snprintf(temp, items[item_i].self_length + 1, "%s", INTEGER_TYPES_NAMES[items[item_i].builtin_integer]);
break;
case FORMAT_SLS_ERROR:
snprintf(temp, items[item_i].self_length + 1, "%s", items[item_i].error.message.str);
break;
case FORMAT_SLS_BOOLEAN:
if (items[item_i].boolean) memcpy(temp, "TRUE", 5);
else memcpy(temp, "FALSE", 6);
break;
}
memcpy(str + target_i, temp, items[item_i].self_length);
target_i += items[item_i].self_length;
item_i++;
}
memcpy(str + target_i, s.str + source_i, s.len - source_i);
free(items);
free(temp);
return str_new;
}