From: Kevin Day Date: Mon, 25 May 2020 04:02:22 +0000 (-0500) Subject: Feature: add push and pop directory functions X-Git-Tag: 0.5.0~237 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=847d721d57c953f41dbfed99c49b97d9e7b8b033;p=fll Feature: add push and pop directory functions These functions should help make appending interactive or user-data for directory path building easier. --- diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index 452d35a..bb8db8f 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -38,6 +38,106 @@ extern "C" { } #endif // _di_fl_directory_list_ +#ifndef _di_fl_directory_path_pop_ + f_return_status fl_directory_path_pop(f_string_static *path) { + #ifndef _di_level_0_parameter_checking_ + if (path->used > path->size) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (path->used == 0) { + return F_data_not; + } + + bool null_terminated = path->string[path->used] == 0; + bool first_nulless = F_false; + + f_string_length i = path->used - 1; + f_string_length j = 0; + + f_status status = F_none; + + for (; i > 0; i--) { + if (path->string[i] == 0) continue; + + status = f_utf_is_control(path->string + i, path->used - i); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (first_nulless) { + if (path->string[i] == f_path_separator[0]) { + if (null_terminated) { + path->string[i + 1] = 0; + path->used = i + 2; + } + else { + path->used = i + 1; + } + + return F_none; + } + } + else { + first_nulless = F_true; + + for (j = i; j > 0; j--) { + if (path->string[j] == 0) continue; + + status = f_utf_is_control(path->string + j, path->used - j); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (path->string[j] != f_path_separator[0]) { + i = j + 1; + break; + } + } // for + } + } // for + + path->used = 0; + return F_none; + } +#endif // _di_fl_directory_path_pop_ + +#ifndef _di_fl_directory_path_push_ + f_return_status fl_directory_path_push(const f_string source, f_string_length length, f_string_dynamic *destination) { + #ifndef _di_level_0_parameter_checking_ + if (destination->used > destination->size) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (length == 0) { + return F_data_not; + } + + return private_fl_directory_path_push(source, length, destination); + } +#endif // _di_fl_directory_path_push_ + +#ifndef _di_fl_directory_path_push_dynamic_ + f_return_status fl_directory_path_push_dynamic(const f_string_static source, f_string_dynamic *destination) { + #ifndef _di_level_0_parameter_checking_ + if (source.used > source.size) return F_status_set_error(F_parameter); + if (destination->used > destination->size) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (source.used == 0) { + return F_data_not; + } + + return private_fl_directory_path_push(source.string, source.used, destination); + } +#endif // _di_fl_directory_path_push_dynamic_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h index bd5b082..1009997 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_1/fl_directory/c/directory.h @@ -34,8 +34,10 @@ #include #include #include -#include +#include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -187,6 +189,75 @@ extern "C" { extern f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing); #endif // _di_fl_directory_list_ +/** + * Append a path string onto the destination path. + * + * This ensures that there is a trailing '/' after pop. + * This ignores control characters. + * This does not dynamically reallocate the string. + * + * @param path + * The path to remove a single directory. + * This will only be NULL terminated if path string is already NULL terminated. + * + * @return + * F_none on success. + * F_data_not if path.used is 0. + * F_parameter (with error bit) if a parameter is invalid. + */ +#ifndef _di_fl_directory_path_pop_ + extern f_return_status fl_directory_path_pop(f_string_static *path); +#endif // _di_fl_directory_path_pop_ + +/** + * Append a path string onto the destination path. + * + * This ensures that there is a leading and trailing '/' from source. + * This ignores control characters. + * + * @param source + * The path to append onto the destination. + * This need not be NULL terminated. + * @param length + * The length of the string. + * Must not exceed length of source. + * @param destination + * The destination path to push the path part onto. + * Any terminating NULLs at the end of the destination string are removed before appending. + * This will only be NULL terminated if destination string is already NULL terminated. + * + * @return + * F_none on success. + * F_data_not if length is 0. + * F_parameter (with error bit) if a parameter is invalid. + */ +#ifndef _di_fl_directory_path_push_ + extern f_return_status fl_directory_path_push(const f_string source, f_string_length length, f_string_dynamic *destination); +#endif // _di_fl_directory_path_push_ + +/** + * Append a dynamic path string onto the destination path. + * + * This ensures that there is a leading and trailing '/' from source. + * This ignores control characters. + * + * @param source + * The path to append onto the destination. + * This need not be NULL terminated. + * @param destination + * The destination path to push the path part onto. + * Any terminating NULLs at the end of the destination string are removed before appending. + * This will only be NULL terminated if destination string is already NULL terminated. + * + * @return + * F_none on success. + * F_data_not if source.used is 0. + * F_parameter (with error bit) if a parameter is invalid. + */ +#ifndef _di_fl_directory_path_push_dynamic_ + extern f_return_status fl_directory_path_push_dynamic(const f_string_static source, f_string_dynamic *destination); +#endif // _di_fl_directory_path_push_dynamic_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c index 9ee5299..38e482e 100644 --- a/level_1/fl_directory/c/private-directory.c +++ b/level_1/fl_directory/c/private-directory.c @@ -246,6 +246,214 @@ extern "C" { } #endif // !defined(_di_fl_directory_list_) +#if !defined(_di_fl_directory_path_push_) || !defined(_di_fl_directory_path_push_dynamic_) + f_return_status private_fl_directory_path_push(const f_string source, const f_string_length length, f_string_dynamic *destination) { + bool terminated_null = F_false; + bool separator_prepend = F_false; + bool separator_append = F_false; + + f_string_length total = 0; + f_string_length start = 0; + f_string_length length_truncated = length; + f_status status = F_none; + + { + f_string_length i = 0; + f_string_length j = 0; + + if (destination->used > 0) { + if (destination->string[destination->used - 1] == 0) { + terminated_null = F_true; + total = 1; + + destination->used--; + } + + for (i = destination->used - 1; i > 0; i--) { + if (destination->string[i] == 0) continue; + + status = f_utf_is_control(destination->string + i, destination->used - i); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (destination->string[i] == f_path_separator[0]) { + if (i - 1 > 0) { + for (j = i - 1; j > 0; j--) { + if (destination->string[j] == 0) continue; + + status = f_utf_is_control(destination->string + j, destination->used - j); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (destination->string[j] == f_path_separator[0]) { + destination->used = j + 1; + } + else { + break; + } + } // for + } + } + else { + separator_prepend = F_true; + total++; + } + + break; + } // for + + if (destination->used > 0 && i == 0) { + if (destination->string[0] != 0 && destination->string[0] != f_path_separator[0]) { + separator_prepend = F_true; + total++; + } + } + } + + for (i = length - 1; i > 0; i--) { + if (source[i] == 0) continue; + + status = f_utf_is_control(source + i, length - i); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (source[i] == f_path_separator[0]) { + if (!separator_prepend && destination->used > 0) { + destination->used--; + } + + if (i - 1 > 0) { + for (j = i - 1; j > 0; j--) { + if (source[j] == 0) continue; + + status = f_utf_is_control(source + j, length - j); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (source[j] == f_path_separator[0]) { + length_truncated = j + 1; + } + else { + break; + } + } // for + } + } + else { + separator_append = F_true; + total++; + } + + break; + } // for + + if (i == 0 && source[0] != f_path_separator[0]) { + separator_append = F_true; + total++; + } + + for (i = 0; i < length_truncated; i++) { + if (source[i] == 0) continue; + + status = f_utf_is_control(source + i, length - i); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + start = i; + + if (source[0] == f_path_separator[0]) { + if (i + 1 < length_truncated) { + for (j = i + 1; j < length_truncated; j++) { + if (source[j] == 0) continue; + + status = f_utf_is_control(source + j, length - j); + if (status == F_true) continue; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_incomplete_utf) continue; + + return status; + } + + if (source[j] == f_path_separator[0]) { + start = j; + } + else { + break; + } + } // for + } + } + + break; + } // for + + total += length_truncated - start; + + if (destination->used + total > destination->size) { + if (destination->used + total > f_string_length_size) { + return F_status_set_error(F_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*destination), destination->used + total); + if (F_status_is_error(status)) return status; + } + } + + if (separator_prepend) { + destination->string[destination->used] = f_path_separator[0]; + destination->used++; + total--; + } + + if (length_truncated - start > 0) { + memcpy(destination->string + destination->used, source + start, length_truncated - start); + } + + destination->used += total; + + if (separator_append) { + if (terminated_null) { + destination->string[destination->used - 2] = f_path_separator[0]; + destination->string[destination->used - 1] = 0; + } + else { + destination->string[destination->used - 1] = f_path_separator[0]; + } + } + else if (terminated_null) { + destination->string[destination->used - 1] = 0; + } + + return F_none; + } +#endif // !defined(_di_fl_directory_path_push_) || !defined(_di_fl_directory_path_push_dynamic_) + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h index 4be289f..5f49025 100644 --- a/level_1/fl_directory/c/private-directory.h +++ b/level_1/fl_directory/c/private-directory.h @@ -72,6 +72,34 @@ extern "C" { extern f_return_status private_fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing) f_gcc_attribute_visibility_internal; #endif // !defined(_di_fl_directory_list_) +/** + * Private implementation of fl_directory_path_push(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param source + * The path to append onto the destination. + * This need not be NULL terminated. + * @param length + * The length of the string. + * Must not exceed length of source. + * @param destination + * The destination path to push the path part onto. + * Any terminating NULLs at the end of the destination string are removed before appending. + * This will only be NULL terminated if destination string is already NULL terminated. + * + * @return + * F_none on success. + * F_data_not if length is 0. + * F_parameter (with error bit) if a parameter is invalid. + * + * @see fl_directory_path_push() + * @see fl_directory_path_push_dynamic() + */ +#if !defined(_di_fl_directory_path_push_) || !defined(_di_fl_directory_path_push_dynamic_) + extern f_return_status private_fl_directory_path_push(const f_string source, const f_string_length length, f_string_dynamic *destination) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_directory_path_push_) || !defined(_di_fl_directory_path_push_dynamic_) + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_directory/data/build/dependencies b/level_1/fl_directory/data/build/dependencies index 1e76143..c1d179c 100644 --- a/level_1/fl_directory/data/build/dependencies +++ b/level_1/fl_directory/data/build/dependencies @@ -2,5 +2,7 @@ f_type f_status f_memory f_string -f_file +f_utf f_directory +f_file +f_path diff --git a/level_1/fl_directory/data/build/settings b/level_1/fl_directory/data/build/settings index 3e20c08..64381b8 100644 --- a/level_1/fl_directory/data/build/settings +++ b/level_1/fl_directory/data/build/settings @@ -10,9 +10,9 @@ version_micro 0 build_compiler gcc build_linker ar build_libraries -lc -build_libraries_fll -lf_file -lf_directory -lf_memory +build_libraries_fll -lf_file -lf_directory -lf_path -lf_utf -lf_memory build_sources_library directory.c private-directory.c -build_sources_program +build_sources_program build_sources_headers directory.h build_sources_bash build_sources_settings