Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (stdstring.h). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #ifndef __LIBRETRO_SDK_STDSTRING_H | |
24 | #define __LIBRETRO_SDK_STDSTRING_H | |
25 | ||
26 | #include <stdlib.h> | |
27 | #include <stddef.h> | |
28 | #include <ctype.h> | |
29 | #include <string.h> | |
30 | #include <boolean.h> | |
31 | ||
32 | #include <retro_common_api.h> | |
33 | #include <retro_inline.h> | |
34 | #include <compat/strl.h> | |
35 | ||
36 | RETRO_BEGIN_DECLS | |
37 | ||
38 | #define STRLEN_CONST(x) ((sizeof((x))-1)) | |
39 | ||
40 | #define strcpy_literal(a, b) strcpy(a, b) | |
41 | ||
42 | #define string_is_not_equal(a, b) !string_is_equal((a), (b)) | |
43 | ||
44 | #define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0) | |
45 | #define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0) | |
46 | ||
47 | #define TOLOWER(c) ((c) | (lr_char_props[(unsigned char)(c)] & 0x20)) | |
48 | #define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20)) | |
49 | ||
50 | /* C standard says \f \v are space, but this one disagrees */ | |
51 | #define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80) | |
52 | ||
53 | #define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40) | |
54 | #define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20) | |
55 | #define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04) | |
56 | #define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02) | |
57 | #define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60) | |
58 | #define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28) | |
59 | #define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68) | |
60 | #define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01) | |
61 | ||
62 | /* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */ | |
63 | #define string_is_equal_noncase string_is_equal_case_insensitive | |
64 | ||
65 | static INLINE bool string_is_empty(const char *data) | |
66 | { | |
67 | return !data || (*data == '\0'); | |
68 | } | |
69 | ||
70 | static INLINE bool string_is_equal(const char *a, const char *b) | |
71 | { | |
72 | return (a && b) ? !strcmp(a, b) : false; | |
73 | } | |
74 | ||
75 | static INLINE bool string_starts_with_size(const char *str, const char *prefix, | |
76 | size_t size) | |
77 | { | |
78 | return (str && prefix) ? !strncmp(prefix, str, size) : false; | |
79 | } | |
80 | ||
81 | static INLINE bool string_starts_with(const char *str, const char *prefix) | |
82 | { | |
83 | return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false; | |
84 | } | |
85 | ||
86 | static INLINE bool string_ends_with_size(const char *str, const char *suffix, | |
87 | size_t str_len, size_t suffix_len) | |
88 | { | |
89 | return (str_len < suffix_len) ? false : | |
90 | !memcmp(suffix, str + (str_len - suffix_len), suffix_len); | |
91 | } | |
92 | ||
93 | static INLINE bool string_ends_with(const char *str, const char *suffix) | |
94 | { | |
95 | return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix)); | |
96 | } | |
97 | ||
98 | /** | |
99 | * strlen_size: | |
100 | * | |
101 | * Leaf function. | |
102 | * | |
103 | * @return the length of 'str' (c.f. strlen()), but only | |
104 | * checks the first 'size' characters | |
105 | * - If 'str' is NULL, returns 0 | |
106 | * - If 'str' is not NULL and no '\0' character is found | |
107 | * in the first 'size' characters, returns 'size' | |
108 | **/ | |
109 | static INLINE size_t strlen_size(const char *str, size_t size) | |
110 | { | |
111 | size_t i = 0; | |
112 | if (str) | |
113 | while (i < size && str[i]) i++; | |
114 | return i; | |
115 | } | |
116 | ||
117 | ||
118 | static INLINE bool string_is_equal_case_insensitive(const char *a, | |
119 | const char *b) | |
120 | { | |
121 | int result = 0; | |
122 | const unsigned char *p1 = (const unsigned char*)a; | |
123 | const unsigned char *p2 = (const unsigned char*)b; | |
124 | ||
125 | if (!a || !b) | |
126 | return false; | |
127 | if (p1 == p2) | |
128 | return true; | |
129 | ||
130 | while ((result = tolower (*p1) - tolower (*p2++)) == 0) | |
131 | if (*p1++ == '\0') | |
132 | break; | |
133 | ||
134 | return (result == 0); | |
135 | } | |
136 | ||
137 | static INLINE bool string_starts_with_case_insensitive(const char *str, | |
138 | const char *prefix) | |
139 | { | |
140 | int result = 0; | |
141 | const unsigned char *p1 = (const unsigned char*)str; | |
142 | const unsigned char *p2 = (const unsigned char*)prefix; | |
143 | ||
144 | if (!str || !prefix) | |
145 | return false; | |
146 | if (p1 == p2) | |
147 | return true; | |
148 | ||
149 | while ((result = tolower (*p1++) - tolower (*p2)) == 0) | |
150 | if (*p2++ == '\0') | |
151 | break; | |
152 | ||
153 | return (result == 0 || *p2 == '\0'); | |
154 | } | |
155 | ||
156 | char *string_to_upper(char *s); | |
157 | ||
158 | char *string_to_lower(char *s); | |
159 | ||
160 | char *string_ucwords(char *s); | |
161 | ||
162 | char *string_replace_substring(const char *in, | |
163 | const char *pattern, size_t pattern_len, | |
164 | const char *replacement, size_t replacement_len); | |
165 | ||
166 | /** | |
167 | * string_trim_whitespace_left: | |
168 | * | |
169 | * Remove leading whitespaces | |
170 | **/ | |
171 | char *string_trim_whitespace_left(char *const s); | |
172 | ||
173 | /** | |
174 | * string_trim_whitespace_right: | |
175 | * | |
176 | * Remove trailing whitespaces | |
177 | **/ | |
178 | char *string_trim_whitespace_right(char *const s); | |
179 | ||
180 | /** | |
181 | * string_trim_whitespace: | |
182 | * | |
183 | * Remove leading and trailing whitespaces | |
184 | **/ | |
185 | char *string_trim_whitespace(char *const s); | |
186 | ||
187 | /** | |
188 | * word_wrap: | |
189 | * @dst : pointer to destination buffer. | |
190 | * @dst_size : size of destination buffer. | |
191 | * @src : pointer to input string. | |
192 | * @src_len : length of @src | |
193 | * @line_width : max number of characters per line. | |
194 | * @wideglyph_width : not used, but is necessary to keep | |
195 | * compatibility with word_wrap_wideglyph(). | |
196 | * @max_lines : max lines of destination string. | |
197 | * 0 means no limit. | |
198 | * | |
199 | * Wraps string specified by 'src' to destination buffer | |
200 | * specified by 'dst' and 'dst_size'. | |
201 | * This function assumes that all glyphs in the string | |
202 | * have an on-screen pixel width similar to that of | |
203 | * regular Latin characters - i.e. it will not wrap | |
204 | * correctly any text containing so-called 'wide' Unicode | |
205 | * characters (e.g. CJK languages, emojis, etc.). | |
206 | **/ | |
207 | void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len, | |
208 | int line_width, int wideglyph_width, unsigned max_lines); | |
209 | ||
210 | /** | |
211 | * word_wrap_wideglyph: | |
212 | * @dst : pointer to destination buffer. | |
213 | * @dst_size : size of destination buffer. | |
214 | * @src : pointer to input string. | |
215 | * @src_len : length of @src | |
216 | * @line_width : max number of characters per line. | |
217 | * @wideglyph_width : effective width of 'wide' Unicode glyphs. | |
218 | * the value here is normalised relative to the | |
219 | * typical on-screen pixel width of a regular | |
220 | * Latin character: | |
221 | * - a regular Latin character is defined to | |
222 | * have an effective width of 100 | |
223 | * - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width) | |
224 | * - e.g. if 'wide' Unicode characters in 'src' | |
225 | * have an on-screen pixel width twice that of | |
226 | * regular Latin characters, wideglyph_width | |
227 | * would be 200 | |
228 | * @max_lines : max lines of destination string. | |
229 | * 0 means no limit. | |
230 | * | |
231 | * Wraps string specified by @src to destination buffer | |
232 | * specified by @dst and @dst_size. | |
233 | * This function assumes that all glyphs in the string | |
234 | * are: | |
235 | * - EITHER 'non-wide' Unicode glyphs, with an on-screen | |
236 | * pixel width similar to that of regular Latin characters | |
237 | * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.) | |
238 | * with an on-screen pixel width defined by @wideglyph_width | |
239 | * Note that wrapping may occur in inappropriate locations | |
240 | * if @src string contains 'wide' Unicode characters whose | |
241 | * on-screen pixel width deviates greatly from the set | |
242 | * @wideglyph_width value. | |
243 | **/ | |
244 | void word_wrap_wideglyph( | |
245 | char *dst, size_t dst_size, | |
246 | const char *src, size_t src_len, | |
247 | int line_width, int wideglyph_width, | |
248 | unsigned max_lines); | |
249 | ||
250 | /** | |
251 | * string_tokenize: | |
252 | * | |
253 | * Splits string into tokens seperated by @delim | |
254 | * > Returned token string must be free()'d | |
255 | * > Returns NULL if token is not found | |
256 | * > After each call, @str is set to the position after the | |
257 | * last found token | |
258 | * > Tokens *include* empty strings | |
259 | * Usage example: | |
260 | * char *str = "1,2,3,4,5,6,7,,,10,"; | |
261 | * char **str_ptr = &str; | |
262 | * char *token = NULL; | |
263 | * while ((token = string_tokenize(str_ptr, ","))) | |
264 | * { | |
265 | * printf("%s\n", token); | |
266 | * free(token); | |
267 | * token = NULL; | |
268 | * } | |
269 | **/ | |
270 | char* string_tokenize(char **str, const char *delim); | |
271 | ||
272 | /** | |
273 | * string_remove_all_chars: | |
274 | * @str : input string (must be non-NULL, otherwise UB) | |
275 | * | |
276 | * Leaf function. | |
277 | * | |
278 | * Removes every instance of character @c from @str | |
279 | **/ | |
280 | void string_remove_all_chars(char *str, char c); | |
281 | ||
282 | /** | |
283 | * string_replace_all_chars: | |
284 | * @str : input string (must be non-NULL, otherwise UB) | |
285 | * @find : character to find | |
286 | * @replace : character to replace @find with | |
287 | * | |
288 | * Hidden non-leaf function cost: | |
289 | * - Calls strchr (in a loop) | |
290 | * | |
291 | * Replaces every instance of character @find in @str | |
292 | * with character @replace | |
293 | **/ | |
294 | void string_replace_all_chars(char *str, char find, char replace); | |
295 | ||
296 | /** | |
297 | * string_to_unsigned: | |
298 | * @str : input string | |
299 | * | |
300 | * Converts string to unsigned integer. | |
301 | * | |
302 | * @return 0 if string is invalid, otherwise > 0 | |
303 | **/ | |
304 | unsigned string_to_unsigned(const char *str); | |
305 | ||
306 | /** | |
307 | * string_hex_to_unsigned: | |
308 | * @str : input string (must be non-NULL, otherwise UB) | |
309 | * | |
310 | * Converts hexadecimal string to unsigned integer. | |
311 | * Handles optional leading '0x'. | |
312 | * | |
313 | * @return 0 if string is invalid, otherwise > 0 | |
314 | **/ | |
315 | unsigned string_hex_to_unsigned(const char *str); | |
316 | ||
317 | char *string_init(const char *src); | |
318 | ||
319 | void string_set(char **string, const char *src); | |
320 | ||
321 | /** | |
322 | * string_count_occurrences_single_character: | |
323 | * | |
324 | * Leaf function. | |
325 | * | |
326 | * Get the total number of occurrences of character @c in @str. | |
327 | * | |
328 | * @return Total number of occurrences of character @c | |
329 | */ | |
330 | int string_count_occurrences_single_character(const char *str, char c); | |
331 | ||
332 | /** | |
333 | * string_replace_whitespace_with_single_character: | |
334 | * | |
335 | * Leaf function. | |
336 | * | |
337 | * Replaces all spaces with given character @c. | |
338 | **/ | |
339 | void string_replace_whitespace_with_single_character(char *str, char c); | |
340 | ||
341 | /** | |
342 | * string_replace_multi_space_with_single_space: | |
343 | * | |
344 | * Leaf function. | |
345 | * | |
346 | * Replaces multiple spaces with a single space in a string. | |
347 | **/ | |
348 | void string_replace_multi_space_with_single_space(char *str); | |
349 | ||
350 | /** | |
351 | * string_remove_all_whitespace: | |
352 | * | |
353 | * Leaf function. | |
354 | * | |
355 | * Remove all spaces from the given string. | |
356 | **/ | |
357 | void string_remove_all_whitespace(char *str_trimmed, const char *str); | |
358 | ||
359 | /* Retrieve the last occurance of the given character in a string. */ | |
360 | int string_index_last_occurance(const char *str, char c); | |
361 | ||
362 | /** | |
363 | * string_find_index_substring_string: | |
364 | * @str : input string (must be non-NULL, otherwise UB) | |
365 | * @substr : substring to find in @str | |
366 | * | |
367 | * Hidden non-leaf function cost: | |
368 | * - Calls strstr | |
369 | * | |
370 | * Find the position of substring @substr in string @str. | |
371 | **/ | |
372 | int string_find_index_substring_string(const char *str, const char *substr); | |
373 | ||
374 | /** | |
375 | * string_copy_only_ascii: | |
376 | * | |
377 | * Leaf function. | |
378 | * | |
379 | * Strips non-ASCII characters from a string. | |
380 | **/ | |
381 | void string_copy_only_ascii(char *str_stripped, const char *str); | |
382 | ||
383 | extern const unsigned char lr_char_props[256]; | |
384 | ||
385 | RETRO_END_DECLS | |
386 | ||
387 | #endif |