34 char* chardest = NULL;
39 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
41 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
43 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
45 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
47 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
49 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
55 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
57 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
59 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
61 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
63 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
65 n_log(
LOG_INFO,
"charstr (%zu/%zu): %s", written, length, chardest);
73 nstrprintf(nstr,
"Hello, file is %s line %d date %s", __FILE__, __LINE__, __TIME__);
77 nstrprintf_cat(nstr,
" - This will be added at file %s line %d date %s", __FILE__, __LINE__, __TIME__);
87 nstrprintf(nstr,
"Hello, file is %s line %d date %s", __FILE__, __LINE__, __TIME__);
91 nstrprintf_cat(nstr,
" - This will be added at file %s line %d date %s", __FILE__, __LINE__, __TIME__);
122 char data[1048576] =
"";
124 for (
int it = 0; it < 1048575; it++) {
125 data[it] = (char)(32 + rand() % 63);
127 data[1048574] =
'\0';
129 for (
int it = 0; it < 100; it++) {
143 char* trimmed =
trim(
" spaces around ");
149 char trimbuf[] =
" hello ";
159 if (
str_to_long(
"9876543210", &lval, 10) == TRUE) {
162 long long int llval = 0;
170 strup(
"hello world", upper);
172 strlo(
"HELLO WORLD", lower);
176 char** parts =
split(
"one:two:three:four",
":", 0);
180 for (
int it = 0; it < count; it++) {
183 char* joined =
join(parts,
" - ");
198 const char* ordered[] = {
"",
"1",
"01",
"2",
"10",
"a",
"A2",
199 "a10",
"a010",
"b",
"img2.cr3",
"IMG10.cr3",
"img10x",
"photo 9",
200 "photo 10",
"x99999999999999999999",
"x100000000000000000000"};
201 size_t n =
sizeof(ordered) /
sizeof(ordered[0]);
204 for (k = 0; k < n; k++) {
205 for (m = 0; m < n; m++) {
207 int want = k < m ? -1 : (k > m ? 1 : 0);
209 if ((got < 0 ? -1 : (got > 0 ? 1 : 0)) != want) {
210 n_log(
LOG_ERR,
"FAIL: str_natcasecmp(\"%s\", \"%s\") gave %d, not %d", ordered[k], ordered[m], got,
219 n_log(
LOG_ERR,
"FAIL: str_natcasecmp with NULL, case-only differences or bounded lengths");
222 n_log(
LOG_INFO,
"PASS: str_natcasecmp orders %zu strings naturally", n);
227 static const struct {
230 const char* replacement;
231 const char* expected;
233 {
"hello world hello",
"hello",
"bye",
"bye world bye"},
234 {
"aaa",
"a",
"aa",
"aaaaaa"},
235 {
"aaaa",
"aa",
"b",
"bb"},
236 {
"abcabc",
"abc",
"",
""},
237 {
"nothing here",
"xyz",
"q",
"nothing here"},
239 {
"a=b=c",
"=",
" ",
"a b c"},
240 {
"line\r\nnext\r\n",
"\r",
"",
"line\nnext\n"},
241 {
"same",
"",
"x",
"same"},
245 for (k = 0; k <
sizeof(cases) /
sizeof(cases[0]); k++) {
246 char* replaced =
str_replace(cases[k].
string, cases[k].substr, cases[k].replacement);
248 if (!replaced || strcmp(replaced, cases[k].expected) != 0) {
249 n_log(
LOG_ERR,
"FAIL: str_replace(\"%s\", \"%s\", \"%s\") gave \"%s\", not \"%s\"", cases[k].
string,
250 cases[k].substr, cases[k].replacement, replaced ? replaced :
"(null)", cases[k].expected);
259 if (!replaced || strcmp(replaced,
"keep") != 0 ||
str_replace(NULL,
"a",
"b") != NULL) {
260 n_log(
LOG_ERR,
"FAIL: str_replace with a NULL argument");
266 n_log(
LOG_INFO,
"str_replace: %zu cases ok",
sizeof(cases) /
sizeof(cases[0]));
270 char sanitize_buf[] =
"hello; rm -rf /";
286 FILE* empty_fp = fopen(
"nilorea_nstr_empty.txt",
"wb");
290 if (empty_content && empty_content->
data && empty_content->
written == 0)
291 n_log(
LOG_INFO,
"file_to_nstr on an empty file: OK (empty string, no error)");
293 n_log(
LOG_ERR,
"file_to_nstr on an empty file: FAILED (expected an empty N_STR)");
298 char skipbuf[] =
" hello";
300 skipw(skipbuf,
' ', &it, 1);
301 n_log(
LOG_INFO,
"skipw past spaces: pos=%zu char='%c'", it, skipbuf[it]);
303 skipu(skipbuf,
'h', &it, 1);
304 n_log(
LOG_INFO,
"skipu to 'h': pos=%zu char='%c'", it, skipbuf[it]);
315 if (
scan_dir(
".", dir_list, 0) == TRUE) {
321 int url_encode_errors = 0;
325 if (encoded != NULL) {
326 n_log(
LOG_ERR,
"FAIL: n_str_url_encode(NULL) expected NULL, got \"%s\"",
_nstr(encoded));
335 if (!encoded || strcmp(
_nstr(encoded),
"") != 0) {
336 n_log(
LOG_ERR,
"FAIL: n_str_url_encode(\"\") expected \"\", got \"%s\"", encoded ?
_nstr(encoded) :
"NULL");
345 if (!encoded || strcmp(
_nstr(encoded),
"Hello-World_1.0~") != 0) {
346 n_log(
LOG_ERR,
"FAIL: n_str_url_encode(\"Hello-World_1.0~\") expected verbatim, got \"%s\"", encoded ?
_nstr(encoded) :
"NULL");
349 n_log(
LOG_INFO,
"PASS: n_str_url_encode(\"Hello-World_1.0~\") == \"Hello-World_1.0~\"");
355 const char* expected_reserved =
"foo%20bar%26baz%3Dqux%2Fpath%3Fq%3D1%23frag";
356 if (!encoded || strcmp(
_nstr(encoded), expected_reserved) != 0) {
357 n_log(
LOG_ERR,
"FAIL: n_str_url_encode(reserved chars) expected \"%s\", got \"%s\"", expected_reserved, encoded ?
_nstr(encoded) :
"NULL");
360 n_log(
LOG_INFO,
"PASS: n_str_url_encode(\"foo bar&baz=qux/path?q=1#frag\") == \"%s\"", expected_reserved);
366 if (!encoded || strcmp(
_nstr(encoded),
"%C3%A9%FF") != 0) {
367 n_log(
LOG_ERR,
"FAIL: n_str_url_encode(high bytes) expected \"%s\", got \"%s\"",
"%C3%A9%FF", encoded ?
_nstr(encoded) :
"NULL");
370 n_log(
LOG_INFO,
"PASS: n_str_url_encode(\"\\xC3\\xA9\\xFF\") == \"%s\"",
"%C3%A9%FF");
374 if (url_encode_errors > 0) {
375 n_log(
LOG_ERR,
"n_str_url_encode: %d test(s) failed", url_encode_errors);
381#define UTF8_V(str, ok) {str, sizeof(str) - 1, ok}
382 static const struct {
389 UTF8_V(
"caf\xc3\xa9 \xe2\x82\xac \xf0\x9f\x98\x80", 1),
390 UTF8_V(
"\xf4\x8f\xbf\xbf", 1),
394 UTF8_V(
"\xe0\x80\xaf", 0),
395 UTF8_V(
"\xf0\x80\x80\xaf", 0),
396 UTF8_V(
"\xed\xa0\x80", 0),
397 UTF8_V(
"\xf4\x90\x80\x80", 0),
399 UTF8_V(
"\xf5\x80\x80\x80", 0),
403 for (k = 0; k <
sizeof(u) /
sizeof(u[0]); k++) {
422 if (wrapped != NULL) {
423 n_log(
LOG_ERR,
"FAIL: new_nstr(NSTRBYTE max) returned a string instead of NULL");
427 n_log(
LOG_INFO,
"PASS: new_nstr(NSTRBYTE max) refused (terminator would wrap the allocation)");
435 n_log(
LOG_ERR,
"FAIL: new_nstr(16) did not return a 16-byte string");
439 memset(ok->
data,
'x', 16);
442 if (strlen(ok->
data) != 16) {
443 n_log(
LOG_ERR,
"FAIL: new_nstr(16) left no room for the terminator");
447 n_log(
LOG_INFO,
"PASS: new_nstr(16) holds 16 bytes plus its terminator");
#define Free(__ptr)
Free Handler to get errors.
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
size_t nb_items
number of item currently in the list
int list_destroy(LIST **list)
Empty and Free a list container.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Structure of a generic LIST container.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_INFO
informational
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
size_t length
total allocation (in bytes) of the data buffer, padding included
int str_to_long_long(const char *s, long long int *i, const int base)
Helper for string to integer.
char * trim_nocopy(char *s)
trim and zero end the string, WARNING: keep and original pointer to delete the string correctly
N_STR * n_str_url_encode(const char *src)
Percent-encode a C string per RFC 3986 (unreserved set kept as-is).
size_t NSTRBYTE
N_STR base unit.
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
int split_count(char **split_result)
Count split elements.
int str_natncasecmp(const char *a, size_t alen, const char *b, size_t blen)
Compare two byte runs in natural order, ignoring ASCII case.
int nstr_to_file(N_STR *str, char *filename)
Write a N_STR content into a file.
char * join(char **splitresult, const char *delim)
join the array into a string
#define nstrcat(__nstr_dst, __nstr_src)
Macro to quickly concatenate two N_STR.
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
int strlo(const char *string, char *dest)
Lower case a string.
int write_and_fit(char **dest, NSTRBYTE *size, NSTRBYTE *written, const char *src)
Append src to *dest.
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
int resize_nstr(N_STR *nstr, size_t size)
reallocate a nstr internal buffer.
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
int skipu(const char *string, char toskip, NSTRBYTE *iterator, int inc)
skip until 'toskip' occurence is found from 'iterator' to the next 'toskip' value.
int empty_nstr(N_STR *nstr)
empty a N_STR string
int wildmatcase(register const char *text, register const char *p)
Written by Rich Salz rsalz at osf.org, refurbished by me.
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
char * str_replace(const char *string, const char *substr, const char *replacement)
Replace every occurrence of substr by replacement in a copy of string.
char * trim(const char *s)
trim and put a \0 at the end, return new char *
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.
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
int str_natcasecmp(const char *a, const char *b)
Compare two strings in natural order, ignoring ASCII case.
int scan_dir(const char *dir, LIST *result, const int recurse)
Scan a list of directory and return a list of char *file.
int str_sanitize(char *string, const char *mask, const char replacement)
clean a string by replacing evil characteres
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.
int wildmat(register const char *text, register const char *p)
Written by Rich Salz rsalz at osf.org, refurbished by me.
int str_to_long(const char *s, long int *i, const int base)
Helper for string to integer.
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.
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
int free_split_result(char ***tab)
Free a split result allocated array.
int str_to_int(const char *s, int *i, const int base)
Helper for string to integer.
int n_str_utf8_valid(const char *s, size_t len)
Test that [s, s+len) is well-formed UTF-8 (RFC 3629): no overlong form, no surrogate,...
int strup(const char *string, char *dest)
Upper case a string.
A box including a string and his lenght.
N_STR and string function declaration.