diff options
| author | Anton Kling <anton@kling.gg> | 2024-12-10 12:24:07 +0100 | 
|---|---|---|
| committer | Anton Kling <anton@kling.gg> | 2024-12-10 12:24:07 +0100 | 
| commit | 916aa42260290e9e864304bc7d9395b6aa693c27 (patch) | |
| tree | 784cdcbe26e828e18413bf9d31d6a84ed74dd1ba | |
| parent | bcca3d183930eeaf3d024476f39d1d8fccf2ebab (diff) | |
kernel: Add string view and string builder
This makes write/read calls that use strings to communicate much
simpler and less error prone.
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/audio.c | 37 | ||||
| -rw-r--r-- | kernel/includes/ctype.h | 1 | ||||
| -rw-r--r-- | kernel/lib/sb.c | 124 | ||||
| -rw-r--r-- | kernel/lib/sb.h | 30 | ||||
| -rw-r--r-- | kernel/lib/sv.c | 247 | ||||
| -rw-r--r-- | kernel/lib/sv.h | 43 | ||||
| -rw-r--r-- | kernel/libc/ctype/isspace.c | 5 | ||||
| -rw-r--r-- | kernel/libc/include/string.h | 1 | ||||
| -rw-r--r-- | kernel/libc/string/memmove.c | 14 | ||||
| -rw-r--r-- | kernel/timer.c | 22 | 
11 files changed, 482 insertions, 44 deletions
| diff --git a/kernel/Makefile b/kernel/Makefile index a27b108..34b9b30 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@  CC="i686-sb-gcc"  AS="i686-sb-as" -OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o  read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o timer.o queue.o fonts.o drivers/ac97.o audio.o libc/ctype/isdigit.o libc/stdlib/parsenum.o libc/ctype/tolower.o +OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o  read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o timer.o queue.o fonts.o drivers/ac97.o audio.o libc/ctype/isdigit.o libc/stdlib/parsenum.o libc/ctype/tolower.o lib/sv.o lib/sb.o libc/string/memmove.o libc/ctype/isspace.o  CFLAGS = -std=c99 -O0 -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Wextra -Wno-int-conversion -Wno-unused-parameter -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL  LDFLAGS=  #CFLAGS = -std=c99 -O3 -flto -ggdb -ffreestanding -Wall -Wextra -Wno-int-conversion -Wno-unused-parameter -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL diff --git a/kernel/audio.c b/kernel/audio.c index d8fcd3c..fe78938 100644 --- a/kernel/audio.c +++ b/kernel/audio.c @@ -5,6 +5,7 @@  #include <drivers/ac97.h>  #include <errno.h>  #include <fs/devfs.h> +#include <lib/sv.h>  #include <math.h>  int audio_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { @@ -25,24 +26,18 @@ int audio_can_write(vfs_inode_t *inode) {  int volume_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {    (void)offset;    (void)fd; -  int volume = 0; - -  size_t i = 0; -  for (; i < len; i++) { -    u8 c = buffer[i]; -    if (!isdigit(c)) { -      break; -    } -    volume *= 10; -    volume += c - '0'; -    if (volume > 100) { -      volume = 100; -      break; -    } -  } +  struct sv string_view = sv_init(buffer, len); +  struct sv rest; +  u64 volume = sv_parse_unsigned_number(string_view, &rest); +  int i = sv_length(string_view) - sv_length(rest);    if (0 == i) {      return 0;    } + +  if (volume > 100) { +    volume = 0; +  } +    ac97_set_volume(volume);    return i;  } @@ -52,18 +47,8 @@ int volume_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {      return 0;    }    (void)fd; -  if (len < 3) { -    return 0; -  }    int volume = ac97_get_volume(); -  assert(volume <= 100); -  if (volume == 100) { -    memcpy(buffer, "100", 3); -    return 3; -  } -  buffer[1] = (volume % 10) + '0'; -  buffer[0] = ((volume - (volume % 10)) / 10) + '0'; -  return 2; +  return min(len, (u64)kbnprintf(buffer, len, "%d", volume));  }  static int add_files(void) { diff --git a/kernel/includes/ctype.h b/kernel/includes/ctype.h index f6be4f2..e8e0bae 100644 --- a/kernel/includes/ctype.h +++ b/kernel/includes/ctype.h @@ -1,2 +1,3 @@  int isdigit(int c);  int tolower(int c); +int isspace(int c); 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 <kmalloc.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <tb/sb.h> + +#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 <stddef.h> +#include <stdint.h> + +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 <ctype.h> +#include <kmalloc.h> +#include <lib/sv.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> + +#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 diff --git a/kernel/libc/ctype/isspace.c b/kernel/libc/ctype/isspace.c new file mode 100644 index 0000000..a922d91 --- /dev/null +++ b/kernel/libc/ctype/isspace.c @@ -0,0 +1,5 @@ +#include <ctype.h> + +int isspace(int c) { +  return c == ' ' || (unsigned)c - '\t' < 5; +} diff --git a/kernel/libc/include/string.h b/kernel/libc/include/string.h index 89ea5ab..4425085 100644 --- a/kernel/libc/include/string.h +++ b/kernel/libc/include/string.h @@ -15,4 +15,5 @@ char *copy_and_allocate_string(const char *s);  char *copy_and_allocate_user_string(const char *s);  size_t strlcpy(char *dst, const char *src, size_t dsize);  char *strcat(char *s1, const char *s2); +void *memmove(void *s1, const void *s2, size_t n);  #endif diff --git a/kernel/libc/string/memmove.c b/kernel/libc/string/memmove.c new file mode 100644 index 0000000..5fc49f7 --- /dev/null +++ b/kernel/libc/string/memmove.c @@ -0,0 +1,14 @@ +#include <string.h> + +// copy bytes in memory with overlapping areas +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memmove.html +void *memmove(void *s1, const void *s2, size_t n) { +  // Copying takes place as if the n bytes from the object pointed to by s2 are +  // first copied into a temporary array of n bytes that does not overlap the +  // objects pointed to by s1 and s2, and then the n bytes from the temporary +  // array are copied into the object pointed to by s1. +  unsigned char tmp[n]; +  memcpy(tmp, s2, n); +  memcpy(s1, tmp, n); +  return s1; +} diff --git a/kernel/timer.c b/kernel/timer.c index dd92d3d..b84c16a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -2,6 +2,7 @@  #include <drivers/cmos.h>  #include <fs/devfs.h>  #include <interrupts.h> +#include <lib/sv.h>  #include <math.h>  #include <random.h>  #include <time.h> @@ -49,31 +50,18 @@ int clock_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {    if (0 != offset) {      return 0;    } -  // Currently don't have snprintf without NULL termination... -  char tmp[4096];    u64 r = timer_get_ms(); - -  u64 l = ksnprintf(tmp, 4096, "%llu", r); -  l = min(len, l); -  memcpy(buffer, tmp, l); -  return l; +  return min(len, (u64)kbnprintf(buffer, len, "%llu", r));  }  int clock_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {    if (0 != offset) {      return 0;    } -  // TODO: Move sv to kernel or something to just avoid this. I hate null -  // termination -  char tmp[4096]; -  memcpy(tmp, buffer, len); -  tmp[len] = '\0'; -  int err; -  u64 new_value_ms = parse_u64(tmp, NULL, 10, &err); -  if (err) { -    return 0; -  } +  struct sv string_view = sv_init(buffer, len); + +  u64 new_value_ms = sv_parse_unsigned_number(string_view, &string_view);    i64 new_value_seconds = new_value_ms / 1000; |