Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_str.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
28#ifndef NO_NSTR
29
30#include "nilorea/n_common.h"
31#include "nilorea/n_log.h"
32#include "nilorea/n_str.h"
33#include "nilorea/n_hash.h"
34
35#include <errno.h>
36#include <pthread.h>
37#include <math.h>
38#include <ctype.h>
39#include <stdio.h>
40#include <string.h>
41#include <limits.h>
42#include <stdint.h>
43#include <stdlib.h>
44#include <dirent.h>
45
46#ifdef __windows__
53const char* strcasestr(const char* s1, const char* s2) {
54 __n_assert(s1, return NULL);
55 __n_assert(s2, return NULL);
56
57 size_t n = strlen(s2);
58 while (*s1) {
59 if (!strnicmp(s1++, s2, n))
60 return (s1 - 1);
61 }
62 return NULL;
63} /* strcasestr */
64#endif
65
70void free_nstr_ptr(void* ptr) {
71 N_STR* strptr = (N_STR*)ptr;
72 if (ptr && strptr) {
73 FreeNoLog(strptr->data);
74 FreeNoLog(strptr);
75 }
76} /* free_nstr_ptr( ... ) */
77
83int _free_nstr(N_STR** ptr) {
84 __n_assert(ptr && (*ptr), return FALSE);
85
86 FreeNoLog((*ptr)->data);
87 FreeNoLog((*ptr));
88
89 return TRUE;
90} /* free_nstr( ... ) */
91
98 if ((*ptr)) {
99 FreeNoLog((*ptr)->data);
100 FreeNoLog((*ptr));
101 }
102
103 return TRUE;
104} /* free_nstr( ... ) */
105
110void free_nstr_ptr_nolog(void* ptr) {
111 N_STR* strptr = (N_STR*)ptr;
112 if (strptr) {
113 FreeNoLog(strptr->data);
114 FreeNoLog(strptr);
115 }
116} /* free_nstr_ptr_nolog( ... ) */
117
123char* trim_nocopy(char* s) {
124 __n_assert(s, return NULL);
125
126 if (strlen(s) == 0)
127 return s;
128
129 char* start = s;
130
131 /* skip spaces at start */
132 while (*start && isspace((unsigned char)*start))
133 start++;
134
135 char* end = s + strlen(s) - 1;
136 /* iterate over the rest remebering last non-whitespace */
137 while (*end && isspace((unsigned char)*end) && end > s) {
138 end--;
139 }
140 end++;
141 /* write the terminating zero after last non-whitespace */
142 *end = 0;
143
144 return start;
145} /* trim_nocopy */
146
152char* trim(const char* s) {
153 __n_assert(s, return NULL);
154
155 char* copy = strdup(s);
156 __n_assert(copy, return NULL);
157
158 const char* trimmed = trim_nocopy(copy);
159 char* result = strdup(trimmed);
160 free(copy);
161 return result;
162} /* trim */
163
171char* nfgets(char* buffer, NSTRBYTE size, FILE* stream) {
172 __n_assert(buffer, return NULL);
173 __n_assert(stream, return NULL);
174
175 if (size >= INT_MAX) {
176 n_log(LOG_ERR, "size of %zu too big, >INT_MAX for buffer %p", size, buffer);
177 return NULL;
178 }
179
180 if (!fgets(buffer, (int)size, stream)) {
181 return NULL;
182 }
183
184 return buffer;
185} /* nfgets(...) */
186
192int empty_nstr(N_STR* nstr) {
193 __n_assert(nstr, return FALSE);
194 __n_assert(nstr->data, return FALSE);
195
196 nstr->written = 0;
197 memset(nstr->data, 0, nstr->length);
198
199 return TRUE;
200}
201
208 N_STR* str = NULL;
209
210 Malloc(str, N_STR, 1);
211 __n_assert(str, return NULL);
212
213 str->written = 0;
214 if (size == 0) {
215 str->data = NULL;
216 str->length = 0;
217 } else {
218 Malloc(str->data, char, size + 1);
219 __n_assert(str->data, Free(str); return NULL);
220 str->length = size;
221 }
222 return str;
223} /* new_nstr(...) */
224
232int char_to_nstr_ex(const char* from, NSTRBYTE nboct, N_STR** to) {
233 if ((*to)) {
234 n_log(LOG_ERR, "destination N_STR **str is not NULL (%p), it contain (%s). You must provide an empty destination.", (*to), ((*to) && (*to)->data) ? (*to)->data : "DATA_IS_NULL");
235 n_log(LOG_ERR, "Data to copy: %s", _str(from));
236 return FALSE;
237 };
238
239 (*to) = new_nstr(nboct + 1);
240 __n_assert(to && (*to), return FALSE);
241 /* added a sizeof( void * ) to add a consistant and secure padding at the end */
242 __n_assert((*to)->data, Free((*to)); return FALSE);
243
244 memcpy((*to)->data, from, nboct);
245 (*to)->written = nboct;
246
247 return TRUE;
248} /* char_to_nstr(...) */
249
255N_STR* char_to_nstr(const char* src) {
256 __n_assert(src, return NULL);
257 N_STR* strptr = NULL;
258 size_t length = strlen(src);
259 char_to_nstr_ex(src, length, &strptr);
260 return strptr;
261} /* char_to_str(...) */
262
269 __n_assert(src, return NULL);
270
271 N_STR* to = NULL;
272 to = new_nstr(0);
273 __n_assert(to, return NULL);
274
275 to->data = src;
276 to->written = strlen(src);
277 to->length = to->written + 1; // include src end of string
278
279 return to;
280} /* char_to_str_nocopy(...) */
281
288N_STR* file_to_nstr(char* filename) {
289 N_STR* tmpstr = NULL;
290 struct stat filestat;
291 FILE* in = NULL;
292 int error = 0;
293
294 __n_assert(filename, n_log(LOG_ERR, "Unable to make a string from NULL filename"); return NULL);
295
296 int fd = open(filename, O_RDONLY);
297 error = errno;
298 if (fd == -1) {
299 n_log(LOG_ERR, "Unable to open %s for reading. Errno: %s", filename, strerror(error));
300 return NULL;
301 }
302
303 if (fstat(fd, &filestat) != 0) {
304 error = errno;
305#ifdef __linux__
306 if (error == EOVERFLOW) {
307 n_log(LOG_ERR, "%s size is too big ,EOVERFLOW)", filename);
308 } else {
309#endif
310 n_log(LOG_ERR, "Couldn't stat %s. Errno: %s", filename, strerror(error));
311#ifdef __linux__
312 }
313#endif
314 close(fd);
315 return NULL;
316 }
317
318 if ((uint64_t)filestat.st_size >= (uint64_t)UINT32_MAX) {
319 n_log(LOG_ERR, "file size >= 4GB is not possible yet. %s is %lld oct", filename, (long long)filestat.st_size);
320 close(fd);
321 return NULL;
322 }
323
324 n_log(LOG_DEBUG, "%s file size is: %lld", filename, (long long)filestat.st_size);
325
326 in = fdopen(fd, "rb");
327 if (!in) {
328 n_log(LOG_ERR, "fdopen failed on %s (fd=%d)", filename, fd);
329 close(fd);
330 return NULL;
331 }
332
333 tmpstr = new_nstr((size_t)filestat.st_size + 1);
334 __n_assert(tmpstr, fclose(in); n_log(LOG_ERR, "Unable to get a new nstr of %ld octets", filestat.st_size + 1); return NULL);
335
336 tmpstr->written = (size_t)filestat.st_size;
337
338 /* an empty file (0 bytes) is a valid read, not an error: fread would be asked to
339 read 0 bytes and return 0, which is not a failure. Return the empty (calloc'd,
340 NUL-terminated) string so callers treat an empty file as empty content instead
341 of a read error. Only read when there is at least one byte. */
342 if (tmpstr->written > 0) {
343 if (fread(tmpstr->data, sizeof(char), tmpstr->written, in) == 0) {
344 n_log(LOG_ERR, "Couldn't read %s, fread return 0", filename);
345 free_nstr(&tmpstr);
346 fclose(in);
347 return NULL;
348 }
349 if (ferror(in)) {
350 n_log(LOG_ERR, "There were some errors when reading %s", filename);
351 free_nstr(&tmpstr);
352 fclose(in);
353 return NULL;
354 }
355 }
356
357 fclose(in);
358
359 return tmpstr;
360} /*file_to_nstr */
361
370/* Write a whole N_STR into a file */
371int nstr_to_fd(N_STR* str, FILE* out, int lock) {
372#ifdef __linux__
373 struct flock out_lock;
374#endif
375 __n_assert(out, return FALSE);
376 __n_assert(str, return FALSE);
377
378 int ret = TRUE;
379
380 if (lock == 1) {
381#ifdef __linux__
382 memset(&out_lock, 0, sizeof(out_lock));
383 out_lock.l_type = F_WRLCK;
384 /* Place a write lock on the file. */
385 fcntl(fileno(out), F_SETLKW, &out_lock);
386#else
387 // cppcheck-suppress uselessAssignmentArg ; intentional: suppress unused parameter warning on non-POSIX
388 lock = 2;
389#endif
390 }
391
392 size_t written_to_file = 0;
393 if ((written_to_file = fwrite(str->data, sizeof(char), str->written, out)) != (size_t)str->written) {
394 n_log(LOG_ERR, "Couldn't write file, fwrite %d of %d octets", written_to_file, str->written);
395 ret = FALSE;
396 }
397 if (ferror(out)) {
398 n_log(LOG_ERR, "There were some errors when writing to %d", fileno(out));
399 ret = FALSE;
400 }
401
402 if (lock == 1) {
403#ifdef __linux__
404 memset(&out_lock, 0, sizeof(out_lock));
405 out_lock.l_type = F_WRLCK;
406 /* Place a write lock on the file. */
407 fcntl(fileno(out), F_SETLKW, &out_lock);
408#else
409 // cppcheck-suppress uselessAssignmentArg
410 // cppcheck-suppress unreadVariable
411 lock = 2; /* compiler warning suppressor for non-POSIX */
412#endif
413 }
414
415 return ret;
416} /* nstr_to_fd( ... ) */
417
424int nstr_to_file(N_STR* str, char* filename) {
425 __n_assert(str, return FALSE);
426 __n_assert(filename, return FALSE);
427
428 int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600); // Secure permissions: rw-------
429 if (fd == -1) {
430 n_log(LOG_ERR, "Couldn't open %s for writing (0600). Errno: %s", _str(filename), strerror(errno));
431 return FALSE;
432 }
433
434 FILE* out = NULL;
435 out = fdopen(fd, "wb");
436 if (!out) {
437 n_log(LOG_ERR, "fdopen failed for %s (fd=%d). Errno: %s", _str(filename), fd, strerror(errno));
438 close(fd);
439 return FALSE;
440 }
441
442 int ret = nstr_to_fd(str, out, 1);
443
444 fclose(out);
445
446 n_log(LOG_DEBUG, "%s file size is: %lld", _str(filename), (long long)str->written);
447
448 return ret;
449} /* nstr_to_file(...) */
450
462int str_to_int_ex(const char* s, NSTRBYTE start, NSTRBYTE end, int* i, const int base) {
463 char* tmpstr = NULL;
464 char* endstr = NULL;
465 long int l = 0;
466
467 __n_assert(s, return FALSE);
468
469 if (start > end) return FALSE;
470
471 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
472 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
473
474 memcpy(tmpstr, s + start, end - start);
475
476 errno = 0;
477 l = strtol(tmpstr, &endstr, base);
478 if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
479 n_log(LOG_ERR, "OVERFLOW reached when converting %s to int", tmpstr);
480 Free(tmpstr);
481 return FALSE;
482 }
483 if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
484 n_log(LOG_ERR, "UNDERFLOW reached when converting %s to int", tmpstr);
485 Free(tmpstr);
486 return FALSE;
487 }
488 if (*endstr != '\0' && *endstr != '\n') {
489 n_log(LOG_ERR, "Impossible conversion for %s", tmpstr);
490 Free(tmpstr);
491 return FALSE;
492 }
493 Free(tmpstr);
494 *i = (int)l;
495 return TRUE;
496} /* str_to_int_ex( ... ) */
497
510int str_to_int_nolog(const char* s, NSTRBYTE start, NSTRBYTE end, int* i, const int base, N_STR** infos) {
511 char* tmpstr = NULL;
512 char* endstr = NULL;
513 long int l = 0;
514
515 __n_assert(s, return FALSE);
516
517 if (start > end) return FALSE;
518
519 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
520 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
521
522 memcpy(tmpstr, s + start, end - start);
523
524 errno = 0;
525 l = strtol(tmpstr, &endstr, base);
526 if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
527 nstrprintf((*infos), "OVERFLOW reached when converting %s to int", tmpstr);
528 Free(tmpstr);
529 return FALSE;
530 }
531 if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
532 nstrprintf((*infos), "UNDERFLOW reached when converting %s to int", tmpstr);
533 Free(tmpstr);
534 return FALSE;
535 }
536 if (*endstr != '\0' && *endstr != '\n') {
537 nstrprintf((*infos), "Impossible conversion for %s", tmpstr);
538 Free(tmpstr);
539 return FALSE;
540 }
541 Free(tmpstr);
542 *i = (int)l;
543 return TRUE;
544} /* str_to_int_nolog( ... ) */
545
553int str_to_int(const char* s, int* i, const int base) {
554 int ret = FALSE;
555 if (s) {
556 ret = str_to_int_ex(s, 0, strlen(s), i, base);
557 }
558 return ret;
559} /* str_to_int(...) */
560
572int str_to_long_ex(const char* s, NSTRBYTE start, NSTRBYTE end, long int* i, const int base) {
573 char* tmpstr = NULL;
574 char* endstr = NULL;
575 long l = 0;
576
577 __n_assert(s, return FALSE);
578
579 if (start > end) return FALSE;
580
581 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
582 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
583
584 memcpy(tmpstr, s + start, end - start);
585
586 errno = 0;
587 l = strtol(tmpstr, &endstr, base);
588 int error = errno;
589
590 /* test return to number and errno values */
591 if (tmpstr == endstr) {
592 n_log(LOG_ERR, " number : %ld invalid (no digits found, 0 returned)", l);
593 Free(tmpstr);
594 return FALSE;
595 } else if (error == ERANGE && l == LONG_MIN) {
596 n_log(LOG_ERR, " number : %ld invalid (underflow occurred)", l);
597 Free(tmpstr);
598 return FALSE;
599 } else if (error == ERANGE && l == LONG_MAX) {
600 n_log(LOG_ERR, " number : %ld invalid (overflow occurred)", l);
601 Free(tmpstr);
602 return FALSE;
603 } else if (error == EINVAL) /* not in all c99 implementations - gcc OK */
604 {
605 n_log(LOG_ERR, " number : %ld invalid (base contains unsupported value)", l);
606 Free(tmpstr);
607 return FALSE;
608 } else if (error != 0 && l == 0) {
609 n_log(LOG_ERR, " number : %ld invalid (unspecified error occurred)", l);
610 Free(tmpstr);
611 return FALSE;
612 } else if (error == 0 && !*endstr) {
613 n_log(LOG_DEBUG, " number : %ld valid (and represents all characters read)", l);
614 } else if (error == 0 && *endstr != 0) {
615 n_log(LOG_DEBUG, " number : %ld valid (but additional characters remain", l);
616 }
617 Free(tmpstr);
618 *i = l;
619 return TRUE;
620} /* str_to_long_ex( ... ) */
621
631int str_to_long_long_ex(const char* s, NSTRBYTE start, NSTRBYTE end, long long int* i, const int base) {
632 char* tmpstr = NULL;
633 char* endstr = NULL;
634 long long l = 0;
635
636 __n_assert(s, return FALSE);
637
638 if (start > end) return FALSE;
639
640 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
641 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
642
643 memcpy(tmpstr, s + start, end - start);
644
645 errno = 0;
646 l = strtoll(tmpstr, &endstr, base);
647 int error = errno;
648
649 /* test return to number and errno values */
650 if (tmpstr == endstr) {
651 n_log(LOG_ERR, "number: '%s' invalid (no digits found, 0 returned)", s);
652 Free(tmpstr);
653 return FALSE;
654 } else if (error == ERANGE && l == LLONG_MIN) {
655 n_log(LOG_ERR, "number: '%s' invalid (underflow occurred)", s);
656 Free(tmpstr);
657 return FALSE;
658 } else if (error == ERANGE && l == LLONG_MAX) {
659 n_log(LOG_ERR, "number: 's' invalid (overflow occurred)", s);
660 Free(tmpstr);
661 return FALSE;
662 } else if (error == EINVAL) /* not in all c99 implementations - gcc OK */
663 {
664 n_log(LOG_ERR, "number: '%s' invalid (base contains unsupported value)", s);
665 Free(tmpstr);
666 return FALSE;
667 } else if (error != 0 && l == 0) {
668 n_log(LOG_ERR, "number: '%s' invalid (unspecified error occurred)", s);
669 Free(tmpstr);
670 return FALSE;
671 } else if (error == 0 && !*endstr) {
672 n_log(LOG_DEBUG, "number : '%llu' valid (and represents all characters read)", l);
673 } else if (error == 0 && *endstr != 0) {
674 n_log(LOG_DEBUG, " number : '%llu' valid (remaining characters: '%s')", l, s);
675 }
676 Free(tmpstr);
677 *i = l;
678 return TRUE;
679} /* str_to_long_long_ex( ... ) */
680
688int str_to_long(const char* s, long int* i, const int base) {
689 int ret = FALSE;
690 if (s) {
691 ret = str_to_long_ex(s, 0, strlen(s), i, base);
692 }
693 return ret;
694} /* str_to_long(...) */
695
703int str_to_long_long(const char* s, long long int* i, const int base) {
704 int ret = FALSE;
705 if (s) {
706 ret = str_to_long_long_ex(s, 0, strlen(s), i, base);
707 }
708 return ret;
709} /* str_to_long(...) */
710
717 N_STR* new_str = NULL;
718
719 __n_assert(str, return NULL);
720 __n_assert(str->data, return NULL);
721
722 new_str = new_nstr(str->length);
723 if (new_str) {
724 if (new_str->data) {
725 memcpy(new_str->data, str->data, str->written);
726 new_str->length = str->length;
727 new_str->written = str->written;
728 } else {
729 Free(new_str);
730 n_log(LOG_ERR, "Error duplicating N_STR %p -> data", str);
731 }
732 } else {
733 n_log(LOG_ERR, "Error duplicating N_STR %p", str);
734 }
735 return new_str;
736} /* nstrdup(...) */
737
747int skipw(const char* string, char toskip, NSTRBYTE* iterator, int inc) {
748 int error_flag = 0;
749
750 __n_assert(string, return FALSE);
751
752 NSTRBYTE slen = (NSTRBYTE)strlen(string);
753 if (toskip == ' ') {
754 while (*iterator <= slen && isspace((unsigned char)string[*iterator])) {
755 if (inc < 0 && *iterator == 0) {
756 error_flag = 1;
757 break;
758 } else {
759 if (inc > 0)
760 *iterator = *iterator + (NSTRBYTE)inc;
761 else
762 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
763 }
764 }
765 } else {
766 while (*iterator <= slen && string[*iterator] == toskip) {
767 if (inc < 0 && *iterator == 0) {
768 error_flag = 1;
769 break;
770 } else {
771 if (inc > 0)
772 *iterator = *iterator + (NSTRBYTE)inc;
773 else
774 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
775 }
776 }
777 }
778 if (error_flag == 1 || *iterator > slen) {
779 return FALSE;
780 }
781
782 return TRUE;
783} /*skipw(...)*/
784
794int skipu(const char* string, char toskip, NSTRBYTE* iterator, int inc) {
795 int error_flag = 0;
796
797 __n_assert(string, return FALSE);
798
799 NSTRBYTE slen = (NSTRBYTE)strlen(string);
800 if (toskip == ' ') {
801 while (*iterator <= slen && !isspace((unsigned char)string[*iterator])) {
802 if (inc < 0 && *iterator == 0) {
803 error_flag = 1;
804 break;
805 } else {
806 if (inc > 0)
807 *iterator = *iterator + (NSTRBYTE)inc;
808 else
809 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
810 }
811 }
812 } else {
813 while (*iterator <= slen && string[*iterator] != toskip) {
814 if (inc < 0 && *iterator == 0) {
815 error_flag = 1;
816 break;
817 } else {
818 if (inc > 0)
819 *iterator = *iterator + (NSTRBYTE)inc;
820 else
821 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
822 }
823 }
824 }
825
826 if (error_flag == 1 || *iterator > slen) {
827 return FALSE;
828 }
829
830 return TRUE;
831} /*Skipu(...)*/
832
840int strup(const char* string, char* dest) {
841 NSTRBYTE it = 0;
842
843 __n_assert(string, return FALSE);
844 __n_assert(dest, return FALSE);
845
846 for (it = 0; it < (NSTRBYTE)strlen(string); it++)
847 dest[it] = (char)toupper(string[it]);
848
849 dest[strlen(string)] = '\0';
850
851 return TRUE;
852} /*strup(...)*/
853
861int strlo(const char* string, char* dest) {
862 NSTRBYTE it = 0;
863
864 __n_assert(string, return FALSE);
865 __n_assert(dest, return FALSE);
866
867 for (it = 0; it < (NSTRBYTE)strlen(string); it++)
868 dest[it] = (char)tolower(string[it]);
869
870 dest[strlen(string)] = '\0';
871
872 return TRUE;
873} /*strlo(...)*/
874
884int strcpy_u(const char* from, char* to, NSTRBYTE to_size, char delim, NSTRBYTE* it) {
885 NSTRBYTE _it = 0;
886
887 __n_assert(from, return FALSE);
888 __n_assert(to, return FALSE);
889 __n_assert(it, return FALSE);
890
891 while (_it < to_size && from[(*it)] != '\0' && from[(*it)] != delim) {
892 to[_it] = from[(*it)];
893 (*it) = (*it) + 1;
894 _it = _it + 1;
895 }
896
897 if (_it == to_size) {
898 _it--;
899 to[_it] = '\0';
900 n_log(LOG_DEBUG, "strcpy_u: not enough space to write %d octet to dest (%d max) , %s: %d", _it, to_size, __FILE__, __LINE__);
901 return FALSE;
902 }
903
904 to[_it] = '\0';
905
906 if (from[(*it)] != delim) {
907 n_log(LOG_DEBUG, "strcpy_u: delim value not found, written %d octet to dest (%d max) , %s: %d", _it, to_size, __FILE__, __LINE__);
908 return FALSE;
909 }
910 return TRUE;
911} /* strcpy_u(...) */
912
920char** split(const char* str, const char* delim, int empty) {
921 char** tab = NULL; /* result array */
922 char* ptr = NULL; /* tmp pointer */
923 char** tmp = NULL; /* temporary pointer for realloc */
924 size_t sizeStr = 0; /* string token size */
925 size_t sizeTab = 0; /* array size */
926 const char* largestring = NULL; /* pointer to start of string */
927
928 __n_assert(str, return NULL);
929 __n_assert(delim, return NULL);
930
931 size_t sizeDelim = strlen(delim);
932 largestring = str;
933
934 while ((ptr = strstr(largestring, delim)) != NULL) {
935 sizeStr = (size_t)(ptr - largestring);
936 if (empty == 1 || sizeStr != 0) {
937 sizeTab++;
938 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
939 __n_assert(tmp, goto error);
940 tab = tmp;
941
942 Malloc(tab[sizeTab - 1], char, sizeof(char) * (sizeStr + 1));
943 __n_assert(tab[sizeTab - 1], goto error);
944
945 memcpy(tab[sizeTab - 1], largestring, sizeStr);
946 tab[sizeTab - 1][sizeStr] = '\0';
947 }
948 ptr = ptr + sizeDelim;
949 largestring = ptr;
950 }
951
952 /* adding last part if any */
953 if (strlen(largestring) != 0) {
954 sizeStr = strlen(largestring);
955 sizeTab++;
956
957 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
958 __n_assert(tmp, goto error);
959 tab = tmp;
960
961 Malloc(tab[sizeTab - 1], char, sizeof(char) * (sizeStr + 1));
962 __n_assert(tab[sizeTab - 1], goto error);
963
964 memcpy(tab[sizeTab - 1], largestring, sizeStr);
965 tab[sizeTab - 1][sizeStr] = '\0';
966 } else {
967 if (empty == 1) {
968 sizeTab++;
969
970 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
971 __n_assert(tmp, goto error);
972 tab = tmp;
973
974 Malloc(tab[sizeTab - 1], char, (int)(sizeof(char) * 1));
975 __n_assert(tab[sizeTab - 1], goto error);
976
977 tab[sizeTab - 1][0] = '\0';
978 }
979 }
980
981 /* on ajoute une case a null pour finir le tableau */
982 sizeTab++;
983 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
984 __n_assert(tmp, goto error);
985 tab = tmp;
986 tab[sizeTab - 1] = NULL;
987
988 return tab;
989
990error:
991 free_split_result(&tab);
992 return NULL;
993} /* split( ... ) */
994
1000int split_count(char** split_result) {
1001 __n_assert(split_result, return -1);
1002 __n_assert(split_result[0], return -1);
1003
1004 int it = 0;
1005 while (split_result[it]) {
1006 it++;
1007 }
1008 return it;
1009} /* split_count(...) */
1010
1016int free_split_result(char*** tab) {
1017 if (!(*tab))
1018 return FALSE;
1019
1020 int it = 0;
1021 while ((*tab)[it]) {
1022 // cppcheck-suppress identicalInnerCondition ; Free() macro rechecks pointer internally
1023 Free((*tab)[it]);
1024 it++;
1025 }
1026 Free((*tab));
1027
1028 return TRUE;
1029} /* free_split_result(...)*/
1030
1037char* join(char** splitresult, const char* delim) {
1038 size_t delim_length = 0;
1039 if (delim)
1040 delim_length = strlen(delim);
1041 size_t total_length = 0;
1042 int it = 0;
1043 while (splitresult[it]) {
1044 // n_log( LOG_DEBUG , "split entry %d: %s" , it , splitresult[ it ] );
1045 size_t entry_length = strlen(splitresult[it]);
1046 if (entry_length >= SIZE_MAX - total_length) {
1047 n_log(LOG_ERR, "join: total_length overflow accumulating entry %d", it);
1048 return NULL;
1049 }
1050 total_length += entry_length;
1051 // if there is a delimitor and 'it' isn't the last entry
1052 if (delim && splitresult[it + 1]) {
1053 if (delim_length >= SIZE_MAX - total_length) {
1054 n_log(LOG_ERR, "join: total_length overflow accumulating delimiter at entry %d", it);
1055 return NULL;
1056 }
1057 total_length += delim_length;
1058 }
1059 it++;
1060 }
1061 char* result = NULL;
1062 Malloc(result, char, total_length + 1);
1063 __n_assert(result, return NULL);
1064 size_t position = 0;
1065 it = 0;
1066 while (splitresult[it]) {
1067 size_t copy_size = strlen(splitresult[it]);
1068 memcpy(&result[position], splitresult[it], copy_size);
1069 position += copy_size;
1070 // if there is a delimitor and 'it' isn't the last entry
1071 if (delim && splitresult[it + 1]) {
1072 memcpy(&result[position], delim, delim_length);
1073 position += delim_length;
1074 }
1075 it++;
1076 }
1077 result[position] = '\0';
1078 return result;
1079} /* join */
1080
1089N_STR* nstrcat_ex(N_STR** dest, void* src, NSTRBYTE size, int resize_flag) {
1090 char* ptr = NULL;
1091 __n_assert(src, return NULL);
1092
1093 /* guard against size + 1 overflow (also protects new_nstr's internal +1). Must come before any arithmetic using size */
1094 if (size >= SIZE_MAX - 1) {
1095 n_log(LOG_ERR, "size too large in nstrcat_ex: %zu", size);
1096 return NULL;
1097 }
1098
1099 if (resize_flag == 0) {
1100 if ((*dest)) {
1101 /* check for written + size + 1 overflow before evaluating the expression */
1102 if (size > SIZE_MAX - (*dest)->written - 1) {
1103 n_log(LOG_ERR, "integer overflow in nstrcat_ex size calculation");
1104 return NULL;
1105 }
1106 if (((*dest)->written + size + 1) > (*dest)->length) {
1107 n_log(LOG_ERR, "%p to %p: not enough space. Resize forbidden. %zu needed, %zu available", src, (*dest), (*dest)->written + size + 1, (*dest)->length);
1108 return NULL;
1109 }
1110 } else {
1111 n_log(LOG_ERR, "%p to %p: not enough space. Resize forbidden. %zu needed, destination is NULL", src, (*dest), size + 1);
1112 return NULL;
1113 }
1114 }
1115
1116 if (!(*dest)) {
1117 (*dest) = new_nstr(size + 1);
1118 if (!(*dest)) {
1119 n_log(LOG_ERR, "could not allocate new N_STR of size %zu", size + 1);
1120 return NULL;
1121 }
1122 }
1123
1124 /* check for integer overflow before computing new size */
1125 if (size > SIZE_MAX - (*dest)->written - 1) {
1126 n_log(LOG_ERR, "integer overflow in nstrcat_ex size calculation");
1127 return NULL;
1128 }
1129
1130 if ((*dest)->length < (*dest)->written + size + 1) {
1131 (*dest)->length = (*dest)->written + size + 1;
1132 if (Reallocz((*dest)->data, char, (*dest)->written, (*dest)->length) == FALSE) {
1133 free_nstr(dest);
1134 return NULL;
1135 }
1136 }
1137
1138 ptr = (*dest)->data + (*dest)->written;
1139 memcpy(ptr, src, size);
1140 (*dest)->written += size;
1141
1142 (*dest)->data[(*dest)->written] = '\0';
1143
1144 return (*dest);
1145} /* nstrcat_ex( ... ) */
1146
1154N_STR* nstrcat_bytes_ex(N_STR** dest, void* data, NSTRBYTE size) {
1155 __n_assert(dest, return NULL);
1156
1157 if (size == 0) {
1158 n_log(LOG_ERR, "Could not copy 0 or less (%ld) octet!", size);
1159 return NULL;
1160 }
1161
1162 return nstrcat_ex(dest, data, size, 1);
1163} /* nstrcat_bytes_ex( ... )*/
1164
1187int write_and_fit_ex(char** dest, NSTRBYTE* size, NSTRBYTE* written, const char* src, NSTRBYTE src_size, NSTRBYTE additional_padding) {
1188 if (src_size == 0) return TRUE;
1189 NSTRBYTE needed_size = (*written) + src_size + 1;
1190 NSTRBYTE alloc_size = needed_size + additional_padding;
1191 /* unsigned overflow guard: also documents alloc_size >= needed_size >= 2
1192 * to the static analyzer (src_size >= 1 here, so needed_size >= 2). */
1193 if (alloc_size < needed_size) return FALSE;
1194
1195 /* realloc if needed, also if destination is not allocated */
1196 if ((needed_size >= (*size)) || !(*dest)) {
1197 if (!(*dest)) {
1198 (*written) = 0;
1199 (*size) = 0;
1200 }
1201 if (Reallocz((*dest), char, (*size), alloc_size) == FALSE) {
1202 n_log(LOG_ERR, "reallocation error !!!!");
1203 return FALSE;
1204 }
1205 /* *size tracks total allocation (including padding) so the next
1206 * appends that fit in the over-allocation skip the realloc. */
1207 (*size) = alloc_size;
1208 }
1209 char* ptr = (*dest) + (*written);
1210 memcpy(ptr, src, src_size);
1211 (*written) += src_size;
1212 (*dest)[(*written)] = '\0';
1213
1214 return TRUE;
1215} /* write_and_fit_ex( ...) */
1216
1229int write_and_fit(char** dest, NSTRBYTE* size, NSTRBYTE* written, const char* src) {
1230 return write_and_fit_ex(dest, size, written, src, strlen(src), 8);
1231} /* write_and_fit( ...) */
1232
1240int scan_dir(const char* dir, LIST* result, const int recurse) {
1241 return scan_dir_ex(dir, "*", result, recurse, 0);
1242}
1243
1253int scan_dir_ex(const char* dir, const char* pattern, LIST* result, const int recurse, const int mode) {
1254 DIR* dp = NULL;
1255 struct dirent* entry = NULL;
1256 struct stat statbuf;
1257
1258 if (!result)
1259 return FALSE;
1260
1261 if ((dp = opendir(dir)) == NULL) {
1262 n_log(LOG_ERR, "cannot open directory: %s", dir);
1263 return FALSE;
1264 }
1265
1266 N_STR* newname = NULL;
1267 while ((entry = readdir(dp)) != NULL) {
1268 if (!nstrprintf(newname, "%s/%s", dir, entry->d_name)) {
1269 n_log(LOG_ERR, "could not allocate newname for %s/%s", dir, entry->d_name);
1270 free_nstr(&newname);
1271 continue;
1272 }
1273
1274 if (stat(newname->data, &statbuf) >= 0) {
1275 if (S_ISDIR(statbuf.st_mode) != 0) {
1276 if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) {
1277 free_nstr(&newname);
1278 continue;
1279 }
1280
1281 /* Recurse */
1282 if (recurse != FALSE) {
1283 if (scan_dir_ex(newname->data, pattern, result, recurse, mode) != TRUE) {
1284 n_log(LOG_ERR, "scan_dir_ex( %s , %s , %p , %d , %d ) returned FALSE !", newname->data, pattern, result, recurse, mode);
1285 }
1286 }
1287 free_nstr(&newname);
1288 continue;
1289 } else if (S_ISREG(statbuf.st_mode) != 0) {
1290 if (wildmatcase(newname->data, pattern) == TRUE) {
1291 if (mode == 0) {
1292 char* file = strdup(newname->data);
1293 if (file) {
1294 list_push(result, file, &free);
1295 } else {
1296 n_log(LOG_ERR, "Error adding %s/%s to list", dir, entry->d_name);
1297 }
1298 } else if (mode == 1) {
1299 list_push(result, newname, &free_nstr_ptr);
1300 newname = NULL;
1301 }
1302 }
1303 }
1304 }
1305 if (newname)
1306 free_nstr(&newname);
1307 }
1308 closedir(dp);
1309 return TRUE;
1310} /*scan_dir(...) */
1311
1318int wildmat(register const char* text, register const char* p) {
1319 register int last = 0;
1320 register int matched = 0;
1321 register int reverse = 0;
1322
1323 for (; *p; text++, p++) {
1324 if (*text == '\0' && *p != '*')
1325 return WILDMAT_ABORT;
1326 switch (*p) {
1327 case '\\':
1328 /* Literal match with following character. */
1329 p++;
1330 /* FALLTHROUGH */
1331 default:
1332 if (*text != *p)
1333 return FALSE;
1334 continue;
1335 case '?':
1336 /* Match anything. */
1337 continue;
1338 case '*':
1339 while (*++p == '*')
1340 /* Consecutive stars act just like one. */
1341 ;
1342 if (*p == '\0')
1343 /* Trailing star matches everything. */
1344 return TRUE;
1345 while (*text)
1346 if ((matched = wildmat(text++, p)) != FALSE)
1347 return matched;
1348 return WILDMAT_ABORT;
1349 case '[':
1350 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
1351 if (reverse)
1352 /* Inverted character class. */
1353 p++;
1354 matched = FALSE;
1355 if (p[1] == ']' || p[1] == '-')
1356 if (*++p == *text)
1357 matched = TRUE;
1358 for (last = *p; *++p && *p != ']'; last = *p)
1359 /* This next line requires a good C compiler. */
1360 if (*p == '-' && p[1] != ']'
1361 ? *text <= *++p && *text >= last
1362 : *text == *p)
1363 matched = TRUE;
1364 if (matched == reverse)
1365 return FALSE;
1366 continue;
1367 }
1368 }
1369#ifdef WILDMAT_MATCH_TAR_PATTERN
1370 if (*text == '/')
1371 return TRUE;
1372#endif /* MATCH_TAR_ATTERN */
1373 return *text == '\0';
1374} /* wildmatch(...) */
1375
1382int wildmatcase(register const char* text, register const char* p) {
1383 register int last;
1384 register int matched;
1385 register int reverse;
1386
1387 for (; *p; text++, p++) {
1388 if (*text == '\0' && *p != '*')
1389 return WILDMAT_ABORT;
1390 switch (*p) {
1391 case '\\':
1392 /* Literal match with following character. */
1393 p++;
1394 /* FALLTHROUGH */
1395 default:
1396 if (toupper(*text) != toupper(*p))
1397 return FALSE;
1398 continue;
1399 case '?':
1400 /* Match anything. */
1401 continue;
1402 case '*':
1403 while (*++p == '*')
1404 /* Consecutive stars act just like one. */
1405 ;
1406 if (*p == '\0')
1407 /* Trailing star matches everything. */
1408 return TRUE;
1409 while (*text)
1410 if ((matched = wildmatcase(text++, p)) != FALSE)
1411 return matched;
1412 return WILDMAT_ABORT;
1413 case '[':
1414 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
1415 if (reverse)
1416 /* Inverted character class. */
1417 p++;
1418 matched = FALSE;
1419 if (p[1] == ']' || p[1] == '-')
1420 if (toupper(*++p) == toupper(*text))
1421 matched = TRUE;
1422 for (last = toupper(*p); *++p && *p != ']'; last = toupper(*p))
1423 if (*p == '-' && p[1] != ']'
1424 ? toupper(*text) <= toupper(*++p) && toupper(*text) >= last
1425 : toupper(*text) == toupper(*p))
1426 matched = TRUE;
1427 if (matched == reverse)
1428 return FALSE;
1429 continue;
1430 }
1431 }
1432#ifdef WILDMAT_MATCH_TAR_PATTERN
1433 if (*text == '/')
1434 return TRUE;
1435#endif /* MATCH_TAR_ATTERN */
1436 return *text == '\0';
1437} /* wildmatcase(...) */
1438
1448char* str_replace(const char* string, const char* substr, const char* replacement) {
1449 const char* tok = NULL;
1450 char* newstr = NULL;
1451 char* head = NULL;
1452
1453 if (substr == NULL || substr[0] == '\0' || replacement == NULL)
1454 return strdup(string);
1455
1456 size_t substr_len = strlen(substr);
1457 size_t replacement_len = strlen(replacement);
1458
1459 newstr = strdup(string);
1460 if (!newstr) return NULL;
1461 head = newstr;
1462 while ((tok = strstr(head, substr))) {
1463 char* oldstr = newstr;
1464 size_t oldstr_len = strlen(oldstr);
1465 size_t base_len = oldstr_len - substr_len;
1466 /* Prevent size_t overflow in allocation size calculation */
1467 if (base_len > SIZE_MAX - 8 ||
1468 replacement_len > SIZE_MAX - base_len - 8) {
1469 n_log(LOG_ERR, "str_replace: allocation size overflow (base_len=%zu, replacement_len=%zu)", base_len, replacement_len);
1470 free(oldstr);
1471 return NULL;
1472 }
1473 size_t newlen = base_len + replacement_len + 8;
1474 Malloc(newstr, char, newlen);
1475 /*failed to alloc mem, free old string and return NULL */
1476 if (newstr == NULL) {
1477 n_log(LOG_ERR, "str_replace: could not allocate newstr of size %zu", newlen);
1478 free(oldstr);
1479 return NULL;
1480 }
1481 memcpy(newstr, oldstr, (size_t)(tok - oldstr));
1482 memcpy(newstr + (tok - oldstr), replacement, replacement_len);
1483 memcpy(newstr + (tok - oldstr) + replacement_len, tok + substr_len, oldstr_len - substr_len - (size_t)(tok - oldstr));
1484 memset(newstr + oldstr_len - substr_len + replacement_len, 0, 1);
1485 /* move back head right after the last replacement */
1486 head = newstr + (tok - oldstr) + replacement_len;
1487 free(oldstr);
1488 }
1489 return newstr;
1490}
1491
1501int str_sanitize_ex(char* string, const NSTRBYTE string_len, const char* mask, const NSTRBYTE masklen, const char replacement) {
1502 __n_assert(string, return FALSE);
1503 __n_assert(mask, return FALSE);
1504
1505 NSTRBYTE it = 0;
1506 for (it = 0; it < string_len; it++) {
1507 NSTRBYTE mask_it = 0;
1508 while (mask_it < masklen && mask[mask_it] != '\0') {
1509 if (string[it] == mask[mask_it])
1510 string[it] = replacement;
1511 mask_it++;
1512 }
1513 }
1514 return TRUE;
1515}
1516
1524int str_sanitize(char* string, const char* mask, const char replacement) {
1525 return str_sanitize_ex(string, strlen(string), mask, strlen(mask), replacement);
1526}
1527
1534int resize_nstr(N_STR* nstr, size_t size) {
1535 __n_assert(nstr, return FALSE);
1536 if (size == 0) {
1537 // Free the current buffer and reset fields
1538 Free(nstr->data);
1539 nstr->written = 0;
1540 nstr->length = 0;
1541 return TRUE;
1542 }
1543
1544 if (!nstr->data) {
1545 Malloc(nstr->data, char, size);
1546 __n_assert(nstr->data, return FALSE);
1547 } else {
1548 if (Reallocz(nstr->data, char, nstr->length, size) == FALSE) {
1549 return FALSE;
1550 }
1551 }
1552
1553 nstr->length = size;
1554
1555 return TRUE;
1556}
1557
1565N_STR* nstrprintf_ex(N_STR** nstr_var, const char* format, ...) {
1566 __n_assert(format, return NULL);
1567
1568 va_list args;
1569 va_list args_copy;
1570 int needed_size = 0;
1571
1572 // Calculate the required size for the formatted string
1573 va_start(args, format);
1574 va_copy(args_copy, args); // Copy args for reuse
1575 needed_size = vsnprintf(NULL, 0, format, args);
1576 va_end(args);
1577
1578 if (needed_size < 0) {
1579 va_end(args_copy);
1580 n_log(LOG_ERR, "there was an error while computing the new size according to format \"%s\" for N_STR %p", format, (*nstr_var));
1581 return NULL;
1582 }
1583
1584 size_t needed = (size_t)(needed_size + 1); // Include null-terminator
1585
1586 // Allocate or resize the N_STR object as needed
1587 if (!(*nstr_var)) {
1588 (*nstr_var) = new_nstr(needed);
1589 if (!(*nstr_var) || !(*nstr_var)->data) {
1590 va_end(args_copy);
1591 n_log(LOG_ERR, "could not allocate N_STR of size %zu", needed);
1592 return NULL;
1593 }
1594 } else if (needed > (*nstr_var)->length) {
1595 if (resize_nstr((*nstr_var), needed) == FALSE) {
1596 va_end(args_copy);
1597 n_log(LOG_ERR, "could not resize N_STR %p to size %zu", (*nstr_var), needed);
1598 return NULL;
1599 }
1600 }
1601
1602 // Write the formatted string into the buffer
1603 vsnprintf((*nstr_var)->data, needed, format, args_copy);
1604 va_end(args_copy);
1605
1606 (*nstr_var)->written = (size_t)needed_size;
1607 return (*nstr_var);
1608}
1609
1617N_STR* nstrprintf_cat_ex(N_STR** nstr_var, const char* format, ...) {
1618 __n_assert(format, return NULL);
1619
1620 va_list args;
1621 va_start(args, format);
1622
1623 // duplicate va_list
1624 va_list args_copy;
1625 va_copy(args_copy, args);
1626
1627 // compute needed size
1628 int needed_size = vsnprintf(NULL, 0, format, args_copy);
1629 va_end(args_copy);
1630
1631 if (needed_size < 0) {
1632 n_log(LOG_ERR, "vsnprintf size estimation failed for format \"%s\"", format);
1633 va_end(args);
1634 return NULL;
1635 }
1636
1637 size_t needed = (size_t)(needed_size + 1); // +1 for '\0'
1638
1639 // initialize if needed
1640 if (!(*nstr_var)) {
1641 (*nstr_var) = new_nstr(needed);
1642 if (!(*nstr_var)) {
1643 va_end(args);
1644 return NULL;
1645 }
1646 }
1647
1648 // check for overflow before computing total_needed
1649 if (needed > SIZE_MAX - (*nstr_var)->written) {
1650 va_end(args);
1651 n_log(LOG_ERR, "integer overflow computing total_needed in nstrprintf_cat_ex");
1652 return NULL;
1653 }
1654
1655 // resize if needed
1656 size_t total_needed = (*nstr_var)->written + needed;
1657 if (total_needed > (*nstr_var)->length) {
1658 if (resize_nstr((*nstr_var), total_needed) == FALSE) {
1659 va_end(args);
1660 n_log(LOG_ERR, "could not resize N_STR %p to size %zu", (*nstr_var), total_needed);
1661 return NULL;
1662 }
1663 }
1664
1665 // append formatted string
1666 char* write_ptr = (*nstr_var)->data + (*nstr_var)->written;
1667 int written_now = vsnprintf(write_ptr, needed, format, args);
1668 va_end(args);
1669
1670 if (written_now < 0) {
1671 n_log(LOG_ERR, "vsnprintf failed while writing at offset %zu in N_STR %p", (*nstr_var)->written, (*nstr_var));
1672 return NULL;
1673 }
1674
1675 (*nstr_var)->written += (size_t)written_now;
1676 (*nstr_var)->data[(*nstr_var)->written] = '\0'; // ensure final \0
1677
1678 return *nstr_var;
1679}
1680
1681N_STR* n_str_template_expand(const char* tmpl, HASH_TABLE* vars) {
1682 if (!tmpl) return NULL;
1683 N_STR* result = new_nstr(strlen(tmpl) + 256);
1684 if (!result) return NULL;
1685 const char* p = tmpl;
1686 while (*p) {
1687 if (p[0] == '{' && p[1] == '{') {
1688 const char* end = strstr(p + 2, "}}");
1689 if (end) {
1690 size_t klen = (size_t)(end - (p + 2));
1691 char key[256];
1692 if (klen < sizeof(key)) {
1693 memcpy(key, p + 2, klen);
1694 key[klen] = '\0';
1695 char* val = NULL;
1696 if (vars && ht_get_string(vars, key, &val) == TRUE && val) {
1697 nstrprintf_cat(result, "%s", val);
1698 } else {
1699 nstrprintf_cat(result, "{{%s}}", key);
1700 }
1701 p = end + 2;
1702 continue;
1703 }
1704 }
1705 }
1706 char ch[2] = {*p, '\0'};
1707 nstrprintf_cat(result, "%s", ch);
1708 p++;
1709 }
1710 return result;
1711}
1712
1725N_STR* n_str_url_encode(const char* src) {
1726 if (!src) return NULL;
1727 size_t in_len = strlen(src);
1728 /* worst case: every byte expands to "%HH" -> 3x */
1729 if (in_len > (SIZE_MAX - 1) / 3) return NULL;
1730 N_STR* out = new_nstr(in_len * 3 + 1);
1731 if (!out) return NULL;
1732 for (const unsigned char* p = (const unsigned char*)src; *p; p++) {
1733 unsigned char c = *p;
1734 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
1735 (c >= '0' && c <= '9') ||
1736 c == '-' || c == '_' || c == '.' || c == '~') {
1737 char ch[2] = {(char)c, '\0'};
1738 if (!nstrprintf_cat(out, "%s", ch)) {
1739 free_nstr(&out);
1740 return NULL;
1741 }
1742 } else {
1743 if (!nstrprintf_cat(out, "%%%02X", c)) {
1744 free_nstr(&out);
1745 return NULL;
1746 }
1747 }
1748 }
1749 return out;
1750}
1751
1752#endif /* #ifndef NOSTR */
static int mode
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:272
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define _str(__PTR)
define true
Definition n_common.h:193
#define Reallocz(__ptr, __struct, __old_size, __size)
Realloc + zero new memory zone Handler to get errors.
Definition n_common.h:247
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
int ht_get_string(HASH_TABLE *table, const char *key, char **val)
get string at 'key' from 'table'
Definition n_hash.c:2123
structure of a hash table
Definition n_hash.h:138
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:228
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:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
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:703
N_STR * n_str_template_expand(const char *tmpl, HASH_TABLE *vars)
Expand double-brace tokens in a template using a hash table.
Definition n_str.c:1681
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
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:70
N_STR * nstrprintf_cat_ex(N_STR **nstr_var, const char *format,...)
Function to allocate, format, and concatenate a string into an N_STR object.
Definition n_str.c:1617
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:1725
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:1000
int str_sanitize_ex(char *string, const NSTRBYTE string_len, const char *mask, const NSTRBYTE masklen, const char replacement)
clean a string by replacing evil characteres
Definition n_str.c:1501
int nstr_to_file(N_STR *str, char *filename)
Write a N_STR content into a file.
Definition n_str.c:424
int scan_dir_ex(const char *dir, const char *pattern, LIST *result, const int recurse, const int mode)
Scan a list of directory and return a list of char *file.
Definition n_str.c:1253
int str_to_long_long_ex(const char *s, NSTRBYTE start, NSTRBYTE end, long long int *i, const int base)
Helper for string[start to end] to long long integer.
Definition n_str.c:631
char * join(char **splitresult, const char *delim)
join the array into a string
Definition n_str.c:1037
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition n_str.c:716
int strlo(const char *string, char *dest)
Lower case a string.
Definition n_str.c:861
N_STR * nstrcat_ex(N_STR **dest, void *src, NSTRBYTE size, int resize_flag)
Append data into N_STR using internal N_STR size and cursor position.
Definition n_str.c:1089
int write_and_fit(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src)
Append src to *dest.
Definition n_str.c:1229
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
Definition n_str.h:121
int strcpy_u(const char *from, char *to, NSTRBYTE to_size, char delim, NSTRBYTE *it)
Copy from start to dest until from[ iterator ] == delim.
Definition n_str.c:884
int str_to_int_ex(const char *s, NSTRBYTE start, NSTRBYTE end, int *i, const int base)
Helper for string[start to end] to integer.
Definition n_str.c:462
int str_to_int_nolog(const char *s, NSTRBYTE start, NSTRBYTE end, int *i, const int base, N_STR **infos)
Helper for string[start to end] to integer.
Definition n_str.c:510
int resize_nstr(N_STR *nstr, size_t size)
reallocate a nstr internal buffer.
Definition n_str.c:1534
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:255
char * nfgets(char *buffer, NSTRBYTE size, FILE *stream)
try to fgets
Definition n_str.c:171
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:794
#define WILDMAT_ABORT
Abort code to sped up pattern matching.
Definition n_str.h:72
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:1382
#define WILDMAT_NEGATE_CLASS
What character marks an inverted character class?
Definition n_str.h:74
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:207
char * str_replace(const char *string, const char *substr, const char *replacement)
Replace "substr" by "replacement" inside string taken from http://coding.debuntu.org/c-implementing-s...
Definition n_str.c:1448
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:747
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
Definition n_str.h:117
N_STR * nstrcat_bytes_ex(N_STR **dest, void *data, NSTRBYTE size)
Append data into N_STR using internal N_STR size and cursor position.
Definition n_str.c:1154
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:1240
int str_sanitize(char *string, const char *mask, const char replacement)
clean a string by replacing evil characteres
Definition n_str.c:1524
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:920
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:1318
int free_nstr_nolog(N_STR **ptr)
Free a N_STR structure and set the pointer to NULL.
Definition n_str.c:97
int str_to_long(const char *s, long int *i, const int base)
Helper for string to integer.
Definition n_str.c:688
int char_to_nstr_ex(const char *from, NSTRBYTE nboct, N_STR **to)
Convert a char into a N_STR, extended version.
Definition n_str.c:232
N_STR * char_to_nstr_nocopy(char *src)
Convert a char into a N_STR, direct use of linked source pointer.
Definition n_str.c:268
int _free_nstr(N_STR **ptr)
Free a N_STR structure and set the pointer to NULL.
Definition n_str.c:83
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:1187
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
Definition n_str.c:288
int free_split_result(char ***tab)
Free a split result allocated array.
Definition n_str.c:1016
N_STR * nstrprintf_ex(N_STR **nstr_var, const char *format,...)
Function to allocate and format a string into an N_STR object.
Definition n_str.c:1565
void free_nstr_ptr_nolog(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:110
int str_to_int(const char *s, int *i, const int base)
Helper for string to integer.
Definition n_str.c:553
int nstr_to_fd(N_STR *str, FILE *out, int lock)
Write a N_STR content into a file.
Definition n_str.c:371
int str_to_long_ex(const char *s, NSTRBYTE start, NSTRBYTE end, long int *i, const int base)
Helper for string[start to end] to long integer.
Definition n_str.c:572
int strup(const char *string, char *dest)
Upper case a string.
Definition n_str.c:840
A box including a string and his lenght.
Definition n_str.h:61
Common headers and low-level functions & define.
Hash functions and table.
Generic log system.
N_STR and string function declaration.