(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;
/* Convert to an integer */
*crc = (uint32_t)string_hex_to_unsigned(crc_str);
if (*crc == 0)
if ((*crc = (uint32_t)string_hex_to_unsigned(crc_str)) == 0)
goto error;
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))
return false;
crc = (uint32_t)string_hex_to_unsigned(crc_str);
if (crc == 0)
if ((crc = (uint32_t)string_hex_to_unsigned(crc_str)) == 0)
return false;
entry->crc = crc;

View File

@ -82,7 +82,11 @@ struct path_linked_list* path_linked_list_new(void)
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)
{
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
* If the first node's path if it's not yet set the path
* 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
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 '#'
* 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.
*/
**/
const char *path_get_archive_delim(const char *path)
{
char buf[5];
@ -198,8 +205,8 @@ const char *path_get_archive_delim(const char *path)
* Gets extension of file. Only '.'s
* 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 *ext;
@ -216,12 +223,12 @@ const char *path_get_extension(const char *path)
* text after and including the last '.'.
* Only '.'s after the last slash are considered.
*
* Returns:
* @return
* 1) If path has an extension, returns path with the
* extension removed.
* 2) If there is no extension, returns NULL.
* 3) If path is empty or NULL, returns NULL
*/
**/
char *path_remove_extension(char *path)
{
char *last = !string_is_empty(path)
@ -239,7 +246,7 @@ char *path_remove_extension(char *path)
*
* 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)
{
@ -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)
{
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.
*
* @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)
{
@ -398,7 +416,8 @@ void fill_pathname_basedir(char *out_dir,
*
* Copies only the parent directory name of @in_dir into @out_dir.
* 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,
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.
* 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,
const char *in_dir, size_t size)
@ -506,16 +526,15 @@ void fill_str_dated_filename(char *out_filename,
rtime_localtime(&cur_time, &tm_);
strlcpy(out_filename, in_str, size);
if (string_is_empty(ext))
{
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
strlcpy(out_filename, in_str, size);
strlcat(out_filename, format, size);
}
else
{
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, ext, size);
}
@ -584,7 +603,7 @@ void path_parent_dir(char *path, size_t len)
*
* Get basename from @path.
*
* Returns: basename from path.
* @return basename from path.
**/
const char *path_basename(const char *path)
{
@ -604,6 +623,15 @@ const char *path_basename(const char *path)
}
/* 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)
{
/* 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.
*
* 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)
{
@ -655,7 +683,7 @@ bool path_is_absolute(const char *path)
*
* 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: Symlinks are only resolved on Unix-likes
* 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;
/* behavior of strlcpy is undefined if dst and src overlap */
if (out_path == dir)
copied = strlen(dir);
copied = strlen(dir);
else
copied = strlcpy(out_path, dir, size);
copied = strlcpy(out_path, dir, size);
out_path[copied] = delim;
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);
}
/* 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)
{
/* Conform slashes to os standard so we get proper matching */
char* p;
char *p;
for (p = path; *p; p++)
if (*p == '/' || *p == '\\')
*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)
{
/* Conform slashes to os standard so we get proper matching */
char* p;
char *p;
for (p = path; *p; p++)
if (*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)
{
int num_slashes = 0;
@ -1098,11 +1151,18 @@ static int get_pathname_num_slashes(const char *in_path)
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
* 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)
/**
* 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)
{
char in_path_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 abbreviated_path[PATH_MAX_LENGTH];
in_path_conformed[0] = '\0';
in_refpath_conformed[0] = '\0';
expanded_path[0] = '\0';
absolute_path[0] = '\0';
relative_path[0] = '\0';
abbreviated_path[0] = '\0';
strcpy_literal(in_path_conformed, in_path);
strcpy_literal(in_refpath_conformed, in_refpath);
strlcpy(in_path_conformed, in_path, sizeof(in_path_conformed));
strlcpy(in_refpath_conformed, in_refpath, sizeof(in_refpath_conformed));
pathname_conform_slashes_to_os(in_path_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 : 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.
*
* Returns: pointer to the delimiter in the path if it contains
* a compressed file, otherwise NULL.
*/
* @return pointer to the delimiter in the path if it contains
* a path inside a compressed file, otherwise NULL.
**/
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
* 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);
/**
@ -130,7 +134,10 @@ const char *path_get_extension(const char *path);
* text after and including the last '.'.
* 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
* extension removed.
* 2) If there is no extension, returns NULL.
@ -144,9 +151,26 @@ char *path_remove_extension(char *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);
/**
* 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);
/**
@ -179,7 +203,7 @@ void path_parent_dir(char *path, size_t len);
*
* 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: Symlinks are only resolved on Unix-likes
* 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
**/
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:
@ -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.
*
* 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);
@ -234,6 +259,11 @@ bool path_is_absolute(const char *path);
* out_path = "/foo/bar/baz/boo.asm"
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
* 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,
const char *replace, size_t size);
@ -249,6 +279,12 @@ void fill_pathname(char *out_path, const char *in_path,
*
* E.g.:
* 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,
const char *ext, size_t size);
@ -265,17 +301,31 @@ size_t fill_dated_filename(char *out_filename,
*
* E.g.:
* 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,
const char *in_str, const char *ext, size_t size);
/**
* 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);
@ -295,6 +345,11 @@ char *find_last_slash(const char *str);
*
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* 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,
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
*
* 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);
@ -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.
* If in_path is a path without any slashes (relative current directory),
* @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);
@ -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.
* 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,
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.
* Assumes @in_dir is a directory. Keeps trailing '/'.
* 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,
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.
* Makes sure not to get two consecutive slashes
* 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,
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
* 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,
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,
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);
/**
* 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);
/**
@ -422,8 +538,8 @@ void path_basedir_wrapper(char *path);
*
* 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
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
@ -435,8 +551,8 @@ void path_basedir_wrapper(char *path);
*
* Gets the default slash separator.
*
* Returns: default slash separator.
*/
* @return default slash separator.
**/
#ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
@ -452,6 +568,11 @@ void path_basedir_wrapper(char *path);
*
* Assumes path is a directory. Appends a slash
* 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);
@ -467,7 +588,7 @@ void fill_pathname_home_dir(char *buf, size_t size);
*
* 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);
@ -477,7 +598,7 @@ bool path_mkdir(const char *dir);
*
* 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);

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)
{
if (!str || !suffix)
return false;
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
return str && suffix && 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
* - If 'str' is NULL, returns 0
* - 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)
{
size_t i = 0;
@ -158,16 +162,30 @@ char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern,
const char *by);
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
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);
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s);
/*
/**
* 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
@ -184,11 +202,13 @@ char *string_trim_whitespace(char *const s);
* 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);
/*
/**
* 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
@ -219,14 +239,17 @@ void word_wrap(char *dst, size_t dst_size, const char *src,
* 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);
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > 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
* > Tokens *include* empty strings
* Usage example:
@ -239,48 +262,118 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
* free(token);
* token = NULL;
* }
*/
**/
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);
/* 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);
/* 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);
/* 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'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str);
char *string_init(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);
/* 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);
/* 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);
/* 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);
/* Retrieve the last occurance of the given character in a string. */
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);
/* 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);
extern const unsigned char lr_char_props[256];

View File

@ -136,7 +136,11 @@ char *string_replace_substring(const char *in,
return out;
}
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s)
{
if (s && *s)
@ -157,7 +161,11 @@ char *string_trim_whitespace_left(char *const s)
return s;
}
/* Remove trailing whitespaces */
/**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s)
{
if (s && *s)
@ -177,7 +185,11 @@ char *string_trim_whitespace_right(char *const s)
return s;
}
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s)
{
string_trim_whitespace_right(s); /* order matters */
@ -186,7 +198,28 @@ char *string_trim_whitespace(char *const 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;
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';
}
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 *lastwideglyph = NULL;
@ -310,7 +379,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
break;
if (*src == ' ')
lastspace = dst; /* Remember the location of the whitespace */
lastspace = dst; /* Remember the location of the whitespace */
else if (*src == '\n')
{
/* 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
* whose length as UTF-8 >= 3*/
lastwideglyph = dst;
lastwideglyph = dst;
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 */
*lastwideglyph = '\n';
lines++;
src -= dst - lastwideglyph;
dst = lastwideglyph + 1;
lastwideglyph = NULL;
src -= dst - lastwideglyph;
dst = lastwideglyph + 1;
lastwideglyph = NULL;
/* Early return if remaining src string
* 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 */
*lastspace = '\n';
lines++;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
/* Early return if remaining src string
* 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';
}
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > 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
* > Tokens *include* empty strings
* Usage example:
@ -401,7 +473,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* free(token);
* token = NULL;
* }
*/
**/
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# */
@ -440,42 +512,53 @@ char* string_tokenize(char **str, const char *delim)
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)
{
char *read_ptr = NULL;
char *write_ptr = NULL;
if (string_is_empty(str))
return;
read_ptr = str;
write_ptr = str;
char *read_ptr = str;
char *write_ptr = str;
while (*read_ptr != '\0')
{
*write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0;
if (*write_ptr != c)
write_ptr++;
}
*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)
{
if (!string_is_empty(str))
{
char *str_ptr = str;
while ((str_ptr = strchr(str_ptr, find)))
*str_ptr++ = replace;
}
char *str_ptr = str;
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)
{
const char *ptr = NULL;
@ -492,25 +575,33 @@ unsigned string_to_unsigned(const char *str)
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'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str)
{
const char *hex_str = str;
const char *ptr = NULL;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */
if (strlen(str) >= 2)
if (str[0] != '\0' && str[1] != '\0')
{
if ( (str[0] == '0') &&
((str[1] == 'x') ||
(str[1] == 'X')))
{
hex_str = str + 2;
if (string_is_empty(hex_str))
if (string_is_empty(hex_str))
return 0;
}
}
else
return 0;
/* 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)
{
@ -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)
{
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.
*/
**/
void string_replace_multi_space_with_single_space(char *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.
*/
**/
void string_remove_all_whitespace(char *str_trimmed, const char *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)
{
if (!string_is_empty(str))
{
const char *pos = strstr(str, substr);
if (pos)
return pos - str;
}
const char *pos = strstr(str, substr);
if (pos)
return pos - str;
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)
{
for (; *str; str++)