]> Kevux Git Server - fll/commitdiff
Progress: begin implementing fss-003 Extended List
authorKevin Day <thekevinday@gmail.com>
Fri, 11 Oct 2019 04:19:26 +0000 (23:19 -0500)
committerKevin Day <thekevinday@gmail.com>
Fri, 11 Oct 2019 04:19:26 +0000 (23:19 -0500)
level_0/f_fss/c/fss.h
level_1/fl_fss/c/fss_basic_list.c
level_1/fl_fss/c/fss_extended_list.c
level_1/fl_fss/c/fss_extended_list.h
level_1/fl_fss/c/fss_macro.h
level_1/fl_fss/c/fss_status.h
level_2/fll_fss/c/fss_status.c
level_2/fll_fss/c/fss_status.h
specifications/fss-0003.txt

index 696386d732572cfefc3473fe7341ff2f475782b1..d2957b9e942bbb2b858b198d22f7bbbd0d53705d 100644 (file)
@@ -86,8 +86,8 @@ extern "C" {
  * The standard FSS character header is: "# fss-0000\n\0", which is 10 characters + newline + EOS = 12.
  *
  * The UTF-8 BOM is not supported because it is not an actual thing (only a suggestion according to rfc3629).
- * The UTF-8 BOM sequence is actually a different character called "zero-width non breaking space".
- * Because it already has use, this project considers the existence of UTF-8 BOM bad practice in all cases.
+ * The UTF-8 BOM sequence is actually a different character called "zero-width non-breaking space".
+ * Because it already has use, this project considers the existence of UTF-8 BOM bad practice in all cases.
  * After all, if your file begins with a "zero-width non breaking space", you may want to actually use a space and not a "BOM".
  */
 #ifndef _di_f_fss_max_header_length_
@@ -268,6 +268,120 @@ extern "C" {
   #define f_macro_fss_contents_adjust(status, contents, new_length) f_macro_memory_structures_resize(status, contents, f_fss_content, new_length, f_array_length)
 #endif // _di_f_fss_contents_
 
+/**
+ * This holds a object and its associated content.
+ *
+ * To designate that either object or content is non-existent, set start position greater than stop position.
+ * In particular, set start to 1 and stop to 0.
+ *
+ * object: The object.
+ * content: The content associated with the object.
+ * parent: A location referencing a parrent object or content that this object content is nested under.
+ */
+#ifndef _di_fss_content_child_
+  typedef struct {
+    f_fss_object   object;
+    f_fss_content  content;
+    f_array_length parent;
+  } f_fss_content_child;
+
+  #define f_fss_content_child_initialize { f_fss_object_initialize, f_fss_content_initialize, f_array_length_initialize }
+
+  #define f_macro_fss_content_child_clear(object_content) f_macro_memory_structure_new(object_content)
+
+  #define f_macro_fss_content_child_new(status, object_content, length) f_macro_memory_structure_new(status, object_content, f_fss_content_child, length)
+
+  #define f_macro_fss_content_child_delete(status, object_content) f_macro_memory_structure_delete(status, object_content, f_fss_content_child)
+  #define f_macro_fss_content_child_destroy(status, object_content) f_macro_memory_structure_destroy(status, object_content, f_fss_content_child)
+
+  #define f_macro_fss_content_child_resize(status, object_content, new_length) f_macro_memory_structure_resize(status, object_content, f_fss_content_child, new_length)
+  #define f_macro_fss_content_child_adjust(status, object_content, new_length) f_macro_memory_structure_adjust(status, object_content, f_fss_content_child, new_length)
+#endif // _di_fss_content_child_
+
+/**
+ * This holds an array of fss_content_child.
+ *
+ * This is designed to be used as a part of f_fss_content_nest.
+ * Range represents the full range of the particular content set.
+ * Range can exist before the first child and after the last child to represent unnested data within the content.
+ *
+ * For example:
+ *   object {
+ *     fss_basic_content before nested content.
+ *     nested_1 {
+ *        Nested content one.
+ *     }
+ *
+ *     More content in between.
+ *
+ *     nested_2 {
+ *        Nested content two.
+ *        nested_3 {
+ *          Nested content three.
+ *        }
+ *     }
+ *
+ *     More content after.
+ *   }
+ *
+ * range: A location range representing the full start/stop locations of the entire set.
+ * array: The array of objectm their associated content, and their associated parent.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_fss_content_childs_
+  typedef struct {
+    f_string_location   range;
+    f_fss_content_child *array;
+    f_array_length      size;
+    f_array_length      used;
+  } f_fss_content_childs;
+
+  #define f_fss_content_childs_initialize { f_string_location_initialize, 0, 0, 0 }
+
+  // @todo: f_macro_memory_structure.. might not be usable here, review and confirm/deny this.
+  #define f_macro_fss_content_childs_clear(object_contents) f_macro_memory_structure_new(object_contents)
+
+  #define f_macro_fss_content_childs_new(status, object_contents, length) f_macro_memory_structure_new(status, object_contents, f_fss_content_childs, length)
+
+  #define f_macro_fss_content_childs_delete(status, object_contents) f_macro_memory_structure_delete(status, object_contents, f_fss_content_childs)
+  #define f_macro_fss_content_childs_destroy(status, object_contents) f_macro_memory_structure_destroy(status, object_contents, f_fss_content_childs)
+
+  #define f_macro_fss_content_childs_resize(status, object_contents, new_length) f_macro_memory_structure_resize(status, object_contents, f_fss_content_childs, new_length)
+  #define f_macro_fss_content_childs_adjust(status, object_contents, new_length) f_macro_memory_structure_adjust(status, object_contents, f_fss_content_childs, new_length)
+#endif // _di_fss_content_childs_
+
+/**
+ * This holds an array of f_fss_content_childs.
+ *
+ * Each array row represents the nesting depth.
+ * The top-level will not have any parent, so "parent" must be ignored on anything at index 0.
+ * The parent identifier is expected to reference a position in the nesting depth immediately above it.
+ *
+ * array: an array of child objects.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_fss_content_nest_
+  typedef struct {
+    f_fss_content_childs *array;
+    f_array_length       size;
+    f_array_length       used;
+  } f_fss_content_nest;
+
+  #define f_fss_content_nest_initialize { 0, 0, 0 }
+
+  #define f_macro_fss_content_nest_clear(object_content_nested) f_macro_memory_structure_new(object_content_nested)
+
+  #define f_macro_fss_content_nest_new(status, object_content_nested, length) f_macro_memory_structure_new(status, object_content_nested, f_fss_content_nest, length)
+
+  #define f_macro_fss_content_nest_delete(status, object_content_nested) f_macro_memory_structure_delete(status, object_content_nested, f_fss_content_nest)
+  #define f_macro_fss_content_nest_destroy(status, object_content_nested) f_macro_memory_structure_destroy(status, object_content_nested, f_fss_content_nest)
+
+  #define f_macro_fss_content_nest_resize(status, object_content_nested, new_length) f_macro_memory_structure_resize(status, object_content_nested, f_fss_content_nest, new_length)
+  #define f_macro_fss_content_nest_adjust(status, object_content_nested, new_length) f_macro_memory_structure_adjust(status, object_content_nested, f_fss_content_nest, new_length)
+#endif // _di_fss_content_nest_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 07f0f0c4a1f09b0e11c57be1bb914a58ebe387de..e3efcd420d3125dee37b0aada5dbe1d0d522b2dd 100644 (file)
@@ -18,13 +18,13 @@ extern "C" {
 
     f_status status = f_none;
 
-    // delimits must only be applied once a valid object is found
+    // delimits must only be applied once a valid object is found.
     f_string_lengths delimits = f_string_lengths_initialize;
 
     fl_fss_skip_past_whitespace(*buffer, location);
     fl_macro_fss_object_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
-    // return found nothing if this line only contains whitespace and delimit placeholders
+    // return found nothing if this line only contains whitespace and delimit placeholders.
     if (buffer->string[location->start] == f_string_eol) {
       status = fl_fss_increment_buffer(*buffer, location, 1);
       if (f_status_is_error(status)) return status;
@@ -32,10 +32,10 @@ extern "C" {
       return fl_fss_found_no_object;
     }
 
-    // begin the search
+    // begin the search.
     found->start = location->start;
 
-    // ignore all comment lines
+    // ignore all comment lines.
     if (buffer->string[location->start] == f_fss_comment) {
       fl_macro_fss_object_seek_till_newline((*buffer), (*location), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
@@ -45,7 +45,7 @@ extern "C" {
       return fl_fss_found_no_object;
     }
 
-    // identify where the object ends
+    // identify where the object ends.
     while (location->start < buffer->used && location->start <= location->stop && buffer->string[location->start] != f_string_eol) {
       if (buffer->string[location->start] == f_fss_delimit_slash) {
         f_string_length first_slash = location->start;
@@ -85,7 +85,7 @@ extern "C" {
           fl_macro_fss_object_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
           if (buffer->string[location->start] == f_string_eol) {
-            f_string_length length = location->start;
+            f_string_length start = location->start;
 
             location->start = first_slash;
 
@@ -95,7 +95,7 @@ extern "C" {
               f_macro_string_lengths_resize(allocation_status, delimits, delimits.size + (slash_count / 2) + f_fss_default_allocation_step);
 
               if (f_status_is_error(allocation_status)) {
-                f_macro_string_lengths_delete(allocation_status, delimits);
+                f_macro_string_lengths_delete(status, delimits);
                 return allocation_status;
               }
             }
@@ -118,12 +118,12 @@ extern "C" {
               fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
 
               found->stop = stop_point;
-              location->start = length + 1;
+              location->start = start + 1;
 
               return fl_fss_found_object;
             }
 
-            location->start = length + 1;
+            location->start = start + 1;
             return fl_fss_found_no_object;
           }
         }
@@ -167,7 +167,7 @@ extern "C" {
       if (f_status_is_error(status)) return status;
     } // while
 
-    // seek to the end of the line when no valid object is found
+    // seek to the end of the line when no valid object is found.
     while (location->start < buffer->used && location->start <= location->stop && buffer->string[location->start] != f_string_eol) {
       status = fl_fss_increment_buffer(*buffer, location, 1);
       if (f_status_is_error(status)) return status;
@@ -270,12 +270,11 @@ extern "C" {
           }
 
           if (buffer->string[location->start] == f_string_eol) {
-            f_string_length length = location->start;
+            f_string_length start = location->start;
 
             location->start = first_slash;
 
             if (slash_count % 2 == 0) {
-              // FIXME: apply delimits??
               if (found_newline) {
                 fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
 
@@ -295,7 +294,7 @@ extern "C" {
               f_macro_string_lengths_resize(allocation_status, delimits, delimits.size + (slash_count / 2) + f_fss_default_allocation_step);
 
               if (f_status_is_error(allocation_status)) {
-                f_macro_string_lengths_delete(allocation_status, delimits);
+                f_macro_string_lengths_delete(status, delimits);
                 return allocation_status;
               }
             }
@@ -315,7 +314,7 @@ extern "C" {
             } // while
 
             found_newline = f_true;
-            location->start = length + 1;
+            location->start = start + 1;
           }
         }
 
@@ -425,7 +424,7 @@ extern "C" {
     while (location->start <= location->stop && location->start < object.used) {
       if (object.string[location->start] == f_fss_comment) {
         // comments are not allowed and this format has no way of "wrapping" a comment.
-        return f_status_set_error(f_invalid_data);
+        return f_status_set_error(fl_fss_found_comment);
       }
       else if ((status = fl_fss_is_graph(object, *location)) == f_true) {
         break;
@@ -591,7 +590,7 @@ extern "C" {
         } // while
 
         if (content.string[location->start] == f_fss_basic_list_open) {
-          f_string_length length = location->start;
+          f_string_length start = location->start;
 
           status = fl_fss_increment_buffer(content, location, 1);
           if (f_status_is_error(status)) return status;
@@ -630,12 +629,12 @@ extern "C" {
 
           buffer->string[buffer_position.stop] = f_fss_basic_list_open;
           buffer_position.stop++;
-          location->start = length + 1;
+          location->start = start + 1;
           continue;
         }
       }
       else if (content.string[location->start] == f_fss_basic_list_open && !is_comment) {
-        f_string_length length = location->start;
+        f_string_length start = location->start;
 
         has_graph = f_true;
 
@@ -670,7 +669,7 @@ extern "C" {
 
         buffer->string[buffer_position.stop] = f_fss_basic_list_open;
         buffer_position.stop++;
-        location->start = length + 1;
+        location->start = start + 1;
         continue;
       }
       else if (content.string[location->start] == f_fss_comment && !has_graph) {
index 4e90d9b1a9df5ca0556850b792a9944aceba6fc0..6b3d5436c20600da9270db1a351ec4d5e9a56df7 100644 (file)
@@ -18,13 +18,13 @@ extern "C" {
 
     f_status status = f_none;
 
-    // delimits must only be applied once a valid object is found
+    // delimits must only be applied once a valid object is found.
     f_string_lengths delimits = f_string_lengths_initialize;
 
     fl_fss_skip_past_whitespace(*buffer, location);
     fl_macro_fss_object_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
-    // return found nothing if this line only contains whitespace and delimit placeholders
+    // return found nothing if this line only contains whitespace and delimit placeholders.
     if (buffer->string[location->start] == f_string_eol) {
       status = fl_fss_increment_buffer(*buffer, location, 1);
       if (f_status_is_error(status)) return status;
@@ -32,10 +32,10 @@ extern "C" {
       return fl_fss_found_no_object;
     }
 
-    // begin the search
+    // begin the search.
     found->start = location->start;
 
-    // ignore all comment lines
+    // ignore all comment lines.
     if (buffer->string[location->start] == f_fss_comment) {
       fl_macro_fss_object_seek_till_newline((*buffer), (*location), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
@@ -45,7 +45,7 @@ extern "C" {
       return fl_fss_found_no_object;
     }
 
-    // identify where the object ends
+    // identify where the object ends.
     while (location->start < buffer->used && location->start <= location->stop && buffer->string[location->start] != f_string_eol) {
       if (buffer->string[location->start] == f_fss_delimit_slash) {
         f_string_length first_slash = location->start;
@@ -85,7 +85,7 @@ extern "C" {
           fl_macro_fss_object_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
 
           if (buffer->string[location->start] == f_string_eol) {
-            f_string_length length = location->start;
+            f_string_length start = location->start;
 
             location->start = first_slash;
 
@@ -118,12 +118,12 @@ extern "C" {
               fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
 
               found->stop = stop_point;
-              location->start = length + 1;
+              location->start = start + 1;
 
               return fl_fss_found_object;
             }
 
-            location->start = length + 1;
+            location->start = start + 1;
             return fl_fss_found_no_object;
           }
         }
@@ -167,7 +167,7 @@ extern "C" {
       if (f_status_is_error(status)) return status;
     } // while
 
-    // seek to the end of the line when no valid object is found
+    // seek to the end of the line when no valid object is found.
     while (location->start < buffer->used && location->start <= location->stop && buffer->string[location->start] != f_string_eol) {
       status = fl_fss_increment_buffer(*buffer, location, 1);
       if (f_status_is_error(status)) return status;
@@ -183,7 +183,7 @@ extern "C" {
 #endif // _di_fl_fss_extended_list_object_read_
 
 #ifndef _di_fl_fss_extended_list_content_read_
-  f_return_status fl_fss_extended_list_content_read(f_string_dynamic *buffer, f_string_location *location, f_fss_content *found) {
+  f_return_status fl_fss_extended_list_content_read(f_string_dynamic *buffer, f_string_location *location, f_fss_content_nest *found) {
     #ifndef _di_level_1_parameter_checking_
       if (buffer == 0) return f_status_set_error(f_invalid_parameter);
       if (location == 0) return f_status_set_error(f_invalid_parameter);
@@ -196,7 +196,7 @@ extern "C" {
 
     f_status status = f_none;
 
-    // delimits must only be applied once a valid object is found
+    // delimits must only be applied once a valid object is found.
     f_string_lengths delimits = f_string_lengths_initialize;
 
     fl_macro_fss_skip_past_delimit_placeholders((*buffer), (*location))
@@ -205,184 +205,520 @@ extern "C" {
     fl_macro_fss_allocate_content_if_necessary((*found), delimits);
     found->array[found->used].start = location->start;
 
+    f_array_length depth = 0;
+    f_string_lengths positions_start = f_string_lengths_initialize;
+    f_string_length position_previous = location->start;
     f_string_length last_newline = location->start;
-    f_bool found_newline = f_false;
+    f_fss_object object = f_fss_object_initialize;
+
+    f_macro_string_lengths_new(status, positions_start, f_fss_default_allocation_step);
+    if (f_status_is_error(status)) {
+      f_macro_string_lengths_delete(status, delimits);
+
+      return status;
+    }
+
+    // initialize depth 0 start position.
+    // positions_start.used is used as a max depth (such that positions_start.used == max depth + 1).
+    positions_start.array[0] = location->start;
+    positions_start.used = 1;
 
-    // identify where the content ends
     while (location->start < buffer->used && location->start <= location->stop) {
       if (buffer->string[location->start] == f_string_eol) {
-        found_newline = f_true;
         last_newline = location->start;
 
+        position_previous = location->start;
         status = fl_fss_increment_buffer(*buffer, location, 1);
-        if (f_status_is_error(status)) return status;
+        if (f_status_is_error(status)) {
+          f_status allocation_status = f_none;
+
+          f_macro_string_lengths_delete(allocation_status, delimits);
+          f_macro_string_lengths_delete(allocation_status, positions_start);
+
+          return status;
+        }
 
-        fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+        if (depth > 0) {
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
+        }
+        else {
+          fl_macro_fss_content_nest_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_none_on_eos, f_none_on_stop)
+        }
 
         continue;
       }
 
       if (buffer->string[location->start] == f_fss_delimit_slash) {
-        f_string_length first_slash = location->start;
+        f_string_length slash_first = location->start;
+        f_string_length slash_last = location->start;
         f_string_length slash_count = 1;
 
+        position_previous = location->start;
         status = fl_fss_increment_buffer(*buffer, location, 1);
-        if (f_status_is_error(status)) return status;
+        if (f_status_is_error(status)) {
+          f_status allocation_status = f_none;
 
-        while (location->start < buffer->used && location->start <= location->stop && (buffer->string[location->start] == f_fss_delimit_placeholder || buffer->string[location->start] == f_fss_delimit_slash)) {
-          if (buffer->string[location->start] == f_fss_delimit_slash) {
-            slash_count++;
-          }
+          f_macro_string_lengths_delete(allocation_status, delimits);
+          f_macro_string_lengths_delete(allocation_status, positions_start);
 
+          return status;
+        }
+
+        while (location->start < buffer->used && location->start <= location->stop && (buffer->string[location->start] == f_fss_delimit_placeholder || buffer->string[location->start] == f_fss_delimit_slash)) {
+          position_previous = location->start;
           status = fl_fss_increment_buffer(*buffer, location, 1);
-          if (f_status_is_error(status)) return status;
+          if (f_status_is_error(status)) {
+            if (buffer->string[location->start] == f_fss_delimit_slash) {
+              slash_last = location->start;
+              slash_count++;
+            }
+
+            f_status allocation_status = f_none;
+
+            f_macro_string_lengths_delete(allocation_status, delimits);
+            f_macro_string_lengths_delete(allocation_status, positions_start);
+
+            return status;
+          }
         } // while
 
-        if (found_newline) {
-          fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+        if (depth > 0) {
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
         }
         else {
-          fl_macro_fss_content_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
         }
 
-        if (buffer->string[location->start] == f_fss_extended_list_open) {
-          f_string_length stop_point = location->start - 1;
+        // All slashes for an open are delimited (because it could represent a slash in the object name).
+        // for example 'object {' = valid open, name 'object', 'object \{' represents 'object {', 'object \\{' = valid open, name 'object \', 'object \\\{' represents 'object \{', etc..
+        // Only the first slash before a close is delimited, all others are maintained.
+        // for example '}' = valid close, '\}' represents '}', '\\}' represents '\}', '\\\}' represents '\\}', '\\\\}' represents '\\\}', and so on..
+        // When slash is odd and a (delimited) valid open/close is found, then save delimited positions and continue.
+        if (buffer->string[location->start] == f_string_eol) {
+          last_newline = location->start;
+          position_previous = location->start;
+          location->start++;
+        }
+        else if (buffer->string[location->start] == f_fss_extended_list_open || buffer->string[location->start] == f_fss_extended_list_close) {
+          f_bool is_open = f_false;
 
-          status = fl_fss_increment_buffer(*buffer, location, 1);
-          if (f_status_is_error(status)) return status;
+          if (buffer->string[location->start] == f_fss_extended_list_open) {
+            is_open = f_true;
+          }
+
+          position_previous = location->start;
+          location->start++;
 
           while (location->start < buffer->used && location->start <= location->stop) {
-            if (buffer->string[location->start] == f_string_eol || (status = fl_fss_is_graph(*buffer, *location)) == f_true) {
+            if (buffer->string[location->start] == f_string_eol) {
               break;
             }
 
-            if (f_status_is_error(status)) return status;
+            if (buffer->string[location->start] != f_fss_delimit_placeholder && (status = fl_fss_is_space(*buffer, *location)) == f_false) {
+              break;
+            }
+
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
 
+              return status;
+            }
+
+            position_previous = location->start;
             status = fl_fss_increment_buffer(*buffer, location, 1);
-            if (f_status_is_error(status)) return status;
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
           } // while
 
-          if (found_newline) {
-            fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+          if (depth > 0) {
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
           }
           else {
-            fl_macro_fss_content_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
           }
 
+          // this is a valid object open/close that has been delimited, save the slash delimit positions.
           if (buffer->string[location->start] == f_string_eol) {
-            f_string_length length = location->start;
 
-            location->start = first_slash;
+            if (is_open) {
+              f_bool is_object = f_false;
+              f_string_location location_newline = location->start;
 
-            if (slash_count % 2 == 0) {
-              // FIXME: apply delimits??
-              if (found_newline) {
-                fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
+              if (slash_count % 2 == 0) {
+                is_object = f_true;
+              }
+
+              location->start = slash_first;
+
+              if (delimits.used + (slash_count / 2) >= delimits.size) {
+                f_status allocation_status = f_none;
+
+                f_macro_string_lengths_resize(allocation_status, delimits, delimits.size + (slash_count / 2) + f_fss_default_allocation_step);
 
-                found->array[found->used].stop = last_newline;
-                location->start = last_newline + 1;
-                found->used++;
+                if (f_status_is_error(allocation_status)) {
+                  f_macro_string_lengths_delete(status, delimits);
+                  f_macro_string_lengths_delete(status, positions_start);
 
-                return fl_fss_found_content;
+                  return allocation_status;
+                }
               }
 
-              return fl_fss_found_no_content;
-            }
+              // apply slash delimits, only slashes and placeholders should be present.
+              while (slash_count > 0) {
+                if (buffer->string[location->start] == f_fss_delimit_slash) {
+                  if (slash_count % 2 != 0) {
+                    delimits.array[delimits.used] = location->start;
+                    delimits.used++;
+                  }
 
-            if (delimits.used + (slash_count / 2) >= delimits.size) {
-              f_status allocation_status = f_none;
+                  slash_count--;
+                }
 
-              f_macro_string_lengths_resize(allocation_status, delimits, delimits.size + (slash_count / 2) + f_fss_default_allocation_step);
+                // Delimit slashes and placeholders are required to be in the ASCII range.
+                location->start++;
+              } // while
 
-              if (f_status_is_error(allocation_status)) {
-                f_macro_string_lengths_delete(allocation_status, delimits);
-                return allocation_status;
+              // when slashes are even, the object is valid and needs to be processed.
+              if (is_object) {
+                depth++;
+
+                if (depth >= positions_start.size) {
+                  f_macro_string_lengths_resize(status, (*positions_start), positions_start.size + f_fss_default_allocation_step);
+
+                  if (f_status_is_error(status)) {
+                    f_status allocation_status = f_none;
+
+                    f_macro_string_lengths_delete(allocation_status, delimits);
+                    f_macro_string_lengths_delete(allocation_status, positions_start);
+
+                    return status;
+                  }
+                }
+
+                if (positions_start.used <= depth) {
+                  positions_start.used = depth + 1;
+                }
+
+                positions_start.array[depth] = location_newline + 1;
+
+                object.start = last_newline + 1;
+                object.stop = position_previous;
               }
+
+              last_newline = location_newline;
             }
+            else {
+              last_newline = location->start;
+              location->start = slash_last;
 
-            while (slash_count > 0) {
-              if (buffer->string[location->start] == f_fss_delimit_slash) {
-                if (slash_count % 2 != 0) {
-                  delimits.array[delimits.used] = location->start;
-                  delimits.used++;
-                }
+              if (delimits.used + 1 >= delimits.size) {
+                f_status allocation_status = f_none;
+
+                f_macro_string_lengths_resize(allocation_status, delimits, delimits.size + f_fss_default_allocation_step);
 
-                slash_count--;
+                if (f_status_is_error(allocation_status)) {
+                  f_macro_string_lengths_delete(status, delimits);
+                  f_macro_string_lengths_delete(status, positions_start);
+
+                  return allocation_status;
+                }
               }
 
-              status = fl_fss_increment_buffer(*buffer, location, 1);
-              if (f_status_is_error(status)) return status;
-            } // while
+              delimits.array[delimits.used] = slash_last;
+              delimits.used++;
+            }
 
-            found_newline = f_true;
-            location->start = length + 1;
+            location->start = last_newline;
           }
         }
-
-        continue;
       }
       else if (buffer->string[location->start] == f_fss_extended_list_open) {
+        f_string_length location_open = location->start;
+
+        position_previous = location->start;
         status = fl_fss_increment_buffer(*buffer, location, 1);
-        if (f_status_is_error(status)) return status;
+        if (f_status_is_error(status)) {
+          f_status allocation_status = f_none;
+
+          f_macro_string_lengths_delete(allocation_status, delimits);
+          f_macro_string_lengths_delete(allocation_status, positions_start);
+
+          return status;
+        }
 
         while (location->start < buffer->used && location->start <= location->stop) {
-          if (buffer->string[location->start] == f_string_eol || (status = fl_fss_is_graph(*buffer, *location)) == f_true) {
+          if (buffer->string[location->start] == f_string_eol) {
             break;
           }
 
-          if (f_status_is_error(status)) return status;
+          if (buffer->string[location->start] != f_fss_delimit_placeholder && (status = fl_fss_is_space(*buffer, *location)) == f_false) {
+            break;
+          }
+
+          if (f_status_is_error(status)) {
+            f_status allocation_status = f_none;
+
+            f_macro_string_lengths_delete(allocation_status, delimits);
+            f_macro_string_lengths_delete(allocation_status, positions_start);
 
+            return status;
+          }
+
+          position_previous = location->start;
           status = fl_fss_increment_buffer(*buffer, location, 1);
-          if (f_status_is_error(status)) return status;
+          if (f_status_is_error(status)) {
+            f_status allocation_status = f_none;
+
+            f_macro_string_lengths_delete(allocation_status, delimits);
+            f_macro_string_lengths_delete(allocation_status, positions_start);
+
+            return status;
+          }
         } // while
 
-        if (found_newline) {
-          fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+        if (depth > 0) {
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
         }
         else {
-          fl_macro_fss_content_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
         }
 
         if (buffer->string[location->start] == f_string_eol) {
-          if (found_newline) {
-            fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
+          depth++;
 
-            found->array[found->used].stop = last_newline;
-            location->start = last_newline + 1;
-            found->used++;
+          if (depth >= positions_start.size) {
+            f_macro_string_lengths_resize(status, (*positions_start), positions_start.size + f_fss_default_allocation_step);
 
-            return fl_fss_found_content;
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
           }
 
-          if (!found_newline) {
-            location->start = last_newline;
+          if (positions_start.used <= depth) {
+            positions_start.used = depth + 1;
           }
 
-          return fl_fss_found_no_content;
+          positions_start.array[depth] = location->start + 1;
+
+          object.start = last_newline + 1;
+          object.stop = position_previous;
         }
+        // No valid object open found, seek until EOL.
+        else {
+          while (location->start < buffer->used && location->start <= location->stop) {
+            if (buffer->string[location->start] == f_string_eol) {
+              break;
+            }
 
-        continue;
+            position_previous = location->start;
+            status = fl_fss_increment_buffer(*buffer, location, 1);
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
+          } // while
+
+          if (depth > 0) {
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
+          }
+          else {
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
+          }
+        }
+
+        last_newline = location->start;
       }
+      else if (buffer->string[location->start] == f_fss_extended_list_close) {
+        position_previous = location->start;
+        status = fl_fss_increment_buffer(*buffer, location, 1);
+        if (f_status_is_error(status)) {
+          f_status allocation_status = f_none;
+
+          f_macro_string_lengths_delete(allocation_status, delimits);
+          f_macro_string_lengths_delete(allocation_status, positions_start);
+
+          return status;
+        }
+
+        while (location->start < buffer->used && location->start <= location->stop) {
+          if (buffer->string[location->start] == f_string_eol) {
+            break;
+          }
+
+          if (buffer->string[location->start] != f_fss_delimit_placeholder && (status = fl_fss_is_space(*buffer, *location)) == f_false) {
+            break;
+          }
+
+          if (f_status_is_error(status)) {
+            f_status allocation_status = f_none;
+
+            f_macro_string_lengths_delete(allocation_status, delimits);
+            f_macro_string_lengths_delete(allocation_status, positions_start);
 
+            return status;
+          }
+
+          position_previous = location->start;
+          status = fl_fss_increment_buffer(*buffer, location, 1);
+          if (f_status_is_error(status)) {
+            f_status allocation_status = f_none;
+
+            f_macro_string_lengths_delete(allocation_status, delimits);
+            f_macro_string_lengths_delete(allocation_status, positions_start);
+
+            return status;
+          }
+        } // while
+
+        if (depth > 0) {
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
+        }
+        else {
+          fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
+        }
+
+        if (buffer->string[location->start] == f_string_eol) {
+          if (found->used >= found->size) {
+            f_macro_fss_content_nest_resize(status, (*found), found->size + f_fss_default_allocation_step);
+
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
+          }
+
+          if (found->array[depth]->used >= found->array[depth]->size) {
+            f_macro_fss_content_childs_resize(status, found->array[depth], found->array[depth]->size + f_fss_default_allocation_step);
+
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
+          }
+
+          f_array_length position = found->array[depth]->used;
+
+          if (found->array[depth]->array[position]->used >= found->array[depth]->content[position]->size) {
+            f_macro_fss_contents_resize(status, found->array[depth]->array[position], found->array[depth]->array[position]->size + f_fss_default_allocation_step);
+
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
+          }
+
+          found->array[depth]->range.start = positions_start.array[depth];
+          found->array[depth]->range.stop = last_newline;
+          found->array[depth]->array[position]->object.start = object.start;
+          found->array[depth]->array[position]->object.stop = object.stop;
+          found->array[depth]->array[position]->content[found->array[depth]->array[position]->used].stop = last_newline;
+          found->array[depth]->array[position]->used++;
+          found->array[depth]->used++;
+          found->used = positions_start.used;
+
+          if (depth == 0) {
+            last_newline = location->start;
+            break;
+          }
+
+          depth--;
+        }
+        // No valid object close found, seek until EOL.
+        else {
+          while (location->start < buffer->used && location->start <= location->stop) {
+            if (buffer->string[location->start] == f_string_eol) {
+              break;
+            }
+
+            position_previous = location->start;
+            status = fl_fss_increment_buffer(*buffer, location, 1);
+            if (f_status_is_error(status)) {
+              f_status allocation_status = f_none;
+
+              f_macro_string_lengths_delete(allocation_status, delimits);
+              f_macro_string_lengths_delete(allocation_status, positions_start);
+
+              return status;
+            }
+          } // while
+
+          if (depth > 0) {
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_unterminated_nest_on_eos, f_unterminated_nest_on_stop)
+          }
+          else {
+            fl_macro_fss_content_nest_return_on_overflow((*buffer), (*location), (*found), delimits, positions_start, f_no_data_on_eos, f_no_data_on_stop)
+          }
+        }
+
+        last_newline = location->start;
+      }
+
+      position_previous = location->start;
       status = fl_fss_increment_buffer(*buffer, location, 1);
-      if (f_status_is_error(status)) return status;
+      if (f_status_is_error(status)) {
+        f_status allocation_status = f_none;
+
+        f_macro_string_lengths_delete(allocation_status, delimits);
+        f_macro_string_lengths_delete(allocation_status, positions_start);
+
+        return status;
+      }
     } // while
 
-    if (found_newline) {
-      fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
+    fl_macro_fss_apply_delimit_placeholders((*buffer), delimits);
 
-      found->array[found->used].stop = last_newline - 1;
-      location->start = last_newline + 1;
-      found->used++;
+    location->start = last_newline;
+    status = fl_fss_decrement_buffer(*buffer, location, 1);
+    if (f_status_is_error(status)) {
+      f_status allocation_status = f_none;
 
-      fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+      f_macro_string_lengths_delete(allocation_status, delimits);
+      f_macro_string_lengths_delete(allocation_status, positions_start);
 
-      return fl_fss_found_content;
+      return status;
     }
 
-    fl_macro_fss_content_return_on_overflow((*buffer), (*location), (*found), delimits, f_no_data_on_eos, f_no_data_on_stop)
+    found->array[0]->range.start = positions_start.array[0];
+    found->array[0]->range.stop = location->start;
+    location->start = last_newline + 1;
+    found->used++;
+
+    fl_macro_fss_content_delimited_return_on_overflow((*buffer), (*location), (*found), delimits, f_none_on_eos, f_none_on_stop)
+
+    f_macro_string_lengths_delete(status, delimits);
+    f_macro_string_lengths_delete(status, positions_start);
 
-    return fl_fss_found_no_content;
+    return fl_fss_found_content;
   }
 #endif // _di_fl_fss_extended_list_content_read_
 
@@ -425,7 +761,7 @@ extern "C" {
     while (location->start <= location->stop && location->start < object.used) {
       if (object.string[location->start] == f_fss_comment) {
         // comments are not allowed and this format has no way of "wrapping" a comment.
-        return f_status_set_error(f_invalid_data);
+        return f_status_set_error(fl_fss_found_comment);
       }
       else if ((status = fl_fss_is_graph(object, *location)) == f_true) {
         break;
@@ -501,7 +837,6 @@ extern "C" {
         }
       }
       else if (object.string[location->start] == f_string_eol) {
-        // @todo: review what this is doing.
         if (buffer_position.stop == buffer_position.start) {
           return f_no_data_on_eol;
         }
@@ -602,7 +937,7 @@ extern "C" {
         } // while
 
         if (content.string[location->start] == f_fss_extended_list_open) {
-          f_string_length length = location->start;
+          f_string_length start = location->start;
 
           status = fl_fss_increment_buffer(content, location, 1);
           if (f_status_is_error(status)) return status;
@@ -641,12 +976,12 @@ extern "C" {
 
           buffer->string[buffer_position.stop] = f_fss_extended_list_open;
           buffer_position.stop++;
-          location->start = length + 1;
+          location->start = start + 1;
           continue;
         }
       }
       else if (content.string[location->start] == f_fss_extended_list_open && !is_comment) {
-        f_string_length length = location->start;
+        f_string_length start = location->start;
 
         has_graph = f_true;
 
@@ -681,7 +1016,7 @@ extern "C" {
 
         buffer->string[buffer_position.stop] = f_fss_extended_list_open;
         buffer_position.stop++;
-        location->start = length + 1;
+        location->start = start + 1;
         continue;
       }
       else if (content.string[location->start] == f_fss_comment && !has_graph) {
index 7392fcf268a775fdfaaec6cdeb7a83bf08a7d55d..fc8a3fc54975c0ad68ede832a21ff343f905d5e9 100644 (file)
@@ -99,7 +99,7 @@ extern "C" {
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_fl_fss_extended_list_content_read_
-  extern f_return_status fl_fss_extended_list_content_read(f_string_dynamic *buffer, f_string_location *location, f_fss_content *found);
+  extern f_return_status fl_fss_extended_list_content_read(f_string_dynamic *buffer, f_string_location *location, f_fss_content_nest *found);
 #endif // _di_fl_fss_extended_list_content_read_
 
 /**
index 9c40334dd909e4bc7c9ca742bd4b911914fa26b0..ef69da4037ac9b826f3359bc6fa37c083f53d265 100644 (file)
@@ -137,28 +137,28 @@ extern "C" {
     }
 #endif // _di_fl_macro_fss_content_delimited_return_on_overflow_
 
-#ifndef _di_fl_macro_fss_content_return_on_overflow_reset_
-  #define fl_macro_fss_content_return_on_overflow_reset(buffer, location, found, delimits, eos_status, stop_status, set_stop) \
+#ifndef _di_fl_macro_fss_content_nest_return_on_overflow_
+  #define fl_macro_fss_content_nest_return_on_overflow(buffer, location, found, delimits, positions, eos_status, stop_status) \
     if (location.start >= buffer.used) { \
       f_status allocation_status = f_none; \
       f_macro_string_lengths_delete(allocation_status, delimits); \
+      f_macro_string_lengths_delete(allocation_status, positions); \
       \
-      location.start = set_stop; \
-      found.array[found.used].stop = set_stop; \
+      found.array[found.used].stop = buffer.used - 1; \
       return eos_status; \
     } \
     else if (location.start > location.stop) { \
       f_status allocation_status = f_none; \
       f_macro_string_lengths_delete(allocation_status, delimits); \
+      f_macro_string_lengths_delete(allocation_status, positions); \
       \
-      location.start = set_stop; \
-      found.array[found.used].stop = set_stop; \
+      found.array[found.used].stop = location.stop; \
       return stop_status; \
     }
-#endif // _di_fl_macro_fss_content_return_on_overflow_reset_
+#endif // _di_fl_macro_fss_content_nest_return_on_overflow_
 
-#ifndef _di_fl_macro_fss_content_delimited_return_on_overflow_reset_
-  #define fl_macro_fss_content_delimited_return_on_overflow_reset(buffer, location, found, delimits, eos_status, stop_status, set_stop) \
+#ifndef _di_fl_macro_fss_content_nest_delimited_return_on_overflow_
+  #define fl_macro_fss_content_nest_delimited_return_on_overflow(buffer, location, found, delimits, positions, eos_status, stop_status) \
     if (location.start >= buffer.used) { \
       f_status allocation_status = f_none; \
       f_string_length i = 0; \
@@ -168,9 +168,9 @@ extern "C" {
         i++; \
       } \
       f_macro_string_lengths_delete(allocation_status, delimits); \
+      f_macro_string_lengths_delete(allocation_status, positions); \
       \
-      location.start = set_stop; \
-      found.array[found.used].stop = set_stop; \
+      found.array[found.used].stop = buffer.used - 1; \
       return eos_status; \
     } \
     else if (location.start > location.stop) { \
@@ -182,12 +182,12 @@ extern "C" {
         i++; \
       } \
       f_macro_string_lengths_delete(allocation_status, delimits); \
+      f_macro_string_lengths_delete(allocation_status, positions); \
       \
-      location.start = set_stop; \
-      found.array[found.used].stop = set_stop; \
+      found.array[found.used].stop = location.stop; \
       return stop_status; \
     }
-#endif // _di_fl_macro_fss_content_delimited_return_on_overflow_reset_
+#endif // _di_fl_macro_fss_content_nest_delimited_return_on_overflow_
 
 #ifndef _di_fl_macro_fss_allocate_content_if_necessary_
   #define fl_macro_fss_allocate_content_if_necessary(content, delimits) \
index 6852b584c2cb637809be61ce40c36ac22584ecef..e87a6e3353adf65bf76bc57a6da58546e81115b0 100644 (file)
@@ -42,6 +42,10 @@ enum {
     fl_fss_found_object_no_content, // for the case where an object is found but no content could possibly exist
   #endif // _di_fl_fss_status_success_
 
+  #ifndef _di_fl_fss_status_codes_
+    fl_fss_found_comment,
+  #endif // _di_fl_fss_status_codes_
+
   fl_fss_last_error_code,
 }; // enum
 
index 55b8e9353b20952d1cb2731872609ffbd991746b..386573ad47392e36cf8b52602de391651a7e57c3 100644 (file)
@@ -87,6 +87,13 @@ extern "C" {
       }
     #endif // _di_fll_fss_status_success_
 
+    #ifndef _di_fll_fss_status_codes_
+      if (fl_string_compare(string, fll_fss_status_string_found_comment, length, fll_fss_status_string_found_comment_length) == f_equal_to) {
+        *error = fl_fss_found_object;
+        return f_none;
+      }
+    #endif // _di_fll_fss_status_codes_
+
     if (fl_string_compare(string, fll_fss_status_string_last_error_code, length, fll_fss_status_string_last_error_code_length) == f_equal_to) {
       *error = f_last_status_code;
       return f_none;
@@ -147,9 +154,16 @@ extern "C" {
           break;
       #endif // _di_fll_fss_status_success_
 
+      #ifndef _di_fll_fss_status_codes_
+        case fl_fss_found_comment:
+          *string = fll_fss_status_string_found_comment;
+          break;
+      #endif // _di_fll_fss_status_codes_
+
       case fl_fss_last_error_code:
         *string = fll_fss_status_string_last_error_code;
         break;
+
     default:
         return fl_status_to_string(error, string);
     }
index f5a32eea44b90b87bd754bc2ca7e6fe0c3c2c1a4..109dae29d2f2ff9212fb6660bba56c2a20f9a231 100644 (file)
@@ -70,6 +70,11 @@ extern "C" {
     #define fll_fss_status_string_found_object_no_content_length 31
   #endif // _di_fll_fss_status_success_
 
+  #ifndef _di_fll_fss_status_codes_
+    #define fll_fss_status_string_found_comment "fl_fss_found_comment"
+    #define fll_fss_status_string_found_comment_length 15
+  #endif // _di_fll_fss_status_codes_
+
   #define fll_fss_status_string_last_error_code "fl_fss_last_error_code"
   #define fll_fss_status_string_last_error_code_length 23
 #endif // _di_fll_fss_status_string_
index 05621fca2c04c728058f4100c7b892efc83a21d6..851f062a242db326bce2760a0010e4f314f0cafa 100644 (file)
@@ -9,13 +9,15 @@ Any Content that could be interpreted as an end of content must be delimited if
 Whitespace may follow a valid close-brace but a terminating newline must be present to designate a valid end of content.
 
 There is no single-quote or double-quote delimitation in this specification.
-Only the open-brance that would result in a valid Object or the close-brace that would terminate valid Content can be delimited.
+Only the open-brace that would result in a valid Object or the close-brace that would terminate valid Content can be delimited.
+Each delimit slash in an open-brace is treated as a potential delimit such that two slashes represents a single delimited slash ('\\\{' would represent '\{').
+Only the first delimit slash in a close-brace is treated as a potential delimit ('\\\}' would represent '\\}').
 
 Key:
   \s = whitespace, except newline.
   \o = any printable character, except unescaped '{'.
   \l = any printable character or whitespace, except unescaped '}'.
-  \c = either whitespace or printable, including newline, that not interpretable as an Object.
+  \c = either whitespace or printable, including newline, that is not interpretable as an Object.
   \n = newline.
   * = 0 or more occurrences.