Improve string util API

Use prefixed names and improve documentation.
This commit is contained in:
Romain Vimont 2021-11-12 23:08:19 +01:00
parent 9a0bd545d5
commit 979ce64dc0
12 changed files with 169 additions and 134 deletions

View file

@ -190,11 +190,11 @@ adb_push(const char *serial, const char *local, const char *remote) {
#ifdef __WINDOWS__
// Windows will parse the string, so the paths must be quoted
// (see sys/win/command.c)
local = strquote(local);
local = sc_str_quote(local);
if (!local) {
return SC_PROCESS_NONE;
}
remote = strquote(remote);
remote = sc_str_quote(remote);
if (!remote) {
free((void *) local);
return SC_PROCESS_NONE;
@ -217,7 +217,7 @@ adb_install(const char *serial, const char *local) {
#ifdef __WINDOWS__
// Windows will parse the string, so the local name must be quoted
// (see sys/win/command.c)
local = strquote(local);
local = sc_str_quote(local);
if (!local) {
return SC_PROCESS_NONE;
}

View file

@ -779,9 +779,9 @@ parse_integer_arg(const char *s, long *out, bool accept_suffix, long min,
long value;
bool ok;
if (accept_suffix) {
ok = parse_integer_with_suffix(s, &value);
ok = sc_str_parse_integer_with_suffix(s, &value);
} else {
ok = parse_integer(s, &value);
ok = sc_str_parse_integer(s, &value);
}
if (!ok) {
LOGE("Could not parse %s: %s", name, s);
@ -801,7 +801,7 @@ parse_integer_arg(const char *s, long *out, bool accept_suffix, long min,
static size_t
parse_integers_arg(const char *s, size_t max_items, long *out, long min,
long max, const char *name) {
size_t count = parse_integers(s, ':', max_items, out);
size_t count = sc_str_parse_integers(s, ':', max_items, out);
if (!count) {
LOGE("Could not parse %s: %s", name, s);
return 0;

View file

@ -66,7 +66,7 @@ write_position(uint8_t *buf, const struct sc_position *position) {
// write length (2 bytes) + string (non nul-terminated)
static size_t
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
size_t len = utf8_truncation_index(utf8, max_len);
size_t len = sc_str_utf8_truncation_index(utf8, max_len);
buffer_write32be(buf, len);
memcpy(&buf[4], utf8, len);
return 4 + len;

View file

@ -26,7 +26,7 @@ get_icon_path(void) {
if (icon_path_env) {
// if the envvar is set, use it
#ifdef __WINDOWS__
char *icon_path = utf8_from_wide_char(icon_path_env);
char *icon_path = sc_str_from_wchars(icon_path_env);
#else
char *icon_path = strdup(icon_path_env);
#endif

View file

@ -26,7 +26,7 @@ find_muxer(const char *name) {
oformat = av_oformat_next(oformat);
#endif
// until null or containing the requested name
} while (oformat && !strlist_contains(oformat->name, ',', name));
} while (oformat && !sc_str_list_contains(oformat->name, ',', name));
return oformat;
}

View file

@ -29,7 +29,7 @@ get_server_path(void) {
if (server_path_env) {
// if the envvar is set, use it
#ifdef __WINDOWS__
char *server_path = utf8_from_wide_char(server_path_env);
char *server_path = sc_str_from_wchars(server_path_env);
#else
char *server_path = strdup(server_path_env);
#endif

View file

@ -19,12 +19,12 @@ sc_file_get_executable_path(void) {
return NULL;
}
buf[len] = '\0';
return utf8_from_wide_char(buf);
return sc_str_from_wchars(buf);
}
bool
sc_file_is_regular(const char *path) {
wchar_t *wide_path = utf8_to_wide_char(path);
wchar_t *wide_path = sc_str_to_wchars(path);
if (!wide_path) {
LOGC("Could not allocate wide char string");
return false;

View file

@ -13,7 +13,7 @@ build_cmd(char *cmd, size_t len, const char *const argv[]) {
// <http://daviddeley.com/autohotkey/parameters/parameters.htm#WINPASS>
// only make it work for this very specific program
// (don't handle escaping nor quotes)
size_t ret = xstrjoin(cmd, argv, ' ', len);
size_t ret = sc_str_join(cmd, argv, ' ', len);
if (ret >= len) {
LOGE("Command too long (%" SC_PRIsizet " chars)", len - 1);
return false;
@ -88,7 +88,7 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle,
goto error_close_stderr;
}
wchar_t *wide = utf8_to_wide_char(cmd);
wchar_t *wide = sc_str_to_wchars(cmd);
free(cmd);
if (!wide) {
LOGC("Could not allocate wide char string");

View file

@ -13,7 +13,7 @@
#endif
size_t
xstrncpy(char *dest, const char *src, size_t n) {
sc_strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n - 1 && src[i] != '\0'; ++i)
dest[i] = src[i];
@ -23,7 +23,7 @@ xstrncpy(char *dest, const char *src, size_t n) {
}
size_t
xstrjoin(char *dst, const char *const tokens[], char sep, size_t n) {
sc_str_join(char *dst, const char *const tokens[], char sep, size_t n) {
const char *const *remaining = tokens;
const char *token = *remaining++;
size_t i = 0;
@ -33,7 +33,7 @@ xstrjoin(char *dst, const char *const tokens[], char sep, size_t n) {
if (i == n)
goto truncated;
}
size_t w = xstrncpy(dst + i, token, n - i);
size_t w = sc_strncpy(dst + i, token, n - i);
if (w >= n - i)
goto truncated;
i += w;
@ -47,7 +47,7 @@ truncated:
}
char *
strquote(const char *src) {
sc_str_quote(const char *src) {
size_t len = strlen(src);
char *quoted = malloc(len + 3);
if (!quoted) {
@ -61,7 +61,7 @@ strquote(const char *src) {
}
bool
parse_integer(const char *s, long *out) {
sc_str_parse_integer(const char *s, long *out) {
char *endptr;
if (*s == '\0') {
return false;
@ -80,7 +80,8 @@ parse_integer(const char *s, long *out) {
}
size_t
parse_integers(const char *s, const char sep, size_t max_items, long *out) {
sc_str_parse_integers(const char *s, const char sep, size_t max_items,
long *out) {
size_t count = 0;
char *endptr;
do {
@ -109,7 +110,7 @@ parse_integers(const char *s, const char sep, size_t max_items, long *out) {
}
bool
parse_integer_with_suffix(const char *s, long *out) {
sc_str_parse_integer_with_suffix(const char *s, long *out) {
char *endptr;
if (*s == '\0') {
return false;
@ -143,7 +144,7 @@ parse_integer_with_suffix(const char *s, long *out) {
}
bool
strlist_contains(const char *list, char sep, const char *s) {
sc_str_list_contains(const char *list, char sep, const char *s) {
char *p;
do {
p = strchr(list, sep);
@ -161,7 +162,7 @@ strlist_contains(const char *list, char sep, const char *s) {
}
size_t
utf8_truncation_index(const char *utf8, size_t max_len) {
sc_str_utf8_truncation_index(const char *utf8, size_t max_len) {
size_t len = strlen(utf8);
if (len <= max_len) {
return len;
@ -179,7 +180,7 @@ utf8_truncation_index(const char *utf8, size_t max_len) {
#ifdef _WIN32
wchar_t *
utf8_to_wide_char(const char *utf8) {
sc_str_to_wchars(const char *utf8) {
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
if (!len) {
return NULL;
@ -195,7 +196,7 @@ utf8_to_wide_char(const char *utf8) {
}
char *
utf8_from_wide_char(const wchar_t *ws) {
sc_str_from_wchars(const wchar_t *ws) {
int len = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL);
if (!len) {
return NULL;
@ -212,7 +213,8 @@ utf8_from_wide_char(const wchar_t *ws) {
#endif
char *sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent) {
char *
sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent) {
assert(indent < columns);
struct sc_strbuf buf;

View file

@ -1,65 +1,97 @@
#ifndef STRUTIL_H
#define STRUTIL_H
#ifndef SC_STRUTIL_H
#define SC_STRUTIL_H
#include "common.h"
#include <stdbool.h>
#include <stddef.h>
// like strncpy, except:
// - it copies at most n-1 chars
// - the dest string is nul-terminated
// - it does not write useless bytes if strlen(src) < n
// - it returns the number of chars actually written (max n-1) if src has
// been copied completely, or n if src has been truncated
/**
* Like strncpy(), except:
* - it copies at most n-1 chars
* - the dest string is nul-terminated
* - it does not write useless bytes if strlen(src) < n
* - it returns the number of chars actually written (max n-1) if src has
* been copied completely, or n if src has been truncated
*/
size_t
xstrncpy(char *dest, const char *src, size_t n);
sc_strncpy(char *dest, const char *src, size_t n);
// join tokens by sep into dst
// returns the number of chars actually written (max n-1) if no truncation
// occurred, or n if truncated
/**
* Join tokens by separator `sep` into `dst`
*
* Return the number of chars actually written (max n-1) if no truncation
* occurred, or n if truncated.
*/
size_t
xstrjoin(char *dst, const char *const tokens[], char sep, size_t n);
sc_str_join(char *dst, const char *const tokens[], char sep, size_t n);
// quote a string
// returns the new allocated string, to be freed by the caller
/**
* Quote a string
*
* Return a new allocated string, surrounded with quotes (`"`).
*/
char *
strquote(const char *src);
sc_str_quote(const char *src);
// parse s as an integer into value
// returns true if the conversion succeeded, false otherwise
/**
* Parse `s` as an integer into `out`
*
* Return true if the conversion succeeded, false otherwise.
*/
bool
parse_integer(const char *s, long *out);
sc_str_parse_integer(const char *s, long *out);
// parse s as integers separated by sep (for example '1234:2000')
// returns the number of integers on success, 0 on failure
/**
* Parse `s` as integers separated by `sep` (for example `1234:2000`) into `out`
*
* Returns the number of integers on success, 0 on failure.
*/
size_t
parse_integers(const char *s, const char sep, size_t max_items, long *out);
sc_str_parse_integers(const char *s, const char sep, size_t max_items,
long *out);
// parse s as an integer into value
// like parse_integer(), but accept 'k'/'K' (x1000) and 'm'/'M' (x1000000) as
// suffix
// returns true if the conversion succeeded, false otherwise
/**
* Parse `s` as an integer into `out`
*
* Like `sc_str_parse_integer()`, but accept 'k'/'K' (x1000) and 'm'/'M'
* (x1000000) as suffixes.
*
* Return true if the conversion succeeded, false otherwise.
*/
bool
parse_integer_with_suffix(const char *s, long *out);
sc_str_parse_integer_with_suffix(const char *s, long *out);
// search s in the list separated by sep
// for example, strlist_contains("a,bc,def", ',', "bc") returns true
/**
* Search `s` in the list separated by `sep`
*
* For example, sc_str_list_contains("a,bc,def", ',', "bc") returns true.
*/
bool
strlist_contains(const char *list, char sep, const char *s);
sc_str_list_contains(const char *list, char sep, const char *s);
// return the index to truncate a UTF-8 string at a valid position
/**
* Return the index to truncate a UTF-8 string at a valid position
*/
size_t
utf8_truncation_index(const char *utf8, size_t max_len);
sc_str_utf8_truncation_index(const char *utf8, size_t max_len);
#ifdef _WIN32
// convert a UTF-8 string to a wchar_t string
// returns the new allocated string, to be freed by the caller
/**
* Convert a UTF-8 string to a wchar_t string
*
* Return the new allocated string, to be freed by the caller.
*/
wchar_t *
utf8_to_wide_char(const char *utf8);
sc_str_to_wchars(const char *utf8);
/**
* Convert a wchar_t string to a UTF-8 string
*
* Return the new allocated string, to be freed by the caller.
*/
char *
utf8_from_wide_char(const wchar_t *s);
sc_str_from_wchars(const wchar_t *s);
#endif
/**
@ -68,6 +100,7 @@ utf8_from_wide_char(const wchar_t *s);
* Break input lines at word boundaries (spaces) so that they fit in `columns`
* columns, left-indented by `indent` spaces.
*/
char *sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent);
char *
sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent);
#endif

View file

@ -21,7 +21,7 @@ find_muxer(const char *name) {
oformat = av_oformat_next(oformat);
#endif
// until null or containing the requested name
} while (oformat && !strlist_contains(oformat->name, ',', name));
} while (oformat && !sc_str_list_contains(oformat->name, ',', name));
return oformat;
}

View file

@ -7,9 +7,9 @@
#include "util/str_util.h"
static void test_xstrncpy_simple(void) {
static void test_strncpy_simple(void) {
char s[] = "xxxxxxxxxx";
size_t w = xstrncpy(s, "abcdef", sizeof(s));
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
// returns strlen of copied string
assert(w == 6);
@ -24,9 +24,9 @@ static void test_xstrncpy_simple(void) {
assert(!strcmp("abcdef", s));
}
static void test_xstrncpy_just_fit(void) {
static void test_strncpy_just_fit(void) {
char s[] = "xxxxxx";
size_t w = xstrncpy(s, "abcdef", sizeof(s));
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
// returns strlen of copied string
assert(w == 6);
@ -38,9 +38,9 @@ static void test_xstrncpy_just_fit(void) {
assert(!strcmp("abcdef", s));
}
static void test_xstrncpy_truncated(void) {
static void test_strncpy_truncated(void) {
char s[] = "xxx";
size_t w = xstrncpy(s, "abcdef", sizeof(s));
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
// returns 'n' (sizeof(s))
assert(w == 4);
@ -52,10 +52,10 @@ static void test_xstrncpy_truncated(void) {
assert(!strncmp("abcdef", s, 3));
}
static void test_xstrjoin_simple(void) {
static void test_join_simple(void) {
const char *const tokens[] = { "abc", "de", "fghi", NULL };
char s[] = "xxxxxxxxxxxxxx";
size_t w = xstrjoin(s, tokens, ' ', sizeof(s));
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
// returns strlen of concatenation
assert(w == 11);
@ -70,10 +70,10 @@ static void test_xstrjoin_simple(void) {
assert(!strcmp("abc de fghi", s));
}
static void test_xstrjoin_just_fit(void) {
static void test_join_just_fit(void) {
const char *const tokens[] = { "abc", "de", "fghi", NULL };
char s[] = "xxxxxxxxxxx";
size_t w = xstrjoin(s, tokens, ' ', sizeof(s));
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
// returns strlen of concatenation
assert(w == 11);
@ -85,10 +85,10 @@ static void test_xstrjoin_just_fit(void) {
assert(!strcmp("abc de fghi", s));
}
static void test_xstrjoin_truncated_in_token(void) {
static void test_join_truncated_in_token(void) {
const char *const tokens[] = { "abc", "de", "fghi", NULL };
char s[] = "xxxxx";
size_t w = xstrjoin(s, tokens, ' ', sizeof(s));
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
// returns 'n' (sizeof(s))
assert(w == 6);
@ -100,10 +100,10 @@ static void test_xstrjoin_truncated_in_token(void) {
assert(!strcmp("abc d", s));
}
static void test_xstrjoin_truncated_before_sep(void) {
static void test_join_truncated_before_sep(void) {
const char *const tokens[] = { "abc", "de", "fghi", NULL };
char s[] = "xxxxxx";
size_t w = xstrjoin(s, tokens, ' ', sizeof(s));
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
// returns 'n' (sizeof(s))
assert(w == 7);
@ -115,10 +115,10 @@ static void test_xstrjoin_truncated_before_sep(void) {
assert(!strcmp("abc de", s));
}
static void test_xstrjoin_truncated_after_sep(void) {
static void test_join_truncated_after_sep(void) {
const char *const tokens[] = { "abc", "de", "fghi", NULL };
char s[] = "xxxxxxx";
size_t w = xstrjoin(s, tokens, ' ', sizeof(s));
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
// returns 'n' (sizeof(s))
assert(w == 8);
@ -130,9 +130,9 @@ static void test_xstrjoin_truncated_after_sep(void) {
assert(!strcmp("abc de ", s));
}
static void test_strquote(void) {
static void test_quote(void) {
const char *s = "abcde";
char *out = strquote(s);
char *out = sc_str_quote(s);
// add '"' at the beginning and the end
assert(!strcmp("\"abcde\"", out));
@ -146,71 +146,71 @@ static void test_utf8_truncate(void) {
size_t count;
count = utf8_truncation_index(s, 1);
count = sc_str_utf8_truncation_index(s, 1);
assert(count == 1);
count = utf8_truncation_index(s, 2);
count = sc_str_utf8_truncation_index(s, 2);
assert(count == 1); // É is 2 bytes-wide
count = utf8_truncation_index(s, 3);
count = sc_str_utf8_truncation_index(s, 3);
assert(count == 3);
count = utf8_truncation_index(s, 4);
count = sc_str_utf8_truncation_index(s, 4);
assert(count == 4);
count = utf8_truncation_index(s, 5);
count = sc_str_utf8_truncation_index(s, 5);
assert(count == 4); // Ô is 2 bytes-wide
count = utf8_truncation_index(s, 6);
count = sc_str_utf8_truncation_index(s, 6);
assert(count == 6);
count = utf8_truncation_index(s, 7);
count = sc_str_utf8_truncation_index(s, 7);
assert(count == 7);
count = utf8_truncation_index(s, 8);
count = sc_str_utf8_truncation_index(s, 8);
assert(count == 7); // no more chars
}
static void test_parse_integer(void) {
long value;
bool ok = parse_integer("1234", &value);
bool ok = sc_str_parse_integer("1234", &value);
assert(ok);
assert(value == 1234);
ok = parse_integer("-1234", &value);
ok = sc_str_parse_integer("-1234", &value);
assert(ok);
assert(value == -1234);
ok = parse_integer("1234k", &value);
ok = sc_str_parse_integer("1234k", &value);
assert(!ok);
ok = parse_integer("123456789876543212345678987654321", &value);
ok = sc_str_parse_integer("123456789876543212345678987654321", &value);
assert(!ok); // out-of-range
}
static void test_parse_integers(void) {
long values[5];
size_t count = parse_integers("1234", ':', 5, values);
size_t count = sc_str_parse_integers("1234", ':', 5, values);
assert(count == 1);
assert(values[0] == 1234);
count = parse_integers("1234:5678", ':', 5, values);
count = sc_str_parse_integers("1234:5678", ':', 5, values);
assert(count == 2);
assert(values[0] == 1234);
assert(values[1] == 5678);
count = parse_integers("1234:5678", ':', 2, values);
count = sc_str_parse_integers("1234:5678", ':', 2, values);
assert(count == 2);
assert(values[0] == 1234);
assert(values[1] == 5678);
count = parse_integers("1234:-5678", ':', 2, values);
count = sc_str_parse_integers("1234:-5678", ':', 2, values);
assert(count == 2);
assert(values[0] == 1234);
assert(values[1] == -5678);
count = parse_integers("1:2:3:4:5", ':', 5, values);
count = sc_str_parse_integers("1:2:3:4:5", ':', 5, values);
assert(count == 5);
assert(values[0] == 1);
assert(values[1] == 2);
@ -218,85 +218,85 @@ static void test_parse_integers(void) {
assert(values[3] == 4);
assert(values[4] == 5);
count = parse_integers("1234:5678", ':', 1, values);
count = sc_str_parse_integers("1234:5678", ':', 1, values);
assert(count == 0); // max_items == 1
count = parse_integers("1:2:3:4:5", ':', 3, values);
count = sc_str_parse_integers("1:2:3:4:5", ':', 3, values);
assert(count == 0); // max_items == 3
count = parse_integers(":1234", ':', 5, values);
count = sc_str_parse_integers(":1234", ':', 5, values);
assert(count == 0); // invalid
count = parse_integers("1234:", ':', 5, values);
count = sc_str_parse_integers("1234:", ':', 5, values);
assert(count == 0); // invalid
count = parse_integers("1234:", ':', 1, values);
count = sc_str_parse_integers("1234:", ':', 1, values);
assert(count == 0); // invalid, even when max_items == 1
count = parse_integers("1234::5678", ':', 5, values);
count = sc_str_parse_integers("1234::5678", ':', 5, values);
assert(count == 0); // invalid
}
static void test_parse_integer_with_suffix(void) {
long value;
bool ok = parse_integer_with_suffix("1234", &value);
bool ok = sc_str_parse_integer_with_suffix("1234", &value);
assert(ok);
assert(value == 1234);
ok = parse_integer_with_suffix("-1234", &value);
ok = sc_str_parse_integer_with_suffix("-1234", &value);
assert(ok);
assert(value == -1234);
ok = parse_integer_with_suffix("1234k", &value);
ok = sc_str_parse_integer_with_suffix("1234k", &value);
assert(ok);
assert(value == 1234000);
ok = parse_integer_with_suffix("1234m", &value);
ok = sc_str_parse_integer_with_suffix("1234m", &value);
assert(ok);
assert(value == 1234000000);
ok = parse_integer_with_suffix("-1234k", &value);
ok = sc_str_parse_integer_with_suffix("-1234k", &value);
assert(ok);
assert(value == -1234000);
ok = parse_integer_with_suffix("-1234m", &value);
ok = sc_str_parse_integer_with_suffix("-1234m", &value);
assert(ok);
assert(value == -1234000000);
ok = parse_integer_with_suffix("123456789876543212345678987654321", &value);
ok = sc_str_parse_integer_with_suffix("123456789876543212345678987654321", &value);
assert(!ok); // out-of-range
char buf[32];
sprintf(buf, "%ldk", LONG_MAX / 2000);
ok = parse_integer_with_suffix(buf, &value);
ok = sc_str_parse_integer_with_suffix(buf, &value);
assert(ok);
assert(value == LONG_MAX / 2000 * 1000);
sprintf(buf, "%ldm", LONG_MAX / 2000);
ok = parse_integer_with_suffix(buf, &value);
ok = sc_str_parse_integer_with_suffix(buf, &value);
assert(!ok);
sprintf(buf, "%ldk", LONG_MIN / 2000);
ok = parse_integer_with_suffix(buf, &value);
ok = sc_str_parse_integer_with_suffix(buf, &value);
assert(ok);
assert(value == LONG_MIN / 2000 * 1000);
sprintf(buf, "%ldm", LONG_MIN / 2000);
ok = parse_integer_with_suffix(buf, &value);
ok = sc_str_parse_integer_with_suffix(buf, &value);
assert(!ok);
}
static void test_strlist_contains(void) {
assert(strlist_contains("a,bc,def", ',', "bc"));
assert(!strlist_contains("a,bc,def", ',', "b"));
assert(strlist_contains("", ',', ""));
assert(strlist_contains("abc,", ',', ""));
assert(strlist_contains(",abc", ',', ""));
assert(strlist_contains("abc,,def", ',', ""));
assert(!strlist_contains("abc", ',', ""));
assert(strlist_contains(",,|x", '|', ",,"));
assert(strlist_contains("xyz", '\0', "xyz"));
assert(sc_str_list_contains("a,bc,def", ',', "bc"));
assert(!sc_str_list_contains("a,bc,def", ',', "b"));
assert(sc_str_list_contains("", ',', ""));
assert(sc_str_list_contains("abc,", ',', ""));
assert(sc_str_list_contains(",abc", ',', ""));
assert(sc_str_list_contains("abc,,def", ',', ""));
assert(!sc_str_list_contains("abc", ',', ""));
assert(sc_str_list_contains(",,|x", '|', ",,"));
assert(sc_str_list_contains("xyz", '\0', "xyz"));
}
static void test_wrap_lines(void) {
@ -341,15 +341,15 @@ int main(int argc, char *argv[]) {
(void) argc;
(void) argv;
test_xstrncpy_simple();
test_xstrncpy_just_fit();
test_xstrncpy_truncated();
test_xstrjoin_simple();
test_xstrjoin_just_fit();
test_xstrjoin_truncated_in_token();
test_xstrjoin_truncated_before_sep();
test_xstrjoin_truncated_after_sep();
test_strquote();
test_strncpy_simple();
test_strncpy_just_fit();
test_strncpy_truncated();
test_join_simple();
test_join_just_fit();
test_join_truncated_in_token();
test_join_truncated_before_sep();
test_join_truncated_after_sep();
test_quote();
test_utf8_truncate();
test_parse_integer();
test_parse_integers();