From f8217d240d598f39f70047f7a623dd46312542c6 Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Sat, 4 Dec 2021 16:01:12 -0800
Subject: Initial commit.

---
 cstring/CMakeLists.txt    | 11 ++++++++
 cstring/include/cstring.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100644 cstring/CMakeLists.txt
 create mode 100644 cstring/include/cstring.h

(limited to 'cstring')

diff --git a/cstring/CMakeLists.txt b/cstring/CMakeLists.txt
new file mode 100644
index 0000000..67fb366
--- /dev/null
+++ b/cstring/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(cstring)
+
+add_library(cstring INTERFACE)
+
+target_include_directories(cstring INTERFACE
+  include)
+
+target_link_libraries(cstring INTERFACE
+  -lbsd)
diff --git a/cstring/include/cstring.h b/cstring/include/cstring.h
new file mode 100644
index 0000000..644f1e1
--- /dev/null
+++ b/cstring/include/cstring.h
@@ -0,0 +1,64 @@
+/// Fixed-size strings with value semantics.
+#pragma once
+
+#include <assert.h>
+#include <bsd/string.h>
+
+/// A fixed-size string.
+/// The string is null-terminated so that it can be used with the usual C APIs.
+#define DEF_STRING(STRING, SIZE)                                               \
+  typedef struct STRING {                                                      \
+    int length;                                                                \
+    char str[SIZE];                                                            \
+  } STRING;                                                                    \
+                                                                               \
+  static const size_t STRING##_size = SIZE;                                    \
+                                                                               \
+  static inline const char* STRING##_cstring(const STRING* str) {              \
+    return str->str;                                                           \
+  }                                                                            \
+                                                                               \
+  static inline STRING STRING##_make(const char* cstr) {                       \
+    if (!cstr) {                                                               \
+      return (STRING){0};                                                      \
+    } else {                                                                   \
+      STRING str = (STRING){0};                                                \
+      str.length = strlcpy(str.str, cstr, SIZE);                               \
+      return str;                                                              \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  static inline STRING STRING##_dirname(STRING path) {                         \
+    STRING str = path;                                                         \
+    for (int i = str.length - 1; i >= 0; --i) {                                \
+      if (str.str[i] == '/' || str.str[i] == '\\') {                           \
+        str.str[i] = 0;                                                        \
+        str.length = i;                                                        \
+        return str;                                                            \
+      } else {                                                                 \
+        str.str[i] = 0;                                                        \
+      }                                                                        \
+    }                                                                          \
+    str = (STRING){0};                                                         \
+    str.str[0] = '.';                                                          \
+    str.length = 1;                                                            \
+    return str;                                                                \
+  }                                                                            \
+                                                                               \
+  static inline STRING STRING##_concat(STRING a, STRING b) {                   \
+    assert(a.length + b.length + 1 < SIZE);                                    \
+    STRING str = {0};                                                          \
+    strlcpy(str.str, a.str, SIZE);                                             \
+    strlcpy(str.str + a.length, b.str, SIZE);                                  \
+    str.length = a.length + b.length;                                          \
+    return str;                                                                \
+  }                                                                            \
+                                                                               \
+  static inline STRING STRING##_concat_path(STRING a, STRING b) {              \
+    return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b);         \
+  }
+
+DEF_STRING(sstring, 32)    // Small.
+DEF_STRING(mstring, 256)   // Medium.
+DEF_STRING(lstring, 1024)  // Large.
+DEF_STRING(xlstring, 4096) // Extra large.
-- 
cgit v1.2.3