Initial commit
This commit is contained in:
301
lstring.c
Normal file
301
lstring.c
Normal file
@@ -0,0 +1,301 @@
|
||||
// LCZ libraries v0.1b
|
||||
|
||||
#include "lstring.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// String building / constructors
|
||||
String string_take(char *src)
|
||||
{
|
||||
String res;
|
||||
res.text = src;
|
||||
res.length = rstring_length(src);
|
||||
return res;
|
||||
}
|
||||
|
||||
DString dstring_take(char *src)
|
||||
{
|
||||
DString res;
|
||||
res.text = src;
|
||||
res.length = rstring_length(src);
|
||||
res.capacity = res.length;
|
||||
return res;
|
||||
}
|
||||
|
||||
String string_copy(const char *src, u64 length)
|
||||
{
|
||||
String res;
|
||||
res.text = malloc(length + 1);
|
||||
assert(res.text != NULL);
|
||||
|
||||
memcpy(res.text, src, length);
|
||||
res.text[length] = '\0';
|
||||
res.length = length;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DString dstring_copy(const char *src, u64 length)
|
||||
{
|
||||
DString res;
|
||||
res.text = malloc(length + 1);
|
||||
assert(res.text != NULL);
|
||||
|
||||
memcpy(res.text, src, length);
|
||||
res.text[length] = '\0';
|
||||
res.length = length;
|
||||
res.capacity = length;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
DString dstring_new(u64 capacity)
|
||||
{
|
||||
DString res;
|
||||
res.text = malloc(capacity + 1);
|
||||
assert(res.text != NULL);
|
||||
res.text[0] = '\0';
|
||||
res.length = 0;
|
||||
res.capacity = capacity;
|
||||
return res;
|
||||
}
|
||||
|
||||
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||
String string_concat(u32 n, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
|
||||
const char *strings[n];
|
||||
u64 sizes[n];
|
||||
u64 tot_len = 0;
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
strings[i] = va_arg(ap, const char *);
|
||||
sizes[i] = va_arg(ap, u64);
|
||||
tot_len += sizes[i];
|
||||
}
|
||||
|
||||
String res;
|
||||
res.text = malloc(tot_len + 1);
|
||||
assert(res.text != NULL);
|
||||
res.length = tot_len;
|
||||
char *cursor = res.text;
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
memcpy(cursor, strings[i], sizes[i]);
|
||||
cursor += sizes[i];
|
||||
}
|
||||
*cursor = '\0';
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||
DString dstring_concat(u32 n, ...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *strings[n];
|
||||
u64 sizes[n];
|
||||
u64 tot_len = 0;
|
||||
|
||||
va_start(ap, n);
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
strings[i] = va_arg(ap, const char *);
|
||||
sizes[i] = va_arg(ap, u64);
|
||||
tot_len += sizes[i];
|
||||
}
|
||||
|
||||
DString res;
|
||||
res.text = malloc(tot_len + 1);
|
||||
assert(res.text != NULL);
|
||||
res.length = tot_len;
|
||||
res.capacity = tot_len;
|
||||
char *cursor = res.text;
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
memcpy(cursor, strings[i], sizes[i]);
|
||||
cursor += sizes[i];
|
||||
}
|
||||
*cursor = '\0';
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Compute string length, excluding zero-terminator
|
||||
u64 rstring_length(const char *src)
|
||||
{
|
||||
u64 length = 0;
|
||||
while(*(src++) != '\0')
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// Comparison
|
||||
int rstring_compare(const char* left, const char *right)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (*left < *right)
|
||||
return -1;
|
||||
if (*left > *right)
|
||||
return +1;
|
||||
right++;
|
||||
} while (*(left++));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool string_equal(String left, String right)
|
||||
{
|
||||
if (left.length != right.length)
|
||||
return false;
|
||||
|
||||
char *l = left.text;
|
||||
char *r = right.text;
|
||||
char *l_end = l + left.length;
|
||||
|
||||
while (l != l_end)
|
||||
{
|
||||
if (*l != *r)
|
||||
return false;
|
||||
l++; r++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string_find(String str, u64 start_index, String to_find, u64 *found_index)
|
||||
{
|
||||
// @TODO: Replace with better algorithm (Knuth-Morris-Pratt?)
|
||||
char *end = str.text + str.length;
|
||||
char *last_valid_start = end - to_find.length;
|
||||
|
||||
for (char *curr = str.text + start_index; curr <= last_valid_start; curr++)
|
||||
{
|
||||
bool found = true;
|
||||
for (u64 i = 0; i < to_find.length; i++)
|
||||
{
|
||||
if (curr[i] != to_find.text[i])
|
||||
{
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
*found_index = curr - str.text;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String string_substring(String *str, u64 start, u64 end)
|
||||
{
|
||||
String res;
|
||||
res.text = &str->text[start];
|
||||
end = (end < str->length ? end : str->length);
|
||||
end = (start < end ? end : start);
|
||||
res.length = end - start;
|
||||
return res;
|
||||
}
|
||||
|
||||
String string_trim(String *str)
|
||||
{
|
||||
u64 start = 0;
|
||||
u64 end = str->length;
|
||||
|
||||
while(start < str->length && isspace(str->text[start]))
|
||||
start++;
|
||||
while(end > start && isspace(str->text[end-1]))
|
||||
end--;
|
||||
|
||||
return string_substring(str, start, end);
|
||||
}
|
||||
|
||||
|
||||
// DString specific operations
|
||||
void dstring_reserve(DString *dstr, u64 new_length)
|
||||
{
|
||||
if (dstr->length < new_length)
|
||||
dstr->text = realloc(dstr->text, new_length + 1); // + 1 --> reserve space for '\0'
|
||||
assert(dstr->text != NULL);
|
||||
}
|
||||
|
||||
void dstring_append(DString *dstr, const char *to_append, u64 count)
|
||||
{
|
||||
u64 len;
|
||||
|
||||
// Make sure we have enought space
|
||||
len = dstr->length + count;
|
||||
dstring_reserve(dstr, len);
|
||||
|
||||
// Copy bytes
|
||||
memcpy(dstr->text + dstr->length, to_append, count);
|
||||
|
||||
dstr->text[len] = '\0';
|
||||
dstr->length = len;
|
||||
}
|
||||
|
||||
void dstring_insert(DString *dstr, u64 index, const char *to_insert, u64 count)
|
||||
{
|
||||
u64 len;
|
||||
char *insert_start;
|
||||
char *insert_end;
|
||||
|
||||
// Make sure we have enought space
|
||||
len = dstr->length + count;
|
||||
dstring_reserve(dstr, len);
|
||||
|
||||
// Move content to make space for the data we have to insert
|
||||
insert_start = dstr->text + index;
|
||||
insert_end = insert_start + count;
|
||||
|
||||
memmove(insert_end, insert_start, dstr->length - index + 1);
|
||||
|
||||
// Insert
|
||||
memcpy(insert_start, to_insert, count);
|
||||
dstr->length = len;
|
||||
}
|
||||
|
||||
void dstring_erase(DString *dstr, u64 index, u64 count)
|
||||
{
|
||||
if (index + count > dstr->length)
|
||||
count = dstr->length - index;
|
||||
|
||||
char *start = dstr->text + index;
|
||||
char *end = start + count;
|
||||
u64 to_move_from_end = dstr->length - index - count + 1; // Remember to move terminating zero
|
||||
memmove(start, end, to_move_from_end);
|
||||
dstr->length -= count;
|
||||
}
|
||||
|
||||
void dstring_replace(DString *dstr, u64 index, u64 rem_count, const char *to_insert, u64 ins_count)
|
||||
{
|
||||
if (index + rem_count > dstr->length)
|
||||
rem_count = dstr->length - index;
|
||||
|
||||
u64 len = dstr->length - rem_count + ins_count;
|
||||
dstring_reserve(dstr, len);
|
||||
|
||||
char *start = dstr->text + index;
|
||||
char *rem_end = start + rem_count;
|
||||
char *ins_end = start + ins_count;
|
||||
u64 to_move_from_end = dstr->length - index - rem_count + 1;
|
||||
memmove(ins_end, rem_end, to_move_from_end);
|
||||
memcpy(start, to_insert, ins_count);
|
||||
dstr->length = len;
|
||||
}
|
||||
Reference in New Issue
Block a user