294 lines
6.1 KiB
C
294 lines
6.1 KiB
C
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "apfl.h"
|
|
|
|
#include "alloc.h"
|
|
#include "gc.h"
|
|
#include "resizable.h"
|
|
#include "strings.h"
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_from_view(struct apfl_string_view view)
|
|
{
|
|
return view;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_from_cstr(char *cstr)
|
|
{
|
|
return (struct apfl_string_view) {
|
|
.bytes = (unsigned char *)cstr,
|
|
.len = strlen(cstr),
|
|
};
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_from_const_cstr(const char *cstr)
|
|
{
|
|
return (struct apfl_string_view) {
|
|
.bytes = (unsigned char *)cstr,
|
|
.len = strlen(cstr),
|
|
};
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_from_string(struct apfl_string string)
|
|
{
|
|
return (struct apfl_string_view) {
|
|
.bytes = string.bytes,
|
|
.len = string.len,
|
|
};
|
|
}
|
|
|
|
int
|
|
apfl_string_view_cmp(struct apfl_string_view a, struct apfl_string_view b)
|
|
{
|
|
size_t n = a.len > b.len ? b.len : a.len;
|
|
if (n != 0) {
|
|
int cmp = memcmp(a.bytes, b.bytes, n);
|
|
if (cmp != 0) {
|
|
return cmp;
|
|
}
|
|
}
|
|
if (a.len == b.len) {
|
|
return 0;
|
|
}
|
|
return a.len > b.len ? 1 : -1;
|
|
}
|
|
|
|
struct apfl_string
|
|
apfl_string_blank(void)
|
|
{
|
|
return (struct apfl_string) {
|
|
.bytes = NULL,
|
|
.len = 0,
|
|
.cap = 0
|
|
};
|
|
}
|
|
|
|
void
|
|
apfl_string_deinit(struct apfl_allocator allocator, struct apfl_string *string)
|
|
{
|
|
FREE_BYTES(allocator, string->bytes, string->cap);
|
|
*string = apfl_string_blank();
|
|
}
|
|
|
|
bool
|
|
apfl_string_copy(struct apfl_allocator allocator, struct apfl_string *dst, struct apfl_string_view src)
|
|
{
|
|
apfl_string_deinit(allocator, dst);
|
|
|
|
if (src.len == 0) {
|
|
return true;
|
|
}
|
|
|
|
if ((dst->bytes = ALLOC_BYTES(allocator, src.len)) == NULL) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(dst->bytes, src.bytes, src.len);
|
|
dst->len = src.len;
|
|
dst->cap = src.len;
|
|
|
|
return true;
|
|
}
|
|
|
|
struct apfl_string
|
|
apfl_string_move(struct apfl_string *src)
|
|
{
|
|
struct apfl_string out = *src;
|
|
*src = apfl_string_blank();
|
|
return out;
|
|
}
|
|
|
|
static void
|
|
builder_reset(struct apfl_string_builder *builder)
|
|
{
|
|
apfl_resizable_init((void **)&(builder->bytes), &(builder->len), &(builder->cap));
|
|
}
|
|
|
|
struct apfl_string_builder
|
|
apfl_string_builder_init(struct apfl_allocator allocator)
|
|
{
|
|
struct apfl_string_builder builder;
|
|
builder.allocator = allocator;
|
|
builder_reset(&builder);
|
|
return builder;
|
|
}
|
|
|
|
void
|
|
apfl_string_builder_deinit(struct apfl_string_builder *builder)
|
|
{
|
|
FREE_BYTES(builder->allocator, builder->bytes, builder->cap);
|
|
builder_reset(builder);
|
|
}
|
|
|
|
bool
|
|
apfl_string_builder_append_bytes(struct apfl_string_builder *builder, const unsigned char *bytes, size_t len)
|
|
{
|
|
return apfl_resizable_append(
|
|
builder->allocator,
|
|
sizeof(char),
|
|
APFL_RESIZABLE_ARGS(*builder, bytes),
|
|
bytes,
|
|
len
|
|
);
|
|
}
|
|
|
|
bool
|
|
apfl_string_builder_prealloc(struct apfl_string_builder *builder, size_t newcap)
|
|
{
|
|
return apfl_resizable_ensure_cap(
|
|
builder->allocator,
|
|
sizeof(char),
|
|
(void **)&builder->bytes,
|
|
&builder->cap,
|
|
newcap
|
|
);
|
|
}
|
|
|
|
bool
|
|
apfl_string_builder_append(struct apfl_string_builder *builder, struct apfl_string_view view)
|
|
{
|
|
return apfl_string_builder_append_bytes(builder, view.bytes, view.len);
|
|
}
|
|
|
|
bool
|
|
apfl_string_builder_append_byte(struct apfl_string_builder *builder, unsigned char byte)
|
|
{
|
|
return apfl_string_builder_append_bytes(builder, &byte, 1);
|
|
}
|
|
|
|
struct apfl_string
|
|
apfl_string_builder_move_string(struct apfl_string_builder *builder)
|
|
{
|
|
struct apfl_string str;
|
|
|
|
str.bytes = builder->bytes;
|
|
str.len = builder->len;
|
|
str.cap = builder->cap;
|
|
|
|
builder_reset(builder);
|
|
|
|
return str;
|
|
}
|
|
|
|
struct apfl_string *
|
|
apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in)
|
|
{
|
|
struct apfl_string *str = apfl_gc_new_string(gc);
|
|
if (str == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
*str = apfl_string_move(in);
|
|
return str;
|
|
}
|
|
|
|
struct apfl_string *
|
|
apfl_string_copy_to_new_gc_string(struct gc *gc, struct apfl_string_view sv)
|
|
{
|
|
struct apfl_string s = apfl_string_blank();
|
|
if (!apfl_string_copy(gc->allocator, &s, sv)) {
|
|
return NULL;
|
|
}
|
|
|
|
struct apfl_string *out = apfl_string_move_into_new_gc_string(gc, &s);
|
|
if (out == NULL) {
|
|
apfl_string_deinit(gc->allocator, &s);
|
|
return NULL;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_offset(struct apfl_string_view sv, size_t off)
|
|
{
|
|
if (off >= sv.len) {
|
|
return (struct apfl_string_view) {
|
|
.bytes = NULL,
|
|
.len = 0,
|
|
};
|
|
}
|
|
|
|
sv.bytes += off;
|
|
sv.len -= off;
|
|
|
|
return sv;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_trunc(struct apfl_string_view sv, size_t newlen)
|
|
{
|
|
if (newlen < sv.len) {
|
|
sv.len = newlen;
|
|
}
|
|
return sv;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_substr(struct apfl_string_view sv, size_t off, size_t newlen)
|
|
{
|
|
sv = apfl_string_view_offset(sv, off);
|
|
sv = apfl_string_view_trunc(sv, newlen);
|
|
return sv;
|
|
}
|
|
|
|
ptrdiff_t
|
|
apfl_string_view_search(const struct apfl_string_view haystack, const struct apfl_string_view needle)
|
|
{
|
|
// TODO: This is not very efficient. Use a faster algorithm here.
|
|
|
|
if (needle.len == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (needle.len > haystack.len || haystack.len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
size_t lim = haystack.len - needle.len;
|
|
if (lim > PTRDIFF_MAX) {
|
|
return -1;
|
|
}
|
|
|
|
for (size_t i = 0; i <= lim; i++) {
|
|
if (memcmp(haystack.bytes + i, needle.bytes, needle.len) == 0) {
|
|
return (ptrdiff_t)i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_ltrim(struct apfl_string_view sv)
|
|
{
|
|
while (sv.len > 0 && isspace(sv.bytes[0])) {
|
|
sv.len--;
|
|
sv.bytes++;
|
|
}
|
|
return sv;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_rtrim(struct apfl_string_view sv)
|
|
{
|
|
while (sv.len > 0 && isspace(sv.bytes[sv.len - 1])) {
|
|
sv.len--;
|
|
}
|
|
return sv;
|
|
}
|
|
|
|
struct apfl_string_view
|
|
apfl_string_view_trim(struct apfl_string_view sv)
|
|
{
|
|
return apfl_string_view_ltrim(apfl_string_view_rtrim(sv));
|
|
}
|