Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_nstr.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27
28#include "nilorea/n_str.h"
29#include "nilorea/n_log.h"
30
31int main(void) {
33
34 char* chardest = NULL;
35 NSTRBYTE written = 0,
36 length = 0;
37
38 write_and_fit(&chardest, &length, &written, "Hello");
39 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
40 write_and_fit(&chardest, &length, &written, " ");
41 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
42 write_and_fit(&chardest, &length, &written, "world !");
43 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
44 write_and_fit(&chardest, &length, &written, "world ! ");
45 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
46 write_and_fit(&chardest, &length, &written, "world ! ");
47 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
48 write_and_fit(&chardest, &length, &written, "world ! ");
49 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
50
51 Free(chardest);
52 written = length = 0;
53
54 write_and_fit_ex(&chardest, &length, &written, "Hello", 5, 0);
55 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
56 write_and_fit_ex(&chardest, &length, &written, " ", 1, 0);
57 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
58 write_and_fit_ex(&chardest, &length, &written, "world !", 7, 0);
59 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
60 write_and_fit_ex(&chardest, &length, &written, "Hello", 5, 0);
61 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
62 write_and_fit_ex(&chardest, &length, &written, " ", 1, 10); // alocate 10 more byte if resize needed
63 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
64 write_and_fit_ex(&chardest, &length, &written, "world !", 7, 0);
65 n_log(LOG_INFO, "charstr (%zu/%zu): %s", written, length, chardest);
66
67 Free(chardest);
68
69 N_STR* nstr = NULL;
70
71 n_log(LOG_INFO, "NULL str:%s", _nstr(nstr));
72
73 nstrprintf(nstr, "Hello, file is %s line %d date %s", __FILE__, __LINE__, __TIME__);
74
75 n_log(LOG_INFO, "str:%s", _nstr(nstr));
76
77 nstrprintf_cat(nstr, " - This will be added at file %s line %d date %s", __FILE__, __LINE__, __TIME__);
78
79 n_log(LOG_INFO, "str:%s", _nstr(nstr));
80
81 free_nstr(&nstr);
82
83 nstr = new_nstr(0);
84
85 n_log(LOG_INFO, "EMPTY str:%s", _nstr(nstr));
86
87 nstrprintf(nstr, "Hello, file is %s line %d date %s", __FILE__, __LINE__, __TIME__);
88
89 n_log(LOG_INFO, "str:%s", _nstr(nstr));
90
91 nstrprintf_cat(nstr, " - This will be added at file %s line %d date %s", __FILE__, __LINE__, __TIME__);
92
93 n_log(LOG_INFO, "str:%s", _nstr(nstr));
94
95 nstrprintf_cat(nstr, " - some more texte");
96
97 N_STR* nstr2 = nstrdup(nstr);
98
99 n_log(LOG_INFO, "str: %s\n str2: %s", _nstr(nstr), _nstr(nstr2));
100
101 N_STR* nstr3 = NULL;
102
103 nstrcat(nstr3, nstr);
104 nstrcat(nstr3, nstr2);
105
106 n_log(LOG_INFO, "str:%s", _nstr(nstr3));
107
108 free_nstr(&nstr3);
109
110 nstr3 = new_nstr(10);
111
112 nstrcat(nstr3, nstr);
113 nstrcat(nstr3, nstr2);
114
115 n_log(LOG_INFO, "str:%s", _nstr(nstr3));
116
117 free_nstr(&nstr);
118 free_nstr(&nstr2);
119 free_nstr(&nstr3);
120
121 nstr = new_nstr(128);
122 char data[1048576] = "";
123
124 for (int it = 0; it < 1048575; it++) {
125 data[it] = (char)(32 + rand() % 63);
126 }
127 data[1048574] = '\0';
128
129 for (int it = 0; it < 100; it++) {
130 write_and_fit(&nstr->data, &nstr->length, &nstr->written, data);
131 }
132
133 free_nstr(&nstr);
134
135 /* test char_to_nstr and empty_nstr */
136 nstr = char_to_nstr("char_to_nstr test");
137 n_log(LOG_INFO, "char_to_nstr: %s", _nstr(nstr));
138 empty_nstr(nstr);
139 n_log(LOG_INFO, "after empty_nstr: '%s' written=%zu", _nstr(nstr), nstr->written);
140 free_nstr(&nstr);
141
142 /* test trim */
143 char* trimmed = trim(" spaces around ");
144 if (trimmed) {
145 n_log(LOG_INFO, "trim result: '%s'", trimmed);
146 Free(trimmed);
147 }
148 /* test trim_nocopy */
149 char trimbuf[] = " hello ";
150 char* trimptr = trim_nocopy(trimbuf);
151 n_log(LOG_INFO, "trim_nocopy result: '%s'", trimptr);
152
153 /* test str_to_int, str_to_long, str_to_long_long */
154 int ival = 0;
155 if (str_to_int("12345", &ival, 10) == TRUE) {
156 n_log(LOG_INFO, "str_to_int: %d", ival);
157 }
158 long int lval = 0;
159 if (str_to_long("9876543210", &lval, 10) == TRUE) {
160 n_log(LOG_INFO, "str_to_long: %ld", lval);
161 }
162 long long int llval = 0;
163 if (str_to_long_long("123456789012345", &llval, 10) == TRUE) {
164 n_log(LOG_INFO, "str_to_long_long: %lld", llval);
165 }
166
167 /* test strup, strlo */
168 char upper[32] = "";
169 char lower[32] = "";
170 strup("hello world", upper);
171 n_log(LOG_INFO, "strup: %s", upper);
172 strlo("HELLO WORLD", lower);
173 n_log(LOG_INFO, "strlo: %s", lower);
174
175 /* test split, split_count, join, free_split_result */
176 char** parts = split("one:two:three:four", ":", 0);
177 if (parts) {
178 int count = split_count(parts);
179 n_log(LOG_INFO, "split count: %d", count);
180 for (int it = 0; it < count; it++) {
181 n_log(LOG_INFO, " split[%d]: %s", it, parts[it]);
182 }
183 char* joined = join(parts, " - ");
184 if (joined) {
185 n_log(LOG_INFO, "join result: %s", joined);
186 Free(joined);
187 }
188 free_split_result(&parts);
189 }
190
191 /* test wildmat, wildmatcase */
192 n_log(LOG_INFO, "wildmat(\"hello.txt\", \"*.txt\"): %d", wildmat("hello.txt", "*.txt"));
193 n_log(LOG_INFO, "wildmat(\"hello.txt\", \"*.csv\"): %d", wildmat("hello.txt", "*.csv"));
194 n_log(LOG_INFO, "wildmatcase(\"Hello.TXT\", \"*.txt\"): %d", wildmatcase("Hello.TXT", "*.txt"));
195
196 /* test str_natcasecmp: every pair must come out in the order listed */
197 {
198 const char* ordered[] = {"", "1", "01", "2", "10", "a", "A2",
199 "a10", "a010", "b", "img2.cr3", "IMG10.cr3", "img10x", "photo 9",
200 "photo 10", "x99999999999999999999", "x100000000000000000000"};
201 size_t n = sizeof(ordered) / sizeof(ordered[0]);
202 size_t k = 0, m = 0;
203
204 for (k = 0; k < n; k++) {
205 for (m = 0; m < n; m++) {
206 int got = str_natcasecmp(ordered[k], ordered[m]);
207 int want = k < m ? -1 : (k > m ? 1 : 0);
208
209 if ((got < 0 ? -1 : (got > 0 ? 1 : 0)) != want) {
210 n_log(LOG_ERR, "FAIL: str_natcasecmp(\"%s\", \"%s\") gave %d, not %d", ordered[k], ordered[m], got,
211 want);
212 exit(1);
213 }
214 }
215 }
216 if (str_natcasecmp(NULL, "a") >= 0 || str_natcasecmp("a", NULL) <= 0 || str_natcasecmp(NULL, NULL) != 0 ||
217 str_natcasecmp("abc", "ABC") == 0 || str_natncasecmp("img10xyz", 5, "img10", 5) != 0 ||
218 str_natncasecmp("img2zz", 4, "img10", 5) >= 0 || str_natncasecmp("a1", 2, "a", 1) <= 0) {
219 n_log(LOG_ERR, "FAIL: str_natcasecmp with NULL, case-only differences or bounded lengths");
220 exit(1);
221 }
222 n_log(LOG_INFO, "PASS: str_natcasecmp orders %zu strings naturally", n);
223 }
224
225 /* test str_replace: every case checked, the example fails on any */
226 {
227 static const struct {
228 const char* string;
229 const char* substr;
230 const char* replacement;
231 const char* expected;
232 } cases[] = {
233 {"hello world hello", "hello", "bye", "bye world bye"},
234 {"aaa", "a", "aa", "aaaaaa"}, /* the replacement is not searched again */
235 {"aaaa", "aa", "b", "bb"}, /* occurrences do not overlap */
236 {"abcabc", "abc", "", ""}, /* replaced by nothing */
237 {"nothing here", "xyz", "q", "nothing here"},
238 {"", "a", "b", ""},
239 {"a=b=c", "=", " ", "a b c"}, /* what n_config_file asks of it */
240 {"line\r\nnext\r\n", "\r", "", "line\nnext\n"},
241 {"same", "", "x", "same"}, /* an empty search changes nothing */
242 };
243 size_t k = 0;
244
245 for (k = 0; k < sizeof(cases) / sizeof(cases[0]); k++) {
246 char* replaced = str_replace(cases[k].string, cases[k].substr, cases[k].replacement);
247
248 if (!replaced || strcmp(replaced, cases[k].expected) != 0) {
249 n_log(LOG_ERR, "FAIL: str_replace(\"%s\", \"%s\", \"%s\") gave \"%s\", not \"%s\"", cases[k].string,
250 cases[k].substr, cases[k].replacement, replaced ? replaced : "(null)", cases[k].expected);
251 Free(replaced);
252 exit(1);
253 }
254 Free(replaced);
255 }
256 {
257 char* replaced = str_replace("keep", "k", NULL);
258
259 if (!replaced || strcmp(replaced, "keep") != 0 || str_replace(NULL, "a", "b") != NULL) {
260 n_log(LOG_ERR, "FAIL: str_replace with a NULL argument");
261 Free(replaced);
262 exit(1);
263 }
264 Free(replaced);
265 }
266 n_log(LOG_INFO, "str_replace: %zu cases ok", sizeof(cases) / sizeof(cases[0]));
267 }
268
269 /* test str_sanitize */
270 char sanitize_buf[] = "hello; rm -rf /";
271 str_sanitize(sanitize_buf, ";/", '_');
272 n_log(LOG_INFO, "str_sanitize: %s", sanitize_buf);
273
274 /* test file_to_nstr and nstr_to_file */
275 N_STR* file_content = char_to_nstr("file content test\nsecond line\n");
276 nstr_to_file(file_content, "nilorea_nstr_test.txt");
277 free_nstr(&file_content);
278 file_content = file_to_nstr("nilorea_nstr_test.txt");
279 if (file_content) {
280 n_log(LOG_INFO, "file_to_nstr: %s", _nstr(file_content));
281 free_nstr(&file_content);
282 }
283
284 /* an empty (0-byte) file is a valid read: file_to_nstr must return an empty
285 N_STR (data != NULL, written == 0), not NULL, and must log no error */
286 FILE* empty_fp = fopen("nilorea_nstr_empty.txt", "wb");
287 if (empty_fp)
288 fclose(empty_fp);
289 N_STR* empty_content = file_to_nstr("nilorea_nstr_empty.txt");
290 if (empty_content && empty_content->data && empty_content->written == 0)
291 n_log(LOG_INFO, "file_to_nstr on an empty file: OK (empty string, no error)");
292 else
293 n_log(LOG_ERR, "file_to_nstr on an empty file: FAILED (expected an empty N_STR)");
294 if (empty_content)
295 free_nstr(&empty_content);
296
297 /* test skipw, skipu */
298 char skipbuf[] = " hello";
299 NSTRBYTE it = 0;
300 skipw(skipbuf, ' ', &it, 1);
301 n_log(LOG_INFO, "skipw past spaces: pos=%zu char='%c'", it, skipbuf[it]);
302 it = 0;
303 skipu(skipbuf, 'h', &it, 1);
304 n_log(LOG_INFO, "skipu to 'h': pos=%zu char='%c'", it, skipbuf[it]);
305
306 /* test resize_nstr */
307 nstr = new_nstr(16);
308 n_log(LOG_INFO, "before resize: length=%zu", nstr->length);
309 resize_nstr(nstr, 256);
310 n_log(LOG_INFO, "after resize: length=%zu", nstr->length);
311 free_nstr(&nstr);
312
313 /* test scan_dir */
314 LIST* dir_list = new_generic_list(0);
315 if (scan_dir(".", dir_list, 0) == TRUE) {
316 n_log(LOG_INFO, "scan_dir found %zu entries", dir_list->nb_items);
317 }
318 list_destroy(&dir_list);
319
320 /* test n_str_url_encode */
321 int url_encode_errors = 0;
322
323 /* NULL input -> NULL */
324 N_STR* encoded = n_str_url_encode(NULL);
325 if (encoded != NULL) {
326 n_log(LOG_ERR, "FAIL: n_str_url_encode(NULL) expected NULL, got \"%s\"", _nstr(encoded));
327 url_encode_errors++;
328 free_nstr(&encoded);
329 } else {
330 n_log(LOG_INFO, "PASS: n_str_url_encode(NULL) == NULL");
331 }
332
333 /* empty string -> empty result */
334 encoded = n_str_url_encode("");
335 if (!encoded || strcmp(_nstr(encoded), "") != 0) {
336 n_log(LOG_ERR, "FAIL: n_str_url_encode(\"\") expected \"\", got \"%s\"", encoded ? _nstr(encoded) : "NULL");
337 url_encode_errors++;
338 } else {
339 n_log(LOG_INFO, "PASS: n_str_url_encode(\"\") == \"\"");
340 }
341 free_nstr(&encoded);
342
343 /* unreserved characters (A-Z a-z 0-9 - _ . ~) must be kept verbatim */
344 encoded = n_str_url_encode("Hello-World_1.0~");
345 if (!encoded || strcmp(_nstr(encoded), "Hello-World_1.0~") != 0) {
346 n_log(LOG_ERR, "FAIL: n_str_url_encode(\"Hello-World_1.0~\") expected verbatim, got \"%s\"", encoded ? _nstr(encoded) : "NULL");
347 url_encode_errors++;
348 } else {
349 n_log(LOG_INFO, "PASS: n_str_url_encode(\"Hello-World_1.0~\") == \"Hello-World_1.0~\"");
350 }
351 free_nstr(&encoded);
352
353 /* reserved / special characters must be percent-encoded */
354 encoded = n_str_url_encode("foo bar&baz=qux/path?q=1#frag");
355 const char* expected_reserved = "foo%20bar%26baz%3Dqux%2Fpath%3Fq%3D1%23frag";
356 if (!encoded || strcmp(_nstr(encoded), expected_reserved) != 0) {
357 n_log(LOG_ERR, "FAIL: n_str_url_encode(reserved chars) expected \"%s\", got \"%s\"", expected_reserved, encoded ? _nstr(encoded) : "NULL");
358 url_encode_errors++;
359 } else {
360 n_log(LOG_INFO, "PASS: n_str_url_encode(\"foo bar&baz=qux/path?q=1#frag\") == \"%s\"", expected_reserved);
361 }
362 free_nstr(&encoded);
363
364 /* bytes >= 0x80 (high-byte / non-ASCII) must be percent-encoded */
365 encoded = n_str_url_encode("\xC3\xA9\xFF");
366 if (!encoded || strcmp(_nstr(encoded), "%C3%A9%FF") != 0) {
367 n_log(LOG_ERR, "FAIL: n_str_url_encode(high bytes) expected \"%s\", got \"%s\"", "%C3%A9%FF", encoded ? _nstr(encoded) : "NULL");
368 url_encode_errors++;
369 } else {
370 n_log(LOG_INFO, "PASS: n_str_url_encode(\"\\xC3\\xA9\\xFF\") == \"%s\"", "%C3%A9%FF");
371 }
372 free_nstr(&encoded);
373
374 if (url_encode_errors > 0) {
375 n_log(LOG_ERR, "n_str_url_encode: %d test(s) failed", url_encode_errors);
376 exit(1);
377 }
378
379 /* n_str_utf8_valid: the verdicts match PHP's mb_check_encoding(..., 'UTF-8') */
380 {
381#define UTF8_V(str, ok) {str, sizeof(str) - 1, ok}
382 static const struct {
383 const char* s;
384 size_t len;
385 int valid;
386 } u[] = {
387 UTF8_V("", 1),
388 UTF8_V("ascii", 1),
389 UTF8_V("caf\xc3\xa9 \xe2\x82\xac \xf0\x9f\x98\x80", 1),
390 UTF8_V("\xf4\x8f\xbf\xbf", 1), /* U+10FFFF */
391 UTF8_V("a\0b", 1), /* NUL is valid UTF-8 */
392 UTF8_V("\x80", 0), /* stray continuation */
393 UTF8_V("\xc0\xaf", 0), /* overlong 2-byte */
394 UTF8_V("\xe0\x80\xaf", 0), /* overlong 3-byte */
395 UTF8_V("\xf0\x80\x80\xaf", 0), /* overlong 4-byte */
396 UTF8_V("\xed\xa0\x80", 0), /* surrogate U+D800 */
397 UTF8_V("\xf4\x90\x80\x80", 0), /* above U+10FFFF */
398 UTF8_V("\xe2\x82", 0), /* truncated */
399 UTF8_V("\xf5\x80\x80\x80", 0), /* lead above F4 */
400 };
401#undef UTF8_V
402 size_t k;
403 for (k = 0; k < sizeof(u) / sizeof(u[0]); k++) {
404 if ((n_str_utf8_valid(u[k].s, u[k].len) ? 1 : 0) != u[k].valid) {
405 n_log(LOG_ERR, "FAIL: n_str_utf8_valid vector %zu", k);
406 exit(1);
407 }
408 }
409 if (n_str_utf8_valid(NULL, 0) != TRUE || n_str_utf8_valid(NULL, 1) != FALSE) {
410 n_log(LOG_ERR, "FAIL: n_str_utf8_valid NULL");
411 exit(1);
412 }
413 n_log(LOG_INFO, "PASS: n_str_utf8_valid vectors");
414 }
415
416 /* new_nstr allocates size + 1 for the terminator, so the maximum representable
417 size wraps that sum to 0 and calloc(0, 1) hands back a one-element buffer for
418 what the caller believes is a huge string. Anything writing size bytes into it
419 then runs off the end. The size is refused instead. */
420 {
421 N_STR* wrapped = new_nstr((NSTRBYTE)-1);
422 if (wrapped != NULL) {
423 n_log(LOG_ERR, "FAIL: new_nstr(NSTRBYTE max) returned a string instead of NULL");
424 free_nstr(&wrapped);
425 exit(1);
426 }
427 n_log(LOG_INFO, "PASS: new_nstr(NSTRBYTE max) refused (terminator would wrap the allocation)");
428 }
429 {
430 /* an ordinary size is unaffected: length still reports the usable bytes,
431 and writing all of them plus the terminator stays in bounds (ASan would
432 say otherwise if the guard had changed the allocation) */
433 N_STR* ok = new_nstr(16);
434 if (!ok || ok->length != 16 || !ok->data) {
435 n_log(LOG_ERR, "FAIL: new_nstr(16) did not return a 16-byte string");
436 free_nstr(&ok);
437 exit(1);
438 }
439 memset(ok->data, 'x', 16);
440 ok->data[16] = '\0';
441 ok->written = 16;
442 if (strlen(ok->data) != 16) {
443 n_log(LOG_ERR, "FAIL: new_nstr(16) left no room for the terminator");
444 free_nstr(&ok);
445 exit(1);
446 }
447 n_log(LOG_INFO, "PASS: new_nstr(16) holds 16 bytes plus its terminator");
448 free_nstr(&ok);
449 }
450
451 exit(0);
452}
int main(void)
Definition ex_atlas.c:117
#define UTF8_V(str, ok)
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
Definition n_common.h:199
size_t nb_items
number of item currently in the list
Definition n_list.h:61
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:548
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:37
Structure of a generic LIST container.
Definition n_list.h:59
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_DEBUG
debug-level messages
Definition n_log.h:108
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_INFO
informational
Definition n_log.h:106
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
Definition n_str.h:68
char * data
the string
Definition n_str.h:63
size_t length
total allocation (in bytes) of the data buffer, padding included
Definition n_str.h:65
int str_to_long_long(const char *s, long long int *i, const int base)
Helper for string to integer.
Definition n_str.c:710
char * trim_nocopy(char *s)
trim and zero end the string, WARNING: keep and original pointer to delete the string correctly
Definition n_str.c:123
N_STR * n_str_url_encode(const char *src)
Percent-encode a C string per RFC 3986 (unreserved set kept as-is).
Definition n_str.c:1819
size_t NSTRBYTE
N_STR base unit.
Definition n_str.h:58
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
int split_count(char **split_result)
Count split elements.
Definition n_str.c:1007
int str_natncasecmp(const char *a, size_t alen, const char *b, size_t blen)
Compare two byte runs in natural order, ignoring ASCII case.
Definition n_str.c:1524
int nstr_to_file(N_STR *str, char *filename)
Write a N_STR content into a file.
Definition n_str.c:431
char * join(char **splitresult, const char *delim)
join the array into a string
Definition n_str.c:1044
#define nstrcat(__nstr_dst, __nstr_src)
Macro to quickly concatenate two N_STR.
Definition n_str.h:125
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition n_str.c:723
int strlo(const char *string, char *dest)
Lower case a string.
Definition n_str.c:868
int write_and_fit(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src)
Append src to *dest.
Definition n_str.c:1236
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
Definition n_str.h:121
int resize_nstr(N_STR *nstr, size_t size)
reallocate a nstr internal buffer.
Definition n_str.c:1628
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:262
int skipu(const char *string, char toskip, NSTRBYTE *iterator, int inc)
skip until 'toskip' occurence is found from 'iterator' to the next 'toskip' value.
Definition n_str.c:801
int empty_nstr(N_STR *nstr)
empty a N_STR string
Definition n_str.c:192
int wildmatcase(register const char *text, register const char *p)
Written by Rich Salz rsalz at osf.org, refurbished by me.
Definition n_str.c:1389
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:209
char * str_replace(const char *string, const char *substr, const char *replacement)
Replace every occurrence of substr by replacement in a copy of string.
Definition n_str.c:1460
char * trim(const char *s)
trim and put a \0 at the end, return new char *
Definition n_str.c:152
int skipw(const char *string, char toskip, NSTRBYTE *iterator, int inc)
skip while 'toskip' occurence is found from 'iterator' to the next non 'toskip' position.
Definition n_str.c:754
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
Definition n_str.h:117
int str_natcasecmp(const char *a, const char *b)
Compare two strings in natural order, ignoring ASCII case.
Definition n_str.c:1582
int scan_dir(const char *dir, LIST *result, const int recurse)
Scan a list of directory and return a list of char *file.
Definition n_str.c:1247
int str_sanitize(char *string, const char *mask, const char replacement)
clean a string by replacing evil characteres
Definition n_str.c:1618
char ** split(const char *str, const char *delim, int empty)
split the strings into a an array of char *pointer , ended by a NULL one.
Definition n_str.c:927
int wildmat(register const char *text, register const char *p)
Written by Rich Salz rsalz at osf.org, refurbished by me.
Definition n_str.c:1325
int str_to_long(const char *s, long int *i, const int base)
Helper for string to integer.
Definition n_str.c:695
int write_and_fit_ex(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src, NSTRBYTE src_size, NSTRBYTE additional_padding)
Append src_size bytes from src to *dest, updating size/written, growing the buffer if needed.
Definition n_str.c:1194
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
Definition n_str.c:295
int free_split_result(char ***tab)
Free a split result allocated array.
Definition n_str.c:1023
int str_to_int(const char *s, int *i, const int base)
Helper for string to integer.
Definition n_str.c:560
int n_str_utf8_valid(const char *s, size_t len)
Test that [s, s+len) is well-formed UTF-8 (RFC 3629): no overlong form, no surrogate,...
Definition n_str.c:1855
int strup(const char *string, char *dest)
Upper case a string.
Definition n_str.c:847
A box including a string and his lenght.
Definition n_str.h:61
Generic log system.
N_STR and string function declaration.