From 1996f392c066001613dd5ddc17b07de5b0a658a7 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 10 Oct 2019 23:19:26 -0500 Subject: [PATCH] Progress: begin implementing fss-003 Extended List --- level_0/f_fss/c/fss.h | 118 +++++++- level_1/fl_fss/c/fss_basic_list.c | 37 ++- level_1/fl_fss/c/fss_extended_list.c | 537 ++++++++++++++++++++++++++++------- level_1/fl_fss/c/fss_extended_list.h | 2 +- level_1/fl_fss/c/fss_macro.h | 28 +- level_1/fl_fss/c/fss_status.h | 4 + level_2/fll_fss/c/fss_status.c | 14 + level_2/fll_fss/c/fss_status.h | 5 + specifications/fss-0003.txt | 6 +- 9 files changed, 612 insertions(+), 139 deletions(-) diff --git a/level_0/f_fss/c/fss.h b/level_0/f_fss/c/fss.h index 696386d..d2957b9 100644 --- a/level_0/f_fss/c/fss.h +++ b/level_0/f_fss/c/fss.h @@ -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 a 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 diff --git a/level_1/fl_fss/c/fss_basic_list.c b/level_1/fl_fss/c/fss_basic_list.c index 07f0f0c..e3efcd4 100644 --- a/level_1/fl_fss/c/fss_basic_list.c +++ b/level_1/fl_fss/c/fss_basic_list.c @@ -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) { diff --git a/level_1/fl_fss/c/fss_extended_list.c b/level_1/fl_fss/c/fss_extended_list.c index 4e90d9b..6b3d543 100644 --- a/level_1/fl_fss/c/fss_extended_list.c +++ b/level_1/fl_fss/c/fss_extended_list.c @@ -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) { diff --git a/level_1/fl_fss/c/fss_extended_list.h b/level_1/fl_fss/c/fss_extended_list.h index 7392fcf..fc8a3fc 100644 --- a/level_1/fl_fss/c/fss_extended_list.h +++ b/level_1/fl_fss/c/fss_extended_list.h @@ -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_ /** diff --git a/level_1/fl_fss/c/fss_macro.h b/level_1/fl_fss/c/fss_macro.h index 9c40334..ef69da4 100644 --- a/level_1/fl_fss/c/fss_macro.h +++ b/level_1/fl_fss/c/fss_macro.h @@ -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) \ diff --git a/level_1/fl_fss/c/fss_status.h b/level_1/fl_fss/c/fss_status.h index 6852b58..e87a6e3 100644 --- a/level_1/fl_fss/c/fss_status.h +++ b/level_1/fl_fss/c/fss_status.h @@ -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 diff --git a/level_2/fll_fss/c/fss_status.c b/level_2/fll_fss/c/fss_status.c index 55b8e93..386573a 100644 --- a/level_2/fll_fss/c/fss_status.c +++ b/level_2/fll_fss/c/fss_status.c @@ -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); } diff --git a/level_2/fll_fss/c/fss_status.h b/level_2/fll_fss/c/fss_status.h index f5a32ee..109dae2 100644 --- a/level_2/fll_fss/c/fss_status.h +++ b/level_2/fll_fss/c/fss_status.h @@ -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_ diff --git a/specifications/fss-0003.txt b/specifications/fss-0003.txt index 05621fc..851f062 100644 --- a/specifications/fss-0003.txt +++ b/specifications/fss-0003.txt @@ -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. -- 1.8.3.1