From 916aa42260290e9e864304bc7d9395b6aa693c27 Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Tue, 10 Dec 2024 12:24:07 +0100 Subject: kernel: Add string view and string builder This makes write/read calls that use strings to communicate much simpler and less error prone. --- kernel/lib/sb.c | 124 ++++++++++++++++++++++++++++ kernel/lib/sb.h | 30 +++++++ kernel/lib/sv.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/lib/sv.h | 43 ++++++++++ 4 files changed, 444 insertions(+) create mode 100644 kernel/lib/sb.c create mode 100644 kernel/lib/sb.h create mode 100644 kernel/lib/sv.c create mode 100644 kernel/lib/sv.h (limited to 'kernel/lib') diff --git a/kernel/lib/sb.c b/kernel/lib/sb.c new file mode 100644 index 0000000..3f99d95 --- /dev/null +++ b/kernel/lib/sb.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#define DEFAULT_CAPACITY 256 + +void sb_init(struct sb *ctx) { + (void)sb_init_capacity(ctx, DEFAULT_CAPACITY); +} + +int sb_init_capacity(struct sb *ctx, size_t starting_capacity) { + ctx->length = 0; + ctx->prebuffer = 0; + ctx->string = kmalloc(starting_capacity); + if (NULL == ctx->string) { + ctx->capacity = 0; + return 0; + } + ctx->capacity = starting_capacity; + return 1; +} + +void sb_init_buffer(struct sb *ctx, char *buffer, size_t size) { + ctx->string = buffer; + ctx->capacity = size; + ctx->length = 0; + ctx->prebuffer = 1; +} + +void sb_free(struct sb *ctx) { + if (ctx->prebuffer) { + ctx->length = 0; + return; + } + ctx->length = 0; + ctx->capacity = 0; + kfree(ctx->string); + ctx->string = NULL; +} + +void sb_reset(struct sb *ctx) { + ctx->length = 0; +} + +int sb_isempty(const struct sb *ctx) { + return (0 == ctx->length); +} + +int sb_increase_buffer(struct sb *ctx, size_t min) { + if (ctx->prebuffer) { + return 0; + } + size_t new_capacity = ctx->capacity + max(32, min); + char *new_allocation = krealloc(ctx->string, new_capacity); + if (!new_allocation) { + return 0; + } + + ctx->string = new_allocation; + ctx->capacity = new_capacity; + return 1; +} + +int sb_append_char(struct sb *ctx, char c) { + if (1 > ctx->capacity - ctx->length) { + if (!sb_increase_buffer(ctx, 1)) { + return 0; + } + } + memcpy(ctx->string + ctx->length, &c, 1); + ctx->length++; + return 1; +} + +int sb_delete_right(struct sb *ctx, size_t n) { + n = min(n, ctx->length); + ctx->length -= n; + return n; +} + +int sb_append(struct sb *ctx, const char *s) { + size_t l = strlen(s); + if (l > ctx->capacity - ctx->length) { + if (!sb_increase_buffer(ctx, l)) { + return 0; + } + } + memcpy(ctx->string + ctx->length, s, l); + ctx->length += l; + return 1; +} + +int sb_prepend_sv(struct sb *ctx, struct sv sv) { + return sb_prepend_buffer(ctx, sv.s, sv.length); +} + +int sb_prepend_buffer(struct sb *ctx, const char *buffer, size_t length) { + if (length > ctx->capacity - ctx->length) { + if (!sb_increase_buffer(ctx, length)) { + return 0; + } + } + memmove(ctx->string + length, ctx->string, ctx->length); + memcpy(ctx->string, buffer, length); + ctx->length += length; + return 1; +} + +int sb_append_buffer(struct sb *ctx, const char *buffer, size_t length) { + if (length > ctx->capacity - ctx->length) { + if (!sb_increase_buffer(ctx, length)) { + return 0; + } + } + memcpy(ctx->string + ctx->length, buffer, length); + ctx->length += length; + return 1; +} + +int sb_append_sv(struct sb *ctx, struct sv sv) { + return sb_append_buffer(ctx, sv.s, sv.length); +} diff --git a/kernel/lib/sb.h b/kernel/lib/sb.h new file mode 100644 index 0000000..8493997 --- /dev/null +++ b/kernel/lib/sb.h @@ -0,0 +1,30 @@ +#ifndef SB_H +#define SB_H +#include "sv.h" +#include +#include + +struct sb { + char *string; + size_t length; + size_t capacity; + uint8_t prebuffer; +}; + +struct sv; + +void sb_init(struct sb *ctx); +int sb_init_capacity(struct sb *ctx, size_t starting_capacity); +void sb_init_buffer(struct sb *ctx, char *buffer, size_t size); +void sb_free(struct sb *ctx); +void sb_reset(struct sb *ctx); +int sb_isempty(const struct sb *ctx); +int sb_append_char(struct sb *ctx, char c); +int sb_delete_right(struct sb *ctx, size_t n); +int sb_append(struct sb *ctx, const char *s); +int sb_append_buffer(struct sb *ctx, const char *buffer, + size_t length); +int sb_append_sv(struct sb *ctx, struct sv sv); +int sb_prepend_sv(struct sb *ctx, struct sv sv); +int sb_prepend_buffer(struct sb *ctx, const char *buffer, size_t length); +#endif diff --git a/kernel/lib/sv.c b/kernel/lib/sv.c new file mode 100644 index 0000000..580e63a --- /dev/null +++ b/kernel/lib/sv.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include + +struct sv sv_init(const char *s, size_t length) { + return (struct sv){.s = s, .length = length}; +} + +char *SV_TO_C(struct sv s) { + char *c_string = kmalloc(s.length + 1); + memcpy(c_string, s.s, s.length); + c_string[s.length] = '\0'; + return c_string; +} + +size_t sv_to_cstring_buffer(struct sv s, char *buffer, size_t length) { + if (0 == length || length - 1 < s.length) { + return s.length; + } + memcpy(buffer, s.s, s.length); + buffer[s.length] = '\0'; + return s.length; +} + +struct sv sv_next(struct sv s) { + if (0 == s.length) { + return s; + } + s.length--; + s.s++; + return s; +} + +struct sv sv_skip_chars(const struct sv input, const char *chars) { + struct sv r = input; + for (; r.length > 0;) { + int found = 0; + const char *p = chars; + for (; *p; p++) { + if (*p == r.s[0]) { + r.s++; + r.length--; + found = 1; + break; + } + } + if (!found) { + break; + } + } + return r; +} + +uint64_t sv_parse_unsigned_number(struct sv input, struct sv *rest) { + uint64_t r = 0; + size_t i = 0; + for (; i < input.length; i++) { + if (!isdigit(input.s[i])) { + break; + } + r *= 10; + r += input.s[i] - '0'; + } + input.length -= i; + input.s += i; + if (rest) { + *rest = input; + } + return r; +} + +struct sv sv_split_function(const struct sv input, struct sv *rest, + int (*function)(int)) { + struct sv r = { + .s = input.s, + }; + for (size_t i = 0; i < input.length; i++) { + if (function(input.s[i])) { + r.length = i; + if (rest) { + rest->s += i; + rest->length -= i; + } + return r; + } + } + + if (rest) { + rest->s = NULL; + rest->length = 0; + } + return input; +} + +struct sv sv_split_space(const struct sv input, struct sv *rest) { + return sv_split_function(input, rest, isspace); +} + +struct sv sv_end_split_delim(const struct sv input, struct sv *rest, + char delim) { + for (size_t i = input.length - 1; i > 0; i--) { + if (delim == input.s[i]) { + struct sv r = { + .s = (input.s + i), + .length = input.length - i, + }; + if (rest) { + rest->s = input.s; + rest->length = i; + } + return r; + } + } + + if (rest) { + rest->s = NULL; + rest->length = 0; + } + return input; +} + +struct sv sv_split_delim(const struct sv input, struct sv *rest, char delim) { + struct sv r = { + .s = input.s, + }; + for (size_t i = 0; i < input.length; i++) { + if (delim == input.s[i]) { + r.length = i; + if (rest) { + rest->s += i + 1; + rest->length -= (i + 1); + } + return r; + } + } + + if (rest) { + rest->s = NULL; + rest->length = 0; + } + return input; +} + +int sv_isempty(struct sv s) { + return (0 == s.length); +} + +char sv_peek(struct sv s) { + if (0 == s.length) { + return '\0'; + } + return s.s[0]; +} + +int sv_partial_eq(struct sv a, struct sv b) { + if (a.length < b.length) { + return 0; + } + for (size_t i = 0; i < b.length; i++) { + if (a.s[i] != b.s[i]) { + return 0; + } + } + return 1; +} + +int sv_eq(struct sv a, struct sv b) { + if (a.length != b.length) { + return 0; + } + for (size_t i = 0; i < a.length; i++) { + if (a.s[i] != b.s[i]) { + return 0; + } + } + return 1; +} + +struct sv sv_take(struct sv s, struct sv *rest, size_t n) { + if (s.length < n) { + if (rest) { + rest->length = 0; + } + return s; + } + s.length = n; + if (rest) { + rest->length -= n; + rest->s += n; + } + return s; +} + +struct sv sv_take_end(struct sv s, struct sv *rest, size_t n) { + if (s.length < n) { + if (rest) { + rest->length = 0; + } + return s; + } + if (rest) { + rest->length = s.length - n; + } + s.s += (s.length - n); + s.length = n; + return s; +} + +struct sv sv_trim_left(struct sv s, size_t n) { + if (s.length < n) { + s.s += s.length; + s.length = 0; + return s; + } + s.s += n; + s.length -= n; + return s; +} + +struct sv sv_clone(struct sv s) { + struct sv new_sv; + new_sv.length = s.length; + char *new_string = kmalloc(s.length); + memcpy(new_string, s.s, s.length); + new_sv.s = new_string; + return new_sv; +} + +char *sv_copy_to_c(struct sv s, char *out, size_t buffer_length) { + int copy_len = min(s.length + 1, buffer_length); + if (0 == copy_len) { + return NULL; + } + if (!out) { + out = kmalloc(copy_len); + } + memcpy(out, s.s, copy_len - 1); + out[copy_len - 1] = '\0'; + return out; +} + +struct sv sv_clone_from_c(const char *s) { + return sv_clone(C_TO_SV(s)); +} diff --git a/kernel/lib/sv.h b/kernel/lib/sv.h new file mode 100644 index 0000000..b5cb0c9 --- /dev/null +++ b/kernel/lib/sv.h @@ -0,0 +1,43 @@ +#ifndef SV_H +#define SV_H +#include "sb.h" +#include + +#define SB_TO_SV(_sb) \ + (struct sv) { \ + .s = (_sb).string, .length = (_sb).length \ + } + +#define C_TO_SV(_c_string) \ + ((struct sv){.length = strlen(_c_string), .s = (_c_string)}) + +#define sv_length(a) ((a).length) + +struct sv { + const char *s; + size_t length; +}; + +struct sv sv_init(const char *s, size_t length); +char *SV_TO_C(struct sv s); +size_t sv_to_cstring_buffer(struct sv s, char *buffer, size_t length); +struct sv sv_split_delim(const struct sv input, struct sv *rest, char delim); +struct sv sv_end_split_delim(const struct sv input, struct sv *rest, + char delim); +struct sv sv_split_space(const struct sv input, struct sv *rest); +struct sv sv_skip_chars(const struct sv input, const char *chars); +struct sv sv_split_function(const struct sv input, struct sv *rest, + int (*function)(int)); +struct sv sv_take(struct sv s, struct sv *rest, size_t n); +struct sv sv_take_end(struct sv s, struct sv *rest, size_t n); +struct sv sv_next(struct sv s); +int sv_isempty(struct sv s); +char sv_peek(struct sv s); +int sv_eq(struct sv a, struct sv b); +int sv_partial_eq(struct sv a, struct sv b); +struct sv sv_trim_left(struct sv s, size_t n); +struct sv sv_clone(struct sv s); +struct sv sv_clone_from_c(const char *s); +char *sv_copy_to_c(struct sv s, char *out, size_t buffer_length); +uint64_t sv_parse_unsigned_number(struct sv input, struct sv *rest); +#endif -- cgit v1.2.3