]> Kevux Git Server - fll/commitdiff
Feature: add push and pop directory functions
authorKevin Day <thekevinday@gmail.com>
Mon, 25 May 2020 04:02:22 +0000 (23:02 -0500)
committerKevin Day <thekevinday@gmail.com>
Mon, 25 May 2020 04:02:22 +0000 (23:02 -0500)
These functions should help make appending interactive or user-data for directory path building easier.

level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c
level_1/fl_directory/c/private-directory.h
level_1/fl_directory/data/build/dependencies
level_1/fl_directory/data/build/settings

index 452d35ac3aca793a0a85cc554eb8eab17171a442..bb8db8f6a988ccb79f54fa356eecb0cf1ecb5bd7 100644 (file)
@@ -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
index bd5b0828207eb1275acf4baedf0cd377144a26af..100999770f0b0128e98b9ceee65a0dfac232729f 100644 (file)
 #include <level_0/memory.h>
 #include <level_0/string.h>
 #include <level_0/type.h>
-#include <level_0/file.h>
+#include <level_0/utf.h>
 #include <level_0/directory.h>
+#include <level_0/file.h>
+#include <level_0/path.h>
 
 #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
index 9ee529929b6d9ae111c54463950f323f2834e4e6..38e482e2b48ff9065d7a4ffb91f65a3555b40d2e 100644 (file)
@@ -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
index 4be289f523afe3c70bc914b66d9f10b5b763a141..5f49025568b74a13a0b7d4f1adbe66d000407c6a 100644 (file)
@@ -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
index 1e761430773783c3fa6f0b1e4048c69983f6b670..c1d179c3ee90c4688a68d60c9c63f73eb3db7a98 100644 (file)
@@ -2,5 +2,7 @@ f_type
 f_status
 f_memory
 f_string
-f_file
+f_utf
 f_directory
+f_file
+f_path
index 3e20c0891666e06b94339391f75add40b0a201f7..64381b8d002d0e976bf2798b03ea3624fa61e5eb 100644 (file)
@@ -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