summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/lib.c51
-rw-r--r--lib/lib.h13
-rw-r--r--lib/map.c87
-rw-r--r--lib/map.h15
-rw-r--r--lib/stream.c144
-rw-r--r--lib/stream.h27
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);