diff src/util.cc @ 30:a76e55e098d1

util: rewrite functions in C-ish there are C++ bindings still put in place. the code should be valid C, except for the use of <regex>, which ought to go anyway. eventually I'll actually *test* this stuff aside from the TrimRight crap
author Paper <paper@tflc.us>
date Sun, 09 Feb 2025 23:18:57 -0500
parents 27b988a1048c
children
line wrap: on
line diff
--- a/src/util.cc	Sun Feb 09 23:15:55 2025 -0500
+++ b/src/util.cc	Sun Feb 09 23:18:57 2025 -0500
@@ -1,85 +1,138 @@
-#include <algorithm>
-#include <fstream>
-#include <regex>
-#include <sstream>
-#include <string>
-
 #include "animone/util.h"
 
-namespace animone::internal::util {
+#include <string.h>
+
+#include <regex> // FIXME use a C library for this
 
-bool ReadFile(const std::string& path, std::string& data) {
-	std::ifstream file(path.c_str(), std::ios::in | std::ios::binary);
-	if (!file)
-		return false;
+int animone_internal_util_ReadFile(const char *path, char **data, size_t *size)
+{
+	// whatever
+	size_t sz_local;
+	if (!size)
+		size = &sz_local;
+
+	FILE *f = fopen(path, "r");
+	if (!f)
+		return 0;
 
-	std::ostringstream string;
-	string << file.rdbuf();
-	file.close();
+	fseek(f, 0, SEEK_END);
+	long end = ftell(f);
+	if (end < 0)
+		return 0;
+	fseek(f, 0, SEEK_SET);
+
+	*size = end;
 
-	data = string.str();
+	if (data) {
+		// add a NUL terminator anyway
+		*data = (char *)malloc(end + 1);
+		if (!*data) {
+			*size = 0;
+			return 0;
+		}
 
-	return true;
+		*size = fread(*data, 1, *size, f);
+		(*data)[*size] = '\0';
+	}
+
+	return 1;
 }
 
-/* this assumes ASCII... which really should be the case for what we need, anyway */
-bool EqualStrings(const std::string& str1, const std::string& str2) {
-	auto tolower = [](const char c) -> char { return ('A' <= c && c <= 'Z') ? c + ('a' - 'A') : c; };
-
-	auto equal_chars = [&tolower](const char c1, const char c2) -> bool { return tolower(c1) == tolower(c2); };
-
-	return str1.length() == str2.length() && std::equal(str1.begin(), str1.end(), str2.begin(), equal_chars);
+static inline unsigned char _animone_internal_tolower(unsigned char c)
+{
+	return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c;
 }
 
-bool Stem(const std::string& filename, std::string& stem) {
-	unsigned long long pos = filename.find_last_of(".");
-	if (pos != std::string::npos)
-		return false;
+/* this is, in essence, strcasecmp. */
+int animone_internal_util_EqualStrings(const char *str1, const char *str2)
+{
+	unsigned char c1, c2;
 
-	stem = filename.substr(0, pos);
-	return true;
+	do {
+		c1 = _animone_internal_tolower(*str1++);
+		c2 = _animone_internal_tolower(*str2++);
+	} while (c1 == c2 && c1);
+
+	return !!(c1 - c2);
 }
 
-bool CheckPattern(const std::string& pattern, const std::string& str) {
-	if (pattern.empty())
-		return false;
-	if (pattern.front() == '^' && std::regex_match(str, std::regex(pattern)))
-		return true;
-	return util::EqualStrings(pattern, str);
+char *animone_internal_Stem(const char *filename)
+{
+	const char *ptr = strrchr(filename, '.');
+	if (!ptr)
+		return NULL;
+
+	size_t len = ptr - filename;
+
+	char *stem = (char *)malloc(len + 1);
+	if (!stem)
+		return NULL;
+
+	memcpy(stem, filename, len);
+	stem[len] = '\0';
+
+	return stem;
+}
+
+int animone_internal_util_CheckPattern(const char *pattern, const char *str)
+{
+	switch (*pattern) {
+	case '\0': return 0;
+	case '^':
+		// FIXME: Convert to C
+		if (std::regex_match(std::string(str), std::regex(pattern)))
+			return 1;
+	default:
+		break;
+	}
+
+	return animone_internal_util_EqualStrings(pattern, str);
 }
 
-bool TrimLeft(std::string& str, const char* chars) {
-	if (str.empty())
-		return false;
-
-	const auto found = str.find_first_not_of(chars);
+/* Modifies `str` inplace */
+int animone_internal_util_TrimLeft(char *str, const char* chars)
+{
+	if (!str || !*str)
+		return 0;
 
-	if (found == 0)
-		return false;
+	const size_t found = strcspn(str, chars);
+	const size_t len = strlen(str);
 
-	if (found == std::string::npos)
-		str.clear();
-	else
-		str.erase(0, found);
+	if (found == len)
+		return 1; // nothing to do
 
-	return true;
+	memmove(str, str + found, len - found);
+	str[len - found] = '\0';
+
+	return 1;
 }
 
-bool TrimRight(std::string& str, const char* chars) {
-	if (str.empty())
-		return false;
-
-	const auto found = str.find_last_not_of(chars);
+// reverse version of strcspn
+static inline size_t _animone_internal_strrcspn(const char *str1, const char *str2)
+{
+	const size_t str1len = strlen(str1);
+	ptrdiff_t i; /* FIXME: this should be using size_t */
 
-	if (found == str.size() - 1)
-		return false;
+	for (i = str1len - 1; i >= 0; i--) {
+		size_t found = strcspn(str1 + i, str2);
+		if (found != str1len - i)
+            return i;
+	}
 
-	if (found == std::string::npos)
-		str.clear();
-	else
-		str.resize(found + 1);
-
-	return true;
+    return str1len;
 }
 
-} // namespace animone::internal::util
+int animone_internal_util_TrimRight(char *str, const char* chars)
+{
+	if (!str || !*str)
+		return 0;
+
+	// We can get away without really moving memory around here.
+	// The old version simply used std::string::find_last_not_of,
+	// which I'm fairly sure isn't the intention of this function
+	// (for example find_last_not_of("gb    ") returns "gb   ").
+	const size_t found = _animone_internal_strrcspn(str, chars);
+	str[found] = '\0';
+
+	return 1;
+}