]> Kevux Git Server - fll/commitdiff
Feature: Add several reverse string search functions.
authorKevin Day <Kevin@kevux.org>
Mon, 20 Jan 2025 03:01:31 +0000 (21:01 -0600)
committerKevin Day <Kevin@kevux.org>
Mon, 20 Jan 2025 03:22:38 +0000 (21:22 -0600)
These "_back" functions work based on the stop position of the range.

47 files changed:
build/stand_alone/byte_dump.config.h
build/stand_alone/example.config.h
build/stand_alone/fake.config.h
build/stand_alone/firewall.config.h
build/stand_alone/utf8.config.h
level_0/f_string/c/string.c
level_0/f_string/c/string.h
level_0/f_string/c/string/dynamic.c
level_0/f_string/c/string/dynamic.h
level_0/f_string/data/build/settings-tests
level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_line_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_line_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_line_to_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_line_to_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_to_back.c [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string-seek_to_back.h [new file with mode: 0644]
level_0/f_string/tests/unit/c/test-string.c
level_0/f_string/tests/unit/c/test-string.h
level_0/f_utf/c/utf/dynamic.c
level_0/f_utf/c/utf/dynamic.h
level_0/f_utf/c/utf/string.c
level_0/f_utf/c/utf/string.h
level_0/f_utf/c/utf/strings.c
level_0/f_utf/c/utf/strings.h
level_0/f_utf/c/utf/stringss.c
level_0/f_utf/c/utf/stringss.h
level_0/f_utf/data/build/settings-tests
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_line_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_line_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_to_back.c [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf-seek_to_back.h [new file with mode: 0644]
level_0/f_utf/tests/unit/c/test-utf.c
level_0/f_utf/tests/unit/c/test-utf.h

index 9b00419de6eb7f9398286d0a6116c2f9f8399472..5b5a939b5e9b110af9215c00206abafda629df93 100644 (file)
 #define _di_f_string_dynamic_prepend_assure_nulless_
 #define _di_f_string_dynamic_prepend_nulless_
 #define _di_f_string_dynamic_seek_line_
+#define _di_f_string_dynamic_seek_line_back_
 #define _di_f_string_dynamic_seek_line_to_
+#define _di_f_string_dynamic_seek_line_to_back_
 #define _di_f_string_dynamic_seek_to_
+#define _di_f_string_dynamic_seek_to_back_
 #define _di_f_string_dynamic_strip_null_
 #define _di_f_string_dynamic_strip_null_range_
 //#define _di_f_string_dynamic_t_
 #define _di_f_string_prepend_assure_nulless_
 #define _di_f_string_prepend_nulless_
 #define _di_f_string_seek_line_
+#define _di_f_string_seek_line_back_
 #define _di_f_string_seek_line_to_
+#define _di_f_string_seek_line_to_back_
 #define _di_f_string_seek_to_
+#define _di_f_string_seek_to_back_
 //#define _di_f_string_space_s_
 //#define _di_f_string_static_t_
 //#define _di_f_string_statics_t_
 #define _di_f_utf_string_dynamic_prepend_assure_nulless_
 #define _di_f_utf_string_dynamic_prepend_nulless_
 #define _di_f_utf_string_dynamic_seek_line_
+#define _di_f_utf_string_dynamic_seek_line_back_
 #define _di_f_utf_string_dynamic_seek_line_to_
+#define _di_f_utf_string_dynamic_seek_line_to_back_
 #define _di_f_utf_string_dynamic_seek_to_
+#define _di_f_utf_string_dynamic_seek_to_back_
 //#define _di_f_utf_string_dynamic_t_
 #define _di_f_utf_string_dynamic_terminate_
 #define _di_f_utf_string_dynamic_terminate_after_
 #define _di_f_utf_string_prepend_assure_nulless_
 #define _di_f_utf_string_prepend_nulless_
 #define _di_f_utf_string_seek_line_
+#define _di_f_utf_string_seek_line_back_
 #define _di_f_utf_string_seek_line_to_
+#define _di_f_utf_string_seek_line_to_back_
 #define _di_f_utf_string_seek_to_
+#define _di_f_utf_string_seek_to_back_
 //#define _di_f_utf_string_static_t_
 #define _di_f_utf_string_statics_t_
 #define _di_f_utf_string_staticss_t_
index de4490e49bb4de1620af6bcb462c1e58be82e720..f489fc10656a0ac4a22f13ce920c7ef8af5797d3 100644 (file)
 #define _di_f_string_dynamic_prepend_assure_nulless_
 #define _di_f_string_dynamic_prepend_nulless_
 #define _di_f_string_dynamic_seek_line_
+#define _di_f_string_dynamic_seek_line_back_
 #define _di_f_string_dynamic_seek_line_to_
+#define _di_f_string_dynamic_seek_line_to_back_
 #define _di_f_string_dynamic_seek_to_
+#define _di_f_string_dynamic_seek_to_back_
 #define _di_f_string_dynamic_strip_null_
 #define _di_f_string_dynamic_strip_null_range_
 //#define _di_f_string_dynamic_t_
 #define _di_f_string_prepend_assure_nulless_
 #define _di_f_string_prepend_nulless_
 #define _di_f_string_seek_line_
+#define _di_f_string_seek_line_back_
 #define _di_f_string_seek_line_to_
+#define _di_f_string_seek_line_to_back_
 #define _di_f_string_seek_to_
+#define _di_f_string_seek_to_back_
 #define _di_f_string_space_s_
 //#define _di_f_string_static_t_
 //#define _di_f_string_statics_t_
 #define _di_f_utf_string_dynamic_prepend_assure_nulless_
 #define _di_f_utf_string_dynamic_prepend_nulless_
 #define _di_f_utf_string_dynamic_seek_line_
+#define _di_f_utf_string_dynamic_seek_line_back_
 #define _di_f_utf_string_dynamic_seek_line_to_
+#define _di_f_utf_string_dynamic_seek_line_to_back_
 #define _di_f_utf_string_dynamic_seek_to_
+#define _di_f_utf_string_dynamic_seek_to_back_
 #define _di_f_utf_string_dynamic_t_
 #define _di_f_utf_string_dynamic_terminate_
 #define _di_f_utf_string_dynamic_terminate_after_
 #define _di_f_utf_string_prepend_assure_nulless_
 #define _di_f_utf_string_prepend_nulless_
 #define _di_f_utf_string_seek_line_
+#define _di_f_utf_string_seek_line_back_
 #define _di_f_utf_string_seek_line_to_
+#define _di_f_utf_string_seek_line_to_back_
 #define _di_f_utf_string_seek_to_
+#define _di_f_utf_string_seek_to_back_
 #define _di_f_utf_string_static_t_
 #define _di_f_utf_string_statics_t_
 #define _di_f_utf_string_staticss_t_
index e53427206f41db8246450910b8ac838f4b3bed82..c8d3981903ba2b5e83693bcc16e57fe95e8a9ddc 100644 (file)
 #define _di_f_string_dynamic_prepend_assure_nulless_
 #define _di_f_string_dynamic_prepend_nulless_
 #define _di_f_string_dynamic_seek_line_
+#define _di_f_string_dynamic_seek_line_back_
 #define _di_f_string_dynamic_seek_line_to_
+#define _di_f_string_dynamic_seek_line_to_back_
 #define _di_f_string_dynamic_seek_to_
+#define _di_f_string_dynamic_seek_to_back_
 #define _di_f_string_dynamic_strip_null_
 #define _di_f_string_dynamic_strip_null_range_
 //#define _di_f_string_dynamic_t_
 #define _di_f_string_prepend_assure_nulless_
 #define _di_f_string_prepend_nulless_
 #define _di_f_string_seek_line_
+#define _di_f_string_seek_line_back_
 #define _di_f_string_seek_line_to_
+#define _di_f_string_seek_line_to_back_
 #define _di_f_string_seek_to_
+#define _di_f_string_seek_to_back_
 //#define _di_f_string_space_s_
 //#define _di_f_string_static_t_
 //#define _di_f_string_statics_t_
 #define _di_f_utf_string_dynamic_prepend_assure_nulless_
 #define _di_f_utf_string_dynamic_prepend_nulless_
 #define _di_f_utf_string_dynamic_seek_line_
+#define _di_f_utf_string_dynamic_seek_line_back_
 #define _di_f_utf_string_dynamic_seek_line_to_
+#define _di_f_utf_string_dynamic_seek_line_to_back_
 #define _di_f_utf_string_dynamic_seek_to_
+#define _di_f_utf_string_dynamic_seek_to_back_
 //#define _di_f_utf_string_dynamic_t_
 #define _di_f_utf_string_dynamic_terminate_
 //#define _di_f_utf_string_dynamic_terminate_after_
 #define _di_f_utf_string_prepend_assure_nulless_
 #define _di_f_utf_string_prepend_nulless_
 #define _di_f_utf_string_seek_line_
+#define _di_f_utf_string_seek_line_back_
 #define _di_f_utf_string_seek_line_to_
+#define _di_f_utf_string_seek_line_to_back_
 #define _di_f_utf_string_seek_to_
+#define _di_f_utf_string_seek_to_back_
 //#define _di_f_utf_string_static_t_
 //#define _di_f_utf_string_statics_t_
 #define _di_f_utf_string_staticss_t_
index 5926c4a1321e88b5f11c9739be6f4d539359e0ad..95ec51a2892468a823469f61172db449deaa4ad6 100644 (file)
 #define _di_f_string_dynamic_prepend_assure_nulless_
 #define _di_f_string_dynamic_prepend_nulless_
 #define _di_f_string_dynamic_seek_line_
+#define _di_f_string_dynamic_seek_line_back_
 #define _di_f_string_dynamic_seek_line_to_
+#define _di_f_string_dynamic_seek_line_to_back_
 #define _di_f_string_dynamic_seek_to_
+#define _di_f_string_dynamic_seek_to_back_
 #define _di_f_string_dynamic_strip_null_
 #define _di_f_string_dynamic_strip_null_range_
 //#define _di_f_string_dynamic_t_
 #define _di_f_string_prepend_assure_nulless_
 #define _di_f_string_prepend_nulless_
 #define _di_f_string_seek_line_
+#define _di_f_string_seek_line_back_
 #define _di_f_string_seek_line_to_
+#define _di_f_string_seek_line_to_back_
 #define _di_f_string_seek_to_
+#define _di_f_string_seek_to_back_
 #define _di_f_string_space_s_
 //#define _di_f_string_static_t_
 //#define _di_f_string_statics_t_
 #define _di_f_utf_string_dynamic_prepend_assure_nulless_
 #define _di_f_utf_string_dynamic_prepend_nulless_
 #define _di_f_utf_string_dynamic_seek_line_
+#define _di_f_utf_string_dynamic_seek_line_back_
 #define _di_f_utf_string_dynamic_seek_line_to_
+#define _di_f_utf_string_dynamic_seek_line_to_back_
 #define _di_f_utf_string_dynamic_seek_to_
+#define _di_f_utf_string_dynamic_seek_to_back_
 #define _di_f_utf_string_dynamic_t_
 #define _di_f_utf_string_dynamic_terminate_
 #define _di_f_utf_string_dynamic_terminate_after_
 #define _di_f_utf_string_prepend_assure_nulless_
 #define _di_f_utf_string_prepend_nulless_
 #define _di_f_utf_string_seek_line_
+#define _di_f_utf_string_seek_line_back_
 #define _di_f_utf_string_seek_line_to_
+#define _di_f_utf_string_seek_line_to_back_
 #define _di_f_utf_string_seek_to_
+#define _di_f_utf_string_seek_to_back_
 #define _di_f_utf_string_static_t_
 #define _di_f_utf_string_statics_t_
 #define _di_f_utf_string_staticss_t_
index 34d216083a39619925a3e5d629c25d443c246901..0be76fc8fd23532d90b6628334e0b8da365dc133 100644 (file)
 #define _di_f_string_dynamic_prepend_assure_nulless_
 #define _di_f_string_dynamic_prepend_nulless_
 #define _di_f_string_dynamic_seek_line_
+#define _di_f_string_dynamic_seek_line_back_
 #define _di_f_string_dynamic_seek_line_to_
+#define _di_f_string_dynamic_seek_line_to_back_
 #define _di_f_string_dynamic_seek_to_
+#define _di_f_string_dynamic_seek_to_back_
 #define _di_f_string_dynamic_strip_null_
 #define _di_f_string_dynamic_strip_null_range_
 //#define _di_f_string_dynamic_t_
 #define _di_f_string_prepend_assure_nulless_
 #define _di_f_string_prepend_nulless_
 #define _di_f_string_seek_line_
+#define _di_f_string_seek_line_back_
 #define _di_f_string_seek_line_to_
+#define _di_f_string_seek_line_to_back_
 #define _di_f_string_seek_to_
+#define _di_f_string_seek_to_back_
 //#define _di_f_string_space_s_
 //#define _di_f_string_static_t_
 //#define _di_f_string_statics_t_
 #define _di_f_utf_string_dynamic_prepend_assure_nulless_
 #define _di_f_utf_string_dynamic_prepend_nulless_
 #define _di_f_utf_string_dynamic_seek_line_
+#define _di_f_utf_string_dynamic_seek_line_back_
 #define _di_f_utf_string_dynamic_seek_line_to_
+#define _di_f_utf_string_dynamic_seek_line_to_back_
 #define _di_f_utf_string_dynamic_seek_to_
+#define _di_f_utf_string_dynamic_seek_to_back_
 //#define _di_f_utf_string_dynamic_t_
 #define _di_f_utf_string_dynamic_terminate_
 #define _di_f_utf_string_dynamic_terminate_after_
 #define _di_f_utf_string_prepend_assure_nulless_
 #define _di_f_utf_string_prepend_nulless_
 #define _di_f_utf_string_seek_line_
+#define _di_f_utf_string_seek_line_back_
 #define _di_f_utf_string_seek_line_to_
+#define _di_f_utf_string_seek_line_to_back_
 #define _di_f_utf_string_seek_to_
+#define _di_f_utf_string_seek_to_back_
 //#define _di_f_utf_string_static_t_
 #define _di_f_utf_string_statics_t_
 #define _di_f_utf_string_staticss_t_
index 5b26bc2cac6a7cad79a195e36a6a6030e51db646..cf9b27fd2f8ef133b760d2331711b95fd0847cc6 100644 (file)
@@ -292,6 +292,25 @@ extern "C" {
   }
 #endif // _di_f_string_seek_line_
 
+#ifndef _di_f_string_seek_line_back_
+  f_status_t f_string_seek_line_back(const f_string_t string, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != f_string_eol_s.string[0]) {
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_seek_line_back_
+
 #ifndef _di_f_string_seek_line_to_
   f_status_t f_string_seek_line_to(const f_string_t string, const f_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -313,6 +332,27 @@ extern "C" {
   }
 #endif // _di_f_string_seek_line_to_
 
+#ifndef _di_f_string_seek_line_to_back_
+  f_status_t f_string_seek_line_to_back(const f_string_t string, const f_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      if (string[range->stop] == f_string_eol_s.string[0]) return F_okay_eol;
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_seek_line_to_back_
+
 #ifndef _di_f_string_seek_to_
   f_status_t f_string_seek_to(const f_string_t string, const f_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -332,6 +372,25 @@ extern "C" {
   }
 #endif // _di_f_string_seek_to_
 
+#ifndef _di_f_string_seek_to_back_
+  f_status_t f_string_seek_to_back(const f_string_t string, const f_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index a869348b173cae41be4af6f30d699f4f978919f9..c902e6148b66856578abbe4900c637309e421e79 100644 (file)
@@ -419,6 +419,30 @@ extern "C" {
 #endif // _di_f_string_seek_line_
 
 /**
+ * Seek the string location backward until EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_f_string_seek_line_back_
+  extern f_status_t f_string_seek_line_back(const f_string_t string, f_range_t * const range);
+#endif // _di_f_string_seek_line_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param string
@@ -442,6 +466,29 @@ extern "C" {
 #endif // _di_f_string_seek_line_to_
 
 /**
+ * Seek the string location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decrementd by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eol on success, but stopped at EOL.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_string_seek_line_to_back_
+  extern f_status_t f_string_seek_line_to_back(const f_string_t string, const f_char_t seek_to, f_range_t * const range);
+#endif // _di_f_string_seek_line_to_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) is reached.
  *
  * @param string
@@ -465,6 +512,30 @@ extern "C" {
   extern f_status_t f_string_seek_to(const f_string_t string, const f_char_t seek_to, f_range_t * const range);
 #endif // _di_f_string_seek_to_
 
+/**
+ * Seek the string location backward until the character (1-byte wide) is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_complete_not_utf (with error bit) if character is an incomplete UTF-8 fragment.
+ *   F_complete_not_utf_stop (with error bit) if the stop location is reached before the complete UTF-8 character can be processed.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_string_seek_to_back_
+  extern f_status_t f_string_seek_to_back(const f_string_t string, const f_char_t seek_to, f_range_t * const range);
+#endif // _di_f_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 8806fff582da9485fd8cfcaa4a9ccdf61920f31b..604bc6c6de88d5b79ae0cfcd1148a5516dd9a44e 100644 (file)
@@ -578,6 +578,27 @@ extern "C" {
   }
 #endif // _di_f_string_dynamic_seek_line_
 
+#ifndef _di_f_string_dynamic_seek_line_back_
+  f_status_t f_string_dynamic_seek_line_back(const f_string_static_t buffer, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != f_string_eol_s.string[0]) {
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[range->stop] == f_string_eol_s.string[0]) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_dynamic_seek_line_back_
+
 #ifndef _di_f_string_dynamic_seek_line_to_
   f_status_t f_string_dynamic_seek_line_to(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -601,6 +622,29 @@ extern "C" {
   }
 #endif // _di_f_string_dynamic_seek_line_to_
 
+#ifndef _di_f_string_dynamic_seek_line_to_back_
+  f_status_t f_string_dynamic_seek_line_to_back(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != seek_to_this) {
+
+      if (buffer.string[range->stop] == f_string_eol_s.string[0]) return F_okay_eol;
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[0] == seek_to_this) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_dynamic_seek_line_to_back_
+
 #ifndef _di_f_string_dynamic_seek_to_
   f_status_t f_string_dynamic_seek_to(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -622,6 +666,27 @@ extern "C" {
   }
 #endif // _di_f_string_dynamic_seek_to_
 
+#ifndef _di_f_string_dynamic_seek_to_back_
+  f_status_t f_string_dynamic_seek_to_back(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != seek_to_this) {
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[0] == seek_to_this) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_string_dynamic_seek_to_back_
+
 #ifndef _di_f_string_dynamic_strip_null_
   f_status_t f_string_dynamic_strip_null(f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
index d18299cd651a743dadfdbc5bd16fd9fcf276950c..96add5336543992e666aeb7090c19edc332e5c93 100644 (file)
@@ -690,6 +690,30 @@ extern "C" {
 #endif // _di_f_string_dynamic_seek_line_
 
 /**
+ * Seek the buffer location backward until EOL is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_string_dynamic_seek_line_back_
+  extern f_status_t f_string_dynamic_seek_line_back(const f_string_static_t buffer, f_range_t * const range);
+#endif // _di_f_string_dynamic_seek_line_back_
+
+/**
  * Seek the buffer location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param buffer
@@ -716,6 +740,32 @@ extern "C" {
 #endif // _di_f_string_dynamic_seek_line_to_
 
 /**
+ * Seek the buffer location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param seek_to_this
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_string_dynamic_seek_line_to_back_
+  extern f_status_t f_string_dynamic_seek_line_to_back(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range);
+#endif // _di_f_string_dynamic_seek_line_to_back_
+
+/**
  * Seek the buffer location forward until the character (1-byte wide) is reached.
  *
  * @param buffer
@@ -742,6 +792,32 @@ extern "C" {
 #endif // _di_f_string_dynamic_seek_to_
 
 /**
+ * Seek the buffer location backward until the character (1-byte wide) is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param seek_to_this
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_string_dynamic_seek_to_back_
+  extern f_status_t f_string_dynamic_seek_to_back(const f_string_static_t buffer, const f_char_t seek_to_this, f_range_t * const range);
+#endif // _di_f_string_dynamic_seek_to_back_
+
+/**
  * String all NULLs from the given string.
  *
  * This does not resize the string.
index d2f58227198622cb434a05ba974026fccf122714..827849629aa91c1cbf6c22e6848fc01cfdd5107c 100644 (file)
@@ -34,7 +34,7 @@ build_sources_program test-string-dynamic_partial_mash.c test-string-dynamic_par
 build_sources_program test-string-dynamic_partial_mish.c test-string-dynamic_partial_mish_nulless.c
 build_sources_program test-string-dynamic_partial_prepend.c test-string-dynamic_partial_prepend_assure.c test-string-dynamic_partial_prepend_assure_nulless.c test-string-dynamic_partial_prepend_nulless.c
 build_sources_program test-string-dynamic_prepend.c test-string-dynamic_prepend_assure.c test-string-dynamic_prepend_assure_nulless.c test-string-dynamic_prepend_nulless.c
-build_sources_program test-string-dynamic_seek_line.c test-string-dynamic_seek_line_to.c test-string-dynamic_seek_to.c
+build_sources_program test-string-dynamic_seek_line.c test-string-dynamic_seek_line_back.c test-string-dynamic_seek_line_to.c test-string-dynamic_seek_line_to_back.c test-string-dynamic_seek_to.c test-string-dynamic_seek_to_back.c
 build_sources_program test-string-dynamic_strip_null.c test-string-dynamic_strip_null_range.c
 build_sources_program test-string-dynamic_terminate.c test-string-dynamic_terminate_after.c
 build_sources_program test-string-dynamics_append.c test-string-dynamics_append_all.c test-string-dynamicss_append.c test-string-dynamicss_append_all.c
@@ -49,7 +49,7 @@ build_sources_program test-string-mapss_delete_callback.c test-string-mapss_dest
 build_sources_program test-string-mash.c test-string-mash_nulless.c
 build_sources_program test-string-mish.c test-string-mish_nulless.c
 build_sources_program test-string-prepend.c test-string-prepend_assure.c test-string-prepend_assure_nulless.c test-string-prepend_nulless.c
-build_sources_program test-string-seek_line.c test-string-seek_line_to.c test-string-seek_to.c
+build_sources_program test-string-seek_line.c test-string-seek_line_back.c test-string-seek_line_to.c test-string-seek_line_to_back.c test-string-seek_to.c test-string-seek_to_back.c
 build_sources_program test-string-triples_append.c test-string-triples_append_all.c test-string-tripless_append.c test-string-tripless_append_all.c
 build_sources_program test-string-triples_delete_callback.c test-string-triples_destroy_callback.c
 build_sources_program test-string-tripless_delete_callback.c test-string-tripless_destroy_callback.c
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.c b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.c
new file mode 100644 (file)
index 0000000..b065ebd
--- /dev/null
@@ -0,0 +1,82 @@
+#include "test-string.h"
+#include "test-string-dynamic_seek_line_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_dynamic_seek_line_back__parameter_checking(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_dynamic_seek_line_back(source, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_dynamic_seek_line_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_dynamic_seek_line_back__returns_none_eos(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_string_dynamic_seek_line_back__returns_none_stop(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_dynamic_seek_line_back__works(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 4);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.h b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_back.h
new file mode 100644 (file)
index 0000000..d2f821d
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_dynamic_seek_line_back_h
+#define _TEST__F_string_dynamic_seek_line_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_dynamic_seek_line_back()
+ */
+extern void test__f_string_dynamic_seek_line_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_dynamic_seek_line_back()
+ */
+extern void test__f_string_dynamic_seek_line_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_string_dynamic_seek_line_back()
+ */
+extern void test__f_string_dynamic_seek_line_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_dynamic_seek_line_back()
+ */
+extern void test__f_string_dynamic_seek_line_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_dynamic_seek_line_back()
+ */
+extern void test__f_string_dynamic_seek_line_back__works(void **state);
+
+#endif // _TEST__F_string_dynamic_seek_line_back_h
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.c b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.c
new file mode 100644 (file)
index 0000000..3a6f83b
--- /dev/null
@@ -0,0 +1,104 @@
+#include "test-string.h"
+#include "test-string-dynamic_seek_line_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_dynamic_seek_line_to_back__at_newline(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("te\nXst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_string_dynamic_seek_line_to_back__parameter_checking(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_dynamic_seek_line_to_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_dynamic_seek_line_to_back__returns_none_eos(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_string_dynamic_seek_line_to_back__returns_none_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_dynamic_seek_line_to_back__works(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eol);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.h b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_line_to_back.h
new file mode 100644 (file)
index 0000000..c197d48
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_dynamic_seek_line_to_back_h
+#define _TEST__F_string_dynamic_seek_line_to_back_h
+
+/**
+ * Test that the function works but stops at newline rather than search string.
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__at_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_string_dynamic_seek_line_to_back__works(void **state);
+
+#endif // _TEST__F_string_dynamic_seek_line_to_back_h
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.c b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.c
new file mode 100644 (file)
index 0000000..2fd2df4
--- /dev/null
@@ -0,0 +1,87 @@
+#include "test-string.h"
+#include "test-string-dynamic_seek_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_dynamic_seek_to_back__parameter_checking(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_dynamic_seek_to_back(source, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_dynamic_seek_to_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_dynamic_seek_to_back__returns_none_eos(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_string_dynamic_seek_to_back__returns_none_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_dynamic_seek_to_back__works(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("te\nXst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.h b/level_0/f_string/tests/unit/c/test-string-dynamic_seek_to_back.h
new file mode 100644 (file)
index 0000000..e62069b
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_dynamic_seek_to_back_h
+#define _TEST__F_string_dynamic_seek_to_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_dynamic_seek_to_back()
+ */
+extern void test__f_string_dynamic_seek_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_dynamic_seek_to_back()
+ */
+extern void test__f_string_dynamic_seek_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_string_dynamic_seek_to_back()
+ */
+extern void test__f_string_dynamic_seek_to_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_dynamic_seek_to_back()
+ */
+extern void test__f_string_dynamic_seek_to_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_dynamic_seek_to_back()
+ */
+extern void test__f_string_dynamic_seek_to_back__works(void **state);
+
+#endif // _TEST__F_string_dynamic_seek_to_back_h
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_line_back.c b/level_0/f_string/tests/unit/c/test-string-seek_line_back.c
new file mode 100644 (file)
index 0000000..e8422b3
--- /dev/null
@@ -0,0 +1,66 @@
+#include "test-string.h"
+#include "test-string-seek_line_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_seek_line_back__parameter_checking(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_seek_line_back(source.string, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_seek_line_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_seek_line_back__returns_none_stop(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_seek_line_back__works(void **state) {
+
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 4);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_line_back.h b/level_0/f_string/tests/unit/c/test-string-seek_line_back.h
new file mode 100644 (file)
index 0000000..f36a17c
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_seek_line_back_h
+#define _TEST__F_string_seek_line_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_seek_line_back()
+ */
+extern void test__f_string_seek_line_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_seek_line_back()
+ */
+extern void test__f_string_seek_line_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_seek_line_back()
+ */
+extern void test__f_string_seek_line_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_seek_line_back()
+ */
+extern void test__f_string_seek_line_back__works(void **state);
+
+#endif // _TEST__F_string_seek_line_back_h
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_line_to_back.c b/level_0/f_string/tests/unit/c/test-string-seek_line_to_back.c
new file mode 100644 (file)
index 0000000..7ade414
--- /dev/null
@@ -0,0 +1,87 @@
+#include "test-string.h"
+#include "test-string-seek_line_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_seek_line_to_back__at_newline(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("te\nXst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_string_seek_line_to_back__parameter_checking(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_seek_line_to_back(source.string, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_seek_line_to_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_seek_line_to_back__returns_none_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_seek_line_to_back__works(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eol);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_line_to_back.h b/level_0/f_string/tests/unit/c/test-string-seek_line_to_back.h
new file mode 100644 (file)
index 0000000..00e5753
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_seek_line_to_back_h
+#define _TEST__F_string_seek_line_to_back_h
+
+/**
+ * Test that the function works but stops at newline rather than search string.
+ *
+ * @see f_string_seek_line_to_back()
+ */
+extern void test__f_string_seek_line_to_back__at_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_seek_line_to_back()
+ */
+extern void test__f_string_seek_line_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_seek_line_to_back()
+ */
+extern void test__f_string_seek_line_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_seek_line_to_back()
+ */
+extern void test__f_string_seek_line_to_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_seek_line_to_back()
+ */
+extern void test__f_string_seek_line_to_back__works(void **state);
+
+#endif // _TEST__F_string_seek_line_to_back_h
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_to_back.c b/level_0/f_string/tests/unit/c/test-string-seek_to_back.c
new file mode 100644 (file)
index 0000000..18fe24a
--- /dev/null
@@ -0,0 +1,70 @@
+#include "test-string.h"
+#include "test-string-seek_to.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_string_seek_to_back__parameter_checking(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("teX\nst", 0, 6);
+
+  {
+    const f_status_t status = f_string_seek_to_back(source.string, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_string_seek_to_back__returns_data_not_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_string_seek_to_back__returns_none_stop(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("test\nafter", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_string_seek_to_back__works(void **state) {
+
+  const f_string_static_t to = macro_f_string_static_t_initialize_1("X", 0, 1);
+  const f_string_static_t source = macro_f_string_static_t_initialize_1("te\nXst", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_string/tests/unit/c/test-string-seek_to_back.h b/level_0/f_string/tests/unit/c/test-string-seek_to_back.h
new file mode 100644 (file)
index 0000000..966f563
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: String
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the string project.
+ */
+#ifndef _TEST__F_string_seek_to_back_h
+#define _TEST__F_string_seek_to_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_string_seek_to_back()
+ */
+extern void test__f_string_seek_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_string_seek_to_back()
+ */
+extern void test__f_string_seek_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_string_seek_to_back()
+ */
+extern void test__f_string_seek_to_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_string_seek_to_back()
+ */
+extern void test__f_string_seek_to_back__works(void **state);
+
+#endif // _TEST__F_string_seek_to_back_h
index 7abebf3fd4e0a4e952acf96ddccb7ea9e1c50706..167046ba8325b8e0a42f27d566761400ebc9e15b 100644 (file)
@@ -61,17 +61,33 @@ int main(void) {
     cmocka_unit_test(test__f_string_dynamic_seek_line__returns_none_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_line__works),
 
+    cmocka_unit_test(test__f_string_dynamic_seek_line_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_back__returns_none_eos),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_back__works),
+
     cmocka_unit_test(test__f_string_dynamic_seek_line_to__at_newline),
     cmocka_unit_test(test__f_string_dynamic_seek_line_to__returns_data_not_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_line_to__returns_none_eos),
     cmocka_unit_test(test__f_string_dynamic_seek_line_to__returns_none_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_line_to__works),
 
+    cmocka_unit_test(test__f_string_dynamic_seek_line_to_back__at_newline),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_to_back__returns_none_eos),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_to_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_line_to_back__works),
+
     cmocka_unit_test(test__f_string_dynamic_seek_to__returns_data_not_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_to__returns_none_eos),
     cmocka_unit_test(test__f_string_dynamic_seek_to__returns_none_stop),
     cmocka_unit_test(test__f_string_dynamic_seek_to__works),
 
+    cmocka_unit_test(test__f_string_dynamic_seek_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_to_back__returns_none_eos),
+    cmocka_unit_test(test__f_string_dynamic_seek_to_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_dynamic_seek_to_back__works),
+
     cmocka_unit_test(test__f_string_dynamic_strip_null__returns_data_not),
     cmocka_unit_test(test__f_string_dynamic_strip_null__works),
 
@@ -137,15 +153,28 @@ int main(void) {
     cmocka_unit_test(test__f_string_seek_line__returns_none_stop),
     cmocka_unit_test(test__f_string_seek_line__works),
 
+    cmocka_unit_test(test__f_string_seek_line_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_seek_line_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_seek_line_back__works),
+
     cmocka_unit_test(test__f_string_seek_line_to__at_newline),
     cmocka_unit_test(test__f_string_seek_line_to__returns_data_not_stop),
     cmocka_unit_test(test__f_string_seek_line_to__returns_none_stop),
     cmocka_unit_test(test__f_string_seek_line_to__works),
 
+    cmocka_unit_test(test__f_string_seek_line_to_back__at_newline),
+    cmocka_unit_test(test__f_string_seek_line_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_seek_line_to_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_seek_line_to_back__works),
+
     cmocka_unit_test(test__f_string_seek_to__returns_data_not_stop),
     cmocka_unit_test(test__f_string_seek_to__returns_none_stop),
     cmocka_unit_test(test__f_string_seek_to__works),
 
+    cmocka_unit_test(test__f_string_seek_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_string_seek_to_back__returns_none_stop),
+    cmocka_unit_test(test__f_string_seek_to_back__works),
+
     cmocka_unit_test(test__f_string_dynamics_delete_callback__fails),
     cmocka_unit_test(test__f_string_dynamics_destroy_callback__fails),
     cmocka_unit_test(test__f_string_dynamics_delete_callback__works),
index fbe350c87f85f2414affd183c7c37c7954a8f8c9..440fee34deaf1b671583a0c32c001ec9cae186aa 100644 (file)
 #include "test-string-dynamic_prepend_assure_nulless.h"
 #include "test-string-dynamic_prepend_nulless.h"
 #include "test-string-dynamic_seek_line.h"
+#include "test-string-dynamic_seek_line_back.h"
 #include "test-string-dynamic_seek_line_to.h"
+#include "test-string-dynamic_seek_line_to_back.h"
 #include "test-string-dynamic_seek_to.h"
+#include "test-string-dynamic_seek_to_back.h"
 #include "test-string-dynamic_strip_null.h"
 #include "test-string-dynamic_strip_null_range.h"
 #include "test-string-dynamic_terminate.h"
 #include "test-string-prepend_assure_nulless.h"
 #include "test-string-prepend_nulless.h"
 #include "test-string-seek_line.h"
+#include "test-string-seek_line_back.h"
 #include "test-string-seek_line_to.h"
+#include "test-string-seek_line_to_back.h"
 #include "test-string-seek_to.h"
+#include "test-string-seek_to_back.h"
 #include "test-string-triples_append.h"
 #include "test-string-triples_append_all.h"
 #include "test-string-triples_delete_callback.h"
index 01e7052b7387dea13c595945bad09d508298aa20..bec54bebbbb17c6b1b459d46138f3033212298a4 100644 (file)
@@ -613,6 +613,29 @@ extern "C" {
   }
 #endif // _di_f_utf_string_dynamic_seek_line_
 
+#ifndef _di_f_utf_string_dynamic_seek_line_back_
+  f_status_t f_utf_string_dynamic_seek_line_back(const f_utf_string_static_t buffer, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != f_utf_char_eol_s) {
+
+      if (macro_f_utf_char_t_width_is(buffer.string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[range->stop] == f_utf_char_eol_s) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_dynamic_seek_line_back_
+
 #ifndef _di_f_utf_string_dynamic_seek_line_to_
   f_status_t f_utf_string_dynamic_seek_line_to(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -637,6 +660,30 @@ extern "C" {
   }
 #endif // _di_f_utf_string_dynamic_seek_line_to_
 
+#ifndef _di_f_utf_string_dynamic_seek_line_to_back_
+  f_status_t f_utf_string_dynamic_seek_line_to_back(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != seek_to_this) {
+
+      if (macro_f_utf_char_t_width_is(buffer.string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+      if (buffer.string[range->stop] == f_utf_char_eol_s) return F_okay_eol;
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[range->stop] == f_utf_char_eol_s) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_dynamic_seek_line_to_back_
+
 #ifndef _di_f_utf_string_dynamic_seek_to_
   f_status_t f_utf_string_dynamic_seek_to(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -660,6 +707,29 @@ extern "C" {
   }
 #endif // _di_f_utf_string_dynamic_seek_to_
 
+#ifndef _di_f_utf_string_dynamic_seek_to_back_
+  f_status_t f_utf_string_dynamic_seek_to_back(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (!buffer.used) return F_data_not;
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (buffer.string[range->stop] != seek_to_this) {
+
+      if (macro_f_utf_char_t_width_is(buffer.string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+
+      --range->stop;
+
+      if (!range->stop) return (buffer.string[range->stop] == f_utf_char_eol_s) ? F_okay : F_okay_eos;
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_dynamic_seek_to_back_
+
 #ifndef _di_f_utf_string_dynamic_terminate_
   f_status_t f_utf_string_dynamic_terminate(f_utf_string_dynamic_t * const destination) {
     #ifndef _di_level_0_parameter_checking_
index f546614d82edef07f337c9b8384419466057cde4..0243a09cdba937986acd370b32a00cd8055a9779 100644 (file)
@@ -689,6 +689,31 @@ extern "C" {
 #endif // _di_f_utf_string_dynamic_seek_line_
 
 /**
+ * Seek the buffer location backward until EOL is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_dynamic_seek_line_back_
+  extern f_status_t f_utf_string_dynamic_seek_line_back(const f_utf_string_static_t buffer, f_range_t * const range);
+#endif // _di_f_utf_string_dynamic_seek_line_back_
+
+/**
  * Seek the buffer location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param buffer
@@ -716,6 +741,33 @@ extern "C" {
 #endif // _di_f_utf_string_dynamic_seek_line_to_
 
 /**
+ * Seek the buffer location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param seek_to_this
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_dynamic_seek_line_to_back_
+  extern f_status_t f_utf_string_dynamic_seek_line_to_back(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range);
+#endif // _di_f_utf_string_dynamic_seek_line_to_back_
+
+/**
  * Seek the buffer location forward until the character (1-byte wide) is reached.
  *
  * @param buffer
@@ -743,6 +795,33 @@ extern "C" {
 #endif // _di_f_utf_string_dynamic_seek_to_
 
 /**
+ * Seek the buffer location backward until the character (1-byte wide) is reached.
+ *
+ * @param buffer
+ *   The buffer to traverse.
+ * @param seek_to_this
+ *   A single-width character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eos on success, but stopped at end of string.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not on success, but there was no string data to seek.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_dynamic_seek_to_back_
+  extern f_status_t f_utf_string_dynamic_seek_to_back(const f_utf_string_static_t buffer, const f_utf_char_t seek_to_this, f_range_t * const range);
+#endif // _di_f_utf_string_dynamic_seek_to_back_
+
+/**
  * Guarantee that an end of string (NULL) exists at the end of the string.
  *
  * This is intended to be used for anything requiring NULL terminated strings.
index 25dd41a1987c4cd58d32c8b7abca9fca0b0145a6..868820c9a517b2fb297360e68cb7dc8de2fd11ce 100644 (file)
@@ -314,6 +314,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_
 
+#ifndef _di_f_utf_string_seek_line_back_
+  f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != f_utf_char_eol_s) {
+
+      if (macro_f_utf_char_t_width_is(string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_back_
+
 #ifndef _di_f_utf_string_seek_line_to_
   f_status_t f_utf_string_seek_line_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -335,6 +356,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_to_
 
+#ifndef _di_f_utf_string_seek_line_to_back_
+  f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      if (string[range->stop] == f_utf_char_eol_s) return F_okay_eol;
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_to_back_
+
 #ifndef _di_f_utf_string_seek_to_
   f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -354,6 +396,25 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_to_
 
+#ifndef _di_f_utf_string_seek_to_back_
+  f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c419b78c04ef2e6f6f973b02a4f14217d404d43f..cbccc4dc537de20d015643774d2f5cc971361aab 100644 (file)
@@ -372,6 +372,30 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_
 
 /**
+ * Seek the string location backward until EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_seek_line_back_
+  extern f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param string
@@ -395,6 +419,29 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_to_
 
 /**
+ * Seek the string location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eol on success, but stopped at EOL.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_utf_string_seek_line_to_back_
+  extern f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_to_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) is reached.
  *
  * @param string
@@ -418,6 +465,30 @@ extern "C" {
   extern f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
 #endif // _di_f_utf_string_seek_to_
 
+/**
+ * Seek the string location backward until the character (1-byte wide) is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ */
+#ifndef _di_f_utf_string_seek_to_back_
+  extern f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 7639bc7e082057d5e0c8c286cf2ccc225b9abd2b..12aefb43fdd199685aef9a7ef1af6f805d867f7d 100644 (file)
@@ -302,6 +302,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_
 
+#ifndef _di_f_utf_string_seek_line_back
+  f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != f_utf_char_t_eol_s) {
+
+      if (macro_f_utf_char_t_width_is(string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_back_
+
 #ifndef _di_f_utf_string_seek_line_to_
   f_status_t f_utf_string_seek_line_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -323,6 +344,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_to_
 
+#ifndef _di_f_utf_string_seek_line_to_back_
+  f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      if (string[range->stop] == f_utf_char_t_eol_s) return F_okay_eol;
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_to_back_
+
 #ifndef _di_f_utf_string_seek_to_
   f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -342,6 +384,25 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_to_
 
+#ifndef _di_f_utf_string_seek_to_back_
+  f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c419b78c04ef2e6f6f973b02a4f14217d404d43f..cbccc4dc537de20d015643774d2f5cc971361aab 100644 (file)
@@ -372,6 +372,30 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_
 
 /**
+ * Seek the string location backward until EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_seek_line_back_
+  extern f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param string
@@ -395,6 +419,29 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_to_
 
 /**
+ * Seek the string location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eol on success, but stopped at EOL.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_utf_string_seek_line_to_back_
+  extern f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_to_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) is reached.
  *
  * @param string
@@ -418,6 +465,30 @@ extern "C" {
   extern f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
 #endif // _di_f_utf_string_seek_to_
 
+/**
+ * Seek the string location backward until the character (1-byte wide) is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ */
+#ifndef _di_f_utf_string_seek_to_back_
+  extern f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 5d5386c13da623da053abb859f78b3a5f59985d0..de80b567a2cf6ae66d750907a8d57653ed7084ee 100644 (file)
@@ -302,6 +302,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_
 
+#ifndef _di_f_utf_string_seek_line_back_
+  f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != f_utf_char_t_eol_s) {
+
+      if (macro_f_utf_char_t_width_is(string[range->stop]) == 1) return F_status_set_error(F_utf_fragment);
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_back_
+
 #ifndef _di_f_utf_string_seek_line_to_
   f_status_t f_utf_string_seek_line_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -323,6 +344,27 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_line_to_
 
+#ifndef _di_f_utf_string_seek_line_to_back_
+  f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      if (string[range->stop] == f_utf_char_t_eol_s) return F_okay_eol;
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_line_to_back_
+
 #ifndef _di_f_utf_string_seek_to_
   f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
     #ifndef _di_level_0_parameter_checking_
@@ -342,6 +384,25 @@ extern "C" {
   }
 #endif // _di_f_utf_string_seek_to_
 
+#ifndef _di_f_utf_string_seek_to_back_
+  f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!range) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (range->start > range->stop) return F_data_not_stop;
+
+    while (string[range->stop] != seek_to) {
+
+      --range->stop;
+
+      if (range->start > range->stop) return F_okay_stop;
+    } // while
+
+    return F_okay;
+  }
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c419b78c04ef2e6f6f973b02a4f14217d404d43f..cbccc4dc537de20d015643774d2f5cc971361aab 100644 (file)
@@ -372,6 +372,30 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_
 
 /**
+ * Seek the string location backward until EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at end of range.
+ *   F_data_not_stop on success, but the range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_f_utf_string_seek_line_back_
+  extern f_status_t f_utf_string_seek_line_back(const f_utf_string_t string, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) or EOL is reached.
  *
  * @param string
@@ -395,6 +419,29 @@ extern "C" {
 #endif // _di_f_utf_string_seek_line_to_
 
 /**
+ * Seek the string location backward until the character (1-byte wide) or EOL is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_eol on success, but stopped at EOL.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_utf_string_seek_line_to_back_
+  extern f_status_t f_utf_string_seek_line_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_line_to_back_
+
+/**
  * Seek the string location forward until the character (1-byte wide) is reached.
  *
  * @param string
@@ -418,6 +465,30 @@ extern "C" {
   extern f_status_t f_utf_string_seek_to(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
 #endif // _di_f_utf_string_seek_to_
 
+/**
+ * Seek the string location backward until the character (1-byte wide) is reached.
+ *
+ * @param string
+ *   The string to traverse.
+ * @param seek_to
+ *   A character representing a character to seek to.
+ * @param range
+ *   A range within the buffer representing the start and stop locations.
+ *   The stop location will be decremented by the seek.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_okay_stop on success, but stopped at the stop location.
+ *   F_data_not_stop if range.start > range.stop.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_utf_fragment (with error bit) if character is a UTF-8 fragment.
+ *   F_utf_not (with error bit) if unicode is an invalid Unicode character.
+ */
+#ifndef _di_f_utf_string_seek_to_back_
+  extern f_status_t f_utf_string_seek_to_back(const f_utf_string_t string, const f_utf_char_t seek_to, f_range_t * const range);
+#endif // _di_f_utf_string_seek_to_back_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 85d7ba000e4c16de0234202dcdf36afb419058f3..5acc23b3fe40d1cfe99e4fbdd8ff8267a4c0bd1e 100644 (file)
@@ -58,7 +58,7 @@ build_sources_program test-utf-dynamic_partial_mash.c test-utf-dynamic_partial_m
 build_sources_program test-utf-dynamic_partial_mish.c test-utf-dynamic_partial_mish_nulless.c
 build_sources_program test-utf-dynamic_partial_prepend.c test-utf-dynamic_partial_prepend_assure.c test-utf-dynamic_partial_prepend_assure_nulless.c test-utf-dynamic_partial_prepend_nulless.c
 build_sources_program test-utf-dynamic_prepend.c test-utf-dynamic_prepend_assure.c test-utf-dynamic_prepend_assure_nulless.c test-utf-dynamic_prepend_nulless.c
-build_sources_program test-utf-dynamic_seek_line.c test-utf-dynamic_seek_line_to.c test-utf-dynamic_seek_to.c
+build_sources_program test-utf-dynamic_seek_line.c test-utf-dynamic_seek_line_back.c test-utf-dynamic_seek_line_to.c test-utf-dynamic_seek_line_to_back.c test-utf-dynamic_seek_to.c test-utf-dynamic_seek_to_back.c
 build_sources_program test-utf-dynamic_terminate.c test-utf-dynamic_terminate_after.c
 build_sources_program test-utf-dynamics_append.c test-utf-dynamics_append_all.c test-utf-dynamicss_append.c test-utf-dynamicss_append_all.c
 build_sources_program test-utf-dynamicss_delete_callback.c test-utf-dynamicss_destroy_callback.c
@@ -71,7 +71,7 @@ build_sources_program test-utf-map_multiss_delete_callback.c test-utf-map_multis
 build_sources_program test-utf-mash.c test-utf-mash_nulless.c
 build_sources_program test-utf-mish.c test-utf-mish_nulless.c
 build_sources_program test-utf-prepend.c test-utf-prepend_assure.c test-utf-prepend_assure_nulless.c test-utf-prepend_nulless.c
-build_sources_program test-utf-seek_line.c test-utf-seek_line_to.c test-utf-seek_to.c
+build_sources_program test-utf-seek_line.c test-utf-seek_line_back.c test-utf-seek_line_to.c test-utf-seek_line_to_back.c test-utf-seek_to.c test-utf-seek_to_back.c
 build_sources_program test-utf-triples_append.c test-utf-triples_append_all.c test-utf-tripless_append.c test-utf-tripless_append_all.c
 build_sources_program test-utf-triples_delete_callback.c test-utf-triples_destroy_callback.c
 build_sources_program test-utf-tripless_delete_callback.c test-utf-tripless_destroy_callback.c
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.c b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.c
new file mode 100644 (file)
index 0000000..f10621a
--- /dev/null
@@ -0,0 +1,82 @@
+#include "test-utf.h"
+#include "test-utf-dynamic_seek_line_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_string_dynamic_seek_line_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_dynamic_seek_line_back(source, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_back__returns_none_eos(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_back__works(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_back(source, &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 4);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.h b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_back.h
new file mode 100644 (file)
index 0000000..9072e45
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_dynamic_seek_line_back_h
+#define _TEST__F_utf_dynamic_seek_line_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_dynamic_seek_line_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_dynamic_seek_line_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_line_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_line_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_utf_string_dynamic_seek_line_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_back__works(void **state);
+
+#endif // _TEST__F_utf_dynamic_seek_line_back_h
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.c b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.c
new file mode 100644 (file)
index 0000000..fac88f9
--- /dev/null
@@ -0,0 +1,104 @@
+#include "test-utf.h"
+#include "test-utf-dynamic_seek_line_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_string_dynamic_seek_line_to_back__after_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eol);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_to_back__before_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0\n\0\0\0X\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_to_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_to_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_to_back__returns_none_eos(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_line_to_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_line_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.h b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_line_to_back.h
new file mode 100644 (file)
index 0000000..a1a17d5
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_dynamic_seek_line_to_back_h
+#define _TEST__F_utf_dynamic_seek_line_to_back_h
+
+/**
+ * Test that the function works where seek target is after a newline.
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__after_newline(void **state);
+
+/**
+ * Test that the function works where seek target is before a newline.
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__before_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_line_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_line_to_back__returns_none_stop(void **state);
+
+#endif // _TEST__F_utf_dynamic_seek_line_to_back_h
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.c b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.c
new file mode 100644 (file)
index 0000000..aa39502
--- /dev/null
@@ -0,0 +1,135 @@
+#include "test-utf.h"
+#include "test-utf-dynamic_seek_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_string_dynamic_seek_to_back__after_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 2);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__before_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0\n\0\0\0X\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__returns_none_eos(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eos);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 0);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_utf_string_dynamic_seek_to_back__works(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+
+  // Test where newline is before "X".
+  {
+    const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0\n\0\0\0X\0\0\0s\0\0\0t", 0, 6);
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+
+  // Test where newline is after "X".
+  {
+    const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_dynamic_seek_to_back(source, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 2);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.h b/level_0/f_utf/tests/unit/c/test-utf-dynamic_seek_to_back.h
new file mode 100644 (file)
index 0000000..ff87eca
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_dynamic_seek_to_back_h
+#define _TEST__F_utf_dynamic_seek_to_back_h
+
+/**
+ * Test that the function works where seek target is after a newline.
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__after_newline(void **state);
+
+/**
+ * Test that the function works where seek target is before a newline.
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__before_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_eos stopped after end of string because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__returns_none_eos(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_dynamic_seek_to_back()
+ */
+extern void test__f_utf_string_dynamic_seek_to_back__returns_none_stop(void **state);
+
+#endif // _TEST__F_utf_dynamic_seek_to_back_h
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_line_back.c b/level_0/f_utf/tests/unit/c/test-utf-seek_line_back.c
new file mode 100644 (file)
index 0000000..b6c75f2
--- /dev/null
@@ -0,0 +1,66 @@
+#include "test-utf.h"
+#include "test-utf-seek_line_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_seek_line_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_seek_line_back(source.string, 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_seek_line_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_seek_line_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+void test__f_utf_seek_line_back__works(void **state) {
+
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_line_back(source.string, &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 4);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_line_back.h b/level_0/f_utf/tests/unit/c/test-utf-seek_line_back.h
new file mode 100644 (file)
index 0000000..b29663d
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_seek_line_back_h
+#define _TEST__F_utf_seek_line_back_h
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_seek_line_back()
+ */
+extern void test__f_utf_seek_line_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_seek_line_back()
+ */
+extern void test__f_utf_seek_line_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_seek_line_back()
+ */
+extern void test__f_utf_seek_line_back__returns_none_stop(void **state);
+
+/**
+ * Test that the function works.
+ *
+ * @see f_utf_string_seek_line_back()
+ */
+extern void test__f_utf_seek_line_back__works(void **state);
+
+#endif // _TEST__F_utf_seek_line_back_h
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.c b/level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.c
new file mode 100644 (file)
index 0000000..1fcc41a
--- /dev/null
@@ -0,0 +1,87 @@
+#include "test-utf.h"
+#include "test-utf-seek_line_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_seek_line_to_back__after_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_eol);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_seek_line_to_back__before_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0\n\0\0\0X\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_seek_line_to_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_seek_line_to_back(source.string, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_seek_line_to_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_seek_line_to_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t", 0, 4);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_line_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.h b/level_0/f_utf/tests/unit/c/test-utf-seek_line_to_back.h
new file mode 100644 (file)
index 0000000..2081091
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_seek_line_to_back_h
+#define _TEST__F_utf_seek_line_to_back_h
+
+/**
+ * Test that the function works where seek target is after a newline.
+ *
+ * @see f_utf_string_seek_line_to_back()
+ */
+extern void test__f_utf_seek_line_to_back__after_newline(void **state);
+
+/**
+ * Test that the function works where seek target is before a newline.
+ *
+ * @see f_utf_string_seek_line_to_back()
+ */
+extern void test__f_utf_seek_line_to_back__before_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_seek_line_to_back()
+ */
+extern void test__f_utf_seek_line_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_seek_line_to_back()
+ */
+extern void test__f_utf_seek_line_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_seek_line_to_back()
+ */
+extern void test__f_utf_seek_line_to_back__returns_none_stop(void **state);
+
+#endif // _TEST__F_utf_seek_line_to_back_h
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_to_back.c b/level_0/f_utf/tests/unit/c/test-utf-seek_to_back.c
new file mode 100644 (file)
index 0000000..50421fd
--- /dev/null
@@ -0,0 +1,87 @@
+#include "test-utf.h"
+#include "test-utf-seek_to_back.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_utf_seek_to_back__after_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 2);
+  }
+}
+
+void test__f_utf_seek_to_back__before_newline(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0\n\0\0\0X\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(0, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay);
+
+    assert_int_equal(range.start, 0);
+    assert_int_equal(range.stop, 3);
+  }
+}
+
+void test__f_utf_seek_to_back__parameter_checking(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0X\0\0\0\n\0\0\0s\0\0\0t", 0, 6);
+
+  {
+    const f_status_t status = f_utf_string_seek_to_back(source.string, to.string[0], 0);
+
+    assert_int_equal(status, F_status_set_error(F_parameter));
+  }
+}
+
+void test__f_utf_seek_to_back__returns_data_not_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = f_range_t_initialize;
+
+    const f_status_t status = f_utf_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_data_not_stop);
+  }
+}
+
+void test__f_utf_seek_to_back__returns_none_stop(void **state) {
+
+  const f_utf_string_static_t to = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0X", 0, 1);
+  const f_utf_string_static_t source = macro_f_utf_string_static_t_initialize_1((f_utf_string_t) "\0\0\0t\0\0\0e\0\0\0s\0\0\0t\0\0\0\n\0\0\0a\0\0\0f\0\0\0t\0\0\0e\0\0\0r", 0, 10);
+
+  {
+    f_range_t range = macro_f_range_t_initialize_1(2, source.used - 1);
+
+    const f_status_t status = f_utf_string_seek_to_back(source.string, to.string[0], &range);
+
+    assert_int_equal(status, F_okay_stop);
+
+    assert_int_equal(range.start, 2);
+    assert_int_equal(range.stop, 1);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_utf/tests/unit/c/test-utf-seek_to_back.h b/level_0/f_utf/tests/unit/c/test-utf-seek_to_back.h
new file mode 100644 (file)
index 0000000..c846604
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: UTF
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the functions in the utf project.
+ */
+#ifndef _TEST__F_utf_seek_to_back_h
+#define _TEST__F_utf_seek_to_back_h
+
+/**
+ * Test that the function works where seek target is after a newline.
+ *
+ * @see f_utf_string_seek_to_back()
+ */
+extern void test__f_utf_seek_to_back__after_newline(void **state);
+
+/**
+ * Test that the function works where seek target is before a newline.
+ *
+ * @see f_utf_string_seek_to_back()
+ */
+extern void test__f_utf_seek_to_back__before_newline(void **state);
+
+/**
+ * Test that the function correctly fails on invalid parameter.
+ *
+ * @see f_utf_string_seek_to_back()
+ */
+extern void test__f_utf_seek_to_back__parameter_checking(void **state);
+
+/**
+ * Test that the function returns F_data_not_stop because range is an empty range (range.start > range.stop).
+ *
+ * @see f_utf_string_seek_to_back()
+ */
+extern void test__f_utf_seek_to_back__returns_data_not_stop(void **state);
+
+/**
+ * Test that the function returns F_okay_stop stopped after end of range because no newline is found.
+ *
+ * @see f_utf_string_seek_to_back()
+ */
+extern void test__f_utf_seek_to_back__returns_none_stop(void **state);
+
+#endif // _TEST__F_utf_seek_to_back_h
index 3b969f948342ae10754c9121a92ca9df91a972c0..e60c5db32aa0c42618346c9ea7d11d5961f32900 100644 (file)
@@ -92,18 +92,35 @@ int main(void) {
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line__returns_none_stop),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line__works),
 
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_back__returns_none_eos),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_back__returns_none_stop),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_back__works),
+
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to__after_newline),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to__before_newline),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to__returns_data_not_stop),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to__returns_none_eos),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to__returns_none_stop),
 
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to_back__after_newline),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to_back__before_newline),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to_back__returns_none_eos),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_line_to_back__returns_none_stop),
+
     cmocka_unit_test(test__f_utf_string_dynamic_seek_to__after_newline),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_to__before_newline),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_to__returns_data_not_stop),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_to__returns_none_eos),
     cmocka_unit_test(test__f_utf_string_dynamic_seek_to__returns_none_stop),
 
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_to_back__after_newline),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_to_back__before_newline),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_to_back__returns_none_eos),
+    cmocka_unit_test(test__f_utf_string_dynamic_seek_to_back__returns_none_stop),
+
     cmocka_unit_test(test__f_utf_string_dynamic_terminate__appends_null),
     cmocka_unit_test(test__f_utf_string_dynamic_terminate__doesnt_append_null),
 
@@ -192,16 +209,30 @@ int main(void) {
     cmocka_unit_test(test__f_utf_seek_line__returns_none_stop),
     cmocka_unit_test(test__f_utf_seek_line__works),
 
+    cmocka_unit_test(test__f_utf_seek_line_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_seek_line_back__returns_none_stop),
+    cmocka_unit_test(test__f_utf_seek_line_back__works),
+
     cmocka_unit_test(test__f_utf_seek_line_to__after_newline),
     cmocka_unit_test(test__f_utf_seek_line_to__before_newline),
     cmocka_unit_test(test__f_utf_seek_line_to__returns_data_not_stop),
     cmocka_unit_test(test__f_utf_seek_line_to__returns_none_stop),
 
+    cmocka_unit_test(test__f_utf_seek_line_to_back__after_newline),
+    cmocka_unit_test(test__f_utf_seek_line_to_back__before_newline),
+    cmocka_unit_test(test__f_utf_seek_line_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_seek_line_to_back__returns_none_stop),
+
     cmocka_unit_test(test__f_utf_seek_to__after_newline),
     cmocka_unit_test(test__f_utf_seek_to__before_newline),
     cmocka_unit_test(test__f_utf_seek_to__returns_data_not_stop),
     cmocka_unit_test(test__f_utf_seek_to__returns_none_stop),
 
+    cmocka_unit_test(test__f_utf_seek_to_back__after_newline),
+    cmocka_unit_test(test__f_utf_seek_to_back__before_newline),
+    cmocka_unit_test(test__f_utf_seek_to_back__returns_data_not_stop),
+    cmocka_unit_test(test__f_utf_seek_to_back__returns_none_stop),
+
     cmocka_unit_test(test__f_utf_string_dynamicss_delete_callback__fails),
     cmocka_unit_test(test__f_utf_string_dynamicss_destroy_callback__fails),
 
index a5ecd13529d0bde328756a66cd4b3b925389e0e3..0650dfbf598088b3f06f822012d987cf8633c5c1 100644 (file)
 #include "test-utf-dynamic_prepend_assure_nulless.h"
 #include "test-utf-dynamic_prepend_nulless.h"
 #include "test-utf-dynamic_seek_line.h"
+#include "test-utf-dynamic_seek_line_back.h"
 #include "test-utf-dynamic_seek_line_to.h"
+#include "test-utf-dynamic_seek_line_to_back.h"
 #include "test-utf-dynamic_seek_to.h"
+#include "test-utf-dynamic_seek_to_back.h"
 #include "test-utf-dynamic_terminate.h"
 #include "test-utf-dynamic_terminate_after.h"
 #include "test-utf-dynamics_append.h"
 #include "test-utf-prepend_assure_nulless.h"
 #include "test-utf-prepend_nulless.h"
 #include "test-utf-seek_line.h"
+#include "test-utf-seek_line_back.h"
 #include "test-utf-seek_line_to.h"
+#include "test-utf-seek_line_to_back.h"
 #include "test-utf-seek_to.h"
+#include "test-utf-seek_to_back.h"
 #include "test-utf-triples_append.h"
 #include "test-utf-triples_append_all.h"
 #include "test-utf-triples_delete_callback.h"