(libretro-common) Start documenting leaf functon calls in function documentation

(libretro-common) docs - document when string has to be non-NULL or else UB (undefined behavior)
(libretro-common) stdstring.c - string_hex_to_unsigned - make strlen call unneeded
This commit is contained in:
LibretroAdmin 2022-08-01 09:52:39 +02:00
parent 20c4407928
commit c7a1d83675
6 changed files with 533 additions and 151 deletions

View file

@ -279,9 +279,7 @@ bool core_backup_get_backup_crc(char *backup_path, uint32_t *crc)
goto error; goto error;
/* Convert to an integer */ /* Convert to an integer */
*crc = (uint32_t)string_hex_to_unsigned(crc_str); if ((*crc = (uint32_t)string_hex_to_unsigned(crc_str)) == 0)
if (*crc == 0)
goto error; goto error;
string_list_free(metadata_list); string_list_free(metadata_list);

View file

@ -371,9 +371,7 @@ static bool core_updater_list_set_crc(
if (!entry || string_is_empty(crc_str)) if (!entry || string_is_empty(crc_str))
return false; return false;
crc = (uint32_t)string_hex_to_unsigned(crc_str); if ((crc = (uint32_t)string_hex_to_unsigned(crc_str)) == 0)
if (crc == 0)
return false; return false;
entry->crc = crc; entry->crc = crc;

View file

@ -82,7 +82,11 @@ struct path_linked_list* path_linked_list_new(void)
return paths_list; return paths_list;
} }
/* Free the entire linked list */ /**
* path_linked_list_free:
*
* Free the entire linked list
**/
void path_linked_list_free(struct path_linked_list *in_path_linked_list) void path_linked_list_free(struct path_linked_list *in_path_linked_list)
{ {
struct path_linked_list *node_tmp = (struct path_linked_list*)in_path_linked_list; struct path_linked_list *node_tmp = (struct path_linked_list*)in_path_linked_list;
@ -99,11 +103,14 @@ void path_linked_list_free(struct path_linked_list *in_path_linked_list)
} }
/** /**
* path_linked_list_add_path:
*
* Add a node to the linked list with this path * Add a node to the linked list with this path
* If the first node's path if it's not yet set the path * If the first node's path if it's not yet set the path
* on this node instead * on this node instead
**/ **/
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path) void path_linked_list_add_path(struct path_linked_list *in_path_linked_list,
char *path)
{ {
/* If the first item does not have a path this is /* If the first item does not have a path this is
a list which has just been created, so we just fill a list which has just been created, so we just fill
@ -142,9 +149,9 @@ void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, cha
* Find delimiter of an archive file. Only the first '#' * Find delimiter of an archive file. Only the first '#'
* after a compression extension is considered. * after a compression extension is considered.
* *
* Returns: pointer to the delimiter in the path if it contains * @return pointer to the delimiter in the path if it contains
* a path inside a compressed file, otherwise NULL. * a path inside a compressed file, otherwise NULL.
*/ **/
const char *path_get_archive_delim(const char *path) const char *path_get_archive_delim(const char *path)
{ {
char buf[5]; char buf[5];
@ -198,8 +205,8 @@ const char *path_get_archive_delim(const char *path)
* Gets extension of file. Only '.'s * Gets extension of file. Only '.'s
* after the last slash are considered. * after the last slash are considered.
* *
* Returns: extension part from the path. * @return extension part from the path.
*/ **/
const char *path_get_extension(const char *path) const char *path_get_extension(const char *path)
{ {
const char *ext; const char *ext;
@ -216,12 +223,12 @@ const char *path_get_extension(const char *path)
* text after and including the last '.'. * text after and including the last '.'.
* Only '.'s after the last slash are considered. * Only '.'s after the last slash are considered.
* *
* Returns: * @return
* 1) If path has an extension, returns path with the * 1) If path has an extension, returns path with the
* extension removed. * extension removed.
* 2) If there is no extension, returns NULL. * 2) If there is no extension, returns NULL.
* 3) If path is empty or NULL, returns NULL * 3) If path is empty or NULL, returns NULL
*/ **/
char *path_remove_extension(char *path) char *path_remove_extension(char *path)
{ {
char *last = !string_is_empty(path) char *last = !string_is_empty(path)
@ -239,7 +246,7 @@ char *path_remove_extension(char *path)
* *
* Checks if path is a compressed file. * Checks if path is a compressed file.
* *
* Returns: true (1) if path is a compressed file, otherwise false (0). * @return true if path is a compressed file, otherwise false.
**/ **/
bool path_is_compressed_file(const char* path) bool path_is_compressed_file(const char* path)
{ {
@ -286,6 +293,17 @@ void fill_pathname(char *out_path, const char *in_path,
} }
/**
* find_last_slash:
* @str : path
* @size : size of path
*
* Find last slash in path. Tries to find
* a backslash on Windows too which takes precedence
* over regular slash.
* @return pointer to last slash/backslash found in @str.
**/
char *find_last_slash(const char *str) char *find_last_slash(const char *str)
{ {
const char *slash = strrchr(str, '/'); const char *slash = strrchr(str, '/');
@ -362,7 +380,7 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
* *
* Copies basename of @in_path into @out_path. * Copies basename of @in_path into @out_path.
* *
* @return length of the string copied into @out * @return Length of the string copied into @out
**/ **/
size_t fill_pathname_base(char *out, const char *in_path, size_t size) size_t fill_pathname_base(char *out, const char *in_path, size_t size)
{ {
@ -398,7 +416,8 @@ void fill_pathname_basedir(char *out_dir,
* *
* Copies only the parent directory name of @in_dir into @out_dir. * Copies only the parent directory name of @in_dir into @out_dir.
* The two buffers must not overlap. Removes trailing '/'. * The two buffers must not overlap. Removes trailing '/'.
* Returns true on success, false if a slash was not found in the path. *
* @return true on success, false if a slash was not found in the path.
**/ **/
bool fill_pathname_parent_dir_name(char *out_dir, bool fill_pathname_parent_dir_name(char *out_dir,
const char *in_dir, size_t size) const char *in_dir, size_t size)
@ -446,7 +465,8 @@ bool fill_pathname_parent_dir_name(char *out_dir,
* *
* Copies parent directory of @in_dir into @out_dir. * Copies parent directory of @in_dir into @out_dir.
* Assumes @in_dir is a directory. Keeps trailing '/'. * Assumes @in_dir is a directory. Keeps trailing '/'.
* If the path was already at the root directory, @out_dir will be an empty string. * If the path was already at the root directory,
* @out_dir will be an empty string.
**/ **/
void fill_pathname_parent_dir(char *out_dir, void fill_pathname_parent_dir(char *out_dir,
const char *in_dir, size_t size) const char *in_dir, size_t size)
@ -506,16 +526,15 @@ void fill_str_dated_filename(char *out_filename,
rtime_localtime(&cur_time, &tm_); rtime_localtime(&cur_time, &tm_);
strlcpy(out_filename, in_str, size);
if (string_is_empty(ext)) if (string_is_empty(ext))
{ {
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_); strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
strlcpy(out_filename, in_str, size);
strlcat(out_filename, format, size); strlcat(out_filename, format, size);
} }
else else
{ {
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_); strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
strlcpy(out_filename, in_str, size);
strlcat(out_filename, format, size); strlcat(out_filename, format, size);
strlcat(out_filename, ext, size); strlcat(out_filename, ext, size);
} }
@ -584,7 +603,7 @@ void path_parent_dir(char *path, size_t len)
* *
* Get basename from @path. * Get basename from @path.
* *
* Returns: basename from path. * @return basename from path.
**/ **/
const char *path_basename(const char *path) const char *path_basename(const char *path)
{ {
@ -604,6 +623,15 @@ const char *path_basename(const char *path)
} }
/* Specialized version */ /* Specialized version */
/**
* path_basename_nocompression:
* @path : path
*
* Specialized version of path_basename().
* Get basename from @path.
*
* @return basename from path.
**/
const char *path_basename_nocompression(const char *path) const char *path_basename_nocompression(const char *path)
{ {
/* We cut at the last slash */ /* We cut at the last slash */
@ -619,7 +647,7 @@ const char *path_basename_nocompression(const char *path)
* *
* Checks if @path is an absolute path or a relative path. * Checks if @path is an absolute path or a relative path.
* *
* Returns: true if path is absolute, false if path is relative. * @return true if path is absolute, false if path is relative.
**/ **/
bool path_is_absolute(const char *path) bool path_is_absolute(const char *path)
{ {
@ -655,7 +683,7 @@ bool path_is_absolute(const char *path)
* *
* Relative paths are rebased on the current working dir. * Relative paths are rebased on the current working dir.
* *
* Returns: @buf if successful, NULL otherwise. * @return @buf if successful, NULL otherwise.
* Note: Not implemented on consoles * Note: Not implemented on consoles
* Note: Symlinks are only resolved on Unix-likes * Note: Symlinks are only resolved on Unix-likes
* Note: The current working dir might not be what you expect, * Note: The current working dir might not be what you expect,
@ -921,9 +949,9 @@ size_t fill_pathname_join_delim(char *out_path, const char *dir,
size_t copied; size_t copied;
/* behavior of strlcpy is undefined if dst and src overlap */ /* behavior of strlcpy is undefined if dst and src overlap */
if (out_path == dir) if (out_path == dir)
copied = strlen(dir); copied = strlen(dir);
else else
copied = strlcpy(out_path, dir, size); copied = strlcpy(out_path, dir, size);
out_path[copied] = delim; out_path[copied] = delim;
out_path[copied+1] = '\0'; out_path[copied+1] = '\0';
@ -1060,28 +1088,53 @@ void fill_pathname_abbreviate_special(char *out_path,
retro_assert(strlcpy(out_path, in_path, size) < size); retro_assert(strlcpy(out_path, in_path, size) < size);
} }
/* Changes the slashes to the correct kind for the os /**
* So forward slash on linux and backslash on Windows */ * pathname_conform_slashes_to_os:
*
* @path : path
*
* Leaf function.
*
* Changes the slashes to the correct kind for the os
* So forward slash on linux and backslash on Windows
**/
void pathname_conform_slashes_to_os(char *path) void pathname_conform_slashes_to_os(char *path)
{ {
/* Conform slashes to os standard so we get proper matching */ /* Conform slashes to os standard so we get proper matching */
char* p; char *p;
for (p = path; *p; p++) for (p = path; *p; p++)
if (*p == '/' || *p == '\\') if (*p == '/' || *p == '\\')
*p = PATH_DEFAULT_SLASH_C(); *p = PATH_DEFAULT_SLASH_C();
} }
/* Change all shashes to forward so they are more portable between Windows and Linux */ /**
* pathname_make_slashes_portable:
* @path : path
*
* Leaf function.
*
* Change all slashes to forward so they are more
* portable between Windows and Linux
**/
void pathname_make_slashes_portable(char *path) void pathname_make_slashes_portable(char *path)
{ {
/* Conform slashes to os standard so we get proper matching */ /* Conform slashes to os standard so we get proper matching */
char* p; char *p;
for (p = path; *p; p++) for (p = path; *p; p++)
if (*p == '/' || *p == '\\') if (*p == '/' || *p == '\\')
*p = '/'; *p = '/';
} }
/* Get the number of slashes in a path, returns an integer */ /**
* get_pathname_num_slashes:
* @in_path : input path
*
* Leaf function.
*
* Get the number of slashes in a path.
*
* @return number of slashes found in @in_path.
**/
static int get_pathname_num_slashes(const char *in_path) static int get_pathname_num_slashes(const char *in_path)
{ {
int num_slashes = 0; int num_slashes = 0;
@ -1098,11 +1151,18 @@ static int get_pathname_num_slashes(const char *in_path)
return num_slashes; return num_slashes;
} }
/* Fills the supplied path with either the abbreviated path or the relative path, which ever /**
* one is has less depth / number of slashes * fill_pathname_abbreviated_or_relative:
* If lengths of abbreviated and relative paths are the same the relative path will be used *
* in_path can be an absolute, relative or abbreviated path */ * Fills the supplied path with either the abbreviated path or
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size) * the relative path, which ever one has less depth / number of slashes
*
* If lengths of abbreviated and relative paths are the same,
* the relative path will be used
* @in_path can be an absolute, relative or abbreviated path
**/
void fill_pathname_abbreviated_or_relative(char *out_path,
const char *in_refpath, const char *in_path, size_t size)
{ {
char in_path_conformed[PATH_MAX_LENGTH]; char in_path_conformed[PATH_MAX_LENGTH];
char in_refpath_conformed[PATH_MAX_LENGTH]; char in_refpath_conformed[PATH_MAX_LENGTH];
@ -1111,15 +1171,13 @@ void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpat
char relative_path[PATH_MAX_LENGTH]; char relative_path[PATH_MAX_LENGTH];
char abbreviated_path[PATH_MAX_LENGTH]; char abbreviated_path[PATH_MAX_LENGTH];
in_path_conformed[0] = '\0';
in_refpath_conformed[0] = '\0';
expanded_path[0] = '\0'; expanded_path[0] = '\0';
absolute_path[0] = '\0'; absolute_path[0] = '\0';
relative_path[0] = '\0'; relative_path[0] = '\0';
abbreviated_path[0] = '\0'; abbreviated_path[0] = '\0';
strcpy_literal(in_path_conformed, in_path); strlcpy(in_path_conformed, in_path, sizeof(in_path_conformed));
strcpy_literal(in_refpath_conformed, in_refpath); strlcpy(in_refpath_conformed, in_refpath, sizeof(in_refpath_conformed));
pathname_conform_slashes_to_os(in_path_conformed); pathname_conform_slashes_to_os(in_path_conformed);
pathname_conform_slashes_to_os(in_refpath_conformed); pathname_conform_slashes_to_os(in_refpath_conformed);

View file

@ -103,12 +103,12 @@ bool path_is_compressed_file(const char *path);
* path_get_archive_delim: * path_get_archive_delim:
* @path : path * @path : path
* *
* Gets delimiter of an archive file. Only the first '#' * Find delimiter of an archive file. Only the first '#'
* after a compression extension is considered. * after a compression extension is considered.
* *
* Returns: pointer to the delimiter in the path if it contains * @return pointer to the delimiter in the path if it contains
* a compressed file, otherwise NULL. * a path inside a compressed file, otherwise NULL.
*/ **/
const char *path_get_archive_delim(const char *path); const char *path_get_archive_delim(const char *path);
/** /**
@ -118,8 +118,12 @@ const char *path_get_archive_delim(const char *path);
* Gets extension of file. Only '.'s * Gets extension of file. Only '.'s
* after the last slash are considered. * after the last slash are considered.
* *
* Returns: extension part from the path. * Hidden non-leaf function cost:
*/ * - calls string_is_empty
* - calls strrchr
*
* @return extension part from the path.
**/
const char *path_get_extension(const char *path); const char *path_get_extension(const char *path);
/** /**
@ -130,7 +134,10 @@ const char *path_get_extension(const char *path);
* text after and including the last '.'. * text after and including the last '.'.
* Only '.'s after the last slash are considered. * Only '.'s after the last slash are considered.
* *
* Returns: * Hidden non-leaf function cost:
* - calls strrchr
*
* @return
* 1) If path has an extension, returns path with the * 1) If path has an extension, returns path with the
* extension removed. * extension removed.
* 2) If there is no extension, returns NULL. * 2) If there is no extension, returns NULL.
@ -144,9 +151,26 @@ char *path_remove_extension(char *path);
* *
* Get basename from @path. * Get basename from @path.
* *
* Returns: basename from path. * Hidden non-leaf function cost:
* - Calls path_get_archive_delim()
* - can call find_last_slash once if it returns NULL
*
* @return basename from path.
**/ **/
const char *path_basename(const char *path); const char *path_basename(const char *path);
/**
* path_basename_nocompression:
* @path : path
*
* Specialized version of path_basename().
* Get basename from @path.
*
* Hidden non-leaf function cost:
* - Calls find_last_slash
*
* @return basename from path.
**/
const char *path_basename_nocompression(const char *path); const char *path_basename_nocompression(const char *path);
/** /**
@ -179,7 +203,7 @@ void path_parent_dir(char *path, size_t len);
* *
* Relative paths are rebased on the current working dir. * Relative paths are rebased on the current working dir.
* *
* Returns: @buf if successful, NULL otherwise. * @return @buf if successful, NULL otherwise.
* Note: Not implemented on consoles * Note: Not implemented on consoles
* Note: Symlinks are only resolved on Unix-likes * Note: Symlinks are only resolved on Unix-likes
* Note: The current working dir might not be what you expect, * Note: The current working dir might not be what you expect,
@ -202,7 +226,8 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
* *
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
**/ **/
size_t path_relative_to(char *out, const char *path, const char *base, size_t size); size_t path_relative_to(char *out, const char *path, const char *base,
size_t size);
/** /**
* path_is_absolute: * path_is_absolute:
@ -210,7 +235,7 @@ size_t path_relative_to(char *out, const char *path, const char *base, size_t si
* *
* Checks if @path is an absolute path or a relative path. * Checks if @path is an absolute path or a relative path.
* *
* Returns: true if path is absolute, false if path is relative. * @return true if path is absolute, false if path is relative.
**/ **/
bool path_is_absolute(const char *path); bool path_is_absolute(const char *path);
@ -234,6 +259,11 @@ bool path_is_absolute(const char *path);
* out_path = "/foo/bar/baz/boo.asm" * out_path = "/foo/bar/baz/boo.asm"
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" => * E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
* out_path = "/foo/bar/baz/boo" * out_path = "/foo/bar/baz/boo"
*
* Hidden non-leaf function cost:
* - calls strlcpy 2x
* - calls strrchr
* - calls strlcat
*/ */
void fill_pathname(char *out_path, const char *in_path, void fill_pathname(char *out_path, const char *in_path,
const char *replace, size_t size); const char *replace, size_t size);
@ -249,6 +279,12 @@ void fill_pathname(char *out_path, const char *in_path,
* *
* E.g.: * E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls rtime_localtime()
* - Calls strftime
* - Calls strlcat
*
**/ **/
size_t fill_dated_filename(char *out_filename, size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size); const char *ext, size_t size);
@ -265,17 +301,31 @@ size_t fill_dated_filename(char *out_filename,
* *
* E.g.: * E.g.:
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}" * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls time
* - Calls rtime_localtime
* - Calls strlcpy
* - Calls string_is_empty
* - Calls strftime
* - Calls strlcat at least 2x
**/ **/
void fill_str_dated_filename(char *out_filename, void fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size); const char *in_str, const char *ext, size_t size);
/** /**
* find_last_slash: * find_last_slash:
* @str : input path * @str : path
* @size : size of path
* *
* Gets a pointer to the last slash in the input path. * Find last slash in path. Tries to find
* a backslash on Windows too which takes precedence
* over regular slash.
* Hidden non-leaf function cost:
* - calls strrchr
* *
* Returns: a pointer to the last slash in the input path. * @return pointer to last slash/backslash found in @str.
**/ **/
char *find_last_slash(const char *str); char *find_last_slash(const char *str);
@ -295,6 +345,11 @@ char *find_last_slash(const char *str);
* *
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
*
* Hidden non-leaf function cost:
* - Calls fill_pathname_slash()
* - Calls path_basename()
* - Calls strlcat 2x
**/ **/
size_t fill_pathname_dir(char *in_dir, const char *in_basename, size_t fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size); const char *replace, size_t size);
@ -306,6 +361,12 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
* @size : size of output path * @size : size of output path
* *
* Copies basename of @in_path into @out_path. * Copies basename of @in_path into @out_path.
*
* Hidden non-leaf function cost:
* - Calls path_basename()
* - Calls strlcpy
*
* @return length of the string copied into @out
**/ **/
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size); size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
@ -318,6 +379,10 @@ size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
* Copies base directory of @in_path into @out_path. * Copies base directory of @in_path into @out_path.
* If in_path is a path without any slashes (relative current directory), * If in_path is a path without any slashes (relative current directory),
* @out_path will get path "./". * @out_path will get path "./".
*
* Hidden non-leaf function cost:
* - Calls strlcpy
* - Calls path_basedir()
**/ **/
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size); void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
@ -329,7 +394,13 @@ void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
* *
* Copies only the parent directory name of @in_dir into @out_dir. * Copies only the parent directory name of @in_dir into @out_dir.
* The two buffers must not overlap. Removes trailing '/'. * The two buffers must not overlap. Removes trailing '/'.
* Returns true on success, false if a slash was not found in the path. *
* Hidden non-leaf function cost:
* - Calls strdup
* - Calls find_last_slash x times
* - Can call strlcpy
*
* @return true on success, false if a slash was not found in the path.
**/ **/
bool fill_pathname_parent_dir_name(char *out_dir, bool fill_pathname_parent_dir_name(char *out_dir,
const char *in_dir, size_t size); const char *in_dir, size_t size);
@ -343,6 +414,11 @@ bool fill_pathname_parent_dir_name(char *out_dir,
* Copies parent directory of @in_dir into @out_dir. * Copies parent directory of @in_dir into @out_dir.
* Assumes @in_dir is a directory. Keeps trailing '/'. * Assumes @in_dir is a directory. Keeps trailing '/'.
* If the path was already at the root directory, @out_dir will be an empty string. * If the path was already at the root directory, @out_dir will be an empty string.
*
* Hidden non-leaf function cost:
* - Can call strlcpy if (@out_dir != @in_dir)
* - Calls strlen if (@out_dir == @in_dir)
* - Calls path_parent_dir()
**/ **/
void fill_pathname_parent_dir(char *out_dir, void fill_pathname_parent_dir(char *out_dir,
const char *in_dir, size_t size); const char *in_dir, size_t size);
@ -372,6 +448,11 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
* Joins a directory (@dir) and path (@path) together. * Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes * Makes sure not to get two consecutive slashes
* between directory and path. * between directory and path.
*
* Hidden non-leaf function cost:
* - calls strlcpy
* - calls fill_pathname_slash()
* - calls strlcat
**/ **/
size_t fill_pathname_join(char *out_path, const char *dir, size_t fill_pathname_join(char *out_path, const char *dir,
const char *path, size_t size); const char *path, size_t size);
@ -391,6 +472,11 @@ size_t fill_pathname_join_special_ext(char *out_path,
* *
* Joins a directory (@dir) and path (@path) together * Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim). * using the given delimiter (@delim).
*
* Hidden non-leaf function cost:
* - can call strlen
* - can call strlcpy
* - can call strlcat
**/ **/
size_t fill_pathname_join_delim(char *out_path, const char *dir, size_t fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size); const char *path, const char delim, size_t size);
@ -401,10 +487,40 @@ void fill_pathname_expand_special(char *out_path,
void fill_pathname_abbreviate_special(char *out_path, void fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size); const char *in_path, size_t size);
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size); /**
* fill_pathname_abbreviated_or_relative:
*
* Fills the supplied path with either the abbreviated path or
* the relative path, which ever one has less depth / number of slashes
*
* If lengths of abbreviated and relative paths are the same,
* the relative path will be used
* @in_path can be an absolute, relative or abbreviated path
**/
void fill_pathname_abbreviated_or_relative(char *out_path,
const char *in_refpath, const char *in_path, size_t size);
/**
* pathname_conform_slashes_to_os:
*
* @path : path
*
* Leaf function.
*
* Changes the slashes to the correct kind for the os
* So forward slash on linux and backslash on Windows
**/
void pathname_conform_slashes_to_os(char *path); void pathname_conform_slashes_to_os(char *path);
/**
* pathname_make_slashes_portable:
* @path : path
*
* Leaf function.
*
* Change all slashes to forward so they are more
* portable between Windows and Linux
**/
void pathname_make_slashes_portable(char *path); void pathname_make_slashes_portable(char *path);
/** /**
@ -422,8 +538,8 @@ void path_basedir_wrapper(char *path);
* *
* Checks if character (@c) is a slash. * Checks if character (@c) is a slash.
* *
* Returns: true (1) if character is a slash, otherwise false (0). * @return true if character is a slash, otherwise false.
*/ **/
#ifdef _WIN32 #ifdef _WIN32
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\')) #define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else #else
@ -435,8 +551,8 @@ void path_basedir_wrapper(char *path);
* *
* Gets the default slash separator. * Gets the default slash separator.
* *
* Returns: default slash separator. * @return default slash separator.
*/ **/
#ifdef _WIN32 #ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\" #define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\' #define PATH_DEFAULT_SLASH_C() '\\'
@ -452,6 +568,11 @@ void path_basedir_wrapper(char *path);
* *
* Assumes path is a directory. Appends a slash * Assumes path is a directory. Appends a slash
* if not already there. * if not already there.
* Hidden non-leaf function cost:
* - calls find_last_slash()
* - can call strlcat once if it returns false
* - calls strlen
**/ **/
void fill_pathname_slash(char *path, size_t size); void fill_pathname_slash(char *path, size_t size);
@ -467,7 +588,7 @@ void fill_pathname_home_dir(char *buf, size_t size);
* *
* Create directory on filesystem. * Create directory on filesystem.
* *
* Returns: true (1) if directory could be created, otherwise false (0). * @return true if directory could be created, otherwise false.
**/ **/
bool path_mkdir(const char *dir); bool path_mkdir(const char *dir);
@ -477,7 +598,7 @@ bool path_mkdir(const char *dir);
* *
* Checks if path is a directory. * Checks if path is a directory.
* *
* Returns: true (1) if path is a directory, otherwise false (0). * @return true if path is a directory, otherwise false.
*/ */
bool path_is_directory(const char *path); bool path_is_directory(const char *path);

View file

@ -92,16 +92,20 @@ static INLINE bool string_ends_with_size(const char *str, const char *suffix,
static INLINE bool string_ends_with(const char *str, const char *suffix) static INLINE bool string_ends_with(const char *str, const char *suffix)
{ {
if (!str || !suffix) return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
return false;
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
} }
/* Returns the length of 'str' (c.f. strlen()), but only /**
* strlen_size:
*
* Leaf function.
*
* @return the length of 'str' (c.f. strlen()), but only
* checks the first 'size' characters * checks the first 'size' characters
* - If 'str' is NULL, returns 0 * - If 'str' is NULL, returns 0
* - If 'str' is not NULL and no '\0' character is found * - If 'str' is not NULL and no '\0' character is found
* in the first 'size' characters, returns 'size' */ * in the first 'size' characters, returns 'size'
**/
static INLINE size_t strlen_size(const char *str, size_t size) static INLINE size_t strlen_size(const char *str, size_t size)
{ {
size_t i = 0; size_t i = 0;
@ -158,16 +162,30 @@ char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern, char *string_replace_substring(const char *in, const char *pattern,
const char *by); const char *by);
/* Remove leading whitespaces */ /**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s); char *string_trim_whitespace_left(char *const s);
/* Remove trailing whitespaces */ /**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s); char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */ /**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s); char *string_trim_whitespace(char *const s);
/* /**
* word_wrap:
*
* Wraps string specified by 'src' to destination buffer * Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'. * specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string * This function assumes that all glyphs in the string
@ -184,11 +202,13 @@ char *string_trim_whitespace(char *const s);
* compatibility with word_wrap_wideglyph(). * compatibility with word_wrap_wideglyph().
* @param max_lines max lines of destination string. * @param max_lines max lines of destination string.
* 0 means no limit. * 0 means no limit.
*/ **/
void word_wrap(char *dst, size_t dst_size, const char *src, void word_wrap(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines); int line_width, int wideglyph_width, unsigned max_lines);
/* /**
* word_wrap_wideglyph:
*
* Wraps string specified by 'src' to destination buffer * Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'. * specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string * This function assumes that all glyphs in the string
@ -219,14 +239,17 @@ void word_wrap(char *dst, size_t dst_size, const char *src,
* would be 200 * would be 200
* @param max_lines max lines of destination string. * @param max_lines max lines of destination string.
* 0 means no limit. * 0 means no limit.
*/ **/
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines); int line_width, int wideglyph_width, unsigned max_lines);
/* Splits string into tokens seperated by 'delim' /**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d * > Returned token string must be free()'d
* > Returns NULL if token is not found * > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the * > After each call, @str is set to the position after the
* last found token * last found token
* > Tokens *include* empty strings * > Tokens *include* empty strings
* Usage example: * Usage example:
@ -239,48 +262,118 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
* free(token); * free(token);
* token = NULL; * token = NULL;
* } * }
*/ **/
char* string_tokenize(char **str, const char *delim); char* string_tokenize(char **str, const char *delim);
/* Removes every instance of character 'c' from 'str' */ /**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c); void string_remove_all_chars(char *str, char c);
/* Replaces every instance of character 'find' in 'str' /**
* with character 'replace' */ * string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Hidden non-leaf function cost:
* - Calls strchr (in a loop)
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace); void string_replace_all_chars(char *str, char find, char replace);
/* Converts string to unsigned integer. /**
* Returns 0 if string is invalid */ * string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str); unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer. /**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'. * Handles optional leading '0x'.
* Returns 0 if string is invalid */ *
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str); unsigned string_hex_to_unsigned(const char *str);
char *string_init(const char *src); char *string_init(const char *src);
void string_set(char **string, const char *src); void string_set(char **string, const char *src);
/* Get the total number of occurrences of a character in the given string. */ /**
* string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/
int string_count_occurrences_single_character(const char *str, char c); int string_count_occurrences_single_character(const char *str, char c);
/* Replaces all spaces with the given character. */ /**
* string_replace_whitespace_with_single_character:
*
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c); void string_replace_whitespace_with_single_character(char *str, char c);
/* Replaces multiple spaces with a single space in a string. */ /**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string.
**/
void string_replace_multi_space_with_single_space(char *str); void string_replace_multi_space_with_single_space(char *str);
/* Remove all spaces from the given string. */ /**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string.
**/
void string_remove_all_whitespace(char *str_trimmed, const char *str); void string_remove_all_whitespace(char *str_trimmed, const char *str);
/* Retrieve the last occurance of the given character in a string. */ /* Retrieve the last occurance of the given character in a string. */
int string_index_last_occurance(const char *str, char c); int string_index_last_occurance(const char *str, char c);
/* Find the position of a substring in a string. */ /**
* string_find_index_substring_string:
* @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Hidden non-leaf function cost:
* - Calls strstr
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr); int string_find_index_substring_string(const char *str, const char *substr);
/* Strips non-ASCII characters from a string. */ /**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str); void string_copy_only_ascii(char *str_stripped, const char *str);
extern const unsigned char lr_char_props[256]; extern const unsigned char lr_char_props[256];

View file

@ -136,7 +136,11 @@ char *string_replace_substring(const char *in,
return out; return out;
} }
/* Remove leading whitespaces */ /**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s) char *string_trim_whitespace_left(char *const s)
{ {
if (s && *s) if (s && *s)
@ -157,7 +161,11 @@ char *string_trim_whitespace_left(char *const s)
return s; return s;
} }
/* Remove trailing whitespaces */ /**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s) char *string_trim_whitespace_right(char *const s)
{ {
if (s && *s) if (s && *s)
@ -177,7 +185,11 @@ char *string_trim_whitespace_right(char *const s)
return s; return s;
} }
/* Remove leading and trailing whitespaces */ /**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s) char *string_trim_whitespace(char *const s)
{ {
string_trim_whitespace_right(s); /* order matters */ string_trim_whitespace_right(s); /* order matters */
@ -186,7 +198,28 @@ char *string_trim_whitespace(char *const s)
return s; return s;
} }
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines) /**
* word_wrap:
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* have an on-screen pixel width similar to that of
* regular Latin characters - i.e. it will not wrap
* correctly any text containing so-called 'wide' Unicode
* characters (e.g. CJK languages, emojis, etc.).
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @param max_lines max lines of destination string.
* 0 means no limit.
**/
void word_wrap(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines)
{ {
char *lastspace = NULL; char *lastspace = NULL;
unsigned counter = 0; unsigned counter = 0;
@ -261,7 +294,43 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
*dst = '\0'; *dst = '\0';
} }
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines) /**
* word_wrap_wideglyph:
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* are:
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
* pixel width similar to that of regular Latin characters
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
* with an on-screen pixel width defined by 'wideglyph_width'
* Note that wrapping may occur in inappropriate locations
* if 'src' string contains 'wide' Unicode characters whose
* on-screen pixel width deviates greatly from the set
* 'wideglyph_width' value.
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
* the value here is normalised relative to the
* typical on-screen pixel width of a regular
* Latin character:
* - a regular Latin character is defined to
* have an effective width of 100
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
* - e.g. if 'wide' Unicode characters in 'src'
* have an on-screen pixel width twice that of
* regular Latin characters, wideglyph_width
* would be 200
* @param max_lines max lines of destination string.
* 0 means no limit.
**/
void word_wrap_wideglyph(char *dst, size_t dst_size,
const char *src, int line_width,
int wideglyph_width, unsigned max_lines)
{ {
char *lastspace = NULL; char *lastspace = NULL;
char *lastwideglyph = NULL; char *lastwideglyph = NULL;
@ -310,7 +379,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
break; break;
if (*src == ' ') if (*src == ' ')
lastspace = dst; /* Remember the location of the whitespace */ lastspace = dst; /* Remember the location of the whitespace */
else if (*src == '\n') else if (*src == '\n')
{ {
/* If newlines embedded in the input, /* If newlines embedded in the input,
@ -330,7 +399,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
{ {
/* Remember the location of the first byte /* Remember the location of the first byte
* whose length as UTF-8 >= 3*/ * whose length as UTF-8 >= 3*/
lastwideglyph = dst; lastwideglyph = dst;
counter_normalized += additional_counter_normalized; counter_normalized += additional_counter_normalized;
} }
@ -349,9 +418,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
/* Insert newline character */ /* Insert newline character */
*lastwideglyph = '\n'; *lastwideglyph = '\n';
lines++; lines++;
src -= dst - lastwideglyph; src -= dst - lastwideglyph;
dst = lastwideglyph + 1; dst = lastwideglyph + 1;
lastwideglyph = NULL; lastwideglyph = NULL;
/* Early return if remaining src string /* Early return if remaining src string
* length is less than line width */ * length is less than line width */
@ -367,9 +436,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* with newline character */ * with newline character */
*lastspace = '\n'; *lastspace = '\n';
lines++; lines++;
src -= dst - lastspace - 1; src -= dst - lastspace - 1;
dst = lastspace + 1; dst = lastspace + 1;
lastspace = NULL; lastspace = NULL;
/* Early return if remaining src string /* Early return if remaining src string
* length is less than line width */ * length is less than line width */
@ -385,10 +454,13 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
*dst = '\0'; *dst = '\0';
} }
/* Splits string into tokens seperated by 'delim' /**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d * > Returned token string must be free()'d
* > Returns NULL if token is not found * > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the * > After each call, @str is set to the position after the
* last found token * last found token
* > Tokens *include* empty strings * > Tokens *include* empty strings
* Usage example: * Usage example:
@ -401,7 +473,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* free(token); * free(token);
* token = NULL; * token = NULL;
* } * }
*/ **/
char* string_tokenize(char **str, const char *delim) char* string_tokenize(char **str, const char *delim)
{ {
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */ /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
@ -440,42 +512,53 @@ char* string_tokenize(char **str, const char *delim)
return token; return token;
} }
/* Removes every instance of character 'c' from 'str' */ /**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c) void string_remove_all_chars(char *str, char c)
{ {
char *read_ptr = NULL; char *read_ptr = str;
char *write_ptr = NULL; char *write_ptr = str;
if (string_is_empty(str))
return;
read_ptr = str;
write_ptr = str;
while (*read_ptr != '\0') while (*read_ptr != '\0')
{ {
*write_ptr = *read_ptr++; *write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0; if (*write_ptr != c)
write_ptr++;
} }
*write_ptr = '\0'; *write_ptr = '\0';
} }
/* Replaces every instance of character 'find' in 'str' /**
* with character 'replace' */ * string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace) void string_replace_all_chars(char *str, char find, char replace)
{ {
if (!string_is_empty(str)) char *str_ptr = str;
{ while ((str_ptr = strchr(str_ptr, find)))
char *str_ptr = str; *str_ptr++ = replace;
while ((str_ptr = strchr(str_ptr, find)))
*str_ptr++ = replace;
}
} }
/* Converts string to unsigned integer. /**
* Returns 0 if string is invalid */ * string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str) unsigned string_to_unsigned(const char *str)
{ {
const char *ptr = NULL; const char *ptr = NULL;
@ -492,25 +575,33 @@ unsigned string_to_unsigned(const char *str)
return (unsigned)strtoul(str, NULL, 10); return (unsigned)strtoul(str, NULL, 10);
} }
/* Converts hexadecimal string to unsigned integer. /**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'. * Handles optional leading '0x'.
* Returns 0 if string is invalid */ *
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str) unsigned string_hex_to_unsigned(const char *str)
{ {
const char *hex_str = str; const char *hex_str = str;
const char *ptr = NULL; const char *ptr = NULL;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */ /* Remove leading '0x', if required */
if (strlen(str) >= 2) if (str[0] != '\0' && str[1] != '\0')
{
if ( (str[0] == '0') && if ( (str[0] == '0') &&
((str[1] == 'x') || ((str[1] == 'x') ||
(str[1] == 'X'))) (str[1] == 'X')))
{
hex_str = str + 2; hex_str = str + 2;
if (string_is_empty(hex_str))
if (string_is_empty(hex_str)) return 0;
}
}
else
return 0; return 0;
/* Check for valid characters */ /* Check for valid characters */
@ -524,7 +615,13 @@ unsigned string_hex_to_unsigned(const char *str)
} }
/** /**
* Get the total number of occurrences of a character in the given string. * string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/ */
int string_count_occurrences_single_character(const char *str, char c) int string_count_occurrences_single_character(const char *str, char c)
{ {
@ -538,8 +635,12 @@ int string_count_occurrences_single_character(const char *str, char c)
} }
/** /**
* Replaces all spaces with the given character. * string_replace_whitespace_with_single_character:
*/ *
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c) void string_replace_whitespace_with_single_character(char *str, char c)
{ {
for (; *str; str++) for (; *str; str++)
@ -548,8 +649,12 @@ void string_replace_whitespace_with_single_character(char *str, char c)
} }
/** /**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string. * Replaces multiple spaces with a single space in a string.
*/ **/
void string_replace_multi_space_with_single_space(char *str) void string_replace_multi_space_with_single_space(char *str)
{ {
char *str_trimmed = str; char *str_trimmed = str;
@ -568,8 +673,12 @@ void string_replace_multi_space_with_single_space(char *str)
} }
/** /**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string. * Remove all spaces from the given string.
*/ **/
void string_remove_all_whitespace(char *str_trimmed, const char *str) void string_remove_all_whitespace(char *str_trimmed, const char *str)
{ {
for (; *str; str++) for (; *str; str++)
@ -589,22 +698,27 @@ int string_index_last_occurance(const char *str, char c)
} }
/** /**
* Find the position of a substring in a string. * string_find_index_substring_string:
*/ * @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr) int string_find_index_substring_string(const char *str, const char *substr)
{ {
if (!string_is_empty(str)) const char *pos = strstr(str, substr);
{ if (pos)
const char *pos = strstr(str, substr); return pos - str;
if (pos)
return pos - str;
}
return -1; return -1;
} }
/* Strips non-ASCII characters from a string. */ /**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str) void string_copy_only_ascii(char *str_stripped, const char *str)
{ {
for (; *str; str++) for (; *str; str++)