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__ #ifdef __WINDOWS__
// Windows will parse the string, so the paths must be quoted // Windows will parse the string, so the paths must be quoted
// (see sys/win/command.c) // (see sys/win/command.c)
local = strquote(local); local = sc_str_quote(local);
if (!local) { if (!local) {
return SC_PROCESS_NONE; return SC_PROCESS_NONE;
} }
remote = strquote(remote); remote = sc_str_quote(remote);
if (!remote) { if (!remote) {
free((void *) local); free((void *) local);
return SC_PROCESS_NONE; return SC_PROCESS_NONE;
@ -217,7 +217,7 @@ adb_install(const char *serial, const char *local) {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
// Windows will parse the string, so the local name must be quoted // Windows will parse the string, so the local name must be quoted
// (see sys/win/command.c) // (see sys/win/command.c)
local = strquote(local); local = sc_str_quote(local);
if (!local) { if (!local) {
return SC_PROCESS_NONE; 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; long value;
bool ok; bool ok;
if (accept_suffix) { if (accept_suffix) {
ok = parse_integer_with_suffix(s, &value); ok = sc_str_parse_integer_with_suffix(s, &value);
} else { } else {
ok = parse_integer(s, &value); ok = sc_str_parse_integer(s, &value);
} }
if (!ok) { if (!ok) {
LOGE("Could not parse %s: %s", name, s); 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 static size_t
parse_integers_arg(const char *s, size_t max_items, long *out, long min, parse_integers_arg(const char *s, size_t max_items, long *out, long min,
long max, const char *name) { 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) { if (!count) {
LOGE("Could not parse %s: %s", name, s); LOGE("Could not parse %s: %s", name, s);
return 0; 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) // write length (2 bytes) + string (non nul-terminated)
static size_t static size_t
write_string(const char *utf8, size_t max_len, unsigned char *buf) { 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); buffer_write32be(buf, len);
memcpy(&buf[4], utf8, len); memcpy(&buf[4], utf8, len);
return 4 + len; return 4 + len;

View file

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

View file

@ -26,7 +26,7 @@ find_muxer(const char *name) {
oformat = av_oformat_next(oformat); oformat = av_oformat_next(oformat);
#endif #endif
// until null or containing the requested name // 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; return oformat;
} }

View file

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

View file

@ -19,12 +19,12 @@ sc_file_get_executable_path(void) {
return NULL; return NULL;
} }
buf[len] = '\0'; buf[len] = '\0';
return utf8_from_wide_char(buf); return sc_str_from_wchars(buf);
} }
bool bool
sc_file_is_regular(const char *path) { 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) { if (!wide_path) {
LOGC("Could not allocate wide char string"); LOGC("Could not allocate wide char string");
return false; 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> // <http://daviddeley.com/autohotkey/parameters/parameters.htm#WINPASS>
// only make it work for this very specific program // only make it work for this very specific program
// (don't handle escaping nor quotes) // (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) { if (ret >= len) {
LOGE("Command too long (%" SC_PRIsizet " chars)", len - 1); LOGE("Command too long (%" SC_PRIsizet " chars)", len - 1);
return false; return false;
@ -88,7 +88,7 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle,
goto error_close_stderr; goto error_close_stderr;
} }
wchar_t *wide = utf8_to_wide_char(cmd); wchar_t *wide = sc_str_to_wchars(cmd);
free(cmd); free(cmd);
if (!wide) { if (!wide) {
LOGC("Could not allocate wide char string"); LOGC("Could not allocate wide char string");

View file

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

View file

@ -1,65 +1,97 @@
#ifndef STRUTIL_H #ifndef SC_STRUTIL_H
#define STRUTIL_H #define SC_STRUTIL_H
#include "common.h" #include "common.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
// like strncpy, except: /**
// - it copies at most n-1 chars * Like strncpy(), except:
// - the dest string is nul-terminated * - it copies at most n-1 chars
// - it does not write useless bytes if strlen(src) < n * - the dest string is nul-terminated
// - it returns the number of chars actually written (max n-1) if src has * - it does not write useless bytes if strlen(src) < n
// been copied completely, or n if src has been truncated * - 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 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 * Join tokens by separator `sep` into `dst`
// occurred, or n if truncated *
* Return the number of chars actually written (max n-1) if no truncation
* occurred, or n if truncated.
*/
size_t 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 * 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 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 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 * Parse `s` as an integer into `out`
// suffix *
// returns true if the conversion succeeded, false otherwise * 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 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 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 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 #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 * 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 * char *
utf8_from_wide_char(const wchar_t *s); sc_str_from_wchars(const wchar_t *s);
#endif #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` * Break input lines at word boundaries (spaces) so that they fit in `columns`
* columns, left-indented by `indent` spaces. * 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 #endif

View file

@ -21,7 +21,7 @@ find_muxer(const char *name) {
oformat = av_oformat_next(oformat); oformat = av_oformat_next(oformat);
#endif #endif
// until null or containing the requested name // 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; return oformat;
} }

View file

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