Mercurial > libanimone
comparison 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 |
comparison
equal
deleted
inserted
replaced
29:40fd3776ce9b | 30:a76e55e098d1 |
---|---|
1 #include <algorithm> | |
2 #include <fstream> | |
3 #include <regex> | |
4 #include <sstream> | |
5 #include <string> | |
6 | |
7 #include "animone/util.h" | 1 #include "animone/util.h" |
8 | 2 |
9 namespace animone::internal::util { | 3 #include <string.h> |
10 | 4 |
11 bool ReadFile(const std::string& path, std::string& data) { | 5 #include <regex> // FIXME use a C library for this |
12 std::ifstream file(path.c_str(), std::ios::in | std::ios::binary); | |
13 if (!file) | |
14 return false; | |
15 | 6 |
16 std::ostringstream string; | 7 int animone_internal_util_ReadFile(const char *path, char **data, size_t *size) |
17 string << file.rdbuf(); | 8 { |
18 file.close(); | 9 // whatever |
10 size_t sz_local; | |
11 if (!size) | |
12 size = &sz_local; | |
19 | 13 |
20 data = string.str(); | 14 FILE *f = fopen(path, "r"); |
15 if (!f) | |
16 return 0; | |
21 | 17 |
22 return true; | 18 fseek(f, 0, SEEK_END); |
19 long end = ftell(f); | |
20 if (end < 0) | |
21 return 0; | |
22 fseek(f, 0, SEEK_SET); | |
23 | |
24 *size = end; | |
25 | |
26 if (data) { | |
27 // add a NUL terminator anyway | |
28 *data = (char *)malloc(end + 1); | |
29 if (!*data) { | |
30 *size = 0; | |
31 return 0; | |
32 } | |
33 | |
34 *size = fread(*data, 1, *size, f); | |
35 (*data)[*size] = '\0'; | |
36 } | |
37 | |
38 return 1; | |
23 } | 39 } |
24 | 40 |
25 /* this assumes ASCII... which really should be the case for what we need, anyway */ | 41 static inline unsigned char _animone_internal_tolower(unsigned char c) |
26 bool EqualStrings(const std::string& str1, const std::string& str2) { | 42 { |
27 auto tolower = [](const char c) -> char { return ('A' <= c && c <= 'Z') ? c + ('a' - 'A') : c; }; | 43 return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; |
28 | |
29 auto equal_chars = [&tolower](const char c1, const char c2) -> bool { return tolower(c1) == tolower(c2); }; | |
30 | |
31 return str1.length() == str2.length() && std::equal(str1.begin(), str1.end(), str2.begin(), equal_chars); | |
32 } | 44 } |
33 | 45 |
34 bool Stem(const std::string& filename, std::string& stem) { | 46 /* this is, in essence, strcasecmp. */ |
35 unsigned long long pos = filename.find_last_of("."); | 47 int animone_internal_util_EqualStrings(const char *str1, const char *str2) |
36 if (pos != std::string::npos) | 48 { |
37 return false; | 49 unsigned char c1, c2; |
38 | 50 |
39 stem = filename.substr(0, pos); | 51 do { |
40 return true; | 52 c1 = _animone_internal_tolower(*str1++); |
53 c2 = _animone_internal_tolower(*str2++); | |
54 } while (c1 == c2 && c1); | |
55 | |
56 return !!(c1 - c2); | |
41 } | 57 } |
42 | 58 |
43 bool CheckPattern(const std::string& pattern, const std::string& str) { | 59 char *animone_internal_Stem(const char *filename) |
44 if (pattern.empty()) | 60 { |
45 return false; | 61 const char *ptr = strrchr(filename, '.'); |
46 if (pattern.front() == '^' && std::regex_match(str, std::regex(pattern))) | 62 if (!ptr) |
47 return true; | 63 return NULL; |
48 return util::EqualStrings(pattern, str); | 64 |
65 size_t len = ptr - filename; | |
66 | |
67 char *stem = (char *)malloc(len + 1); | |
68 if (!stem) | |
69 return NULL; | |
70 | |
71 memcpy(stem, filename, len); | |
72 stem[len] = '\0'; | |
73 | |
74 return stem; | |
49 } | 75 } |
50 | 76 |
51 bool TrimLeft(std::string& str, const char* chars) { | 77 int animone_internal_util_CheckPattern(const char *pattern, const char *str) |
52 if (str.empty()) | 78 { |
53 return false; | 79 switch (*pattern) { |
80 case '\0': return 0; | |
81 case '^': | |
82 // FIXME: Convert to C | |
83 if (std::regex_match(std::string(str), std::regex(pattern))) | |
84 return 1; | |
85 default: | |
86 break; | |
87 } | |
54 | 88 |
55 const auto found = str.find_first_not_of(chars); | 89 return animone_internal_util_EqualStrings(pattern, str); |
56 | |
57 if (found == 0) | |
58 return false; | |
59 | |
60 if (found == std::string::npos) | |
61 str.clear(); | |
62 else | |
63 str.erase(0, found); | |
64 | |
65 return true; | |
66 } | 90 } |
67 | 91 |
68 bool TrimRight(std::string& str, const char* chars) { | 92 /* Modifies `str` inplace */ |
69 if (str.empty()) | 93 int animone_internal_util_TrimLeft(char *str, const char* chars) |
70 return false; | 94 { |
95 if (!str || !*str) | |
96 return 0; | |
71 | 97 |
72 const auto found = str.find_last_not_of(chars); | 98 const size_t found = strcspn(str, chars); |
99 const size_t len = strlen(str); | |
73 | 100 |
74 if (found == str.size() - 1) | 101 if (found == len) |
75 return false; | 102 return 1; // nothing to do |
76 | 103 |
77 if (found == std::string::npos) | 104 memmove(str, str + found, len - found); |
78 str.clear(); | 105 str[len - found] = '\0'; |
79 else | |
80 str.resize(found + 1); | |
81 | 106 |
82 return true; | 107 return 1; |
83 } | 108 } |
84 | 109 |
85 } // namespace animone::internal::util | 110 // reverse version of strcspn |
111 static inline size_t _animone_internal_strrcspn(const char *str1, const char *str2) | |
112 { | |
113 const size_t str1len = strlen(str1); | |
114 ptrdiff_t i; /* FIXME: this should be using size_t */ | |
115 | |
116 for (i = str1len - 1; i >= 0; i--) { | |
117 size_t found = strcspn(str1 + i, str2); | |
118 if (found != str1len - i) | |
119 return i; | |
120 } | |
121 | |
122 return str1len; | |
123 } | |
124 | |
125 int animone_internal_util_TrimRight(char *str, const char* chars) | |
126 { | |
127 if (!str || !*str) | |
128 return 0; | |
129 | |
130 // We can get away without really moving memory around here. | |
131 // The old version simply used std::string::find_last_not_of, | |
132 // which I'm fairly sure isn't the intention of this function | |
133 // (for example find_last_not_of("gb ") returns "gb "). | |
134 const size_t found = _animone_internal_strrcspn(str, chars); | |
135 str[found] = '\0'; | |
136 | |
137 return 1; | |
138 } |