diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/lib.c | 51 | ||||
-rw-r--r-- | lib/lib.h | 13 | ||||
-rw-r--r-- | lib/map.c | 87 | ||||
-rw-r--r-- | lib/map.h | 15 | ||||
-rw-r--r-- | lib/stream.c | 144 | ||||
-rw-r--r-- | lib/stream.h | 27 |
6 files changed, 337 insertions, 0 deletions
diff --git a/lib/lib.c b/lib/lib.c new file mode 100644 index 0000000..e6e691a --- /dev/null +++ b/lib/lib.c @@ -0,0 +1,51 @@ +#include "lib.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +__attribute__((__noreturn__)) +static void die() { + exit(1); +} + +void error_and_die(char *format, ...) { + va_list list; + va_start(list, format); + + vfprintf(stderr, format, list); + + die(); +} + +__attribute__((__noreturn__, format(printf, 1, 2))) +void perror_and_die(char *format, ...) { + va_list list; + va_start(list, format); + + vfprintf(stderr, format, list); + perror(": "); + + die(); +} + +void *xalloc(size_t amount) { + void *res = malloc(amount); + if (res == NULL) + error_and_die("failed to allocate memory"); + return res; +} + +void *xzalloc(size_t amount) { + void *res = xalloc(amount); + memset(res, 0, sizeof(amount)); + return res; +} + +void *xrealloc(void *ptr, size_t amount) { + void *res = realloc(ptr, amount); + if (res == NULL) + error_and_die("failed to allocate memory"); + return res; +} diff --git a/lib/lib.h b/lib/lib.h new file mode 100644 index 0000000..35cbc3c --- /dev/null +++ b/lib/lib.h @@ -0,0 +1,13 @@ +#pragma once + +#include <stddef.h> + +__attribute__((__noreturn__, format(printf, 1, 2))) +void error_and_die(char *format, ...); + +__attribute__((__noreturn__, format(printf, 1, 2))) +void perror_and_die(char *format, ...); + +void *xalloc(size_t amount); +void *xzalloc(size_t amount); +void *xrealloc(void *ptr, size_t amount); diff --git a/lib/map.c b/lib/map.c new file mode 100644 index 0000000..71300fb --- /dev/null +++ b/lib/map.c @@ -0,0 +1,87 @@ +#include "lib.h" +#include "nbt.h" +#include "map.h" + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void map_init(map_t *map) { + map->len = 0; + map->capacity = 0; + map->entries = NULL; +} + +void map_free(map_t *map) { + if (map->entries == NULL) + return; + for (uint32_t i = 0; i < map->capacity; i++) { + if (map->entries[i].name != NULL) + tag_free(&map->entries[i]); + } + free(map->entries); +} + +static uint32_t hash(const char *name, uint16_t len) { + uint32_t hash = 2166136261u; + while(len > 0) { + hash ^= (uint8_t)(*name); + hash *= 16777619; + name++; + len--; + } + return hash; +} + +static tag_t *map_find(tag_t *entries, uint32_t capacity, tag_t *tag) { + uint32_t index = hash(tag->name, tag->name_len) % capacity; + while(true) { + tag_t *entry = &entries[index]; + if (entry->name == NULL) { + return entry; + } else if ( + entry->name_len == tag->name_len && + memcmp(entry->name, tag->name, tag->name_len) == 0 + ) { + return entry; + } + index += 1; + index %= capacity; + } +} + +static void map_grow(map_t *map, uint32_t capacity) { + tag_t *entries = xzalloc(capacity * sizeof(tag_t)); + for (uint32_t i = 0; i < capacity; i++) { + entries[i].name = NULL; + entries[i].name_len = 0; + } + map->len = 0; + for (uint32_t i = 0; i < map->capacity; i++) { + tag_t *tag = &map->entries[i]; + if (tag->name == NULL) continue; + + tag_t *dest = map_find(entries, capacity, tag); + *dest = *tag; + map->len++; + } + free(map->entries); + + map->entries = entries; + map->capacity = capacity; +} + +void map_put(map_t *map, tag_t *tag) { + if (map->len + 1 > map->capacity * 0.75) { + int capacity = (map->capacity == 0 ? 8 : (2 * map->capacity)); + map_grow(map, capacity); + } + tag_t *dest = map_find(map->entries, map->capacity, tag); + if (dest->name == NULL) { + map->len++; + } else { + tag_free(dest); + } + *dest = *tag; +} diff --git a/lib/map.h b/lib/map.h new file mode 100644 index 0000000..d2ab6f8 --- /dev/null +++ b/lib/map.h @@ -0,0 +1,15 @@ +#pragma once + +#include <stdint.h> + +struct tag_t; + +typedef struct { + uint32_t len; + uint32_t capacity; + struct tag_t *entries; +} map_t; + +void map_init(map_t *map); +void map_free(map_t *map); +void map_put(map_t *map, struct tag_t *tag); diff --git a/lib/stream.c b/lib/stream.c new file mode 100644 index 0000000..6780d02 --- /dev/null +++ b/lib/stream.c @@ -0,0 +1,144 @@ +#include "stream.h" +#include "lib.h" + +#include <errno.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static uint64_t longswap(uint64_t ll) { + if (htons(20) == 20) + return ll; + + union { uint64_t ll; uint8_t c[8]; } out = {0}; + union { uint64_t ll; uint8_t c[8]; } in = {ll}; + + for (int i = 0; i < 8; i++) + out.c[7-i] = in.c[i]; + + return out.ll; +} + + +stream_t stream_open(const char *path, const char* mode) { + stream_t stream; + + if (strcmp("-", path) == 0) { + if (*mode == 'r') + stream.__file = stdin; + else + stream.__file = stdout; + stream.__alloc = false; + return stream; + } + + stream.__file = fopen(path, mode); + stream.__alloc = true; + + if (stream.__file == NULL) { + perror_and_die("cannot open '%s'", path); + }; + + return stream; +} + +void stream_close(stream_t *stream) { + if (stream->__alloc) + fclose(stream->__file); +} + +bool stream_read(const stream_t *stream, void *res, size_t amount) { + size_t read; + read = fread(res, 1, amount, stream->__file); + + if (read == 0) { + if (feof(stream->__file) || errno == 0) + return false; + else + perror_and_die("cannot read from stream"); + } + + return true; +} + +bool stream_read_i8(const stream_t *stream, int8_t *res) { + if (stream_read(stream, res, 1) == false) + return false; + return true; +} + +bool stream_read_i16(const stream_t *stream, int16_t *res) { + if (stream_read(stream, res, 2) == false) + return false; + *res = ntohs(*res); + return true; +} + +bool stream_read_i32(const stream_t *stream, int32_t *res) { + if (stream_read(stream, res, 4) == false) + return false; + *res = ntohl(*res); + return true; +} + +bool stream_read_i64(const stream_t *stream, int64_t *res) { + if (stream_read(stream, res, 8) == false) + return false; + *res = longswap(*res); + return true; +} + +bool stream_read_u16(const stream_t *stream, uint16_t *res) { + if (stream_read(stream, res, 2) == false) + return false; + *res = ntohs(*res); + return true; +} + +bool stream_write(const stream_t *stream, const void *buf, size_t amount) { + size_t wrote; + wrote = fwrite(buf, 1, amount, stream->__file); + + if (wrote == 0) + perror_and_die("cannot write to stream"); + + if (wrote < amount) + return false; + + return true; +} + +bool stream_write_i8(const stream_t *stream, int8_t b) { + if (stream_write(stream, &b, 1) == false) + return false; + return true; +} + +bool stream_write_i16(const stream_t *stream, int16_t s) { + s = htons(s); + if (stream_write(stream, &s, 2) == false) + return false; + return true; +} + +bool stream_write_i32(const stream_t *stream, int32_t i) { + i = htonl(i); + if (stream_write(stream, &i, 4) == false) + return false; + return true; +} + +bool stream_write_i64(const stream_t *stream, int64_t l) { + l = longswap(l); + if (stream_write(stream, &l, 8) == false) + return false; + return true; +} + +bool stream_write_u16(const stream_t *stream, uint16_t s) { + s = htons(s); + if (stream_write(stream, &s, 2) == false) + return false; + return true; +} diff --git a/lib/stream.h b/lib/stream.h new file mode 100644 index 0000000..d9a05ce --- /dev/null +++ b/lib/stream.h @@ -0,0 +1,27 @@ +#pragma once + +#include <stdint.h> +#include <stdio.h> +#include <stdbool.h> + +typedef struct { + FILE *__file; + bool __alloc; +} stream_t; + +stream_t stream_open(const char *path, const char* mode); +void stream_close(stream_t *stream); + +bool stream_read(const stream_t *stream, void *res, size_t amount); +bool stream_read_i8(const stream_t *stream, int8_t *res); +bool stream_read_i16(const stream_t *stream, int16_t *res); +bool stream_read_i32(const stream_t *stream, int32_t *res); +bool stream_read_i64(const stream_t *stream, int64_t *res); +bool stream_read_u16(const stream_t *stream, uint16_t *res); + +bool stream_write(const stream_t *stream, const void *buf, size_t amount); +bool stream_write_i8(const stream_t *stream, int8_t b); +bool stream_write_i16(const stream_t *stream, int16_t s); +bool stream_write_i32(const stream_t *stream, int32_t i); +bool stream_write_i64(const stream_t *stream, int64_t l); +bool stream_write_u16(const stream_t *stream, uint16_t s); |