]> Kevux Git Server - fll/commitdiff
Feature: Add string assure functions to assure a given string exists at the beginning...
authorKevin Day <thekevinday@gmail.com>
Sun, 10 May 2020 05:45:03 +0000 (00:45 -0500)
committerKevin Day <thekevinday@gmail.com>
Sun, 10 May 2020 05:45:03 +0000 (00:45 -0500)
This is particularly useful for assuring that a "/" exists and the end of generated path strings.

level_1/fl_string/c/string.c
level_1/fl_string/c/string.h
level_1/fl_utf/c/utf.c
level_1/fl_utf/c/utf.h

index b515eb9e1906087e0e9e2820837415775acee9f5..b1b9a211c5b46cb1b0ac03c35a0d84a3f5ec59f7 100644 (file)
@@ -17,6 +17,82 @@ extern "C" {
   }
 #endif // _di_fl_string_append_
 
+#ifndef _di_fl_string_append_assure_
+  f_return_status fl_string_append_assure(const f_string source, const f_string_length length, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_string_append(source, length, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source[length - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[length - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_append_assure_
+
+#ifndef _di_fl_string_append_assure_nulless_
+  f_return_status fl_string_append_assure_nulless(const f_string source, const f_string_length length, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_string_append_nulless(source, length, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source[length - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[length - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append_nulless(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_append_assure_nulless_
+
 #ifndef _di_fl_string_append_nulless_
   f_return_status fl_string_append_nulless(const f_string source, const f_string_length length, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -65,6 +141,82 @@ extern "C" {
   }
 #endif // _di_fl_string_dynamic_append_
 
+#ifndef _di_fl_string_dynamic_append_assure_
+  f_return_status fl_string_dynamic_append_assure(const f_string_static source, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_string_append(source.string, source.used, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= source.used && j <= destination->used) {
+      if (source.string[source.used - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[source.used - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_dynamic_append_assure_
+
+#ifndef _di_fl_string_dynamic_append_assure_nulless_
+  f_return_status fl_string_dynamic_append_assure_nulless(const f_string_static source, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_string_append_nulless(source.string, source.used, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= source.used && j <= destination->used) {
+      if (source.string[source.used - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[source.used - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append_nulless(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_dynamic_append_assure_nulless_
+
 #ifndef _di_fl_string_dynamic_append_nulless_
   f_return_status fl_string_dynamic_append_nulless(const f_string_static source, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -163,6 +315,86 @@ extern "C" {
   }
 #endif // _di_fl_string_dynamic_partial_append_
 
+#ifndef _di_fl_string_dynamic_partial_append_assure_
+  f_return_status fl_string_dynamic_partial_append_assure(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_string_append(source.string + range.start, length, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source.string[range.stop - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[range.stop - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+  }
+#endif // _di_fl_string_dynamic_partial_append_assure_
+
+#ifndef _di_fl_string_dynamic_partial_append_assure_nulless_
+  f_return_status fl_string_dynamic_partial_append_assure_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_string_append_nulless(source.string + range.start, length, destination);
+    }
+
+    f_string_length i = 1;
+    f_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source.string[range.stop - i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[range.stop - i] != destination->string[destination->used - j]) {
+        return private_fl_string_append_nulless(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+  }
+#endif // _di_fl_string_dynamic_append_assure_nulless_
+
 #ifndef _di_fl_string_dynamic_partial_append_nulless_
   f_return_status fl_string_dynamic_partial_append_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -289,10 +521,94 @@ extern "C" {
     if (source.used == 0) return f_no_data;
     if (range.start > range.stop) return f_no_data;
 
-    return private_fl_string_prepend(source.string + range.start, (range.stop - range.start) + 1, destination);
+    f_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_string_prepend(source.string + range.start, length, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source.string[i + range.start] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i + range.start] != destination->string[i]) {
+        return private_fl_string_prepend(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
   }
 #endif // _di_fl_string_dynamic_partial_prepend_
 
+#ifndef _di_fl_string_dynamic_partial_prepend_assure_
+  f_return_status fl_string_dynamic_partial_prepend_assure(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_string_prepend_nulless(source.string + range.start, length, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source.string[i + range.start] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i + range.start] != destination->string[i]) {
+        return private_fl_string_prepend_nulless(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_dynamic_partial_prepend_assure_
+
+#ifndef _di_fl_string_dynamic_partial_prepend_assure_nulless_
+  f_return_status fl_string_dynamic_partial_prepend_assure_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    return private_fl_string_prepend_nulless(source.string + range.start, (range.stop - range.start) + 1, destination);
+  }
+#endif // _di_fl_string_dynamic_partial_prepend_assure_nulless
+
 #ifndef _di_fl_string_dynamic_partial_prepend_nulless_
   f_return_status fl_string_dynamic_partial_prepend_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -319,6 +635,82 @@ extern "C" {
   }
 #endif // _di_fl_string_dynamic_prepend_
 
+#ifndef _di_fl_string_dynamic_prepend_assure_
+  f_return_status fl_string_dynamic_prepend_assure(const f_string_static source, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_string_prepend(source.string, source.used, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < source.used && j < destination->used) {
+      if (source.string[i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i] != destination->string[i]) {
+        return private_fl_string_prepend(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_dynamic_prepend_assure_
+
+#ifndef _di_fl_string_dynamic_prepend_assure_nulless_
+  f_return_status fl_string_dynamic_prepend_assure_nulless(const f_string_static source, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_string_prepend_nulless(source.string, source.used, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < source.used && j < destination->used) {
+      if (source.string[i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i] != destination->string[i]) {
+        return private_fl_string_prepend_nulless(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_dynamic_prepend_assure_nulless_
+
 #ifndef _di_fl_string_dynamic_prepend_nulless_
   f_return_status fl_string_dynamic_prepend_nulless(const f_string_static source, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -766,6 +1158,82 @@ extern "C" {
   }
 #endif // _di_fl_string_prepend_nulless_
 
+#ifndef _di_fl_string_prepend_assure_
+  f_return_status fl_string_prepend_assure(const f_string source, const f_string_length length, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_string_prepend(source, length, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source[i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[i] != destination->string[i]) {
+        return private_fl_string_prepend(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_prepend_assure_
+
+#ifndef _di_fl_string_prepend_assure_nulless_
+  f_return_status fl_string_prepend_assure_nulless(const f_string source, const f_string_length length, f_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_string_prepend_nulless(source, length, destination);
+    }
+
+    f_string_length i = 0;
+    f_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source[i] == f_string_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_string_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[i] != destination->string[i]) {
+        return private_fl_string_prepend_nulless(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_string_prepend_assure_nulless_
+
 #ifndef _di_fl_string_rip_
   f_return_status fl_string_rip(const f_string source, const f_string_length length, f_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
index 311935d8c8cf7cc934523a940ca8d39efe1bc6ce..2b64c98e5a8c52e6cd0a15509f3997b64202a4dd 100644 (file)
@@ -59,6 +59,59 @@ extern "C" {
 #endif // _di_fl_string_append_
 
 /**
+ * Append the source string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to append.
+ * @param length
+ *   The length of source to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_append_assure_nulless()
+ */
+#ifndef _di_fl_string_append_assure_
+  extern f_return_status fl_string_append_assure(const f_string source, const f_string_length length, f_string_dynamic *destination);
+#endif // _di_fl_string_append_assure_
+
+/**
+ * Append the source string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param length
+ *   The length of source to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_append_assure()
+ */
+#ifndef _di_fl_string_append_assure_nulless_
+  extern f_return_status fl_string_append_assure_nulless(const f_string source, const f_string_length length, f_string_dynamic *destination);
+#endif // _di_fl_string_append_assure_nulless_
+
+/**
  * Append the source string onto the destination.
  *
  * Skips over NULL characters from source when appending.
@@ -168,6 +221,52 @@ extern "C" {
 /**
  * Append the source string onto the destination.
  *
+ * @param source
+ *   The source string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_append_assure_nulless()
+ */
+#ifndef _di_fl_string_dynamic_append_assure_
+  extern f_return_status fl_string_dynamic_append_assure(const f_string_static source, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_append_assure_
+
+/**
+ * Append the source string onto the destination.
+ *
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_append_assure()
+ */
+#ifndef _di_fl_string_dynamic_append_assure_nulless_
+  extern f_return_status fl_string_dynamic_append_assure_nulless(const f_string_static source, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_append_assure_nulless_
+
+/**
+ * Append the source string onto the destination.
+ *
  * Skips over NULL characters from source when appending.
  *
  * @param source
@@ -381,6 +480,60 @@ extern "C" {
 #endif // _di_fl_string_dynamic_partial_append_
 
 /**
+ * Append the source string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to append.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_partial_append_assure_nulless()
+ */
+#ifndef _di_fl_string_dynamic_partial_append_assure_
+  extern f_return_status fl_string_dynamic_partial_append_assure(const f_string_static source, const f_string_range range, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_partial_append_assure_
+
+/**
+ * Append the source string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_partial_append_assure()
+ */
+#ifndef _di_fl_string_dynamic_partial_append_assure_nulless_
+  extern f_return_status fl_string_dynamic_partial_append_assure_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_partial_append_assure_nulless_
+
+/**
  * Append the source string onto the destination, but restricted to the given range.
  *
  * Skips over NULL characters from source when appending.
@@ -616,6 +769,62 @@ extern "C" {
 #endif // _di_fl_string_dynamic_partial_prepend_
 
 /**
+ * Prepend the source string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_partial_prepend_assure_nulless()
+ */
+#ifndef _di_fl_string_dynamic_partial_prepend_assure_
+  extern f_return_status fl_string_dynamic_partial_prepend_assure(const f_string_static source, const f_string_range range, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_partial_prepend_assure_
+
+/**
+ * Prepend the source string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_partial_prepend_assure()
+ */
+#ifndef _di_fl_string_dynamic_partial_prepend_assure_nulless_
+  extern f_return_status fl_string_dynamic_partial_prepend_assure_nulless(const f_string_static source, const f_string_range range, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_partial_prepend_assure_nulless_
+
+/**
  * Prepend the source string onto the destination, but restricted to the given range.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
@@ -666,6 +875,58 @@ extern "C" {
 #endif // _di_fl_string_dynamic_prepend_
 
 /**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_prepend_assure_nulless()
+ */
+#ifndef _di_fl_string_dynamic_prepend_assure_
+  extern f_return_status fl_string_dynamic_prepend_assure(const f_string_static source, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_prepend_assure_
+
+/**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_prepend_assure()
+ */
+#ifndef _di_fl_string_dynamic_prepend_assure_nulless_
+  extern f_return_status fl_string_dynamic_prepend_assure_nulless(const f_string_static source, f_string_dynamic *destination);
+#endif // _di_fl_string_dynamic_prepend_assure_nulless_
+
+/**
  * Prepend the source string onto the destination.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
@@ -1080,10 +1341,68 @@ extern "C" {
 #endif // _di_fl_string_prepend_
 
 /**
- * Prepend the source string onto the destination.
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param length
+ *   The length of source to append.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_prepend_assure_nulless()
+ */
+#ifndef _di_fl_string_prepend_assure_
+  extern f_return_status fl_string_prepend_assure(const f_string source, const f_string_length length, f_string_dynamic *destination);
+#endif // _di_fl_string_prepend_assure_
+
+/**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when prepending.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param length
+ *   The length of source to append.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_string_dynamic_prepend_assure()
+ */
+#ifndef _di_fl_string_prepend_assure_nulless_
+  extern f_return_status fl_string_prepend_assure_nulless(const f_string source, const f_string_length length, f_string_dynamic *destination);
+#endif // _di_fl_string_prepend_assure_nulless_
+
+/**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
  *
+ * This ignores NULL characters when comparing both the source and the destination.
  * Skips over NULL characters from source when prepending.
  *
  * @param source
index a9140ca6e463026950e5758f0dbdb7e642549845..0d82090208318bd7acc7804dfd83bebb226ff384 100644 (file)
@@ -29,6 +29,82 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_append_nulless_
 
+#ifndef _di_fl_utf_string_append_assure_
+  f_return_status fl_utf_string_append_assure(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_append(source, length, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source[length - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[length - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_append_assure_
+
+#ifndef _di_fl_utf_string_append_assure_nulless_
+  f_return_status fl_utf_string_append_assure_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_append_nulless(source, length, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source[length - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[length - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append_nulless(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_append_assure_nulless_
+
 #ifndef _di_fl_utf_string_compare_
   f_return_status fl_utf_string_compare(const f_utf_string string1, const f_utf_string string2, const f_utf_string_length length1, const f_utf_string_length length2) {
     #ifndef _di_level_1_parameter_checking_
@@ -63,6 +139,82 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_dynamic_append_
 
+#ifndef _di_fl_utf_string_dynamic_append_assure_
+  f_return_status fl_utf_string_dynamic_append_assure(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_utf_string_append(source.string, source.used, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= source.used && j <= destination->used) {
+      if (source.string[source.used - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[source.used - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_append_assure_
+
+#ifndef _di_fl_utf_string_dynamic_append_assure_nulless_
+  f_return_status fl_utf_string_dynamic_append_assure_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_utf_string_append_nulless(source.string, source.used, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= source.used && j <= destination->used) {
+      if (source.string[source.used - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[source.used - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append_nulless(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_append_assure_nulless_
+
 #ifndef _di_fl_utf_string_dynamic_append_nulless_
   f_return_status fl_utf_string_dynamic_append_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -181,6 +333,86 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_dynamic_partial_append_
 
+#ifndef _di_fl_utf_string_dynamic_partial_append_assure_
+  f_return_status fl_utf_string_dynamic_partial_append_assure(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_utf_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_append(source.string + range.start, length, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source.string[range.stop - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[range.stop - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+  }
+#endif // _di_fl_utf_string_dynamic_partial_append_assure_
+
+#ifndef _di_fl_utf_string_dynamic_partial_append_assure_nulless_
+  f_return_status fl_utf_string_dynamic_partial_append_assure_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_utf_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_append_nulless(source.string + range.start, length, destination);
+    }
+
+    f_utf_string_length i = 1;
+    f_utf_string_length j = 1;
+
+    while (i <= length && j <= destination->used) {
+      if (source.string[range.stop - i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[destination->used - j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[range.stop - i] != destination->string[destination->used - j]) {
+        return private_fl_utf_string_append_nulless(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+  }
+#endif // _di_fl_utf_string_dynamic_partial_append_assure_nulless_
+
 #ifndef _di_fl_utf_string_dynamic_partial_append_nulless_
   f_return_status fl_utf_string_dynamic_partial_append_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -319,6 +551,90 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_dynamic_partial_prepend_
 
+#ifndef _di_fl_utf_string_dynamic_partial_prepend_assure_
+  f_return_status fl_utf_string_dynamic_partial_prepend_assure(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_utf_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_prepend(source.string + range.start, length, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source.string[i + range.start] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i + range.start] != destination->string[i]) {
+        return private_fl_utf_string_prepend(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_partial_prepend_assure_
+
+#ifndef _di_fl_utf_string_dynamic_partial_prepend_assure_nulless_
+  f_return_status fl_utf_string_dynamic_partial_prepend_assure_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (source.used <= range.stop) return f_status_set_error(f_invalid_parameter);
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+    if (range.start > range.stop) return f_no_data;
+
+    f_utf_string_length length = (range.stop - range.start) + 1;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_prepend_nulless(source.string + range.start, length, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source.string[i + range.start] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i + range.start] != destination->string[i]) {
+        return private_fl_utf_string_prepend_nulless(source.string + range.start, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_partial_prepend_assure_nulless_
+
 #ifndef _di_fl_utf_string_dynamic_partial_prepend_nulless_
   f_return_status fl_utf_string_dynamic_partial_prepend_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -345,6 +661,82 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_dynamic_prepend_
 
+#ifndef _di_fl_utf_string_dynamic_prepend_assure_
+  f_return_status fl_utf_string_dynamic_prepend_assure(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_utf_string_prepend(source.string, source.used, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < source.used && j < destination->used) {
+      if (source.string[i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i] != destination->string[i]) {
+        return private_fl_utf_string_prepend(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_prepend_assure_
+
+#ifndef _di_fl_utf_string_dynamic_prepend_assure_nulless_
+  f_return_status fl_utf_string_dynamic_prepend_assure_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (source.used == 0) return f_no_data;
+
+    if (destination->used < source.used) {
+      return private_fl_utf_string_prepend_nulless(source.string, source.used, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < source.used && j < destination->used) {
+      if (source.string[i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source.string[i] != destination->string[i]) {
+        return private_fl_utf_string_prepend_nulless(source.string, source.used, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_dynamic_prepend_assure_nulless_
+
 #ifndef _di_fl_utf_string_dynamic_prepend_nulless_
   f_return_status fl_utf_string_dynamic_prepend_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
@@ -619,7 +1011,7 @@ extern "C" {
       if (f_status_is_error(status)) return status;
     }
 
-    destination->string[destination->used] = f_string_eos;
+    destination->string[destination->used] = f_utf_character_eos;
     destination->used = total;
 
     return f_none;
@@ -718,6 +1110,82 @@ extern "C" {
   }
 #endif // _di_fl_utf_string_prepend_
 
+#ifndef _di_fl_utf_string_prepend_assure_
+  f_return_status fl_utf_string_prepend_assure(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_prepend(source, length, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source[i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[i] != destination->string[i]) {
+        return private_fl_utf_string_prepend(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_prepend_assure_
+
+#ifndef _di_fl_utf_string_prepend_assure_nulless_
+  f_return_status fl_utf_string_prepend_assure_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination) {
+    #ifndef _di_level_1_parameter_checking_
+      if (destination == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_1_parameter_checking_
+
+    if (length == 0) return f_no_data;
+
+    if (destination->used < length) {
+      return private_fl_utf_string_prepend_nulless(source, length, destination);
+    }
+
+    f_utf_string_length i = 0;
+    f_utf_string_length j = 0;
+
+    while (i < length && j < destination->used) {
+      if (source[i] == f_utf_character_eos) {
+        i++;
+        continue;
+      }
+
+      if (destination->string[j] == f_utf_character_eos) {
+        j++;
+        continue;
+      }
+
+      if (source[i] != destination->string[i]) {
+        return private_fl_utf_string_prepend_nulless(source, length, destination);
+      }
+
+      i++;
+      j++;
+    } // while
+
+    return f_none;
+  }
+#endif // _di_fl_utf_string_prepend_assure_nulless_
+
 #ifndef _di_fl_utf_string_prepend_nulless_
   f_return_status fl_utf_string_prepend_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination) {
     #ifndef _di_level_1_parameter_checking_
index 3b14cd2d9341746a385bcc67a18731c07714f259..de840ad2c3cbbb5227c173d9fb0fd5a05c075525 100644 (file)
@@ -82,13 +82,70 @@ extern "C" {
  *   f_error_allocation (with error bit) on memory allocation error.
  *   f_error_reallocation (with error bit) on memory reallocation error.
  *
- * @see fl_utf_string_append()
+ * @see fl_utf_string_append_assure()
  */
 #ifndef _di_fl_utf_string_append_nulless_
   extern f_return_status fl_utf_string_append_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination);
 #endif // _di_fl_utf_string_append_nulless_
 
 /**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to append.
+ * @param start
+ *   Inclusive start point of string to append.
+ * @param stop
+ *   Inclusive stop point of string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_append_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_append_assure_
+  extern f_return_status fl_utf_string_append_assure(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_append_assure_
+
+/**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param start
+ *   Inclusive start point of string to append.
+ * @param stop
+ *   Inclusive stop point of string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_append()
+ */
+#ifndef _di_fl_utf_string_append_assure_nulless_
+  extern f_return_status fl_utf_string_append_assure_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_append_assure_nulless_
+
+/**
  * Compare two UTF-8 strings, similar to strncmp().
  *
  * This does not stop on NULL.
@@ -172,6 +229,55 @@ extern "C" {
 #endif // _di_fl_utf_string_dynamic_append_
 
 /**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_append_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_dynamic_append_assure_
+  extern f_return_status fl_utf_string_dynamic_append_assure(const f_utf_string_dynamic source, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_append_assure_
+
+/**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_append_assure()
+ */
+#ifndef _di_fl_utf_string_dynamic_append_assure_nulless_
+  extern f_return_status fl_utf_string_dynamic_append_assure_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_append_assure_nulless_
+
+/**
  * Append the source UTF-8 string onto the destination.
  *
  * Skips over NULL characters from source when appending.
@@ -395,6 +501,58 @@ extern "C" {
 /**
  * Append the source UTF-8 string onto the destination, but restricted to the given range.
  *
+ * @param source
+ *   The source string to append.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_partial_append_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_dynamic_partial_append_assure_
+  extern f_return_status fl_utf_string_dynamic_partial_append_assure(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_partial_append_assure_
+
+/**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when appending.
+ *
+ * @param source
+ *   The source string to append.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is appended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_partial_append_assure()
+ */
+#ifndef _di_fl_utf_string_dynamic_partial_append_assure_nulless_
+  extern f_return_status fl_utf_string_dynamic_partial_append_assure_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_partial_append_assure_nulless_
+
+/**
+ * Append the source UTF-8 string onto the destination, but only if the string is not already at the end and restricted to the given range
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
  * Skips over NULL characters from source when appending.
  *
  * @param source
@@ -630,6 +788,62 @@ extern "C" {
 #endif // _di_fl_utf_string_dynamic_partial_prepend_
 
 /**
+ * Prepend the source string onto the destination, but restricted to the given range, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_partial_prepend_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_dynamic_partial_prepend_assure_
+  extern f_return_status fl_utf_string_dynamic_partial_prepend_assure(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_partial_prepend_assure_
+
+/**
+ * Prepend the source string onto the destination, but restricted to the given range, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param range
+ *   A range within the source to restrict the copy from.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 or range is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_partial_prepend_assure()
+ */
+#ifndef _di_fl_utf_string_dynamic_partial_prepend_assure_nulless_
+  extern f_return_status fl_utf_string_dynamic_partial_prepend_assure_nulless(const f_utf_string_dynamic source, const f_utf_string_range range, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_partial_prepend_assure_nulless_
+
+/**
  * Prepend the source string onto the destination, but restricted to the given range.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
@@ -680,6 +894,58 @@ extern "C" {
 #endif // _di_fl_utf_string_dynamic_prepend_
 
 /**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_prepend_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_dynamic_prepend_assure_
+  extern f_return_status fl_utf_string_dynamic_prepend_assure(const f_utf_string_dynamic source, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_prepend_assure_
+
+/**
+ * Prepend the source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0.
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_dynamic_prepend_assure()
+ */
+#ifndef _di_fl_utf_string_dynamic_prepend_assure_nulless_
+  extern f_return_status fl_utf_string_dynamic_prepend_assure_nulless(const f_utf_string_dynamic source, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_dynamic_prepend_assure_nulless_
+
+/**
  * Prepend the source string onto the destination.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
@@ -1118,6 +1384,67 @@ extern "C" {
 #endif // _di_fl_utf_string_prepend_
 
 /**
+ * Prepend the UTF-8 source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param start
+ *   Inclusive start point of string to prepend.
+ * @param stop
+ *   Inclusive stop point of string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_prepend_assure_nulless()
+ */
+#ifndef _di_fl_utf_string_prepend_assure_
+  extern f_return_status fl_utf_string_prepend_assure(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_prepend_assure_
+
+/**
+ * Prepend the UTF-8 source string onto the destination, but only if the string is not already at the beginning.
+ *
+ * Prepend operations require memory move operations and are therefore likely more expensive than append operations.
+ *
+ * This ignores NULL characters when comparing both the source and the destination.
+ * Skips over NULL characters from source when prepending.
+ *
+ * @param source
+ *   The source string to prepend.
+ * @param start
+ *   Inclusive start point of string to prepend.
+ * @param stop
+ *   Inclusive stop point of string to prepend.
+ * @param destination
+ *   The destination string the source is prepended onto.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if source length is 0 (start > stop).
+ *   f_string_max_size (with error bit) if the combined string is too large.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on memory allocation error.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see fl_utf_string_prepend_assure()
+ */
+#ifndef _di_fl_utf_string_prepend_assure_nulless_
+  extern f_return_status fl_utf_string_prepend_assure_nulless(const f_utf_string source, const f_utf_string_length length, f_utf_string_dynamic *destination);
+#endif // _di_fl_utf_string_prepend_assure_nulless_
+
+/**
  * Prepend the UTF-8 source string onto the destination.
  *
  * Prepend operations require memory move operations and are therefore likely more expensive than append operations.