aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-09-15 15:33:47 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-09-15 15:33:47 -0400
commite422079fcced744e3a6247aeb12a09a658989072 (patch)
tree393d5e52ba67dcc822ccfa9a812198edda5e735d /stdlib
parent259c7efcf8c3808d8151d8e15f1167ad2b6f2ca7 (diff)
Add a Byte datatype
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/bytes.c38
-rw-r--r--stdlib/bytes.h29
-rw-r--r--stdlib/integers.c8
-rw-r--r--stdlib/paths.c60
-rw-r--r--stdlib/paths.h4
-rw-r--r--stdlib/tomo.h1
6 files changed, 118 insertions, 22 deletions
diff --git a/stdlib/bytes.c b/stdlib/bytes.c
new file mode 100644
index 00000000..5b471bfe
--- /dev/null
+++ b/stdlib/bytes.c
@@ -0,0 +1,38 @@
+// The logic for unsigned bytes
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bytes.h"
+#include "stdlib.h"
+#include "text.h"
+#include "util.h"
+
+public const Byte_t Byte$min = 0;
+public const Byte_t Byte$max = UINT8_MAX;
+
+PUREFUNC public Text_t Byte$as_text(const Byte_t *b, bool colorize, const TypeInfo *type)
+{
+ (void)type;
+ if (!b) return Text("Byte");
+ return Text$format(colorize ? "\x1b[35m%u[B]\x1b[m" : "%u[B]", *b);
+}
+
+public Byte_t Byte$random(Byte_t min, Byte_t max)
+{
+ if (min > max)
+ fail("Random minimum value (%u) is larger than the maximum value (%u)", min, max);
+ if (min == max)
+ return min;
+
+ uint32_t r = arc4random_uniform((uint32_t)max - (uint32_t)min + 1u);
+ return (Byte_t)(min + r);
+}
+
+public const TypeInfo Byte$info = {
+ .size=sizeof(Byte_t),
+ .align=__alignof__(Byte_t),
+ .tag=CustomInfo,
+ .CustomInfo={.as_text=(void*)Byte$as_text},
+};
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/bytes.h b/stdlib/bytes.h
new file mode 100644
index 00000000..d74ab80c
--- /dev/null
+++ b/stdlib/bytes.h
@@ -0,0 +1,29 @@
+#pragma once
+
+// An unsigned byte datatype
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "types.h"
+#include "util.h"
+
+#define Byte_t uint8_t
+#define Byte(b) ((Byte_t)(b))
+
+PUREFUNC Text_t Byte$as_text(const Byte_t *b, bool colorize, const TypeInfo *type);
+Byte_t Byte$random(Byte_t min, Byte_t max);
+
+extern const Byte_t Byte$min;
+extern const Byte_t Byte$max;
+
+extern const TypeInfo Byte$info;
+
+typedef struct {
+ Byte_t value;
+ bool is_null:1;
+} OptionalByte_t;
+
+#define NULL_BYTE ((OptionalByte_t){.is_null=true})
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/integers.c b/stdlib/integers.c
index ef588984..6caac31e 100644
--- a/stdlib/integers.c
+++ b/stdlib/integers.c
@@ -481,10 +481,10 @@ public const TypeInfo Int$info = {
.CustomInfo={.compare=(void*)KindOfInt##$compare, .as_text=(void*)KindOfInt##$as_text}, \
};
-DEFINE_INT_TYPE(int64_t, Int64, "ld_i64", INT64_MIN, INT64_MAX)
-DEFINE_INT_TYPE(int32_t, Int32, "d_i32", INT32_MIN, INT32_MAX)
-DEFINE_INT_TYPE(int16_t, Int16, "d_i16", INT16_MIN, INT16_MAX)
-DEFINE_INT_TYPE(int8_t, Int8, "d_i8", INT8_MIN, INT8_MAX)
+DEFINE_INT_TYPE(int64_t, Int64, "ld[64]", INT64_MIN, INT64_MAX)
+DEFINE_INT_TYPE(int32_t, Int32, "d[32]", INT32_MIN, INT32_MAX)
+DEFINE_INT_TYPE(int16_t, Int16, "d[16]", INT16_MIN, INT16_MAX)
+DEFINE_INT_TYPE(int8_t, Int8, "d[8]", INT8_MIN, INT8_MAX)
#undef DEFINE_INT_TYPE
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/paths.c b/stdlib/paths.c
index 231a7c23..bebb9389 100644
--- a/stdlib/paths.c
+++ b/stdlib/paths.c
@@ -207,7 +207,7 @@ public bool Path$is_symlink(Path_t path)
return (sb.st_mode & S_IFMT) == S_IFLNK;
}
-static void _write(Path_t path, Text_t text, int mode, int permissions)
+static void _write(Path_t path, Array_t bytes, int mode, int permissions)
{
path = Path$_expand_home(path);
const char *path_str = Text$as_c_string(path);
@@ -215,24 +215,36 @@ static void _write(Path_t path, Text_t text, int mode, int permissions)
if (fd == -1)
fail("Could not write to file: %s\n%s", path_str, strerror(errno));
- const char *str = Text$as_c_string(text);
- size_t len = strlen(str);
- ssize_t written = write(fd, str, len);
- if (written != (ssize_t)len)
+ if (bytes.stride != 1)
+ Array$compact(&bytes, 1);
+ ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
+ if (written != (ssize_t)bytes.length)
fail("Could not write to file: %s\n%s", path_str, strerror(errno));
}
public void Path$write(Path_t path, Text_t text, int permissions)
{
- _write(path, text, O_WRONLY | O_CREAT, permissions);
+ Array_t bytes = Text$utf8_bytes(text);
+ _write(path, bytes, O_WRONLY | O_CREAT, permissions);
+}
+
+public void Path$write_bytes(Path_t path, Array_t bytes, int permissions)
+{
+ _write(path, bytes, O_WRONLY | O_CREAT, permissions);
}
public void Path$append(Path_t path, Text_t text, int permissions)
{
- _write(path, text, O_WRONLY | O_APPEND | O_CREAT, permissions);
+ Array_t bytes = Text$utf8_bytes(text);
+ _write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions);
}
-public Text_t Path$read(Path_t path)
+public void Path$append_bytes(Path_t path, Array_t bytes, int permissions)
+{
+ _write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions);
+}
+
+public Array_t Path$read_bytes(Path_t path)
{
path = Path$_expand_home(path);
int fd = open(Text$as_c_string(path), O_RDONLY);
@@ -245,11 +257,11 @@ public Text_t Path$read(Path_t path)
if ((sb.st_mode & S_IFMT) == S_IFREG) { // Use memory mapping if it's a real file:
const char *mem = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- char *gc_mem = GC_MALLOC_ATOMIC((size_t)sb.st_size+1);
- memcpy(gc_mem, mem, (size_t)sb.st_size);
- gc_mem[sb.st_size] = '\0';
+ char *content = GC_MALLOC_ATOMIC((size_t)sb.st_size+1);
+ memcpy(content, mem, (size_t)sb.st_size);
+ content[sb.st_size] = '\0';
close(fd);
- return Text$from_strn(gc_mem, (size_t)sb.st_size);
+ return (Array_t){.data=content, .atomic=1, .stride=1, .length=(int64_t)sb.st_size};
} else {
size_t capacity = 256, len = 0;
char *content = GC_MALLOC_ATOMIC(capacity);
@@ -279,10 +291,16 @@ public Text_t Path$read(Path_t path)
if (u8_check((uint8_t*)content, len) != NULL)
fail("File does not contain valid UTF8 data!");
- return Text$from_strn(content, len);
+ return (Array_t){.data=content, .atomic=1, .stride=1, .length=len};
}
}
+public Text_t Path$read(Path_t path)
+{
+ Array_t bytes = Path$read_bytes(path);
+ return Text$from_bytes(bytes);
+}
+
public void Path$remove(Path_t path, bool ignore_missing)
{
path = Path$_expand_home(path);
@@ -375,7 +393,7 @@ public Path_t Path$unique_directory(Path_t path)
return Text$format("%s/", created);
}
-public Text_t Path$write_unique(Path_t path, Text_t text)
+public Text_t Path$write_unique_bytes(Path_t path, Array_t bytes)
{
path = Path$_expand_home(path);
const char *path_str = Text$as_c_string(path);
@@ -392,14 +410,20 @@ public Text_t Path$write_unique(Path_t path, Text_t text)
if (fd == -1)
fail("Could not write to unique file: %s\n%s", buf, strerror(errno));
- const char *str = Text$as_c_string(text);
- size_t write_len = strlen(str);
- ssize_t written = write(fd, str, write_len);
- if (written != (ssize_t)write_len)
+ if (bytes.stride != 1)
+ Array$compact(&bytes, 1);
+
+ ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
+ if (written != (ssize_t)bytes.length)
fail("Could not write to file: %s\n%s", buf, strerror(errno));
return Text$format("%s", buf);
}
+public Text_t Path$write_unique(Path_t path, Text_t text)
+{
+ return Path$write_unique_bytes(path, Text$utf8_bytes(text));
+}
+
public Path_t Path$parent(Path_t path)
{
return Path$cleanup(Text$concat(path, Path("/../")));
diff --git a/stdlib/paths.h b/stdlib/paths.h
index e0d85258..d06d4fdc 100644
--- a/stdlib/paths.h
+++ b/stdlib/paths.h
@@ -26,8 +26,11 @@ bool Path$is_pipe(Path_t path, bool follow_symlinks);
bool Path$is_socket(Path_t path, bool follow_symlinks);
bool Path$is_symlink(Path_t path);
void Path$write(Path_t path, Text_t text, int permissions);
+void Path$write_bytes(Path_t path, Array_t bytes, int permissions);
void Path$append(Path_t path, Text_t text, int permissions);
+void Path$append_bytes(Path_t path, Array_t bytes, int permissions);
Text_t Path$read(Path_t path);
+Array_t Path$read_bytes(Path_t path);
void Path$remove(Path_t path, bool ignore_missing);
void Path$create_directory(Path_t path, int permissions);
Array_t Path$children(Path_t path, bool include_hidden);
@@ -35,6 +38,7 @@ Array_t Path$files(Path_t path, bool include_hidden);
Array_t Path$subdirectories(Path_t path, bool include_hidden);
Path_t Path$unique_directory(Path_t path);
Text_t Path$write_unique(Path_t path, Text_t text);
+Text_t Path$write_unique_bytes(Path_t path, Array_t bytes);
Path_t Path$parent(Path_t path);
Text_t Path$base_name(Path_t path);
Text_t Path$extension(Path_t path, bool full);
diff --git a/stdlib/tomo.h b/stdlib/tomo.h
index 7db0f490..d1e61a5d 100644
--- a/stdlib/tomo.h
+++ b/stdlib/tomo.h
@@ -11,6 +11,7 @@
#include "arrays.h"
#include "bools.h"
+#include "bytes.h"
#include "c_strings.h"
#include "channels.h"
#include "datatypes.h"