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 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#ifndef NO_NSTR
28
29#include "nilorea/n_common.h"
30#include "nilorea/n_log.h"
31#include "nilorea/n_str.h"
32#include "nilorea/n_hash.h"
33
34#include <errno.h>
35#include <pthread.h>
36#include <math.h>
37#include <ctype.h>
38#include <stdio.h>
39#include <string.h>
40#include <limits.h>
41#include <stdint.h>
42#include <stdlib.h>
43#include <dirent.h>
44
45#ifdef __windows__
52const char* strcasestr(const char* s1, const char* s2) {
53 __n_assert(s1, return NULL);
54 __n_assert(s2, return NULL);
55
56 size_t n = strlen(s2);
57 while (*s1) {
58 if (!strnicmp(s1++, s2, n))
59 return (s1 - 1);
60 }
61 return NULL;
62} /* strcasestr */
63#endif
64
69void free_nstr_ptr(void* ptr) {
70 N_STR* strptr = (N_STR*)ptr;
71 if (ptr && strptr) {
72 FreeNoLog(strptr->data);
73 FreeNoLog(strptr);
74 }
75} /* free_nstr_ptr( ... ) */
76
82int _free_nstr(N_STR** ptr) {
83 __n_assert(ptr && (*ptr), return FALSE);
84
85 FreeNoLog((*ptr)->data);
86 FreeNoLog((*ptr));
87
88 return TRUE;
89} /* free_nstr( ... ) */
90
97 if ((*ptr)) {
98 FreeNoLog((*ptr)->data);
99 FreeNoLog((*ptr));
100 }
101
102 return TRUE;
103} /* free_nstr( ... ) */
104
109void free_nstr_ptr_nolog(void* ptr) {
110 N_STR* strptr = (N_STR*)ptr;
111 if (strptr) {
112 FreeNoLog(strptr->data);
113 FreeNoLog(strptr);
114 }
115} /* free_nstr_ptr_nolog( ... ) */
116
122char* trim_nocopy(char* s) {
123 __n_assert(s, return NULL);
124
125 if (strlen(s) == 0)
126 return s;
127
128 char* start = s;
129
130 /* skip spaces at start */
131 while (*start && isspace((unsigned char)*start))
132 start++;
133
134 char* end = s + strlen(s) - 1;
135 /* iterate over the rest remebering last non-whitespace */
136 while (*end && isspace((unsigned char)*end) && end > s) {
137 end--;
138 }
139 end++;
140 /* write the terminating zero after last non-whitespace */
141 *end = 0;
142
143 return start;
144} /* trim_nocopy */
145
151char* trim(const char* s) {
152 __n_assert(s, return NULL);
153
154 char* copy = strdup(s);
155 __n_assert(copy, return NULL);
156
157 const char* trimmed = trim_nocopy(copy);
158 char* result = strdup(trimmed);
159 free(copy);
160 return result;
161} /* trim */
162
170char* nfgets(char* buffer, NSTRBYTE size, FILE* stream) {
171 __n_assert(buffer, return NULL);
172 __n_assert(stream, return NULL);
173
174 if (size >= INT_MAX) {
175 n_log(LOG_ERR, "size of %zu too big, >INT_MAX for buffer %p", size, buffer);
176 return NULL;
177 }
178
179 if (!fgets(buffer, (int)size, stream)) {
180 return NULL;
181 }
182
183 return buffer;
184} /* nfgets(...) */
185
191int empty_nstr(N_STR* nstr) {
192 __n_assert(nstr, return FALSE);
193 __n_assert(nstr->data, return FALSE);
194
195 nstr->written = 0;
196 memset(nstr->data, 0, nstr->length);
197
198 return TRUE;
199}
200
207 N_STR* str = NULL;
208
209 Malloc(str, N_STR, 1);
210 __n_assert(str, return NULL);
211
212 str->written = 0;
213 if (size == 0) {
214 str->data = NULL;
215 str->length = 0;
216 } else {
217 Malloc(str->data, char, size + 1);
218 __n_assert(str->data, Free(str); return NULL);
219 str->length = size;
220 }
221 return str;
222} /* new_nstr(...) */
223
231int char_to_nstr_ex(const char* from, NSTRBYTE nboct, N_STR** to) {
232 if ((*to)) {
233 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");
234 n_log(LOG_ERR, "Data to copy: %s", _str(from));
235 return FALSE;
236 };
237
238 (*to) = new_nstr(nboct + 1);
239 __n_assert(to && (*to), return FALSE);
240 /* added a sizeof( void * ) to add a consistant and secure padding at the end */
241 __n_assert((*to)->data, Free((*to)); return FALSE);
242
243 memcpy((*to)->data, from, nboct);
244 (*to)->written = nboct;
245
246 return TRUE;
247} /* char_to_nstr(...) */
248
254N_STR* char_to_nstr(const char* src) {
255 __n_assert(src, return NULL);
256 N_STR* strptr = NULL;
257 size_t length = strlen(src);
258 char_to_nstr_ex(src, length, &strptr);
259 return strptr;
260} /* char_to_str(...) */
261
268 __n_assert(src, return NULL);
269
270 N_STR* to = NULL;
271 to = new_nstr(0);
272 __n_assert(to, return NULL);
273
274 to->data = src;
275 to->written = strlen(src);
276 to->length = to->written + 1; // include src end of string
277
278 return to;
279} /* char_to_str_nocopy(...) */
280
286N_STR* file_to_nstr(char* filename) {
287 N_STR* tmpstr = NULL;
288 struct stat filestat;
289 FILE* in = NULL;
290 int error = 0;
291
292 __n_assert(filename, n_log(LOG_ERR, "Unable to make a string from NULL filename"); return NULL);
293
294 int fd = open(filename, O_RDONLY);
295 error = errno;
296 if (fd == -1) {
297 n_log(LOG_ERR, "Unable to open %s for reading. Errno: %s", filename, strerror(error));
298 return NULL;
299 }
300
301 if (fstat(fd, &filestat) != 0) {
302 error = errno;
303#ifdef __linux__
304 if (error == EOVERFLOW) {
305 n_log(LOG_ERR, "%s size is too big ,EOVERFLOW)", filename);
306 } else {
307#endif
308 n_log(LOG_ERR, "Couldn't stat %s. Errno: %s", filename, strerror(error));
309#ifdef __linux__
310 }
311#endif
312 close(fd);
313 return NULL;
314 }
315
316 if ((uint64_t)filestat.st_size >= (uint64_t)UINT32_MAX) {
317 n_log(LOG_ERR, "file size >= 4GB is not possible yet. %s is %lld oct", filename, (long long)filestat.st_size);
318 close(fd);
319 return NULL;
320 }
321
322 n_log(LOG_DEBUG, "%s file size is: %lld", filename, (long long)filestat.st_size);
323
324 in = fdopen(fd, "rb");
325 if (!in) {
326 n_log(LOG_ERR, "fdopen failed on %s (fd=%d)", filename, fd);
327 close(fd);
328 return NULL;
329 }
330
331 tmpstr = new_nstr((size_t)filestat.st_size + 1);
332 __n_assert(tmpstr, fclose(in); n_log(LOG_ERR, "Unable to get a new nstr of %ld octets", filestat.st_size + 1); return NULL);
333
334 tmpstr->written = (size_t)filestat.st_size;
335
336 if (fread(tmpstr->data, sizeof(char), tmpstr->written, in) == 0) {
337 n_log(LOG_ERR, "Couldn't read %s, fread return 0", filename);
338 free_nstr(&tmpstr);
339 fclose(in);
340 return NULL;
341 }
342 if (ferror(in)) {
343 n_log(LOG_ERR, "There were some errors when reading %s", filename);
344 free_nstr(&tmpstr);
345 fclose(in);
346 return NULL;
347 }
348
349 fclose(in);
350
351 return tmpstr;
352} /*file_to_nstr */
353
362/* Write a whole N_STR into a file */
363int nstr_to_fd(N_STR* str, FILE* out, int lock) {
364#ifdef __linux__
365 struct flock out_lock;
366#endif
367 __n_assert(out, return FALSE);
368 __n_assert(str, return FALSE);
369
370 int ret = TRUE;
371
372 if (lock == 1) {
373#ifdef __linux__
374 memset(&out_lock, 0, sizeof(out_lock));
375 out_lock.l_type = F_WRLCK;
376 /* Place a write lock on the file. */
377 fcntl(fileno(out), F_SETLKW, &out_lock);
378#else
379 // cppcheck-suppress uselessAssignmentArg -- intentional: suppress unused parameter warning on non-POSIX
380 lock = 2;
381#endif
382 }
383
384 size_t written_to_file = 0;
385 if ((written_to_file = fwrite(str->data, sizeof(char), str->written, out)) != (size_t)str->written) {
386 n_log(LOG_ERR, "Couldn't write file, fwrite %d of %d octets", written_to_file, str->written);
387 ret = FALSE;
388 }
389 if (ferror(out)) {
390 n_log(LOG_ERR, "There were some errors when writing to %d", fileno(out));
391 ret = FALSE;
392 }
393
394 if (lock == 1) {
395#ifdef __linux__
396 memset(&out_lock, 0, sizeof(out_lock));
397 out_lock.l_type = F_WRLCK;
398 /* Place a write lock on the file. */
399 fcntl(fileno(out), F_SETLKW, &out_lock);
400#else
401 // cppcheck-suppress uselessAssignmentArg
402 // cppcheck-suppress unreadVariable
403 lock = 2; /* compiler warning suppressor for non-POSIX */
404#endif
405 }
406
407 return ret;
408} /* nstr_to_fd( ... ) */
409
416int nstr_to_file(N_STR* str, char* filename) {
417 __n_assert(str, return FALSE);
418 __n_assert(filename, return FALSE);
419
420 int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600); // Secure permissions: rw-------
421 if (fd == -1) {
422 n_log(LOG_ERR, "Couldn't open %s for writing (0600). Errno: %s", _str(filename), strerror(errno));
423 return FALSE;
424 }
425
426 FILE* out = NULL;
427 out = fdopen(fd, "wb");
428 if (!out) {
429 n_log(LOG_ERR, "fdopen failed for %s (fd=%d). Errno: %s", _str(filename), fd, strerror(errno));
430 close(fd);
431 return FALSE;
432 }
433
434 int ret = nstr_to_fd(str, out, 1);
435
436 fclose(out);
437
438 n_log(LOG_DEBUG, "%s file size is: %lld", _str(filename), (long long)str->written);
439
440 return ret;
441} /* nstr_to_file(...) */
442
454int str_to_int_ex(const char* s, NSTRBYTE start, NSTRBYTE end, int* i, const int base) {
455 char* tmpstr = NULL;
456 char* endstr = NULL;
457 long int l = 0;
458
459 __n_assert(s, return FALSE);
460
461 if (start > end) return FALSE;
462
463 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
464 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
465
466 memcpy(tmpstr, s + start, end - start);
467
468 errno = 0;
469 l = strtol(tmpstr, &endstr, base);
470 if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
471 n_log(LOG_ERR, "OVERFLOW reached when converting %s to int", tmpstr);
472 Free(tmpstr);
473 return FALSE;
474 }
475 if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
476 n_log(LOG_ERR, "UNDERFLOW reached when converting %s to int", tmpstr);
477 Free(tmpstr);
478 return FALSE;
479 }
480 if (*endstr != '\0' && *endstr != '\n') {
481 n_log(LOG_ERR, "Impossible conversion for %s", tmpstr);
482 Free(tmpstr);
483 return FALSE;
484 }
485 Free(tmpstr);
486 *i = (int)l;
487 return TRUE;
488} /* str_to_int_ex( ... ) */
489
502int str_to_int_nolog(const char* s, NSTRBYTE start, NSTRBYTE end, int* i, const int base, N_STR** infos) {
503 char* tmpstr = NULL;
504 char* endstr = NULL;
505 long int l = 0;
506
507 __n_assert(s, return FALSE);
508
509 if (start > end) return FALSE;
510
511 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
512 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
513
514 memcpy(tmpstr, s + start, end - start);
515
516 errno = 0;
517 l = strtol(tmpstr, &endstr, base);
518 if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
519 nstrprintf((*infos), "OVERFLOW reached when converting %s to int", tmpstr);
520 Free(tmpstr);
521 return FALSE;
522 }
523 if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
524 nstrprintf((*infos), "UNDERFLOW reached when converting %s to int", tmpstr);
525 Free(tmpstr);
526 return FALSE;
527 }
528 if (*endstr != '\0' && *endstr != '\n') {
529 nstrprintf((*infos), "Impossible conversion for %s", tmpstr);
530 Free(tmpstr);
531 return FALSE;
532 }
533 Free(tmpstr);
534 *i = (int)l;
535 return TRUE;
536} /* str_to_int_nolog( ... ) */
537
545int str_to_int(const char* s, int* i, const int base) {
546 int ret = FALSE;
547 if (s) {
548 ret = str_to_int_ex(s, 0, strlen(s), i, base);
549 }
550 return ret;
551} /* str_to_int(...) */
552
564int str_to_long_ex(const char* s, NSTRBYTE start, NSTRBYTE end, long int* i, const int base) {
565 char* tmpstr = NULL;
566 char* endstr = NULL;
567 long l = 0;
568
569 __n_assert(s, return FALSE);
570
571 if (start > end) return FALSE;
572
573 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
574 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
575
576 memcpy(tmpstr, s + start, end - start);
577
578 errno = 0;
579 l = strtol(tmpstr, &endstr, base);
580 int error = errno;
581
582 /* test return to number and errno values */
583 if (tmpstr == endstr) {
584 n_log(LOG_ERR, " number : %ld invalid (no digits found, 0 returned)", l);
585 Free(tmpstr);
586 return FALSE;
587 } else if (error == ERANGE && l == LONG_MIN) {
588 n_log(LOG_ERR, " number : %ld invalid (underflow occurred)", l);
589 Free(tmpstr);
590 return FALSE;
591 } else if (error == ERANGE && l == LONG_MAX) {
592 n_log(LOG_ERR, " number : %ld invalid (overflow occurred)", l);
593 Free(tmpstr);
594 return FALSE;
595 } else if (error == EINVAL) /* not in all c99 implementations - gcc OK */
596 {
597 n_log(LOG_ERR, " number : %ld invalid (base contains unsupported value)", l);
598 Free(tmpstr);
599 return FALSE;
600 } else if (error != 0 && l == 0) {
601 n_log(LOG_ERR, " number : %ld invalid (unspecified error occurred)", l);
602 Free(tmpstr);
603 return FALSE;
604 } else if (error == 0 && tmpstr && !*endstr) {
605 n_log(LOG_DEBUG, " number : %ld valid (and represents all characters read)", l);
606 } else if (error == 0 && tmpstr && *endstr != 0) {
607 n_log(LOG_DEBUG, " number : %ld valid (but additional characters remain", l);
608 }
609 Free(tmpstr);
610 *i = l;
611 return TRUE;
612} /* str_to_long_ex( ... ) */
613
623int str_to_long_long_ex(const char* s, NSTRBYTE start, NSTRBYTE end, long long int* i, const int base) {
624 char* tmpstr = NULL;
625 char* endstr = NULL;
626 long long l = 0;
627
628 __n_assert(s, return FALSE);
629
630 if (start > end) return FALSE;
631
632 Malloc(tmpstr, char, sizeof(int) + end - start + 8);
633 __n_assert(tmpstr, n_log(LOG_ERR, "Unable to Malloc( tmpstr , char , sizeof( int ) + %d - %d )", end, start); return FALSE);
634
635 memcpy(tmpstr, s + start, end - start);
636
637 errno = 0;
638 l = strtoll(tmpstr, &endstr, base);
639 int error = errno;
640
641 /* test return to number and errno values */
642 if (tmpstr == endstr) {
643 n_log(LOG_ERR, "number: '%s' invalid (no digits found, 0 returned)", s);
644 Free(tmpstr);
645 return FALSE;
646 } else if (error == ERANGE && l == LLONG_MIN) {
647 n_log(LOG_ERR, "number: '%s' invalid (underflow occurred)", s);
648 Free(tmpstr);
649 return FALSE;
650 } else if (error == ERANGE && l == LLONG_MAX) {
651 n_log(LOG_ERR, "number: 's' invalid (overflow occurred)", s);
652 Free(tmpstr);
653 return FALSE;
654 } else if (error == EINVAL) /* not in all c99 implementations - gcc OK */
655 {
656 n_log(LOG_ERR, "number: '%s' invalid (base contains unsupported value)", s);
657 Free(tmpstr);
658 return FALSE;
659 } else if (error != 0 && l == 0) {
660 n_log(LOG_ERR, "number: '%s' invalid (unspecified error occurred)", s);
661 Free(tmpstr);
662 return FALSE;
663 } else if (error == 0 && tmpstr && !*endstr) {
664 n_log(LOG_DEBUG, "number : '%llu' valid (and represents all characters read)", l);
665 } else if (error == 0 && tmpstr && *endstr != 0) {
666 n_log(LOG_DEBUG, " number : '%llu' valid (remaining characters: '%s')", l, s);
667 }
668 Free(tmpstr);
669 *i = l;
670 return TRUE;
671} /* str_to_long_long_ex( ... ) */
672
680int str_to_long(const char* s, long int* i, const int base) {
681 int ret = FALSE;
682 if (s) {
683 ret = str_to_long_ex(s, 0, strlen(s), i, base);
684 }
685 return ret;
686} /* str_to_long(...) */
687
695int str_to_long_long(const char* s, long long int* i, const int base) {
696 int ret = FALSE;
697 if (s) {
698 ret = str_to_long_long_ex(s, 0, strlen(s), i, base);
699 }
700 return ret;
701} /* str_to_long(...) */
702
709 N_STR* new_str = NULL;
710
711 __n_assert(str, return NULL);
712 __n_assert(str->data, return NULL);
713
714 new_str = new_nstr(str->length);
715 if (new_str) {
716 if (new_str->data) {
717 memcpy(new_str->data, str->data, str->written);
718 new_str->length = str->length;
719 new_str->written = str->written;
720 } else {
721 Free(new_str);
722 n_log(LOG_ERR, "Error duplicating N_STR %p -> data", str);
723 }
724 } else {
725 n_log(LOG_ERR, "Error duplicating N_STR %p", str);
726 }
727 return new_str;
728} /* nstrdup(...) */
729
739int skipw(const char* string, char toskip, NSTRBYTE* iterator, int inc) {
740 int error_flag = 0;
741
742 __n_assert(string, return FALSE);
743
744 NSTRBYTE slen = (NSTRBYTE)strlen(string);
745 if (toskip == ' ') {
746 while (*iterator <= slen && isspace((unsigned char)string[*iterator])) {
747 if (inc < 0 && *iterator == 0) {
748 error_flag = 1;
749 break;
750 } else {
751 if (inc > 0)
752 *iterator = *iterator + (NSTRBYTE)inc;
753 else
754 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
755 }
756 }
757 } else {
758 while (*iterator <= slen && string[*iterator] == toskip) {
759 if (inc < 0 && *iterator == 0) {
760 error_flag = 1;
761 break;
762 } else {
763 if (inc > 0)
764 *iterator = *iterator + (NSTRBYTE)inc;
765 else
766 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
767 }
768 }
769 }
770 if (error_flag == 1 || *iterator > slen) {
771 return FALSE;
772 }
773
774 return TRUE;
775} /*skipw(...)*/
776
786int skipu(const char* string, char toskip, NSTRBYTE* iterator, int inc) {
787 int error_flag = 0;
788
789 __n_assert(string, return FALSE);
790
791 NSTRBYTE slen = (NSTRBYTE)strlen(string);
792 if (toskip == ' ') {
793 while (*iterator <= slen && !isspace((unsigned char)string[*iterator])) {
794 if (inc < 0 && *iterator == 0) {
795 error_flag = 1;
796 break;
797 } else {
798 if (inc > 0)
799 *iterator = *iterator + (NSTRBYTE)inc;
800 else
801 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
802 }
803 }
804 } else {
805 while (*iterator <= slen && string[*iterator] != toskip) {
806 if (inc < 0 && *iterator == 0) {
807 error_flag = 1;
808 break;
809 } else {
810 if (inc > 0)
811 *iterator = *iterator + (NSTRBYTE)inc;
812 else
813 *iterator = (*iterator > (NSTRBYTE)(-inc)) ? (*iterator - (NSTRBYTE)(-inc)) : 0;
814 }
815 }
816 }
817
818 if (error_flag == 1 || *iterator > slen) {
819 return FALSE;
820 }
821
822 return TRUE;
823} /*Skipu(...)*/
824
832int strup(const char* string, char* dest) {
833 NSTRBYTE it = 0;
834
835 __n_assert(string, return FALSE);
836 __n_assert(dest, return FALSE);
837
838 for (it = 0; it < (NSTRBYTE)strlen(string); it++)
839 dest[it] = (char)toupper(string[it]);
840
841 dest[strlen(string)] = '\0';
842
843 return TRUE;
844} /*strup(...)*/
845
853int strlo(const char* string, char* dest) {
854 NSTRBYTE it = 0;
855
856 __n_assert(string, return FALSE);
857 __n_assert(dest, return FALSE);
858
859 for (it = 0; it < (NSTRBYTE)strlen(string); it++)
860 dest[it] = (char)tolower(string[it]);
861
862 dest[strlen(string)] = '\0';
863
864 return TRUE;
865} /*strlo(...)*/
866
876int strcpy_u(const char* from, char* to, NSTRBYTE to_size, char split, NSTRBYTE* it) {
877 NSTRBYTE _it = 0;
878
879 __n_assert(from, return FALSE);
880 __n_assert(to, return FALSE);
881 __n_assert(it, return FALSE);
882
883 while (_it < to_size && from[(*it)] != '\0' && from[(*it)] != split) {
884 to[_it] = from[(*it)];
885 (*it) = (*it) + 1;
886 _it = _it + 1;
887 }
888
889 if (_it == to_size) {
890 _it--;
891 to[_it] = '\0';
892 n_log(LOG_DEBUG, "strcpy_u: not enough space to write %d octet to dest (%d max) , %s: %d", _it, to_size, __FILE__, __LINE__);
893 return FALSE;
894 }
895
896 to[_it] = '\0';
897
898 if (from[(*it)] != split) {
899 n_log(LOG_DEBUG, "strcpy_u: split value not found, written %d octet to dest (%d max) , %s: %d", _it, to_size, __FILE__, __LINE__);
900 return FALSE;
901 }
902 return TRUE;
903} /* strcpy_u(...) */
904
912char** split(const char* str, const char* delim, int empty) {
913 char** tab = NULL; /* result array */
914 char* ptr = NULL; /* tmp pointer */
915 char** tmp = NULL; /* temporary pointer for realloc */
916 size_t sizeStr = 0; /* string token size */
917 size_t sizeTab = 0; /* array size */
918 const char* largestring = NULL; /* pointer to start of string */
919
920 __n_assert(str, return NULL);
921 __n_assert(delim, return NULL);
922
923 size_t sizeDelim = strlen(delim);
924 largestring = str;
925
926 while ((ptr = strstr(largestring, delim)) != NULL) {
927 sizeStr = (size_t)(ptr - largestring);
928 if (empty == 1 || sizeStr != 0) {
929 sizeTab++;
930 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
931 __n_assert(tmp, goto error);
932 tab = tmp;
933
934 Malloc(tab[sizeTab - 1], char, sizeof(char) * (sizeStr + 1));
935 __n_assert(tab[sizeTab - 1], goto error);
936
937 memcpy(tab[sizeTab - 1], largestring, sizeStr);
938 tab[sizeTab - 1][sizeStr] = '\0';
939 }
940 ptr = ptr + sizeDelim;
941 largestring = ptr;
942 }
943
944 /* adding last part if any */
945 if (strlen(largestring) != 0) {
946 sizeStr = strlen(largestring);
947 sizeTab++;
948
949 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
950 __n_assert(tmp, goto error);
951 tab = tmp;
952
953 Malloc(tab[sizeTab - 1], char, sizeof(char) * (sizeStr + 1));
954 __n_assert(tab[sizeTab - 1], goto error);
955
956 memcpy(tab[sizeTab - 1], largestring, sizeStr);
957 tab[sizeTab - 1][sizeStr] = '\0';
958 } else {
959 if (empty == 1) {
960 sizeTab++;
961
962 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
963 __n_assert(tmp, goto error);
964 tab = tmp;
965
966 Malloc(tab[sizeTab - 1], char, (int)(sizeof(char) * 1));
967 __n_assert(tab[sizeTab - 1], goto error);
968
969 tab[sizeTab - 1][0] = '\0';
970 }
971 }
972
973 /* on ajoute une case a null pour finir le tableau */
974 sizeTab++;
975 tmp = (char**)realloc(tab, sizeof(char*) * sizeTab);
976 __n_assert(tmp, goto error);
977 tab = tmp;
978 tab[sizeTab - 1] = NULL;
979
980 return tab;
981
982error:
983 free_split_result(&tab);
984 return NULL;
985} /* split( ... ) */
986
992int split_count(char** split_result) {
993 __n_assert(split_result, return -1);
994 __n_assert(split_result[0], return -1);
995
996 int it = 0;
997 while (split_result[it]) {
998 it++;
999 }
1000 return it;
1001} /* split_count(...) */
1002
1008int free_split_result(char*** tab) {
1009 if (!(*tab))
1010 return FALSE;
1011
1012 int it = 0;
1013 while ((*tab)[it]) {
1014 // cppcheck-suppress identicalInnerCondition -- Free() macro rechecks pointer internally
1015 Free((*tab)[it]);
1016 it++;
1017 }
1018 Free((*tab));
1019
1020 return TRUE;
1021} /* free_split_result(...)*/
1022
1029char* join(char** splitresult, const char* delim) {
1030 size_t delim_length = 0;
1031 if (delim)
1032 delim_length = strlen(delim);
1033 size_t total_length = 0;
1034 int it = 0;
1035 while (splitresult[it]) {
1036 // n_log( LOG_DEBUG , "split entry %d: %s" , it , splitresult[ it ] );
1037 size_t entry_length = strlen(splitresult[it]);
1038 if (entry_length >= SIZE_MAX - total_length) {
1039 n_log(LOG_ERR, "join: total_length overflow accumulating entry %d", it);
1040 return NULL;
1041 }
1042 total_length += entry_length;
1043 // if there is a delimitor and 'it' isn't the last entry
1044 if (delim && splitresult[it + 1]) {
1045 if (delim_length >= SIZE_MAX - total_length) {
1046 n_log(LOG_ERR, "join: total_length overflow accumulating delimiter at entry %d", it);
1047 return NULL;
1048 }
1049 total_length += delim_length;
1050 }
1051 it++;
1052 }
1053 char* result = NULL;
1054 Malloc(result, char, total_length + 1);
1055 __n_assert(result, return NULL);
1056 size_t position = 0;
1057 it = 0;
1058 while (splitresult[it]) {
1059 size_t copy_size = strlen(splitresult[it]);
1060 memcpy(&result[position], splitresult[it], copy_size);
1061 position += copy_size;
1062 // if there is a delimitor and 'it' isn't the last entry
1063 if (delim && splitresult[it + 1]) {
1064 memcpy(&result[position], delim, delim_length);
1065 position += delim_length;
1066 }
1067 it++;
1068 }
1069 result[position] = '\0';
1070 return result;
1071} /* join */
1072
1081N_STR* nstrcat_ex(N_STR** dest, void* src, NSTRBYTE size, int resize_flag) {
1082 char* ptr = NULL;
1083 __n_assert(src, return NULL);
1084
1085 /* guard against size + 1 overflow (also protects new_nstr's internal +1). Must come before any arithmetic using size */
1086 if (size >= SIZE_MAX - 1) {
1087 n_log(LOG_ERR, "size too large in nstrcat_ex: %zu", size);
1088 return NULL;
1089 }
1090
1091 if (resize_flag == 0) {
1092 if ((*dest)) {
1093 /* check for written + size + 1 overflow before evaluating the expression */
1094 if (size > SIZE_MAX - (*dest)->written - 1) {
1095 n_log(LOG_ERR, "integer overflow in nstrcat_ex size calculation");
1096 return NULL;
1097 }
1098 if (((*dest)->written + size + 1) > (*dest)->length) {
1099 n_log(LOG_ERR, "%p to %p: not enough space. Resize forbidden. %zu needed, %zu available", src, (*dest), (*dest)->written + size + 1, (*dest)->length);
1100 return NULL;
1101 }
1102 } else {
1103 n_log(LOG_ERR, "%p to %p: not enough space. Resize forbidden. %zu needed, destination is NULL", src, (*dest), size + 1);
1104 return NULL;
1105 }
1106 }
1107
1108 if (!(*dest)) {
1109 (*dest) = new_nstr(size + 1);
1110 if (!(*dest)) {
1111 n_log(LOG_ERR, "could not allocate new N_STR of size %zu", size + 1);
1112 return NULL;
1113 }
1114 }
1115
1116 /* check for integer overflow before computing new size */
1117 if (size > SIZE_MAX - (*dest)->written - 1) {
1118 n_log(LOG_ERR, "integer overflow in nstrcat_ex size calculation");
1119 return NULL;
1120 }
1121
1122 if ((*dest)->length < (*dest)->written + size + 1) {
1123 (*dest)->length = (*dest)->written + size + 1;
1124 if (Reallocz((*dest)->data, char, (*dest)->written, (*dest)->length) == FALSE) {
1125 free_nstr(dest);
1126 return NULL;
1127 }
1128 }
1129
1130 ptr = (*dest)->data + (*dest)->written;
1131 memcpy(ptr, src, size);
1132 (*dest)->written += size;
1133
1134 (*dest)->data[(*dest)->written] = '\0';
1135
1136 return (*dest);
1137} /* nstrcat_ex( ... ) */
1138
1146N_STR* nstrcat_bytes_ex(N_STR** dest, void* data, NSTRBYTE size) {
1147 __n_assert(dest, return NULL);
1148
1149 if (size == 0) {
1150 n_log(LOG_ERR, "Could not copy 0 or less (%ld) octet!", size);
1151 return NULL;
1152 }
1153
1154 return nstrcat_ex(dest, data, size, 1);
1155} /* nstrcat_bytes_ex( ... )*/
1156
1167int write_and_fit_ex(char** dest, NSTRBYTE* size, NSTRBYTE* written, const char* src, NSTRBYTE src_size, NSTRBYTE additional_padding) {
1168 char* ptr = NULL;
1169 if (src_size == 0) return TRUE;
1170 NSTRBYTE needed_size = (*written) + src_size + 1;
1171
1172 // realloc if needed , also if destination is not allocated
1173 if ((needed_size >= (*size)) || !(*dest)) {
1174 if (!(*dest)) {
1175 (*written) = 0;
1176 (*size) = 0;
1177 }
1178 if (Reallocz((*dest), char, (*size), needed_size + additional_padding) == FALSE) {
1179 n_log(LOG_ERR, "reallocation error !!!!");
1180 return FALSE;
1181 }
1182 (*size) = needed_size;
1183 }
1184 ptr = (*dest) + (*written);
1185 memcpy(ptr, src, src_size);
1186 (*written) += src_size;
1187 (*dest)[(*written)] = '\0';
1188
1189 return TRUE;
1190} /* write_and_fit_ex( ...) */
1191
1200int write_and_fit(char** dest, NSTRBYTE* size, NSTRBYTE* written, const char* src) {
1201 return write_and_fit_ex(dest, size, written, src, strlen(src), 8);
1202} /* write_and_fit( ...) */
1203
1211int scan_dir(const char* dir, LIST* result, const int recurse) {
1212 return scan_dir_ex(dir, "*", result, recurse, 0);
1213}
1214
1224int scan_dir_ex(const char* dir, const char* pattern, LIST* result, const int recurse, const int mode) {
1225 DIR* dp = NULL;
1226 struct dirent* entry = NULL;
1227 struct stat statbuf;
1228
1229 if (!result)
1230 return FALSE;
1231
1232 if ((dp = opendir(dir)) == NULL) {
1233 n_log(LOG_ERR, "cannot open directory: %s", dir);
1234 return FALSE;
1235 }
1236
1237 N_STR* newname = NULL;
1238 while ((entry = readdir(dp)) != NULL) {
1239 if (!nstrprintf(newname, "%s/%s", dir, entry->d_name)) {
1240 n_log(LOG_ERR, "could not allocate newname for %s/%s", dir, entry->d_name);
1241 free_nstr(&newname);
1242 continue;
1243 }
1244
1245 if (stat(newname->data, &statbuf) >= 0) {
1246 if (S_ISDIR(statbuf.st_mode) != 0) {
1247 if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) {
1248 free_nstr(&newname);
1249 continue;
1250 }
1251
1252 /* Recurse */
1253 if (recurse != FALSE) {
1254 if (scan_dir_ex(newname->data, pattern, result, recurse, mode) != TRUE) {
1255 n_log(LOG_ERR, "scan_dir_ex( %s , %s , %p , %d , %d ) returned FALSE !", newname->data, pattern, result, recurse, mode);
1256 }
1257 }
1258 free_nstr(&newname);
1259 continue;
1260 } else if (S_ISREG(statbuf.st_mode) != 0) {
1261 if (wildmatcase(newname->data, pattern) == TRUE) {
1262 if (mode == 0) {
1263 char* file = strdup(newname->data);
1264 if (file) {
1265 list_push(result, file, &free);
1266 } else {
1267 n_log(LOG_ERR, "Error adding %s/%s to list", dir, entry->d_name);
1268 }
1269 } else if (mode == 1) {
1270 list_push(result, newname, &free_nstr_ptr);
1271 newname = NULL;
1272 }
1273 }
1274 }
1275 }
1276 if (newname)
1277 free_nstr(&newname);
1278 }
1279 closedir(dp);
1280 return TRUE;
1281} /*scan_dir(...) */
1282
1289int wildmat(register const char* text, register const char* p) {
1290 register int last = 0;
1291 register int matched = 0;
1292 register int reverse = 0;
1293
1294 for (; *p; text++, p++) {
1295 if (*text == '\0' && *p != '*')
1296 return WILDMAT_ABORT;
1297 switch (*p) {
1298 case '\\':
1299 /* Literal match with following character. */
1300 p++;
1301 /* FALLTHROUGH */
1302 default:
1303 if (*text != *p)
1304 return FALSE;
1305 continue;
1306 case '?':
1307 /* Match anything. */
1308 continue;
1309 case '*':
1310 while (*++p == '*')
1311 /* Consecutive stars act just like one. */
1312 ;
1313 if (*p == '\0')
1314 /* Trailing star matches everything. */
1315 return TRUE;
1316 while (*text)
1317 if ((matched = wildmat(text++, p)) != FALSE)
1318 return matched;
1319 return WILDMAT_ABORT;
1320 case '[':
1321 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
1322 if (reverse)
1323 /* Inverted character class. */
1324 p++;
1325 matched = FALSE;
1326 if (p[1] == ']' || p[1] == '-')
1327 if (*++p == *text)
1328 matched = TRUE;
1329 for (last = *p; *++p && *p != ']'; last = *p)
1330 /* This next line requires a good C compiler. */
1331 if (*p == '-' && p[1] != ']'
1332 ? *text <= *++p && *text >= last
1333 : *text == *p)
1334 matched = TRUE;
1335 if (matched == reverse)
1336 return FALSE;
1337 continue;
1338 }
1339 }
1340#ifdef WILDMAT_MATCH_TAR_PATTERN
1341 if (*text == '/')
1342 return TRUE;
1343#endif /* MATCH_TAR_ATTERN */
1344 return *text == '\0';
1345} /* wildmatch(...) */
1346
1353int wildmatcase(register const char* text, register const char* p) {
1354 register int last;
1355 register int matched;
1356 register int reverse;
1357
1358 for (; *p; text++, p++) {
1359 if (*text == '\0' && *p != '*')
1360 return WILDMAT_ABORT;
1361 switch (*p) {
1362 case '\\':
1363 /* Literal match with following character. */
1364 p++;
1365 /* FALLTHROUGH */
1366 default:
1367 if (toupper(*text) != toupper(*p))
1368 return FALSE;
1369 continue;
1370 case '?':
1371 /* Match anything. */
1372 continue;
1373 case '*':
1374 while (*++p == '*')
1375 /* Consecutive stars act just like one. */
1376 ;
1377 if (*p == '\0')
1378 /* Trailing star matches everything. */
1379 return TRUE;
1380 while (*text)
1381 if ((matched = wildmatcase(text++, p)) != FALSE)
1382 return matched;
1383 return WILDMAT_ABORT;
1384 case '[':
1385 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
1386 if (reverse)
1387 /* Inverted character class. */
1388 p++;
1389 matched = FALSE;
1390 if (p[1] == ']' || p[1] == '-')
1391 if (toupper(*++p) == toupper(*text))
1392 matched = TRUE;
1393 for (last = toupper(*p); *++p && *p != ']'; last = toupper(*p))
1394 if (*p == '-' && p[1] != ']'
1395 ? toupper(*text) <= toupper(*++p) && toupper(*text) >= last
1396 : toupper(*text) == toupper(*p))
1397 matched = TRUE;
1398 if (matched == reverse)
1399 return FALSE;
1400 continue;
1401 }
1402 }
1403#ifdef WILDMAT_MATCH_TAR_PATTERN
1404 if (*text == '/')
1405 return TRUE;
1406#endif /* MATCH_TAR_ATTERN */
1407 return *text == '\0';
1408} /* wildmatcase(...) */
1409
1419char* str_replace(const char* string, const char* substr, const char* replacement) {
1420 const char* tok = NULL;
1421 char* newstr = NULL;
1422 char* head = NULL;
1423
1424 if (substr == NULL || substr[0] == '\0' || replacement == NULL)
1425 return strdup(string);
1426
1427 size_t substr_len = strlen(substr);
1428 size_t replacement_len = strlen(replacement);
1429
1430 newstr = strdup(string);
1431 if (!newstr) return NULL;
1432 head = newstr;
1433 while ((tok = strstr(head, substr))) {
1434 char* oldstr = newstr;
1435 size_t oldstr_len = strlen(oldstr);
1436 size_t base_len = oldstr_len - substr_len;
1437 /* Prevent size_t overflow in allocation size calculation */
1438 if (base_len > SIZE_MAX - 8 ||
1439 replacement_len > SIZE_MAX - base_len - 8) {
1440 n_log(LOG_ERR, "str_replace: allocation size overflow (base_len=%zu, replacement_len=%zu)", base_len, replacement_len);
1441 free(oldstr);
1442 return NULL;
1443 }
1444 size_t newlen = base_len + replacement_len + 8;
1445 Malloc(newstr, char, newlen);
1446 /*failed to alloc mem, free old string and return NULL */
1447 if (newstr == NULL) {
1448 n_log(LOG_ERR, "str_replace: could not allocate newstr of size %zu", newlen);
1449 free(oldstr);
1450 return NULL;
1451 }
1452 memcpy(newstr, oldstr, (size_t)(tok - oldstr));
1453 memcpy(newstr + (tok - oldstr), replacement, replacement_len);
1454 memcpy(newstr + (tok - oldstr) + replacement_len, tok + substr_len, oldstr_len - substr_len - (size_t)(tok - oldstr));
1455 memset(newstr + oldstr_len - substr_len + replacement_len, 0, 1);
1456 /* move back head right after the last replacement */
1457 head = newstr + (tok - oldstr) + replacement_len;
1458 free(oldstr);
1459 }
1460 return newstr;
1461}
1462
1472int str_sanitize_ex(char* string, const NSTRBYTE string_len, const char* mask, const NSTRBYTE masklen, const char replacement) {
1473 __n_assert(string, return FALSE);
1474 __n_assert(mask, return FALSE);
1475
1476 NSTRBYTE it = 0;
1477 for (it = 0; it < string_len; it++) {
1478 NSTRBYTE mask_it = 0;
1479 while (mask_it < masklen && mask[mask_it] != '\0') {
1480 if (string[it] == mask[mask_it])
1481 string[it] = replacement;
1482 mask_it++;
1483 }
1484 }
1485 return TRUE;
1486}
1487
1495int str_sanitize(char* string, const char* mask, const char replacement) {
1496 return str_sanitize_ex(string, strlen(string), mask, strlen(mask), replacement);
1497}
1498
1505int resize_nstr(N_STR* nstr, size_t size) {
1506 __n_assert(nstr, return FALSE);
1507 if (size == 0) {
1508 // Free the current buffer and reset fields
1509 Free(nstr->data);
1510 nstr->written = 0;
1511 nstr->length = 0;
1512 return TRUE;
1513 }
1514
1515 if (!nstr->data) {
1516 Malloc(nstr->data, char, size);
1517 __n_assert(nstr->data, return FALSE);
1518 } else {
1519 if (Reallocz(nstr->data, char, nstr->length, size) == FALSE) {
1520 return FALSE;
1521 }
1522 }
1523
1524 nstr->length = size;
1525
1526 return TRUE;
1527}
1528
1536N_STR* nstrprintf_ex(N_STR** nstr_var, const char* format, ...) {
1537 __n_assert(format, return NULL);
1538
1539 va_list args;
1540 va_list args_copy;
1541 int needed_size = 0;
1542
1543 // Calculate the required size for the formatted string
1544 va_start(args, format);
1545 va_copy(args_copy, args); // Copy args for reuse
1546 needed_size = vsnprintf(NULL, 0, format, args);
1547 va_end(args);
1548
1549 if (needed_size < 0) {
1550 va_end(args_copy);
1551 n_log(LOG_ERR, "there was an error while computing the new size according to format \"%s\" for N_STR %p", format, (*nstr_var));
1552 return NULL;
1553 }
1554
1555 size_t needed = (size_t)(needed_size + 1); // Include null-terminator
1556
1557 // Allocate or resize the N_STR object as needed
1558 if (!(*nstr_var)) {
1559 (*nstr_var) = new_nstr(needed);
1560 if (!(*nstr_var) || !(*nstr_var)->data) {
1561 va_end(args_copy);
1562 n_log(LOG_ERR, "could not allocate N_STR of size %zu", needed);
1563 return NULL;
1564 }
1565 } else if (needed > (*nstr_var)->length) {
1566 if (resize_nstr((*nstr_var), needed) == FALSE) {
1567 va_end(args_copy);
1568 n_log(LOG_ERR, "could not resize N_STR %p to size %zu", (*nstr_var), needed);
1569 return NULL;
1570 }
1571 }
1572
1573 // Write the formatted string into the buffer
1574 vsnprintf((*nstr_var)->data, needed, format, args_copy);
1575 va_end(args_copy);
1576
1577 (*nstr_var)->written = (size_t)needed_size;
1578 return (*nstr_var);
1579}
1580
1588N_STR* nstrprintf_cat_ex(N_STR** nstr_var, const char* format, ...) {
1589 __n_assert(format, return NULL);
1590
1591 va_list args;
1592 va_start(args, format);
1593
1594 // duplicate va_list
1595 va_list args_copy;
1596 va_copy(args_copy, args);
1597
1598 // compute needed size
1599 int needed_size = vsnprintf(NULL, 0, format, args_copy);
1600 va_end(args_copy);
1601
1602 if (needed_size < 0) {
1603 n_log(LOG_ERR, "vsnprintf size estimation failed for format \"%s\"", format);
1604 va_end(args);
1605 return NULL;
1606 }
1607
1608 size_t needed = (size_t)(needed_size + 1); // +1 for '\0'
1609
1610 // initialize if needed
1611 if (!(*nstr_var)) {
1612 (*nstr_var) = new_nstr(needed);
1613 if (!(*nstr_var)) {
1614 va_end(args);
1615 return NULL;
1616 }
1617 }
1618
1619 // check for overflow before computing total_needed
1620 if (needed > SIZE_MAX - (*nstr_var)->written) {
1621 va_end(args);
1622 n_log(LOG_ERR, "integer overflow computing total_needed in nstrprintf_cat_ex");
1623 return NULL;
1624 }
1625
1626 // resize if needed
1627 size_t total_needed = (*nstr_var)->written + needed;
1628 if (total_needed > (*nstr_var)->length) {
1629 if (resize_nstr((*nstr_var), total_needed) == FALSE) {
1630 va_end(args);
1631 n_log(LOG_ERR, "could not resize N_STR %p to size %zu", (*nstr_var), total_needed);
1632 return NULL;
1633 }
1634 }
1635
1636 // append formatted string
1637 char* write_ptr = (*nstr_var)->data + (*nstr_var)->written;
1638 int written_now = vsnprintf(write_ptr, needed, format, args);
1639 va_end(args);
1640
1641 if (written_now < 0) {
1642 n_log(LOG_ERR, "vsnprintf failed while writing at offset %zu in N_STR %p", (*nstr_var)->written, (*nstr_var));
1643 return NULL;
1644 }
1645
1646 (*nstr_var)->written += (size_t)written_now;
1647 (*nstr_var)->data[(*nstr_var)->written] = '\0'; // ensure final \0
1648
1649 return *nstr_var;
1650}
1651
1652N_STR* n_str_template_expand(const char* tmpl, HASH_TABLE* vars) {
1653 if (!tmpl) return NULL;
1654 N_STR* result = new_nstr(strlen(tmpl) + 256);
1655 if (!result) return NULL;
1656 const char* p = tmpl;
1657 while (*p) {
1658 if (p[0] == '{' && p[1] == '{') {
1659 const char* end = strstr(p + 2, "}}");
1660 if (end) {
1661 size_t klen = (size_t)(end - (p + 2));
1662 char key[256];
1663 if (klen < sizeof(key)) {
1664 memcpy(key, p + 2, klen);
1665 key[klen] = '\0';
1666 char* val = NULL;
1667 if (vars && ht_get_string(vars, key, &val) == TRUE && val) {
1668 nstrprintf_cat(result, "%s", val);
1669 } else {
1670 nstrprintf_cat(result, "{{%s}}", key);
1671 }
1672 p = end + 2;
1673 continue;
1674 }
1675 }
1676 }
1677 char ch[2] = {*p, '\0'};
1678 nstrprintf_cat(result, "%s", ch);
1679 p++;
1680 }
1681 return result;
1682}
1683
1684#endif /* #ifndef NOSTR */
static int mode
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:271
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define _str(__PTR)
define true
Definition n_common.h:192
#define Reallocz(__ptr, __struct, __old_size, __size)
Realloc + zero new memory zone Handler to get errors.
Definition n_common.h:246
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:262
int ht_get_string(HASH_TABLE *table, const char *key, char **val)
get string at 'key' from 'table'
Definition n_hash.c:2113
structure of a hash table
Definition n_hash.h:137
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:227
Structure of a generic LIST container.
Definition n_list.h:58
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_DEBUG
debug-level messages
Definition n_log.h:83
#define LOG_ERR
error conditions
Definition n_log.h:75
size_t written
size of the written data inside the string
Definition n_str.h:66
char * data
the string
Definition n_str.h:62
size_t length
length of string (in case we wanna keep information after the 0 end of string value)
Definition n_str.h:64
int str_to_long_long(const char *s, long long int *i, const int base)
Helper for string to integer.
Definition n_str.c:695
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:1652
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:122
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:69
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:1588
size_t NSTRBYTE
N_STR base unit.
Definition n_str.h:57
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:201
int split_count(char **split_result)
Count split elements.
Definition n_str.c:992
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:1472
int nstr_to_file(N_STR *str, char *filename)
Write a N_STR content into a file.
Definition n_str.c:416
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:1224
int strcpy_u(const char *from, char *to, NSTRBYTE to_size, char split, NSTRBYTE *it)
Copy from start to dest until from[ iterator ] == split.
Definition n_str.c:876
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:623
char * join(char **splitresult, const char *delim)
join the array into a string
Definition n_str.c:1029
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition n_str.c:708
int strlo(const char *string, char *dest)
Lower case a string.
Definition n_str.c:853
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:1081
int write_and_fit(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src)
concatenate a copy of src of size strlen( src ) to dest, starting at dest[ written ],...
Definition n_str.c:1200
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
Definition n_str.h:119
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:454
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:502
int resize_nstr(N_STR *nstr, size_t size)
reallocate a nstr internal buffer.
Definition n_str.c:1505
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:254
char * nfgets(char *buffer, NSTRBYTE size, FILE *stream)
try to fgets
Definition n_str.c:170
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:786
#define WILDMAT_ABORT
Abort code to sped up pattern matching.
Definition n_str.h:70
int empty_nstr(N_STR *nstr)
empty a N_STR string
Definition n_str.c:191
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:1353
#define WILDMAT_NEGATE_CLASS
What character marks an inverted character class?
Definition n_str.h:72
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:206
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:1419
char * trim(const char *s)
trim and put a \0 at the end, return new char *
Definition n_str.c:151
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:739
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
Definition n_str.h:115
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:1146
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:1211
int str_sanitize(char *string, const char *mask, const char replacement)
clean a string by replacing evil characteres
Definition n_str.c:1495
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:912
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:1289
int free_nstr_nolog(N_STR **ptr)
Free a N_STR structure and set the pointer to NULL.
Definition n_str.c:96
int str_to_long(const char *s, long int *i, const int base)
Helper for string to integer.
Definition n_str.c:680
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:231
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:267
int _free_nstr(N_STR **ptr)
Free a N_STR structure and set the pointer to NULL.
Definition n_str.c:82
int write_and_fit_ex(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src, NSTRBYTE src_size, NSTRBYTE additional_padding)
concatenate a copy of src of size src_size to dest, starting at dest[ written ], updating written and...
Definition n_str.c:1167
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
Definition n_str.c:286
int free_split_result(char ***tab)
Free a split result allocated array.
Definition n_str.c:1008
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:1536
void free_nstr_ptr_nolog(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:109
int str_to_int(const char *s, int *i, const int base)
Helper for string to integer.
Definition n_str.c:545
int nstr_to_fd(N_STR *str, FILE *out, int lock)
Write a N_STR content into a file.
Definition n_str.c:363
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:564
int strup(const char *string, char *dest)
Upper case a string.
Definition n_str.c:832
A box including a string and his lenght.
Definition n_str.h:60
Common headers and low-level functions & define.
Hash functions and table.
Generic log system.
N_STR and string function declaration.