Incomplete major refactoring
This commit is contained in:
parent
277ea3303c
commit
4b98c6a6b2
|
@ -0,0 +1,24 @@
|
|||
# Linux kernel style
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 8
|
||||
UseTab: Always
|
||||
AlignAfterOpenBracket: true
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Linux
|
||||
BreakStringLiterals: false
|
||||
ContinuationIndentWidth: 8
|
||||
IndentCaseLabels: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
SortIncludes: false
|
||||
|
||||
# Custom
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
SpaceAfterCStyleCast: true
|
|
@ -1 +1 @@
|
|||
Subproject commit da9f3a02644f7bd7fc24ad29832c289460854eae
|
||||
Subproject commit 71152e7ed6e4b1e59d1eac7f583d8e3830632973
|
|
@ -1 +1 @@
|
|||
../ext/nicehash/src/main/c
|
||||
../ext/nicehash/src
|
|
@ -1,8 +0,0 @@
|
|||
# Double underscore files
|
||||
|
||||
## __main__.c
|
||||
|
||||
- Provide initialise function
|
||||
- Include all sources for easy usage (single usage)
|
||||
|
||||
## __base__.c
|
|
@ -0,0 +1,22 @@
|
|||
# Scope naming
|
||||
|
||||
## Public
|
||||
|
||||
```c
|
||||
int hb_sub_function_name(int a, int b);
|
||||
```
|
||||
|
||||
## Internal use only
|
||||
|
||||
Used across multiple files but should only be used by this project's code.
|
||||
|
||||
```c
|
||||
int _hb_sub_function_name(int a, int b);
|
||||
```
|
||||
|
||||
## Within same file only
|
||||
|
||||
```c
|
||||
// Don't declare in header file
|
||||
static int _function_name(int a, int b) {}
|
||||
```
|
|
@ -1,4 +0,0 @@
|
|||
void hb_init(void) {
|
||||
// Set up rules
|
||||
hbr_init();
|
||||
}
|
142
src/cli.c
142
src/cli.c
|
@ -1,142 +0,0 @@
|
|||
#include <getopt.h>
|
||||
#include "./stream/content/html.c"
|
||||
#include "./__main__.c"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
hb_init();
|
||||
|
||||
hbe_err_t err = NULL;
|
||||
hbe_err_t *hbe_err = &err;
|
||||
|
||||
hbu_fstreamout_t output = NULL;
|
||||
hbu_list_char_t output_buffer = NULL;
|
||||
|
||||
// Prepare config
|
||||
char *input_path = NULL;
|
||||
char *output_path = NULL;
|
||||
int logging = 0;
|
||||
int config_keep = 0;
|
||||
int config_buffer = 0;
|
||||
hbu_streamoptions_t config_stream = hbu_streamoptions_create();
|
||||
|
||||
int nondefault_ex_collapse_whitespace = 0;
|
||||
int nondefault_ex_destroy_whole_whitespace = 0;
|
||||
int nondefault_ex_trim_whitespace = 0;
|
||||
|
||||
// Parse arguments
|
||||
while (1) {
|
||||
struct option long_options[] = {
|
||||
{"keep", no_argument, &config_keep, 1},
|
||||
{"buffer", no_argument, &config_buffer, 1},
|
||||
{"verbose", no_argument, &logging, 1},
|
||||
{"input", required_argument, NULL, 'i'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{"suppress", required_argument, NULL, 's'},
|
||||
|
||||
{"MXcollapseWhitespace", optional_argument, NULL, 40},
|
||||
{"MXdestroyWholeWhitespace", optional_argument, NULL, 41},
|
||||
{"MXtrimWhitespace", optional_argument, NULL, 42},
|
||||
|
||||
{"MXtrimClassAttr", no_argument, &(config_stream->trim_class_attr), 0},
|
||||
{"MXdecEnt", no_argument, &(config_stream->decode_entities), 0},
|
||||
{"MXcondComments", no_argument, &(config_stream->min_conditional_comments), 0},
|
||||
{"MXattrQuotes", no_argument, &(config_stream->decode_entities), 0},
|
||||
{"MXcomments", no_argument, &(config_stream->remove_comments), 0},
|
||||
{"MXoptTags", no_argument, &(config_stream->remove_optional_tags), 0},
|
||||
{"MXtagWS", no_argument, &(config_stream->remove_tag_whitespace), 0},
|
||||
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "kbvi:o:s:", long_options, &option_index);
|
||||
|
||||
if (c == -1) {
|
||||
if (optind != argc) {
|
||||
HBE_THROW_F(HBE_CLI_TOO_MANY_OPTIONS, "Too many arguments provided");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'i':
|
||||
input_path = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
output_path = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
HBE_CATCH_F(hbu_streamoptions_parse_and_add_errors_to_suppress, config_stream->suppressed_errors, optarg);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
nondefault_ex_collapse_whitespace = 1;
|
||||
config_stream->ex_collapse_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
|
||||
case 41:
|
||||
nondefault_ex_destroy_whole_whitespace = 1;
|
||||
config_stream->ex_destroy_whole_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
|
||||
case 42:
|
||||
nondefault_ex_trim_whitespace = 1;
|
||||
config_stream->ex_trim_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nondefault_ex_collapse_whitespace) config_stream->ex_collapse_whitespace = hbu_streamoptions_default_ex_collapse_whitespace();
|
||||
if (!nondefault_ex_destroy_whole_whitespace) config_stream->ex_destroy_whole_whitespace = hbu_streamoptions_default_ex_destroy_whole_whitespace();
|
||||
if (!nondefault_ex_trim_whitespace) config_stream->ex_trim_whitespace = hbu_streamoptions_default_ex_trim_whitespace();
|
||||
|
||||
if (logging) {
|
||||
hbl_info_kv_string("Input", input_path);
|
||||
hbl_info_kv_string("Output", output_path);
|
||||
hbl_info_kv_boolean("Buffer output until success", config_buffer);
|
||||
hbl_info_kv_boolean("Keep output file on error", config_keep);
|
||||
hbu_streamoptions_log(config_stream);
|
||||
}
|
||||
|
||||
hbu_pipe_t pipe = hbu_pipe_create_blank(input_path);
|
||||
|
||||
hbu_fstreamin_t input = HBE_CATCH_F(hbu_fstreamin_create, input_path);
|
||||
hbu_pipe_blank_set_input_fstreamin(pipe, input);
|
||||
|
||||
if (config_buffer) {
|
||||
output_buffer = hbu_list_char_create();
|
||||
hbu_pipe_blank_set_output_buffer(pipe, output_buffer);
|
||||
} else {
|
||||
output = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
||||
hbu_pipe_blank_set_output_fstreamout(pipe, output);
|
||||
}
|
||||
|
||||
HBE_CATCH_F(hbs_content, config_stream, pipe, NULL);
|
||||
|
||||
if (config_buffer) {
|
||||
output = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
||||
HBE_CATCH_F(hbu_fstreamout_write_buffer, output, output_buffer);
|
||||
}
|
||||
|
||||
finally:
|
||||
if (err != NULL) {
|
||||
hbl_error(err);
|
||||
if (output != NULL && !config_keep && !config_buffer) {
|
||||
// Delete only after opening output stream (don't delete before existing file has not been touched)
|
||||
// Don't need to set if $config_buffer, as it won't write anything anyway
|
||||
if (unlink(output_path)) {
|
||||
hbl_log(HBL_LOG_WARN, "Failed to delete file %s with error %d", output_path, errno);
|
||||
} else {
|
||||
hbl_log(HBL_LOG_INFO, "%s has been deleted", output_path);
|
||||
}
|
||||
}
|
||||
exit(err->code);
|
||||
}
|
||||
|
||||
if (logging) {
|
||||
hbl_log(HBL_LOG_INFO, "All done!");
|
||||
}
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
#pragma once
|
||||
|
||||
#include <getopt.h>
|
||||
#include "./stream/content/html.c"
|
||||
#include "./__main__.c"
|
||||
|
||||
nh_set_str_t hbu_streamoptions_parse_list_of_tags(hbe_err_t *hbe_err, char *argv) {
|
||||
nh_set_str_t set = NULL;
|
||||
hb_list_charlist_t list = NULL;
|
||||
|
||||
if (argv != NULL && strcmp(argv, "*")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
set = nh_set_str_create();
|
||||
|
||||
if (argv == NULL) {
|
||||
return set;
|
||||
}
|
||||
|
||||
list = hb_list_charlist_create_from_split((hb_proc_char_t *) argv, ',');
|
||||
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
hb_list_char_t part = hb_list_charlist_get(list, i);
|
||||
hb_proc_char_t *part_c = hb_list_char_underlying(part);
|
||||
|
||||
if (hb_list_char_get(part, 0) == '$') {
|
||||
// Set of tags
|
||||
hb_list_char_shift(part);
|
||||
HBE_CATCH_F(hbu_streamoptions_parse_and_add_tag_set, (char *) part_c, set);
|
||||
|
||||
} else {
|
||||
// Single tag
|
||||
if (!hb_rule_tags_check(part_c)) {
|
||||
HBE_THROW_F(HBE_CLI_INVALID_TAG, "%s is not a standard tag and was provided as part of an argument's value", part_c);
|
||||
}
|
||||
nh_set_str_add(set, (char *) hb_list_char_underlying_copy(part));
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
if (list != NULL) {
|
||||
hb_list_charlist_destroy_from_split(list);
|
||||
list = NULL;
|
||||
}
|
||||
if (*hbe_err != NULL) {
|
||||
if (set != NULL) {
|
||||
nh_set_str_destroy(set);
|
||||
set = NULL;
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void hbu_streamoptions_parse_and_add_errors_to_suppress(hbe_err_t *hbe_err, nh_set_int32_t suppressed_errors, char *argv) {
|
||||
hb_list_charlist_t list = NULL;
|
||||
|
||||
if (argv == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
list = hb_list_charlist_create_from_split((hb_proc_char_t *) argv, ',');
|
||||
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
hb_list_char_t part = hb_list_charlist_get(list, i);
|
||||
|
||||
if (hb_list_char_compare_lit(part, "MALFORMED_ENTITY") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_MALFORMED_ENTITY);
|
||||
} else if (hb_list_char_compare_lit(part, "BARE_AMPERSAND") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_BARE_AMPERSAND);
|
||||
} else if (hb_list_char_compare_lit(part, "INVALID_ENTITY") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_INVALID_ENTITY);
|
||||
} else if (hb_list_char_compare_lit(part, "NONSTANDARD_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_NONSTANDARD_TAG);
|
||||
} else if (hb_list_char_compare_lit(part, "UCASE_ATTR") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UCASE_ATTR);
|
||||
} else if (hb_list_char_compare_lit(part, "UCASE_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UCASE_TAG);
|
||||
} else if (hb_list_char_compare_lit(part, "UNQUOTED_ATTR") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UNQUOTED_ATTR);
|
||||
} else if (hb_list_char_compare_lit(part, "SELF_CLOSING_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_SELF_CLOSING_TAG);
|
||||
} else {
|
||||
HBE_THROW_F(HBE_CLI_INVALID_SUPPRESSABLE_ERROR, "Unrecognised suppressable error `%s`", hb_list_char_underlying(part));
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
if (list != NULL) {
|
||||
hb_list_charlist_destroy_from_split(list);
|
||||
list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void hbu_streamoptions_log(hbu_streamoptions_t opt) {
|
||||
hbl_info_kv_boolean("Trim `class` attributes", opt->trim_class_attr);
|
||||
hbl_info_kv_boolean("Decode entities", opt->decode_entities);
|
||||
hbl_info_kv_boolean("Minify conditional comments", opt->min_conditional_comments);
|
||||
hbl_info_kv_boolean("Remove attribute quotes", opt->remove_attr_quotes);
|
||||
hbl_info_kv_boolean("Remove comments", opt->remove_comments);
|
||||
hbl_info_kv_boolean("Remove optional tags", opt->remove_optional_tags);
|
||||
hbl_info_kv_boolean("Remove tag whitespace", opt->remove_tag_whitespace);
|
||||
}
|
||||
|
||||
void hbu_streamoptions_parse_and_add_tag_set(hbe_err_t *hbe_err, char *set_name, nh_set_str_t set) {
|
||||
if (strcmp(set_name, "content") == 0) {
|
||||
hb_rule_contenttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "contentfirst") == 0) {
|
||||
hb_rule_contentfirsttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "formatting") == 0) {
|
||||
hb_rule_formattingtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "layout") == 0) {
|
||||
hb_rule_layouttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "specific") == 0) {
|
||||
hb_rule_specifictags_add_elems(set);
|
||||
} else if (strcmp(set_name, "heading") == 0) {
|
||||
hb_rule_headingtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "media") == 0) {
|
||||
hb_rule_mediatags_add_elems(set);
|
||||
} else if (strcmp(set_name, "sectioning") == 0) {
|
||||
hb_rule_sectioningtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "void") == 0) {
|
||||
hb_rule_voidtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "wss") == 0) {
|
||||
hb_rule_wsstags_add_elems(set);
|
||||
} else {
|
||||
HBE_THROW_V(HBE_CLI_INVALID_TAG_SET, "Unrecognised tag set `%s`", set_name);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
hb_init();
|
||||
|
||||
hbe_err_t err = NULL;
|
||||
hbe_err_t *hbe_err = &err;
|
||||
|
||||
hbu_fstreamout_t output = NULL;
|
||||
hb_list_char_t output_buffer = NULL;
|
||||
|
||||
// Prepare config
|
||||
char *input_path = NULL;
|
||||
char *output_path = NULL;
|
||||
int logging = 0;
|
||||
int config_keep = 0;
|
||||
int config_buffer = 0;
|
||||
hbu_streamoptions_t config_stream = hbu_streamoptions_create();
|
||||
|
||||
int nondefault_ex_collapse_whitespace = 0;
|
||||
int nondefault_ex_destroy_whole_whitespace = 0;
|
||||
int nondefault_ex_trim_whitespace = 0;
|
||||
|
||||
// Parse arguments
|
||||
while (1) {
|
||||
struct option long_options[] = {
|
||||
{"keep", no_argument, &config_keep, 1},
|
||||
{"buffer", no_argument, &config_buffer, 1},
|
||||
{"verbose", no_argument, &logging, 1},
|
||||
{"input", required_argument, NULL, 'i'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{"suppress", required_argument, NULL, 's'},
|
||||
|
||||
{"MXcollapseWhitespace", optional_argument, NULL, 40},
|
||||
{"MXdestroyWholeWhitespace", optional_argument, NULL, 41},
|
||||
{"MXtrimWhitespace", optional_argument, NULL, 42},
|
||||
|
||||
{"MXtrimClassAttr", no_argument, &(config_stream->trim_class_attr), 0},
|
||||
{"MXdecEnt", no_argument, &(config_stream->decode_entities), 0},
|
||||
{"MXcondComments", no_argument, &(config_stream->min_conditional_comments), 0},
|
||||
{"MXattrQuotes", no_argument, &(config_stream->decode_entities), 0},
|
||||
{"MXcomments", no_argument, &(config_stream->remove_comments), 0},
|
||||
{"MXoptTags", no_argument, &(config_stream->remove_optional_tags), 0},
|
||||
{"MXtagWS", no_argument, &(config_stream->remove_tag_whitespace), 0},
|
||||
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "kbvi:o:s:", long_options, &option_index);
|
||||
|
||||
if (c == -1) {
|
||||
if (optind != argc) {
|
||||
HBE_THROW_F(HBE_CLI_TOO_MANY_OPTIONS, "Too many arguments provided");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'i':
|
||||
input_path = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
output_path = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
HBE_CATCH_F(hbu_streamoptions_parse_and_add_errors_to_suppress, config_stream->suppressed_errors, optarg);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
nondefault_ex_collapse_whitespace = 1;
|
||||
config_stream->ex_collapse_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
|
||||
case 41:
|
||||
nondefault_ex_destroy_whole_whitespace = 1;
|
||||
config_stream->ex_destroy_whole_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
|
||||
case 42:
|
||||
nondefault_ex_trim_whitespace = 1;
|
||||
config_stream->ex_trim_whitespace = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nondefault_ex_collapse_whitespace) config_stream->ex_collapse_whitespace = hbu_streamoptions_default_ex_collapse_whitespace();
|
||||
if (!nondefault_ex_destroy_whole_whitespace) config_stream->ex_destroy_whole_whitespace = hbu_streamoptions_default_ex_destroy_whole_whitespace();
|
||||
if (!nondefault_ex_trim_whitespace) config_stream->ex_trim_whitespace = hbu_streamoptions_default_ex_trim_whitespace();
|
||||
|
||||
if (logging) {
|
||||
hbl_info_kv_string("Input", input_path);
|
||||
hbl_info_kv_string("Output", output_path);
|
||||
hbl_info_kv_boolean("Buffer output until success", config_buffer);
|
||||
hbl_info_kv_boolean("Keep output file on error", config_keep);
|
||||
hbu_streamoptions_log(config_stream);
|
||||
}
|
||||
|
||||
hb_proc_t pipe = hb_proc_create_blank(input_path);
|
||||
|
||||
hbu_fstreamin_t input = HBE_CATCH_F(hbu_fstreamin_create, input_path);
|
||||
hb_proc_blank_set_input_fstreamin(pipe, input);
|
||||
|
||||
if (config_buffer) {
|
||||
output_buffer = hb_list_char_create();
|
||||
hb_proc_blank_set_output_buffer(pipe, output_buffer);
|
||||
} else {
|
||||
output = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
||||
hb_proc_blank_set_output_fstreamout(pipe, output);
|
||||
}
|
||||
|
||||
HBE_CATCH_F(hbs_content, config_stream, pipe, NULL);
|
||||
|
||||
if (config_buffer) {
|
||||
output = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
||||
HBE_CATCH_F(hbu_fstreamout_write_buffer, output, output_buffer);
|
||||
}
|
||||
|
||||
finally:
|
||||
if (err != NULL) {
|
||||
hbl_error(err);
|
||||
if (output != NULL && !config_keep && !config_buffer) {
|
||||
// Delete only after opening output stream (don't delete before existing file has not been touched)
|
||||
// Don't need to set if $config_buffer, as it won't write anything anyway
|
||||
if (unlink(output_path)) {
|
||||
hbl_log(HBL_LOG_WARN, "Failed to delete file %s with error %d", output_path, errno);
|
||||
} else {
|
||||
hbl_log(HBL_LOG_INFO, "%s has been deleted", output_path);
|
||||
}
|
||||
}
|
||||
exit(err->code);
|
||||
}
|
||||
|
||||
if (logging) {
|
||||
hbl_log(HBL_LOG_INFO, "All done!");
|
||||
}
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hb-rule.h"
|
||||
#include "hb-config.h"
|
||||
|
||||
static struct hb_config_ex_s _ex_collapse_whitespace_default;
|
||||
static struct hb_config_ex_s _ex_destroy_whole_whitespace_default;
|
||||
static struct hb_config_ex_s _ex_trim_whitespace_default;
|
||||
|
||||
// WARNING: Rules must be initialised before calling this function
|
||||
void hb_config_init(void)
|
||||
{
|
||||
nh_set_str ex_collapse_whitespace_set = nh_set_str_create();
|
||||
hb_rule_wsstags_add_elems(ex_collapse_whitespace_set);
|
||||
_ex_collapse_whitespace_default = {HB_CONFIG_EX_MODE_DEFAULT,
|
||||
ex_collapse_whitespace_set};
|
||||
|
||||
nh_set_str ex_destroy_whole_whitespace_set = nh_set_str_create();
|
||||
hb_rule_wsstags_add_elems(ex_destroy_whole_whitespace_set);
|
||||
hb_rule_contenttags_add_elems(ex_destroy_whole_whitespace_set);
|
||||
hb_rule_formattingtags_add_elems(ex_destroy_whole_whitespace_set);
|
||||
_ex_destroy_whole_whitespace_default = {
|
||||
HB_CONFIG_EX_MODE_DEFAULT, ex_destroy_whole_whitespace_set};
|
||||
|
||||
nh_set_str ex_trim_whitespace_set = nh_set_str_create();
|
||||
hb_rule_wsstags_add_elems(ex_trim_whitespace_set);
|
||||
hb_rule_formattingtags_add_elems(ex_trim_whitespace_set);
|
||||
_ex_trim_whitespace_default = {HB_CONFIG_EX_MODE_DEFAULT,
|
||||
ex_trim_whitespace_set};
|
||||
}
|
||||
|
||||
hb_config_t* hb_config_create(void)
|
||||
{
|
||||
hb_config_t* config = malloc(sizeof(struct hb_config_s));
|
||||
config->ex_collapse_whitespace = _ex_collapse_whitespace_default;
|
||||
config->ex_destroy_whole_whitespace =
|
||||
_ex_destroy_whole_whitespace_default;
|
||||
config->ex_trim_whitespace = _ex_trim_whitespace_default;
|
||||
config->suppressed_errors = nh_set_int32_create();
|
||||
config->trim_class_attr = true;
|
||||
config->decode_entities = true;
|
||||
config->min_conditional_comments = true;
|
||||
config->remove_attr_quotes = true;
|
||||
config->remove_comments = true;
|
||||
config->remove_optional_tags = true;
|
||||
config->remove_tag_whitespace = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
void hb_config_ex_use_none(hb_config_ex_t* config_ex)
|
||||
{
|
||||
*config_ex = {HB_CONFIG_EX_MODE_NONE, NULL};
|
||||
}
|
||||
|
||||
void hb_config_ex_use_custom(hb_config_ex_t* config_ex, nh_set_str custom_set)
|
||||
{
|
||||
*config_ex = {HB_CONFIG_EX_MODE_CUSTOM, custom_set};
|
||||
}
|
||||
|
||||
void hb_config_ex_use_all(hb_config_ex_t* config_ex)
|
||||
{
|
||||
*config_ex = {HB_CONFIG_EX_MODE_ALL};
|
||||
}
|
||||
|
||||
void hb_config_destroy(hb_config_t* opt)
|
||||
{
|
||||
nh_set_int32_destroy(opt->suppressed_errors);
|
||||
free(opt);
|
||||
}
|
||||
|
||||
bool hb_config_supressed_error_check(hb_config_t opt, hb_error_t errcode)
|
||||
{
|
||||
return nh_set_int32_has(&opt->suppressed_errors, errcode);
|
||||
}
|
||||
|
||||
bool hb_config_ex_check(hb_config_t* config, hb_proc_char_t* query)
|
||||
{
|
||||
switch (config->mode) {
|
||||
case HB_CONFIG_EX_MODE_ALL:
|
||||
return true;
|
||||
|
||||
case HB_CONFIG_EX_MODE_NONE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return nh_set_str_has(config->set, query);
|
||||
}
|
||||
if (config->mode == HB_CONFIG_EX_MODE_ALL) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
HB_CONFIG_EX_MODE_NONE, // i.e. minify all without exeption
|
||||
HB_CONFIG_EX_MODE_DEFAULT, // entire struct will not be destroyed
|
||||
HB_CONFIG_EX_MODE_CUSTOM, // set will be destroyed
|
||||
HB_CONFIG_EX_MODE_ALL, // i.e. don't minify
|
||||
} hb_config_ex_mode_t;
|
||||
|
||||
typedef struct {
|
||||
hb_config_ex_mode_t mode;
|
||||
nh_set_str set;
|
||||
} hb_config_ex_t;
|
||||
|
||||
typedef struct {
|
||||
hb_config_ex_t ex_collapse_whitespace;
|
||||
hb_config_ex_t ex_destroy_whole_whitespace;
|
||||
hb_config_ex_t ex_trim_whitespace;
|
||||
nh_set_int32 suppressed_errors;
|
||||
bool trim_class_attributes;
|
||||
bool decode_entities;
|
||||
bool remove_attr_quotes;
|
||||
bool remove_comments;
|
||||
bool remove_optional_tags;
|
||||
bool remove_tag_whitespace;
|
||||
} hb_config_t;
|
||||
|
||||
// WARNING: Rules must be initialised before calling this function
|
||||
void hb_config_init(void);
|
||||
hb_config_t* hb_config_create(void);
|
||||
void hb_config_ex_use_none(hb_config_ex_t* config_ex);
|
||||
void hb_config_ex_use_custom(hb_config_ex_t* config_ex, nh_set_str custom_set);
|
||||
void hb_config_ex_use_all(hb_config_ex_t* config_ex);
|
||||
void hb_config_destroy(hb_config_t* opt);
|
||||
bool hb_config_supressed_error_check(hb_config_t opt, hb_error_t errcode);
|
||||
bool hb_config_ex_check(hb_config_ex_t* config, hb_proc_char_t* query);
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "nicehash/list.h"
|
||||
#include "nicehash/list-ucp.h"
|
||||
#include "nicehash/map-str.h"
|
||||
|
||||
NH_MAP_STR(int32, int32_t);
|
||||
NH_MAP_STR(set_str, nh_set_str*);
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
HBE_NO_ERROR = 0,
|
||||
|
||||
HBE_INTERR_UNKNOWN_ENTITY_TYPE = 2,
|
||||
HBE_INTERR_UNKNOWN_CONTENT_NEXT_STATE,
|
||||
|
||||
HBE_CLI_TOO_MANY_OPTIONS = 17,
|
||||
HBE_CLI_INVALID_TAG_SET,
|
||||
HBE_CLI_INVALID_TAG,
|
||||
HBE_CLI_INVALID_SUPPRESSABLE_ERROR,
|
||||
|
||||
HBE_IO_FOPEN_FAIL = 33,
|
||||
HBE_IO_FCLOSE_FAIL,
|
||||
HBE_IO_FREAD_FAIL,
|
||||
HBE_IO_FWRITE_FAIL,
|
||||
|
||||
HBE_PARSE_MALFORMED_ENTITY = 65,
|
||||
HBE_PARSE_BARE_AMPERSAND,
|
||||
HBE_PARSE_INVALID_ENTITY,
|
||||
HBE_PARSE_NONSTANDARD_TAG,
|
||||
HBE_PARSE_UCASE_TAG,
|
||||
HBE_PARSE_UCASE_ATTR,
|
||||
HBE_PARSE_UNQUOTED_ATTR,
|
||||
HBE_PARSE_ILLEGAL_CHILD,
|
||||
HBE_PARSE_UNCLOSED_TAG,
|
||||
HBE_PARSE_SELF_CLOSING_TAG,
|
||||
HBE_PARSE_NO_SPACE_BEFORE_ATTR,
|
||||
|
||||
HBE_PARSE_UNEXPECTED_END,
|
||||
HBE_PARSE_EXPECTED_NOT_FOUND,
|
||||
} hb_error_t;
|
|
@ -0,0 +1,24 @@
|
|||
#include <errno.h>
|
||||
#include "../char/char.c"
|
||||
#include "../execution/error.c"
|
||||
#include "./__base__.c"
|
||||
|
||||
HBU_FSTREAM_BUILD_INFRA(in, "r", "read", "reading", stdin)
|
||||
|
||||
hb_eod_char_t hbu_fstreamin_read(hbe_err_t* hbe_err, hbu_fstreamin_t fstreamin)
|
||||
{
|
||||
hb_proc_char_t c;
|
||||
|
||||
if (fread(&c, SIZEOF_CHAR, 1, fstreamin->fd) != SIZEOF_CHAR) {
|
||||
if (ferror(fstreamin->fd)) {
|
||||
HBE_THROW(HBE_IO_FREAD_FAIL,
|
||||
"Failed to read input file %s",
|
||||
fstreamin->name);
|
||||
}
|
||||
|
||||
// Must be EOF
|
||||
return HB_EOD;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#include <errno.h>
|
||||
#include "../execution/error.c"
|
||||
#include "../list/char.c"
|
||||
#include "./__base__.c"
|
||||
|
||||
HBU_FSTREAM_BUILD_INFRA(out, "w", "write", "writing", stdout)
|
||||
|
||||
static void _hbu_fstreamout_fwrite(hbe_err_t* hbe_err,
|
||||
hbu_fstreamout_t fstreamout,
|
||||
hb_proc_char_t* source, size_t length)
|
||||
{
|
||||
if (fwrite(source, SIZEOF_CHAR, length, fstreamout->fd)
|
||||
!= SIZEOF_CHAR * length) {
|
||||
HBE_THROW_V(HBE_IO_FWRITE_FAIL,
|
||||
"Failed to write to output file %s",
|
||||
fstreamout->name);
|
||||
}
|
||||
}
|
||||
|
||||
void hbu_fstreamout_write_buffer(hbe_err_t* hbe_err,
|
||||
hbu_fstreamout_t fstreamout,
|
||||
hb_list_char_t buffer)
|
||||
{
|
||||
HBE_CATCH_V(_hbu_fstreamout_fwrite, fstreamout,
|
||||
hb_list_char_underlying(buffer), buffer->length);
|
||||
}
|
||||
|
||||
void hbu_fstreamout_write(hbe_err_t* hbe_err, hbu_fstreamout_t fstreamout,
|
||||
hb_proc_char_t c)
|
||||
{
|
||||
HBE_CATCH_V(_hbu_fstreamout_fwrite, fstreamout, &c, 1);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef enum {
|
||||
HB_FILE_ENC_UTF_8,
|
||||
HB_FILE_ENC_UTF_16,
|
||||
} hb_file_enc_t;
|
||||
|
||||
#define HB_FILE(type, mode, noun, verb, std) \
|
||||
typedef struct { \
|
||||
char const* name; \
|
||||
hb_file_enc_t encoding; \
|
||||
FILE* fd; \
|
||||
} hb_file_##type##_t; \
|
||||
\
|
||||
hb_file_##type##_t* hb_file_##type##_create(char* path) \
|
||||
{ \
|
||||
hb_file_##type##_t* fstream = \
|
||||
malloc(sizeof(hb_file_##type##_t)); \
|
||||
\
|
||||
if (path == NULL) { \
|
||||
fstream->name = #std; \
|
||||
fstream->fd = std; \
|
||||
} else { \
|
||||
fstream->name = path; \
|
||||
\
|
||||
FILE* fd = fopen(path, mode); \
|
||||
\
|
||||
if (fd == NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
fstream->fd = fd; \
|
||||
} \
|
||||
\
|
||||
return fstream; \
|
||||
} \
|
||||
\
|
||||
void hb_file_##type##_destroy(hbe_err_t* hbe_err, \
|
||||
hb_file_##type##_t fstream) \
|
||||
{ \
|
||||
if (fclose(fstream->fd) == EOF) { \
|
||||
HBE_THROW_V(HBE_IO_FCLOSE_FAIL, \
|
||||
"Failed to close " noun \
|
||||
" stream for file %s with error %d", \
|
||||
fstream->name, errno); \
|
||||
} \
|
||||
\
|
||||
free(fstream); \
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* Accepts the next character.
|
||||
* Will cause an error if already at end.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return next character
|
||||
* @throws on read/write error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_proc_char_t hb_proc_accept(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(_hb_proc_read_from_buffer_or_input, pipe);
|
||||
|
||||
HBE_CATCH(_hb_proc_assert_not_eoi, c);
|
||||
|
||||
_hb_proc_update_pos(pipe, c);
|
||||
|
||||
HBE_CATCH(_hb_proc_write_to_output, pipe, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the next <code>count</code> characters.
|
||||
* Requires at least <code>count</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param count amount of characters
|
||||
* @throws on read/write error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
void hb_proc_accept_count(hbe_err_t *hbe_err, hb_proc_t pipe, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following character if it is <code>c</code>.
|
||||
* Won't match or cause an error if there are no characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hb_proc_accept_if(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_char_t c) {
|
||||
hb_eod_char_t n = HBE_CATCH(hb_proc_peek_eoi, pipe);
|
||||
|
||||
if (n == HB_EOD || n != c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hb_proc_accept, pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following characters if they match <code>match</code>.
|
||||
* Won't match or cause an error if there are not enough characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hb_proc_accept_if_matches(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
size_t matchedlen = HBE_CATCH(hb_proc_matches, pipe, match);
|
||||
|
||||
int matched = matchedlen > 0;
|
||||
|
||||
if (matched) {
|
||||
HBE_CATCH(hb_proc_accept_count, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following characters if they are either "\r", "\r\n", or "\n".
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return amount of characters matched
|
||||
* @throws on read/write error
|
||||
*/
|
||||
size_t hb_proc_accept_if_matches_line_terminator(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
size_t matchedlen = HBE_CATCH(hb_proc_matches_line_terminator, pipe);
|
||||
|
||||
if (matchedlen) {
|
||||
HBE_CATCH(hb_proc_accept_count, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matchedlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following character if it satisfies the predicate <code>pred</code>.
|
||||
* Won't do anything if already at the end.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hb_proc_accept_if_predicate(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_predicate_t pred) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi, pipe);
|
||||
|
||||
if (c == HB_EOD || !(*pred)(c)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hb_proc_accept, pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts every following character until one dissatisfies the predicate <code>pred</code>,
|
||||
* or the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return amount of characters accepted
|
||||
* @throws on read/write error
|
||||
*/
|
||||
size_t hb_proc_accept_while_predicate(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_predicate_t pred) {
|
||||
size_t count = 0;
|
||||
|
||||
while (1) {
|
||||
int matched = HBE_CATCH(hb_proc_accept_if_predicate, pipe, pred);
|
||||
if (!matched) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "../../rule/char/ucalpha.c"
|
||||
#include "../char/char.c"
|
||||
#include "../execution/error.c"
|
||||
#include "../list/char.c"
|
||||
#include "../fstream/fstreamin.c"
|
||||
#include "../fstream/fstreamout.c"
|
||||
|
||||
// Use macro to prevent having to allocate (and therefore free/manage) memory
|
||||
#define HB_PROC_FORMAT_WITH_POS(fn, a, format, ...) fn(a, format " at %s [line %d, column %d]", __VA_ARGS__, proc->name, proc->line, proc->column);
|
||||
|
||||
/**
|
||||
* Creates an error using a message with the current position appended.
|
||||
*
|
||||
* @param proc proc
|
||||
* @param errcode error code
|
||||
* @param reason message
|
||||
* @return error
|
||||
*/
|
||||
hbe_err_t hb_proc_error(hb_proc_t* proc, hb_error_t errcode, const char *reason, ...) {
|
||||
va_list args;
|
||||
va_start(args, reason);
|
||||
|
||||
char *msg = calloc(HB_PROC_MAX_ERR_MSG_LEN + 1, SIZEOF_CHAR);
|
||||
vsnprintf(msg, HB_PROC_MAX_ERR_MSG_LEN, reason, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
hbe_err_t err = HBU_FN_FORMAT_WITH_POS(hbe_err_create, errcode, "%s", msg);
|
||||
free(msg);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from input.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param proc proc
|
||||
* @throws on read error
|
||||
*/
|
||||
static hb_eod_char_t _hb_proc_read_from_input(hbe_err_t *hbe_err, hb_proc_t* proc) {
|
||||
hb_eod_char_t c = HBE_CATCH((*proc->reader), proc->input);
|
||||
if (c == HB_EOD) {
|
||||
proc->EOI = 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the buffer has loaded at least the next <code>offset</code> characters, or the remaining
|
||||
* characters from input if there are less than <code>offset</code> characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param proc proc
|
||||
* @throws on read error
|
||||
*/
|
||||
static void _hb_proc_ensure_buffer(hbe_err_t *hbe_err, hb_proc_t* proc, size_t offset) {
|
||||
if (proc->EOI) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t current = proc->buffer->length;
|
||||
|
||||
if (offset <= current) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t gap = offset - current;
|
||||
|
||||
for (size_t i = 0; i < gap; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH_V(_hb_proc_read_from_input, proc);
|
||||
if (c == HB_EOD) {
|
||||
// EOI flag already set by _hb_proc_read_from_input
|
||||
return;
|
||||
}
|
||||
hb_list_char_append(proc->buffer, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next character, whether it's by shifting the buffer or reading from input.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param proc proc
|
||||
* @throws on read error
|
||||
*/
|
||||
static hb_eod_char_t _hb_proc_read_from_buffer_or_input(hbe_err_t *hbe_err, hb_proc_t* proc) {
|
||||
if (proc->EOI) {
|
||||
return HB_EOD;
|
||||
}
|
||||
|
||||
if (proc->buffer->length) {
|
||||
return hb_list_char_shift(proc->buffer);
|
||||
}
|
||||
|
||||
return HBE_CATCH(_hb_proc_read_from_input, proc);
|
||||
}
|
||||
|
||||
static void _hb_proc_update_pos(hb_proc_t* proc, hb_proc_char_t c) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
proc->CR = true;
|
||||
proc->line++;
|
||||
proc->column = 0;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if (!proc->CR) {
|
||||
proc->line++;
|
||||
proc->column = 0;
|
||||
} else {
|
||||
proc->CR = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
proc->column++;
|
||||
proc->CR = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided character is not @{link HB_EOD}, and causes an error otherwise.
|
||||
*
|
||||
* @param c character to test for <code>HB_EOD</code>
|
||||
* @throws HBE_PARSE_UNEXPECTED_END if <code>c</code> is <code>HB_EOD</code>
|
||||
*/
|
||||
static void _hb_proc_assert_not_eoi(hbe_err_t *hbe_err, hb_eod_char_t c) {
|
||||
if (c == HB_EOD) {
|
||||
HBE_THROW_V(HBE_PARSE_UNEXPECTED_END, "Unexpected end of input");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character to the redirect, if enabled, otherwise output, of a proc,
|
||||
* unless the output is masked.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param proc proc
|
||||
* @param c character to write
|
||||
* @return a freshly-created proc
|
||||
* @throws on write error
|
||||
*/
|
||||
static void _hb_proc_write_to_output(hbe_err_t *hbe_err, hb_proc_t* proc, hb_proc_char_t c) {
|
||||
if (!proc->mask) {
|
||||
hb_list_char_t redirect = proc->redirect;
|
||||
if (redirect != NULL) {
|
||||
hb_list_char_append(redirect, c);
|
||||
} else {
|
||||
HBE_CATCH_V((*proc->writer), proc->output, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* INSTANCE MANAGEMENT FUNCTIONS
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocates memory for a proc, and creates one with provided arguments.
|
||||
*
|
||||
* @param input input
|
||||
* @param reader reader
|
||||
* @param name name
|
||||
* @param output output
|
||||
* @param writer writer
|
||||
* @return a freshly-created proc
|
||||
*/
|
||||
hb_proc_t* hb_proc_create_blank(char *name) {
|
||||
hb_proc_t* proc = calloc(1, sizeof(hb_proc_t));
|
||||
|
||||
proc->name = name;
|
||||
|
||||
proc->input = NULL;
|
||||
proc->reader = NULL;
|
||||
proc->EOI = false;
|
||||
|
||||
proc->line = 1;
|
||||
proc->column = 0;
|
||||
proc->CR = false;
|
||||
|
||||
proc->output = NULL;
|
||||
proc->writer = NULL;
|
||||
proc->buffer = nh_list_ucp_create();
|
||||
proc->mask = false;
|
||||
proc->redirect = NULL;
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all memory associated with a proc.
|
||||
*
|
||||
* @param proc proc
|
||||
*/
|
||||
void hb_proc_destroy(hb_proc_t* proc) {
|
||||
nh_list_ucp_destroy(proc->buffer);
|
||||
free(proc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the output mask.
|
||||
* When the output mask is enabled, all writes are simply discarded and not actually written to output.
|
||||
*
|
||||
* @param proc proc
|
||||
* @param mask 1 to enable, 0 to disable
|
||||
* @return previous state
|
||||
*/
|
||||
int hb_proc_toggle_output_mask(hb_proc_t* proc, int mask) {
|
||||
int current = proc->mask;
|
||||
proc->mask = mask;
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the output redirect.
|
||||
* When the output redirect is enabled, all writes are written to a buffer instead of the output.
|
||||
*
|
||||
* @param proc proc
|
||||
* @param redirect buffer to redirect writes to, or NULL to disable
|
||||
*/
|
||||
void hb_proc_set_redirect(hb_proc_t* proc, hb_list_char_t redirect) {
|
||||
proc->redirect = redirect;
|
||||
}
|
||||
|
||||
void hb_proc_blank_set_input_fstreamin(hb_proc_t* proc, hbu_fstreamin_t fstreamin) {
|
||||
proc->input = fstreamin;
|
||||
proc->reader = (hb_proc_reader_cb_t) &hbu_fstreamin_read;
|
||||
}
|
||||
|
||||
// Wrapper function for hb_list_char_shift to make it compatible with hb_proc_reader_cb_t
|
||||
static hb_eod_char_t hb_proc_read_from_list_char_input(hbe_err_t *hbe_err, hb_list_char_t input) {
|
||||
(void) hbe_err;
|
||||
return hb_list_char_shift(input);
|
||||
}
|
||||
|
||||
void hb_proc_blank_set_input_buffer(hb_proc_t* proc, hb_list_char_t buf) {
|
||||
proc->input = buf;
|
||||
proc->reader = (hb_proc_reader_cb_t) &hb_proc_read_from_list_char_input;
|
||||
}
|
||||
|
||||
static void hb_proc_blank_set_output_fstreamout(hb_proc_t* proc, hbu_fstreamout_t fstreamout) {
|
||||
proc->output = fstreamout;
|
||||
proc->writer = (hb_proc_writer_cb_t) &hbu_fstreamout_write;
|
||||
}
|
||||
|
||||
// Wrapper function for hb_list_char_append to make it compatible with hb_proc_writer_cb_t
|
||||
void hb_proc_write_to_list_char_output(hbe_err_t *hbe_err, hb_list_char_t output, hb_proc_char_t c) {
|
||||
(void) hbe_err;
|
||||
hb_list_char_append(output, c);
|
||||
}
|
||||
|
||||
void hb_proc_blank_set_output_buffer(hb_proc_t* proc, hb_list_char_t buf) {
|
||||
proc->output = buf;
|
||||
proc->writer = (hb_proc_writer_cb_t) &hb_proc_write_to_list_char_output;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* Checks if the next sequence of characters is the null-terminated character array <code>match</code>.
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match
|
||||
* @return amount of characters matched, which should be equal to <code>strlen(match)</code>
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hb_proc_matches(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
size_t matchlen = strlen(match);
|
||||
|
||||
for (size_t i = 0; i < matchlen; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi_offset, pipe, i + 1);
|
||||
if (c == HB_EOD || c != match[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the next sequence of characters matches the null-terminated character array <code>match</code>
|
||||
* of lowercase characters case-insensitively.
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match case-insensitively
|
||||
* @return amount of characters matched, which should be equal to <code>strlen(match)</code>
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hb_proc_matches_i(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
size_t matchlen = strlen(match);
|
||||
|
||||
for (size_t i = 0; i < matchlen; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi_offset, pipe, i + 1);
|
||||
if (!(
|
||||
c != HB_EOD &&
|
||||
(
|
||||
c == match[i] ||
|
||||
(hb_rule_ucalpha_check(c) && (c + 32) == match[i])
|
||||
)
|
||||
)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the next sequence of characters is "\r", "\n", or "\r\n".
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return amount of characters matched
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hb_proc_matches_line_terminator(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
// Can't chain into HBE_CATCH(...) || HBE_CATCH(...) || ...
|
||||
// as HBE_CATCH needs auxiliary statement
|
||||
|
||||
// `\r\n` must be before `\r`
|
||||
size_t crlf = HBE_CATCH(hb_proc_matches, pipe, "\r\n");
|
||||
if (crlf) return crlf;
|
||||
|
||||
size_t cr = HBE_CATCH(hb_proc_matches, pipe, "\r");
|
||||
if (cr) return cr;
|
||||
|
||||
return HBE_CATCH(hb_proc_matches, pipe, "\n");
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Gets the next character.
|
||||
* If it's the end, {@link HB_EOD} is returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return character or {@link HB_EOD}
|
||||
* @throws on read error
|
||||
*/
|
||||
hb_eod_char_t hb_proc_peek_eoi(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
// OPTIMISATION: Read directly from buffer if available (no need to unshift later)
|
||||
if (pipe->buffer->length) {
|
||||
return hb_list_char_get(pipe->buffer, 0);
|
||||
}
|
||||
|
||||
hb_eod_char_t c = HBE_CATCH(_hb_proc_read_from_buffer_or_input, pipe);
|
||||
|
||||
if (c != HB_EOD) {
|
||||
hb_list_char_unshift(pipe->buffer, c);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next character.
|
||||
* Will cause an error if it's the end and there is no next character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_proc_char_t hb_proc_peek(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi, pipe);
|
||||
|
||||
HBE_CATCH(_hb_proc_assert_not_eoi, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <i>n</i>th character from current, where <i>n</i> is <code>offset</code>.
|
||||
* When <code>offset</code> is 1, the next character is returned (equivalent to {@link hb_proc_peek_eoi_offset}).
|
||||
* If <code>offset</code> is after the last character, {@link HB_EOD} is returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param offset position of character to get
|
||||
* @return character or {@link HB_EOD}
|
||||
* @throws on read error
|
||||
*/
|
||||
hb_eod_char_t hb_proc_peek_eoi_offset(hbe_err_t *hbe_err, hb_proc_t pipe, size_t offset) {
|
||||
HBE_CATCH(_hb_proc_ensure_buffer, pipe, offset);
|
||||
|
||||
hb_eod_char_t c = hb_list_char_get(pipe->buffer, offset - 1);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <i>n</i>th character from current, where <i>n</i> is <code>offset</code>.
|
||||
* When <code>offset</code> is 1, the next character is returned (equivalent to {@link hb_proc_peek_offset}).
|
||||
* An error will be caused if <code>offset</code> is after the last character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param offset position of character to get
|
||||
* @return character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_proc_char_t hb_proc_peek_offset(hbe_err_t *hbe_err, hb_proc_t pipe, size_t offset) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi_offset, pipe, offset);
|
||||
|
||||
HBE_CATCH(_hb_proc_assert_not_eoi, c);
|
||||
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* Requires the next character to be <code>c</code>.
|
||||
* The matched character is written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hb_proc_require(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_char_t c) {
|
||||
hb_proc_char_t n = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (c != n) {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%c` (0x%x), got `%c` (0x%x)", c, c, n, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to be <code>c</code>.
|
||||
* The matched character is skipped over and NOT written to output, and also returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @return matched character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_proc_char_t hb_proc_require_skip(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_char_t c) {
|
||||
hb_proc_char_t n = HBE_CATCH(hb_proc_skip, pipe);
|
||||
|
||||
if (c != n) {
|
||||
hb_proc_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%c` (0x%x), got `%c` (0x%x) at %s", c, c, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to satisfy the predicate <code>pred</code>.
|
||||
* The matched character is written to output.
|
||||
* If not matched, the error message will describe the expected output using <code>name</code>.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @param name what to output in the error message to describe the requirement
|
||||
* @return required character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_proc_char_t hb_proc_require_predicate(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_predicate_t pred, const char *name) {
|
||||
hb_proc_char_t n = HBE_CATCH(hb_proc_accept, pipe);
|
||||
|
||||
if (!(*pred)(n)) {
|
||||
hb_proc_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected %s, got `%c` (0x%x)", name, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to satisfy the predicate <code>pred</code>.
|
||||
* The matched character is skipped over and NOT written to output.
|
||||
* If not matched, the error message will describe the expected output using <code>name</code>.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @param name what to output in the error message to describe the requirement
|
||||
* @return required character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_proc_char_t hb_proc_require_skip_predicate(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_predicate_t pred, const char *name) {
|
||||
hb_proc_char_t n = HBE_CATCH(hb_proc_skip, pipe);
|
||||
|
||||
if (!(*pred)(n)) {
|
||||
hb_proc_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected %s, got `%c` (0x%x)", name, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next sequence of characters to be equal to <code>match</code>.
|
||||
* Matched characters are written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to require
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hb_proc_require_match(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
int matches = HBE_CATCH_V(hb_proc_accept_if_matches, pipe, match);
|
||||
if (!matches) {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%s`", match);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next sequence of characters to be equal to <code>match</code>.
|
||||
* Matched characters are skipped over and NOT written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to require
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hb_proc_require_skip_match(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
int matches = HBE_CATCH_V(hb_proc_skip_if_matches, pipe, match);
|
||||
if (!matches) {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%s`", match);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Skips over the next character.
|
||||
* Requires that the file has at least one character remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return skipped character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_proc_char_t hb_proc_skip(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(_hb_proc_read_from_buffer_or_input, pipe);
|
||||
|
||||
HBE_CATCH(_hb_proc_assert_not_eoi, c);
|
||||
|
||||
_hb_proc_update_pos(pipe, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the next <code>amount</code> characters.
|
||||
* Requires that the file has at least <code>amount</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param amount amount of characters to skip
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
void hb_proc_skip_amount(hbe_err_t *hbe_err, hb_proc_t pipe, size_t amount) {
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
HBE_CATCH_V(hb_proc_skip, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the following character if it is <code>c</code>.
|
||||
* Won't cause an error if the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to skip if next
|
||||
* @return 1 if skipped, 0 otherwise
|
||||
* @throws on read error
|
||||
*/
|
||||
int hb_proc_skip_if(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_char_t c) {
|
||||
hb_eod_char_t n = HBE_CATCH(hb_proc_peek_eoi, pipe);
|
||||
|
||||
if (n == HB_EOD || n != c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hb_proc_skip, pipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over every following character until one dissatisfies the predicate <code>pred</code>,
|
||||
* or the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return amount of characters skipped
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hb_proc_skip_while_predicate(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_predicate_t pred) {
|
||||
size_t count = 0;
|
||||
|
||||
while (1) {
|
||||
hb_eod_char_t c = HBE_CATCH(hb_proc_peek_eoi, pipe);
|
||||
|
||||
if (c == HB_EOD || !(*pred)(c)) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH(hb_proc_skip, pipe);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the next sequence of characters if they are <code>match</code>.
|
||||
* Requires that the file has at least the length of <code>match</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to match
|
||||
* @return 0 if not matched, 1 otherwise
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
int hb_proc_skip_if_matches(hbe_err_t *hbe_err, hb_proc_t pipe, const char *match) {
|
||||
size_t matchedlen = HBE_CATCH(hb_proc_matches, pipe, match);
|
||||
|
||||
int matched = matchedlen > 0;
|
||||
|
||||
if (matched) {
|
||||
HBE_CATCH(hb_proc_skip_amount, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* Writes a character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character
|
||||
* @throws on write error
|
||||
*/
|
||||
void hb_proc_write(hbe_err_t *hbe_err, hb_proc_t pipe, hb_proc_char_t c) {
|
||||
HBE_CATCH_V(_hb_proc_write_to_output, pipe, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a buffer.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param buffer buffer
|
||||
* @throws on write error
|
||||
*/
|
||||
void hb_proc_write_buffer(hbe_err_t *hbe_err, hb_proc_t pipe, hb_list_char_t buffer) {
|
||||
for (size_t i = 0; i < buffer->length; i++) {
|
||||
HBE_CATCH_V(_hb_proc_write_to_output, pipe, hb_list_char_get(buffer, i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character from its Unicode code point in UTF-8 encoding, which may be multiple bytes.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param code_point Unicode code point
|
||||
* @return amount of bytes written (0 if invalid code point)
|
||||
* @throws on write error
|
||||
*/
|
||||
// Logic copied from https://gist.github.com/MightyPork/52eda3e5677b4b03524e40c9f0ab1da5
|
||||
size_t hb_proc_write_unicode(hbe_err_t *hbe_err, hb_proc_t pipe, uint32_t code_point) {
|
||||
if (code_point <= 0x7F) {
|
||||
// Plain ASCII
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) code_point);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (code_point <= 0x07FF) {
|
||||
// 2-byte unicode
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 6) & 0x1F) | 0xC0));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (code_point <= 0xFFFF) {
|
||||
// 3-byte unicode
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 12) & 0x0F) | 0xE0));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 6) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (code_point <= 0x10FFFF) {
|
||||
// 4-byte unicode
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 18) & 0x07) | 0xF0));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 12) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 6) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hb_proc_write, pipe, (hb_proc_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "hb-data.h"
|
||||
#include "hb-config.h"
|
||||
|
||||
typedef int32_t hb_proc_char_t;
|
||||
|
||||
#define HB_PROC_CHAR_EOD -1 // End Of Data
|
||||
#define HB_PROC_CHAR_SIZE sizeof(hb_proc_char_t)
|
||||
|
||||
typedef bool hb_proc_predicate_t(hb_proc_char_t);
|
||||
|
||||
// Reader and writer callbacks. The last parameter is a pointer to an error
|
||||
// message. If the last parameter is not NULL, it is assumed an error occurred.
|
||||
// The error message WILL BE free'd by the callee automatically, so ensure the
|
||||
// message was created using malloc or strdup, and is not free'd by the function
|
||||
// or anything else afterwards.
|
||||
typedef hb_proc_char_t hb_proc_reader_t(void*, char**);
|
||||
typedef void hb_proc_writer_t(void*, hb_proc_char_t, char**);
|
||||
|
||||
#define HB_PROC_MEMORY_CREATE(name) \
|
||||
hb_proc_list_memory_instance_add_right_and_return( \
|
||||
config->memory_instances, name##_create()); \
|
||||
hb_proc_list_memory_destructor_add_right( \
|
||||
config->memory_destructors, \
|
||||
(hb_proc_memory_destructor_t*) &name##_destroy);
|
||||
|
||||
NH_LIST(hb_proc_list_memory_instance, void*, sizeof(void*), void*, NULL);
|
||||
void* hb_proc_list_memory_instance_add_right_and_return(
|
||||
hb_proc_list_memory_instance*, void*);
|
||||
|
||||
typedef void hb_proc_memory_destructor_t(void*);
|
||||
NH_LIST(hb_proc_list_memory_destructor, hb_proc_memory_destructor_t*,
|
||||
sizeof(hb_proc_memory_destructor_t*), hb_proc_memory_destructor_t*,
|
||||
NULL);
|
||||
|
||||
#define HB_PROC_ERROR_MESSAGE_SIZE 1024
|
||||
typedef struct {
|
||||
hb_error_t code;
|
||||
char* message;
|
||||
} hb_proc_result_t;
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
jmp_buf start;
|
||||
|
||||
hb_proc_list_memory_instance* memory_instances;
|
||||
hb_proc_list_memory_destructor* memory_destructors;
|
||||
|
||||
void* input;
|
||||
hb_proc_reader_t* reader;
|
||||
bool EOI;
|
||||
|
||||
int line;
|
||||
int column;
|
||||
bool CR;
|
||||
|
||||
void* output;
|
||||
hb_proc_writer_t* writer;
|
||||
nh_list_ucp* buffer;
|
||||
bool mask;
|
||||
nh_list_ucp* redirect;
|
||||
|
||||
hb_config_t config;
|
||||
} hb_proc_t;
|
||||
|
||||
hb_proc_t* hb_proc_create_blank(char* name);
|
||||
void hb_proc_result_destroy(hb_proc_result_t* result);
|
||||
|
||||
hb_proc_result_t* hb_proc_start(hb_proc_t* proc);
|
||||
void _hb_proc_error(hb_proc_t* proc, hb_error_t code, char const* format, ...);
|
|
@ -1,83 +1,83 @@
|
|||
#include "./attrval.c"
|
||||
#include "../entity/entity.c"
|
||||
|
||||
hbs_attr_val_type_t hbs_quoteattrval(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, int collapse_and_trim_whitespace) {
|
||||
hbs_attr_val_type_t hbs_quoteattrval(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, int collapse_and_trim_whitespace) {
|
||||
hbs_attr_val_type_t rv = 0;
|
||||
int should_remove_attr_quotes = so->remove_attr_quotes;
|
||||
|
||||
hbu_list_char_t value = NULL;
|
||||
hb_list_char_t value = NULL;
|
||||
if (should_remove_attr_quotes) {
|
||||
value = hbu_list_char_create();
|
||||
hbu_pipe_set_output_redirect(pipe, value);
|
||||
value = hb_list_char_create();
|
||||
hb_proc_set_redirect(pipe, value);
|
||||
}
|
||||
|
||||
hb_char_t quote_char = HBE_CATCH_F(hbu_pipe_require_skip_predicate, pipe, &hbr_attrvalquote_check, "attribute value quote");
|
||||
hb_proc_char_t quote_char = HBE_CATCH_F(hb_proc_require_skip_predicate, pipe, &hb_rule_attrvalquote_check, "attribute value quote");
|
||||
if (!should_remove_attr_quotes) {
|
||||
// Not buffering, so directly output
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, quote_char);
|
||||
HBE_CATCH_F(hb_proc_write, pipe, quote_char);
|
||||
}
|
||||
|
||||
int whitespace = 0;
|
||||
if (collapse_and_trim_whitespace) {
|
||||
HBE_CATCH_F(hbu_pipe_skip_while_predicate, pipe, &hbr_whitespace_check);
|
||||
HBE_CATCH_F(hb_proc_skip_while_predicate, pipe, &hb_rule_whitespace_check);
|
||||
}
|
||||
|
||||
int not_empty = 0;
|
||||
int can_be_unquoted = 1;
|
||||
|
||||
while (1) {
|
||||
hb_char_t c = HBE_CATCH_F(hbu_pipe_peek, pipe);
|
||||
hb_proc_char_t c = HBE_CATCH_F(hb_proc_peek, pipe);
|
||||
if (c == quote_char) {
|
||||
break;
|
||||
}
|
||||
|
||||
not_empty = 1;
|
||||
can_be_unquoted = can_be_unquoted && hbr_unquotedattrval_check(c);
|
||||
can_be_unquoted = can_be_unquoted && hb_rule_unquotedattrval_check(c);
|
||||
|
||||
if (collapse_and_trim_whitespace && hbr_whitespace_check(c)) {
|
||||
if (collapse_and_trim_whitespace && hb_rule_whitespace_check(c)) {
|
||||
whitespace = 1;
|
||||
HBE_CATCH_F(hbu_pipe_skip, pipe);
|
||||
HBE_CATCH_F(hb_proc_skip, pipe);
|
||||
|
||||
} else {
|
||||
if (whitespace) {
|
||||
whitespace = 0;
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, ' ');
|
||||
HBE_CATCH_F(hb_proc_write, pipe, ' ');
|
||||
}
|
||||
|
||||
if (c == '&') {
|
||||
// Call hbs_entity even if not decoding entities, as it will validate the entity
|
||||
HBE_CATCH_F(hbs_entity, so, pipe);
|
||||
} else {
|
||||
HBE_CATCH_F(hbu_pipe_accept, pipe);
|
||||
HBE_CATCH_F(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
can_be_unquoted = not_empty && can_be_unquoted;
|
||||
|
||||
HBE_CATCH_F(hbu_pipe_require_skip, pipe, quote_char);
|
||||
HBE_CATCH_F(hb_proc_require_skip, pipe, quote_char);
|
||||
if (!should_remove_attr_quotes) {
|
||||
// Not buffering, so directly output
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, quote_char);
|
||||
HBE_CATCH_F(hb_proc_write, pipe, quote_char);
|
||||
HB_RETURN_F(HBS_ATTR_QUOTED);
|
||||
|
||||
} else {
|
||||
hbu_pipe_set_output_redirect(pipe, NULL);
|
||||
hb_proc_set_redirect(pipe, NULL);
|
||||
if (!can_be_unquoted) {
|
||||
// Wrap in braces as macro will add auxiliary statement
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, quote_char);
|
||||
HBE_CATCH_F(hb_proc_write, pipe, quote_char);
|
||||
}
|
||||
HBE_CATCH_F(hbu_pipe_write_buffer, pipe, value);
|
||||
HBE_CATCH_F(hb_proc_write_buffer, pipe, value);
|
||||
if (!can_be_unquoted) {
|
||||
// Wrap in braces as macro will add auxiliary statement
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, quote_char);
|
||||
HBE_CATCH_F(hb_proc_write, pipe, quote_char);
|
||||
}
|
||||
HB_RETURN_F(can_be_unquoted ? HBS_ATTR_UNQUOTED : HBS_ATTR_QUOTED);
|
||||
}
|
||||
|
||||
finally:
|
||||
if (value != NULL) {
|
||||
hbu_list_char_destroy(value);
|
||||
hb_list_char_destroy(value);
|
||||
value = NULL;
|
||||
}
|
||||
return rv;
|
|
@ -1,15 +1,15 @@
|
|||
#include "../entity/entity.c"
|
||||
|
||||
void hbs_unquoteattrval(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
||||
// Can't use hbu_pipe_require_predicate, as first char might be `&`,
|
||||
void hbs_unquoteattrval(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe) {
|
||||
// Can't use hb_proc_require_predicate, as first char might be `&`,
|
||||
// which needs to be processed by hbs_entity
|
||||
int at_least_one_char = 0;
|
||||
|
||||
hb_char_t c;
|
||||
hb_proc_char_t c;
|
||||
while (1) {
|
||||
c = HBE_CATCH_V(hbu_pipe_peek, pipe);
|
||||
c = HBE_CATCH_V(hb_proc_peek, pipe);
|
||||
|
||||
if (!hbr_unquotedattrval_check(c)) {
|
||||
if (!hb_rule_unquotedattrval_check(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,11 @@ void hbs_unquoteattrval(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t p
|
|||
if (c == '&') {
|
||||
HBE_CATCH_V(hbs_entity, so, pipe);
|
||||
} else {
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
if (!at_least_one_char) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected unquoted attribute value, got `%c` (0x%x)", c);
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected unquoted attribute value, got `%c` (0x%x)", c);
|
||||
}
|
||||
}
|
|
@ -2,39 +2,39 @@
|
|||
#include "./quoteattrval.c"
|
||||
#include "./unquoteattrval.c"
|
||||
|
||||
hbs_attr_val_type_t hbs_attr(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
||||
hbs_attr_val_type_t hbs_attr(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe) {
|
||||
hbs_attr_val_type_t rv = 0;
|
||||
hbu_list_char_t name = hbu_list_char_create();
|
||||
hb_list_char_t name = hb_list_char_create();
|
||||
|
||||
while (1) {
|
||||
// Char matched by $attrname required at least once
|
||||
hb_char_t c = HBE_CATCH_F(hbu_pipe_require_predicate, pipe, &hbr_attrname_check, "attribute name");
|
||||
hb_proc_char_t c = HBE_CATCH_F(hb_proc_require_predicate, pipe, &hb_rule_attrname_check, "attribute name");
|
||||
|
||||
if (hbr_ucalpha_check(c)) {
|
||||
if (hb_rule_ucalpha_check(c)) {
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_UCASE_ATTR)) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_UCASE_ATTR, "Uppercase letter in attribute name");
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_UCASE_ATTR, "Uppercase letter in attribute name");
|
||||
}
|
||||
// Lowercase to normalise when checking against rules and closing tag
|
||||
hbu_list_char_append(name, c + 32);
|
||||
hb_list_char_append(name, c + 32);
|
||||
} else {
|
||||
hbu_list_char_append(name, c);
|
||||
hb_list_char_append(name, c);
|
||||
}
|
||||
|
||||
// Don't use hbu_pipe_accept_while_predicate as advanced checks might be needed
|
||||
hb_char_t n = HBE_CATCH_F(hbu_pipe_peek, pipe);
|
||||
// Don't use hb_proc_accept_while_predicate as advanced checks might be needed
|
||||
hb_proc_char_t n = HBE_CATCH_F(hb_proc_peek, pipe);
|
||||
|
||||
if (!hbr_attrname_check(n)) {
|
||||
if (!hb_rule_attrname_check(n)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int collapse_and_trim_whitespace = hbu_list_char_compare_lit(name, "class") == 0 &&
|
||||
int collapse_and_trim_whitespace = hb_list_char_compare_lit(name, "class") == 0 &&
|
||||
so->trim_class_attr;
|
||||
|
||||
int has_value = HBE_CATCH_F(hbu_pipe_accept_if, pipe, '=');
|
||||
int has_value = HBE_CATCH_F(hb_proc_accept_if, pipe, '=');
|
||||
if (has_value) {
|
||||
hb_char_t next = HBE_CATCH_F(hbu_pipe_peek, pipe);
|
||||
if (hbr_attrvalquote_check(next)) {
|
||||
hb_proc_char_t next = HBE_CATCH_F(hb_proc_peek, pipe);
|
||||
if (hb_rule_attrvalquote_check(next)) {
|
||||
// Quoted attribute value
|
||||
hbs_attr_val_type_t type = HBE_CATCH_F(hbs_quoteattrval, so, pipe, collapse_and_trim_whitespace);
|
||||
// Don't inline as HBE_CATCH_F adds auxiliary statements
|
||||
|
@ -42,7 +42,7 @@ hbs_attr_val_type_t hbs_attr(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pip
|
|||
}
|
||||
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_UNQUOTED_ATTR)) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_UNQUOTED_ATTR, "Unquoted attribute value");
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_UNQUOTED_ATTR, "Unquoted attribute value");
|
||||
}
|
||||
// Unquoted attribute value
|
||||
HBE_CATCH_F(hbs_unquoteattrval, so, pipe);
|
||||
|
@ -50,7 +50,7 @@ hbs_attr_val_type_t hbs_attr(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pip
|
|||
}
|
||||
|
||||
finally:
|
||||
hbu_list_char_destroy(name);
|
||||
hb_list_char_destroy(name);
|
||||
name = NULL;
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
void hbs_bang(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "<!");
|
||||
|
||||
while (1) {
|
||||
hb_proc_char_t next = HBE_CATCH_V(hb_proc_peek, pipe);
|
||||
if (next == '>') {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
void hbs_comment(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe) {
|
||||
hb_proc_toggle_output_mask(pipe, so->remove_comments);
|
||||
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "<!--");
|
||||
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hb_proc_accept_if_matches, pipe, "-->");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
|
||||
hb_proc_toggle_output_mask(pipe, 0);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// Declare first before tag.c, as tag.c depends on it
|
||||
void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb_char_t *parent);
|
||||
void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, hb_proc_char_t *parent);
|
||||
|
||||
#include "../tag/tag.c"
|
||||
#include "../bang/bang.c"
|
||||
|
@ -19,20 +19,20 @@ static int _hbs_content_state_is_comment_bang_or_opening_tag(int state) {
|
|||
state == HBS_CONTENT_STATE_OPENING_TAG;
|
||||
}
|
||||
|
||||
static int _hbs_content_get_next_state(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_eod_char_t c) {
|
||||
int end_tag = HBE_CATCH(hbu_pipe_matches, pipe, "</");
|
||||
static int _hbs_content_get_next_state(hbe_err_t *hbe_err, hb_proc_t pipe, hb_eod_char_t c) {
|
||||
int end_tag = HBE_CATCH(hb_proc_matches, pipe, "</");
|
||||
if (c == HB_EOD || end_tag) {
|
||||
// End of content
|
||||
return HBS_CONTENT_STATE_END;
|
||||
}
|
||||
|
||||
int comment = HBE_CATCH(hbu_pipe_matches, pipe, "<!--");
|
||||
int comment = HBE_CATCH(hb_proc_matches, pipe, "<!--");
|
||||
if (comment) {
|
||||
// Comment
|
||||
return HBS_CONTENT_STATE_COMMENT;
|
||||
}
|
||||
|
||||
int bang = HBE_CATCH(hbu_pipe_matches, pipe, "<!");
|
||||
int bang = HBE_CATCH(hb_proc_matches, pipe, "<!");
|
||||
if (bang) {
|
||||
// Bang
|
||||
// NOTE: Check after comment
|
||||
|
@ -57,7 +57,7 @@ static int _hbs_content_get_next_state(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_e
|
|||
}
|
||||
|
||||
// $parent can be NULL for top-level content
|
||||
void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb_char_t *parent) {
|
||||
void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, hb_proc_char_t *parent) {
|
||||
int is_first_char = 1;
|
||||
// Set to 1 when $whitespace is instantiated when $is_first_char is 1
|
||||
int whitespace_buffer_started_at_beginning = 0;
|
||||
|
@ -71,21 +71,21 @@ void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb
|
|||
int should_trim_whitespace = !hbu_streamoptions_in_tags_list(so->ex_trim_whitespace, parent);
|
||||
|
||||
int should_buffer_whitespace = should_collapse_whitespace || should_destroy_whole_whitespace || should_trim_whitespace;
|
||||
hbu_list_char_t whitespace = NULL;
|
||||
hb_list_char_t whitespace = NULL;
|
||||
|
||||
while (1) {
|
||||
hb_eod_char_t c = HBE_CATCH_F(hbu_pipe_peek_eoi, pipe);
|
||||
hb_eod_char_t c = HBE_CATCH_F(hb_proc_peek_eoi, pipe);
|
||||
int next_state = HBE_CATCH_F(_hbs_content_get_next_state, pipe, c);
|
||||
|
||||
if (next_state == HBS_CONTENT_STATE_TEXT && hbr_whitespace_check(c) && should_buffer_whitespace) {
|
||||
if (next_state == HBS_CONTENT_STATE_TEXT && hb_rule_whitespace_check(c) && should_buffer_whitespace) {
|
||||
// Next character is whitespace and whitespace should be buffered
|
||||
if (whitespace == NULL) {
|
||||
whitespace = hbu_list_char_create();
|
||||
whitespace = hb_list_char_create();
|
||||
whitespace_buffer_started_at_beginning = is_first_char;
|
||||
whitespace_buffer_started_after_right_chevron = returned_from_comment_bang_or_tag;
|
||||
}
|
||||
hbu_list_char_append(whitespace, c);
|
||||
HBE_CATCH_F(hbu_pipe_skip, pipe);
|
||||
hb_list_char_append(whitespace, c);
|
||||
HBE_CATCH_F(hb_proc_skip, pipe);
|
||||
|
||||
} else {
|
||||
if (whitespace != NULL) {
|
||||
|
@ -101,17 +101,17 @@ void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb
|
|||
// Do nothing
|
||||
|
||||
} else if (should_collapse_whitespace) {
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, ' ');
|
||||
HBE_CATCH_F(hb_proc_write, pipe, ' ');
|
||||
}
|
||||
|
||||
hbu_list_char_destroy(whitespace);
|
||||
hb_list_char_destroy(whitespace);
|
||||
whitespace = NULL;
|
||||
whitespace_buffer_started_at_beginning = 0;
|
||||
}
|
||||
|
||||
switch (next_state) {
|
||||
case HBS_CONTENT_STATE_TEXT:
|
||||
HBE_CATCH_F(hbu_pipe_accept, pipe);
|
||||
HBE_CATCH_F(hb_proc_accept, pipe);
|
||||
break;
|
||||
|
||||
case HBS_CONTENT_STATE_COMMENT:
|
||||
|
@ -145,7 +145,7 @@ void hbs_content(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb
|
|||
|
||||
finally:
|
||||
if (whitespace != NULL) {
|
||||
hbu_list_char_destroy(whitespace);
|
||||
hb_list_char_destroy(whitespace);
|
||||
whitespace = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
static void _hbs_script_slcomment(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "//");
|
||||
|
||||
// Comment can end at closing </script>
|
||||
// NOTE: Closing tag must not contain whitespace
|
||||
while (1) {
|
||||
int line_term = HBE_CATCH_V(hb_proc_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
break;
|
||||
}
|
||||
|
||||
int end_tag = HBE_CATCH_V(hb_proc_matches_i, pipe, "</script>");
|
||||
if (end_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_mlcomment(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "/*");
|
||||
|
||||
// Comment can end at closing </script>
|
||||
// NOTE: Closing tag must not contain whitespace
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hb_proc_accept_if_matches, pipe, "*/");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int end_tag = HBE_CATCH_V(hb_proc_matches_i, pipe, "</script>");
|
||||
if (end_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_string(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
hb_proc_char_t delim = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (delim != '"' && delim != '\'') {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected JavaScript string delimiter");
|
||||
}
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_proc_char_t c = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == delim && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
int line_term = HBE_CATCH_V(hb_proc_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
if (!escaping) {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Unterminated JavaScript string");
|
||||
}
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_template(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "`");
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_proc_char_t c = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '`' && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hbs_script(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hb_proc_matches, pipe, "</");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int sl_comment = HBE_CATCH_V(hb_proc_matches, pipe, "//");
|
||||
if (sl_comment) {
|
||||
HBE_CATCH_V(_hbs_script_slcomment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
int ml_comment = HBE_CATCH_V(hb_proc_matches, pipe, "/*");
|
||||
if (ml_comment) {
|
||||
HBE_CATCH_V(_hbs_script_mlcomment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_proc_char_t next = HBE_CATCH_V(hb_proc_peek, pipe);
|
||||
if (next == '"' || next == '\'') {
|
||||
HBE_CATCH_V(_hbs_script_string, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next == '`') {
|
||||
HBE_CATCH_V(_hbs_script_template, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
static void _hbs_style_comment(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
HBE_CATCH_V(hb_proc_require_match, pipe, "/*");
|
||||
|
||||
// Unlike script tags, style comments do NOT end at closing tag
|
||||
while (1) {
|
||||
int is_end = HBE_CATCH_V(hb_proc_accept_if_matches, pipe, "*/");
|
||||
if (is_end) {
|
||||
break;
|
||||
}
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_style_string(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
hb_proc_char_t delim = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (delim != '"' && delim != '\'') {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected CSS string delimiter");
|
||||
}
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_proc_char_t c = HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == delim && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
int line_term = HBE_CATCH_V(hb_proc_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
if (!escaping) {
|
||||
hb_proc_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Unterminated CSS string");
|
||||
}
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hbs_style(hbe_err_t *hbe_err, hb_proc_t pipe) {
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hb_proc_matches, pipe, "</");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int is_comment = HBE_CATCH_V(hb_proc_matches, pipe, "/*");
|
||||
if (is_comment) {
|
||||
HBE_CATCH_V(_hbs_style_comment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_proc_char_t next = HBE_CATCH_V(hb_proc_peek, pipe);
|
||||
if (next == '"' || next == '\'') {
|
||||
HBE_CATCH_V(_hbs_style_string, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hb_proc_accept, pipe);
|
||||
}
|
||||
}
|
|
@ -11,54 +11,54 @@ static void _hbs_entity_interr_unknown_entity(hbe_err_t *hbe_err, int type) {
|
|||
HBE_THROW_V(HBE_INTERR_UNKNOWN_ENTITY_TYPE, "INTERR %d is not a known entity type", type);
|
||||
}
|
||||
|
||||
static void _hbs_entity_write_literal(hbe_err_t *hbe_err, hbu_pipe_t pipe, int type, hbu_list_char_t entity_raw, int consumed_semicolon) {
|
||||
HBE_CATCH_V(hbu_pipe_write, pipe, '&');
|
||||
static void _hbs_entity_write_literal(hbe_err_t *hbe_err, hb_proc_t pipe, int type, hb_list_char_t entity_raw, int consumed_semicolon) {
|
||||
HBE_CATCH_V(hb_proc_write, pipe, '&');
|
||||
if (type == HBS_ENTITY_TYPE_HEXADECIMAL || type == HBS_ENTITY_TYPE_DECIMAL) {
|
||||
HBE_CATCH_V(hbu_pipe_write, pipe, '#');
|
||||
HBE_CATCH_V(hb_proc_write, pipe, '#');
|
||||
if (type == HBS_ENTITY_TYPE_HEXADECIMAL) {
|
||||
HBE_CATCH_V(hbu_pipe_write, pipe, 'x');
|
||||
HBE_CATCH_V(hb_proc_write, pipe, 'x');
|
||||
}
|
||||
}
|
||||
|
||||
if (entity_raw != NULL) {
|
||||
HBE_CATCH_V(hbu_pipe_write_buffer, pipe, entity_raw);
|
||||
HBE_CATCH_V(hb_proc_write_buffer, pipe, entity_raw);
|
||||
}
|
||||
|
||||
if (consumed_semicolon) {
|
||||
HBE_CATCH_V(hbu_pipe_write, pipe, ';');
|
||||
HBE_CATCH_V(hb_proc_write, pipe, ';');
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_entity_syntax_error(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, int type, hbu_list_char_t entity_raw, int consumed_semicolon, hbe_errcode_t errcode, const char *reason) {
|
||||
static void _hbs_entity_syntax_error(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, int type, hb_list_char_t entity_raw, int consumed_semicolon, hb_error_t errcode, const char *reason) {
|
||||
if (hbu_streamoptions_supressed_error(so, errcode)) {
|
||||
HBE_CATCH_V(_hbs_entity_write_literal, pipe, type, entity_raw, consumed_semicolon);
|
||||
return;
|
||||
}
|
||||
|
||||
HBU_PIPE_THROW_V(pipe, errcode, reason);
|
||||
hb_proc_THROW_V(pipe, errcode, reason);
|
||||
}
|
||||
|
||||
// NOTE: Return 0 if syntax error but suppressed
|
||||
static int _hbs_entity_process_prefix(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_streamoptions_t so) {
|
||||
hb_char_t c = HBE_CATCH(hbu_pipe_peek, pipe);
|
||||
static int _hbs_entity_process_prefix(hbe_err_t *hbe_err, hb_proc_t pipe, hbu_streamoptions_t so) {
|
||||
hb_proc_char_t c = HBE_CATCH(hb_proc_peek, pipe);
|
||||
|
||||
if (hbr_lcalpha_check(c) || hbr_ucalpha_check(c)) {
|
||||
if (hb_rule_lcalpha_check(c) || hb_rule_ucalpha_check(c)) {
|
||||
// Name-based entity
|
||||
return HBS_ENTITY_TYPE_NAME;
|
||||
}
|
||||
|
||||
hb_eod_char_t c2 = HBE_CATCH(hbu_pipe_peek_eoi_offset, pipe, 2);
|
||||
hb_eod_char_t c2 = HBE_CATCH(hb_proc_peek_eoi_offset, pipe, 2);
|
||||
|
||||
if (c == '#' && c2 == 'x') {
|
||||
// Hexadecimal-based entity
|
||||
// NOTE: Check before decimal-based
|
||||
HBE_CATCH(hbu_pipe_skip_amount, pipe, 2);
|
||||
HBE_CATCH(hb_proc_skip_amount, pipe, 2);
|
||||
return HBS_ENTITY_TYPE_HEXADECIMAL;
|
||||
}
|
||||
|
||||
if (c == '#') {
|
||||
// Decimal-based entity
|
||||
HBE_CATCH(hbu_pipe_skip, pipe);
|
||||
HBE_CATCH(hb_proc_skip, pipe);
|
||||
return HBS_ENTITY_TYPE_DECIMAL;
|
||||
}
|
||||
|
||||
|
@ -66,17 +66,17 @@ static int _hbs_entity_process_prefix(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_s
|
|||
HBE_PASS(_hbs_entity_syntax_error, so, pipe, -1, NULL, 0, HBE_PARSE_MALFORMED_ENTITY, "Invalid character after ampersand");
|
||||
}
|
||||
|
||||
void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
||||
hbu_list_char_t entity_raw = NULL;
|
||||
void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe) {
|
||||
hb_list_char_t entity_raw = NULL;
|
||||
|
||||
HBE_CATCH_F(hbu_pipe_require_skip, pipe, '&');
|
||||
HBE_CATCH_F(hb_proc_require_skip, pipe, '&');
|
||||
|
||||
// Quickly check and short circuit if BARE_AMPERSAND is suppressed
|
||||
// and next character is whitespace
|
||||
if (hbu_streamoptions_supressed_error(so, HBE_PARSE_BARE_AMPERSAND)) {
|
||||
hb_eod_char_t next = HBE_CATCH_F(hbu_pipe_peek_eoi, pipe);
|
||||
if (hbr_whitespace_check(next)) {
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, '&');
|
||||
hb_eod_char_t next = HBE_CATCH_F(hb_proc_peek_eoi, pipe);
|
||||
if (hb_rule_whitespace_check(next)) {
|
||||
HBE_CATCH_F(hb_proc_write, pipe, '&');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -87,11 +87,11 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
goto finally;
|
||||
}
|
||||
|
||||
entity_raw = hbu_list_char_create_size(0, HBS_ENTITY_MAX_ENTITY_LENGTH + 1);
|
||||
entity_raw = hb_list_char_create_size(0, HBS_ENTITY_MAX_ENTITY_LENGTH + 1);
|
||||
int under_max = 0;
|
||||
|
||||
for (int i = 0; i < HBS_ENTITY_MAX_ENTITY_LENGTH; i++) {
|
||||
hb_char_t e = HBE_CATCH_F(hbu_pipe_skip, pipe);
|
||||
hb_proc_char_t e = HBE_CATCH_F(hb_proc_skip, pipe);
|
||||
|
||||
if (e == ';') {
|
||||
under_max = 1;
|
||||
|
@ -102,15 +102,15 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
|
||||
switch (type) {
|
||||
case HBS_ENTITY_TYPE_NAME:
|
||||
well_formed = hbr_lcalpha_check(e) || hbr_ucalpha_check(e);
|
||||
well_formed = hb_rule_lcalpha_check(e) || hb_rule_ucalpha_check(e);
|
||||
break;
|
||||
|
||||
case HBS_ENTITY_TYPE_DECIMAL:
|
||||
well_formed = hbr_digit_check(e);
|
||||
well_formed = hb_rule_digit_check(e);
|
||||
break;
|
||||
|
||||
case HBS_ENTITY_TYPE_HEXADECIMAL:
|
||||
well_formed = hbr_hex_check(e);
|
||||
well_formed = hb_rule_hex_check(e);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -121,7 +121,7 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
HBE_PASS_F(_hbs_entity_syntax_error, so, pipe, type, entity_raw, 0, HBE_PARSE_MALFORMED_ENTITY, "Characters after ampersand don't form entity");
|
||||
}
|
||||
|
||||
hbu_list_char_append(entity_raw, e);
|
||||
hb_list_char_append(entity_raw, e);
|
||||
}
|
||||
|
||||
if (!under_max) {
|
||||
|
@ -130,14 +130,14 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
}
|
||||
|
||||
int valid = 1;
|
||||
hb_char_t *entity_raw_u = hbu_list_char_underlying(entity_raw);
|
||||
hb_proc_char_t *entity_raw_u = hb_list_char_underlying(entity_raw);
|
||||
uintmax_t code_point;
|
||||
|
||||
switch (type) {
|
||||
case HBS_ENTITY_TYPE_NAME:
|
||||
valid = hbr_entityrefs_check(entity_raw_u);
|
||||
valid = hb_rule_entity_references_check(entity_raw_u);
|
||||
if (valid && so->decode_entities) {
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, hbr_entityrefs_get(entity_raw_u));
|
||||
HBE_CATCH_F(hb_proc_write, pipe, hb_rule_entity_references_get(entity_raw_u));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -146,7 +146,7 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
code_point = strtoumax((char *) entity_raw_u, NULL, (type == HBS_ENTITY_TYPE_DECIMAL) ? 10 : 16);
|
||||
valid = errno == 0 && code_point <= 0x10FFFF;
|
||||
if (valid && so->decode_entities) {
|
||||
valid = HBE_CATCH_F(hbu_pipe_write_unicode, pipe, code_point);
|
||||
valid = HBE_CATCH_F(hb_proc_write_unicode, pipe, code_point);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -164,7 +164,7 @@ void hbs_entity(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
|||
|
||||
finally:
|
||||
if (entity_raw != NULL) {
|
||||
hbu_list_char_destroy(entity_raw);
|
||||
hb_list_char_destroy(entity_raw);
|
||||
entity_raw = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
hb_list_char_t hbs_tagname(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe) {
|
||||
hb_list_char_t name = hb_list_char_create();
|
||||
|
||||
while (1) {
|
||||
hb_proc_char_t c = HBE_CATCH_F(hb_proc_peek, pipe);
|
||||
|
||||
if (!hb_rule_tagname_check(c)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (hb_rule_ucalpha_check(c)) {
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_UCASE_TAG)) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_UCASE_TAG, "Uppercase character in tag");
|
||||
}
|
||||
// Lowercase to normalise when checking against rules and closing tag
|
||||
hb_list_char_append(name, c + 32);
|
||||
} else {
|
||||
hb_list_char_append(name, c);
|
||||
}
|
||||
|
||||
HBE_CATCH_F(hb_proc_accept, pipe);
|
||||
}
|
||||
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_NONSTANDARD_TAG) && !hb_rule_tags_check(hb_list_char_underlying(name))) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_NONSTANDARD_TAG, "Non-standard tag");
|
||||
}
|
||||
|
||||
finally:
|
||||
if (*hbe_err != NULL) {
|
||||
hb_list_char_destroy(name);
|
||||
name = NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// Declare first before content.c, as content.c depends on it
|
||||
void hbs_tag(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, hb_proc_char_t *parent);
|
||||
|
||||
#include "./tagname.c"
|
||||
#include "../attr/attr.c"
|
||||
#include "../content/script.c"
|
||||
#include "../content/style.c"
|
||||
#include "../content/html.c"
|
||||
|
||||
// $parent could be NULL
|
||||
void hbs_tag(hbe_err_t *hbe_err, hbu_streamoptions_t so, hb_proc_t pipe, hb_proc_char_t *parent) {
|
||||
hb_list_char_t opening_name = NULL;
|
||||
|
||||
int self_closing = 0;
|
||||
|
||||
HBE_CATCH_F(hb_proc_require, pipe, '<');
|
||||
opening_name = HBE_CATCH_F(hbs_tagname, so, pipe);
|
||||
|
||||
int last_attr_type = -1;
|
||||
|
||||
while (1) {
|
||||
// At the beginning of this loop, the last parsed unit was either the tag name
|
||||
// or an attribute (including its value, if it had one)
|
||||
size_t ws_accepted;
|
||||
if (so->remove_tag_whitespace) {
|
||||
ws_accepted = HBE_CATCH_F(hb_proc_skip_while_predicate, pipe, &hb_rule_whitespace_check);
|
||||
} else {
|
||||
ws_accepted = HBE_CATCH_F(hb_proc_accept_while_predicate, pipe, &hb_rule_whitespace_check);
|
||||
}
|
||||
|
||||
int end_of_tag = HBE_CATCH_F(hb_proc_accept_if, pipe, '>');
|
||||
if (end_of_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
self_closing = HBE_CATCH_F(hb_proc_accept_if_matches, pipe, "/>");
|
||||
if (self_closing) {
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_SELF_CLOSING_TAG)) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_SELF_CLOSING_TAG, "Self-closing tag");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// HBE_PARSE_NO_SPACE_BEFORE_ATTR is not suppressable as then there would be difficulty
|
||||
// in determining what is the end of a tag/attribute name/attribute value
|
||||
if (!ws_accepted) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_NO_SPACE_BEFORE_ATTR, "No whitespace before attribute");
|
||||
}
|
||||
|
||||
if (so->remove_tag_whitespace) {
|
||||
if (last_attr_type != HBS_ATTR_QUOTED) {
|
||||
HBE_CATCH_F(hb_proc_write, pipe, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
last_attr_type = HBE_CATCH_F(hbs_attr, so, pipe);
|
||||
}
|
||||
|
||||
hb_proc_char_t *tag_name = hb_list_char_underlying(opening_name);
|
||||
|
||||
// Non-standard tag checking is done in hbs_tagname
|
||||
if (parent != NULL && (
|
||||
!hb_rule_whitelistparents_allowed(tag_name, parent) ||
|
||||
!hb_rule_whitelistchildren_allowed(parent, tag_name) ||
|
||||
!hb_rule_blacklistparents_allowed(tag_name, parent) ||
|
||||
!hb_rule_blacklistchildren_allowed(parent, tag_name))) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_ILLEGAL_CHILD, "Tag can't be a child there");
|
||||
}
|
||||
|
||||
// Self-closing or void tag
|
||||
if (self_closing || hb_rule_voidtags_check(tag_name)) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
if (hb_list_char_compare_lit(opening_name, "script") == 0) {
|
||||
// Script tag
|
||||
HBE_CATCH_F(hbs_script, pipe);
|
||||
} else if (hb_list_char_compare_lit(opening_name, "style") == 0) {
|
||||
// Style tag
|
||||
HBE_CATCH_F(hbs_style, pipe);
|
||||
} else {
|
||||
// Content
|
||||
HBE_CATCH_F(hbs_content, so, pipe, tag_name);
|
||||
}
|
||||
|
||||
// Closing tag for non-void
|
||||
HBE_CATCH_F(hb_proc_require, pipe, '<');
|
||||
HBE_CATCH_F(hb_proc_require, pipe, '/');
|
||||
hb_list_char_t closing_name = HBE_CATCH_F(hbs_tagname, so, pipe);
|
||||
HBE_CATCH_F(hb_proc_require, pipe, '>');
|
||||
|
||||
if (!hb_list_char_equal(opening_name, closing_name)) {
|
||||
hb_proc_THROW_F(pipe, HBE_PARSE_UNCLOSED_TAG, "Tag not closed (expected `%s` closing tag, got `%s`)", tag_name, hb_list_char_underlying(closing_name));
|
||||
}
|
||||
|
||||
finally:
|
||||
if (opening_name) {
|
||||
hb_list_char_destroy(opening_name);
|
||||
opening_name = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
void hb_init(void) {
|
||||
// Set up rules
|
||||
hb_rule_init();
|
||||
// Set up config
|
||||
hb_config_init();
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
#include "./char/unquotedattrval.c"
|
||||
#include "./char/whitespace.c"
|
||||
|
||||
#include "./entity/entityrefs.c"
|
||||
#include "./entity/entity_references.c"
|
||||
|
||||
#include "./relation/blacklistchildren.c"
|
||||
#include "./relation/blacklistparents.c"
|
||||
|
@ -33,48 +33,48 @@
|
|||
#include "./tag/svgtags.c"
|
||||
#include "./tag/tags.c"
|
||||
|
||||
void hbr_init(void) {
|
||||
void hb_rule_init(void) {
|
||||
// Core
|
||||
hbr_c0_init();
|
||||
hbr_digit_init();
|
||||
hbr_hex_init();
|
||||
hbr_ucalpha_init();
|
||||
hbr_lcalpha_init();
|
||||
hbr_whitespace_init();
|
||||
hb_rule_c0_init();
|
||||
hb_rule_digit_init();
|
||||
hb_rule_hex_init();
|
||||
hb_rule_ucalpha_init();
|
||||
hb_rule_lcalpha_init();
|
||||
hb_rule_whitespace_init();
|
||||
|
||||
// Identifiers
|
||||
hbr_tagname_init();
|
||||
hbr_attrname_init();
|
||||
hb_rule_tagname_init();
|
||||
hb_rule_attrname_init();
|
||||
|
||||
// Values
|
||||
hbr_attrvalquote_init();
|
||||
hbr_unquotedattrval_init();
|
||||
hbr_entityrefs_init();
|
||||
hb_rule_attrvalquote_init();
|
||||
hb_rule_unquotedattrval_init();
|
||||
hb_rule_entity_references_init();
|
||||
|
||||
// Specification tag categories
|
||||
hbr_headingtags_init();
|
||||
hbr_mediatags_init();
|
||||
hbr_sectioningtags_init();
|
||||
hb_rule_headingtags_init();
|
||||
hb_rule_mediatags_init();
|
||||
hb_rule_sectioningtags_init();
|
||||
|
||||
hbr_voidtags_init();
|
||||
hbr_wsstags_init();
|
||||
hb_rule_voidtags_init();
|
||||
hb_rule_wsstags_init();
|
||||
|
||||
hbr_htmltags_init();
|
||||
hbr_svgtags_init();
|
||||
hbr_tags_init();
|
||||
hb_rule_htmltags_init();
|
||||
hb_rule_svgtags_init();
|
||||
hb_rule_tags_init();
|
||||
|
||||
// Hyperbuild tag categories
|
||||
hbr_contentfirsttags_init();
|
||||
hbr_contenttags_init();
|
||||
hbr_formattingtags_init();
|
||||
hbr_layouttags_init();
|
||||
hbr_specifictags_init();
|
||||
hb_rule_contentfirsttags_init();
|
||||
hb_rule_contenttags_init();
|
||||
hb_rule_formattingtags_init();
|
||||
hb_rule_layouttags_init();
|
||||
hb_rule_specifictags_init();
|
||||
|
||||
// Relations
|
||||
hbr_whitelistparents_init();
|
||||
hbr_blacklistparents_init();
|
||||
hbr_whitelistchildren_init();
|
||||
hbr_blacklistchildren_init();
|
||||
hb_rule_whitelistparents_init();
|
||||
hb_rule_blacklistparents_init();
|
||||
hb_rule_whitelistchildren_init();
|
||||
hb_rule_blacklistchildren_init();
|
||||
}
|
||||
|
||||
#endif // _HDR_HYPERBUILD_RULE_INIT
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#include "./c0.c"
|
||||
|
||||
static nh_set_int32_t hbr_attrname_blacklist;
|
||||
static nh_set_int32_t hb_rule_attrname_blacklist;
|
||||
|
||||
void hbr_attrname_init(void) {
|
||||
hbr_attrname_blacklist = nh_set_int32_create();
|
||||
hbr_c0_add_elems(hbr_attrname_blacklist);
|
||||
nh_set_int32_add(hbr_attrname_blacklist, ' ');
|
||||
nh_set_int32_add(hbr_attrname_blacklist, '"');
|
||||
nh_set_int32_add(hbr_attrname_blacklist, '\'');
|
||||
nh_set_int32_add(hbr_attrname_blacklist, '>');
|
||||
nh_set_int32_add(hbr_attrname_blacklist, '/');
|
||||
nh_set_int32_add(hbr_attrname_blacklist, '=');
|
||||
void hb_rule_attrname_init(void) {
|
||||
hb_rule_attrname_blacklist = nh_set_int32_create();
|
||||
hb_rule_c0_add_elems(hb_rule_attrname_blacklist);
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, ' ');
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, '"');
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, '\'');
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, '>');
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, '/');
|
||||
nh_set_int32_add(hb_rule_attrname_blacklist, '=');
|
||||
// NOTE: Unicode noncharacters not tested (https://html.spec.whatwg.org/multipage/syntax.html#syntax-attribute-name)
|
||||
}
|
||||
|
||||
int hbr_attrname_check(hb_char_t c) {
|
||||
return !nh_set_int32_has(hbr_attrname_blacklist, c);
|
||||
int hb_rule_attrname_check(hb_proc_char_t c) {
|
||||
return !nh_set_int32_has(hb_rule_attrname_blacklist, c);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "./c0.c"
|
||||
|
||||
static nh_set_int32_t hbr_attrvalquote_set;
|
||||
static nh_set_int32_t hb_rule_attrvalquote_set;
|
||||
|
||||
void hbr_attrvalquote_init(void) {
|
||||
hbr_attrvalquote_set = nh_set_int32_create();
|
||||
nh_set_int32_add(hbr_attrvalquote_set, '\'');
|
||||
nh_set_int32_add(hbr_attrvalquote_set, '"');
|
||||
void hb_rule_attrvalquote_init(void) {
|
||||
hb_rule_attrvalquote_set = nh_set_int32_create();
|
||||
nh_set_int32_add(hb_rule_attrvalquote_set, '\'');
|
||||
nh_set_int32_add(hb_rule_attrvalquote_set, '"');
|
||||
}
|
||||
|
||||
int hbr_attrvalquote_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_attrvalquote_set, c);
|
||||
int hb_rule_attrvalquote_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_attrvalquote_set, c);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
static nh_set_int32_t hbr_c0_set;
|
||||
static nh_set_int32_t hb_rule_c0_set;
|
||||
|
||||
void hbr_c0_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_c0_add_elems(nh_set_int32_t set) {
|
||||
for (char c = 0x0; c <= 0x1F; c++) {
|
||||
nh_set_int32_add(set, c);
|
||||
}
|
||||
}
|
||||
|
||||
void hbr_c0_init(void) {
|
||||
hbr_c0_set = nh_set_int32_create();
|
||||
hbr_c0_add_elems(hbr_c0_set);
|
||||
void hb_rule_c0_init(void) {
|
||||
hb_rule_c0_set = nh_set_int32_create();
|
||||
hb_rule_c0_add_elems(hb_rule_c0_set);
|
||||
}
|
||||
|
||||
int hbr_c0_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_c0_set, c);
|
||||
int hb_rule_c0_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_c0_set, c);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
static nh_set_int32_t hbr_digit_set;
|
||||
static nh_set_int32_t hb_rule_digit_set;
|
||||
|
||||
void hbr_digit_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_digit_add_elems(nh_set_int32_t set) {
|
||||
for (char c = 0x30; c <= 0x39; c++) {
|
||||
nh_set_int32_add(set, c);
|
||||
}
|
||||
}
|
||||
|
||||
void hbr_digit_init(void) {
|
||||
hbr_digit_set = nh_set_int32_create();
|
||||
hbr_digit_add_elems(hbr_digit_set);
|
||||
void hb_rule_digit_init(void) {
|
||||
hb_rule_digit_set = nh_set_int32_create();
|
||||
hb_rule_digit_add_elems(hb_rule_digit_set);
|
||||
}
|
||||
|
||||
int hbr_digit_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_digit_set, c);
|
||||
int hb_rule_digit_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_digit_set, c);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_int32_t hbr_hex_set;
|
||||
static nh_set_int32_t hb_rule_hex_set;
|
||||
|
||||
void hbr_hex_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_hex_add_elems(nh_set_int32_t set) {
|
||||
for (char c = 0x30; c <= 0x39; c++) { // 0-9
|
||||
nh_set_int32_add(set, c);
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ void hbr_hex_add_elems(nh_set_int32_t set) {
|
|||
}
|
||||
}
|
||||
|
||||
void hbr_hex_init(void) {
|
||||
hbr_hex_set = nh_set_int32_create();
|
||||
hbr_hex_add_elems(hbr_hex_set);
|
||||
void hb_rule_hex_init(void) {
|
||||
hb_rule_hex_set = nh_set_int32_create();
|
||||
hb_rule_hex_add_elems(hb_rule_hex_set);
|
||||
}
|
||||
|
||||
int hbr_hex_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_hex_set, c);
|
||||
int hb_rule_hex_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_hex_set, c);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
static nh_set_int32_t hbr_lcalpha_set;
|
||||
static nh_set_int32_t hb_rule_lcalpha_set;
|
||||
|
||||
void hbr_lcalpha_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_lcalpha_add_elems(nh_set_int32_t set) {
|
||||
for (char c = 0x61; c <= 0x7A; c++) {
|
||||
nh_set_int32_add(set, c);
|
||||
}
|
||||
}
|
||||
|
||||
void hbr_lcalpha_init(void) {
|
||||
hbr_lcalpha_set = nh_set_int32_create();
|
||||
hbr_lcalpha_add_elems(hbr_lcalpha_set);
|
||||
void hb_rule_lcalpha_init(void) {
|
||||
hb_rule_lcalpha_set = nh_set_int32_create();
|
||||
hb_rule_lcalpha_add_elems(hb_rule_lcalpha_set);
|
||||
}
|
||||
|
||||
int hbr_lcalpha_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_lcalpha_set, c);
|
||||
int hb_rule_lcalpha_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_lcalpha_set, c);
|
||||
}
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
#include "./ucalpha.c"
|
||||
#include "./digit.c"
|
||||
|
||||
static nh_set_int32_t hbr_tagname_set;
|
||||
static nh_set_int32_t hb_rule_tagname_set;
|
||||
|
||||
void hbr_tagname_init(void) {
|
||||
hbr_tagname_set = nh_set_int32_create();
|
||||
hbr_lcalpha_add_elems(hbr_tagname_set);
|
||||
hbr_ucalpha_add_elems(hbr_tagname_set);
|
||||
hbr_digit_add_elems(hbr_tagname_set);
|
||||
nh_set_int32_add(hbr_tagname_set, ':');
|
||||
nh_set_int32_add(hbr_tagname_set, '-');
|
||||
void hb_rule_tagname_init(void) {
|
||||
hb_rule_tagname_set = nh_set_int32_create();
|
||||
hb_rule_lcalpha_add_elems(hb_rule_tagname_set);
|
||||
hb_rule_ucalpha_add_elems(hb_rule_tagname_set);
|
||||
hb_rule_digit_add_elems(hb_rule_tagname_set);
|
||||
nh_set_int32_add(hb_rule_tagname_set, ':');
|
||||
nh_set_int32_add(hb_rule_tagname_set, '-');
|
||||
}
|
||||
|
||||
int hbr_tagname_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_tagname_set, c);
|
||||
int hb_rule_tagname_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_tagname_set, c);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
static nh_set_int32_t hbr_ucalpha_set;
|
||||
static nh_set_int32_t hb_rule_ucalpha_set;
|
||||
|
||||
void hbr_ucalpha_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_ucalpha_add_elems(nh_set_int32_t set) {
|
||||
for (char c = 0x41; c <= 0x5A; c++) {
|
||||
nh_set_int32_add(set, c);
|
||||
}
|
||||
}
|
||||
|
||||
void hbr_ucalpha_init(void) {
|
||||
hbr_ucalpha_set = nh_set_int32_create();
|
||||
hbr_ucalpha_add_elems(hbr_ucalpha_set);
|
||||
void hb_rule_ucalpha_init(void) {
|
||||
hb_rule_ucalpha_set = nh_set_int32_create();
|
||||
hb_rule_ucalpha_add_elems(hb_rule_ucalpha_set);
|
||||
}
|
||||
|
||||
int hbr_ucalpha_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_ucalpha_set, c);
|
||||
int hb_rule_ucalpha_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_ucalpha_set, c);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
#include "./whitespace.c"
|
||||
|
||||
static nh_set_int32_t hbr_unquotedattrval_blacklist;
|
||||
static nh_set_int32_t hb_rule_unquotedattrval_blacklist;
|
||||
|
||||
void hbr_unquotedattrval_init(void) {
|
||||
hbr_unquotedattrval_blacklist = nh_set_int32_create();
|
||||
hbr_whitespace_add_elems(hbr_unquotedattrval_blacklist);
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '"');
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '\'');
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '`');
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '=');
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '<');
|
||||
nh_set_int32_add(hbr_unquotedattrval_blacklist, '>');
|
||||
void hb_rule_unquotedattrval_init(void) {
|
||||
hb_rule_unquotedattrval_blacklist = nh_set_int32_create();
|
||||
hb_rule_whitespace_add_elems(hb_rule_unquotedattrval_blacklist);
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '"');
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '\'');
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '`');
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '=');
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '<');
|
||||
nh_set_int32_add(hb_rule_unquotedattrval_blacklist, '>');
|
||||
}
|
||||
|
||||
int hbr_unquotedattrval_check(hb_char_t c) {
|
||||
return !nh_set_int32_has(hbr_unquotedattrval_blacklist, c);
|
||||
int hb_rule_unquotedattrval_check(hb_proc_char_t c) {
|
||||
return !nh_set_int32_has(hb_rule_unquotedattrval_blacklist, c);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_int32_t hbr_whitespace_set;
|
||||
static nh_set_int32_t hb_rule_whitespace_set;
|
||||
|
||||
void hbr_whitespace_add_elems(nh_set_int32_t set) {
|
||||
void hb_rule_whitespace_add_elems(nh_set_int32_t set) {
|
||||
nh_set_int32_add(set, 0x09); // TAB
|
||||
nh_set_int32_add(set, 0x0A); // LF
|
||||
nh_set_int32_add(set, 0x0C); // FF
|
||||
|
@ -8,11 +8,11 @@ void hbr_whitespace_add_elems(nh_set_int32_t set) {
|
|||
nh_set_int32_add(set, 0x20); // SPACE
|
||||
}
|
||||
|
||||
void hbr_whitespace_init(void) {
|
||||
hbr_whitespace_set = nh_set_int32_create();
|
||||
hbr_whitespace_add_elems(hbr_whitespace_set);
|
||||
void hb_rule_whitespace_init(void) {
|
||||
hb_rule_whitespace_set = nh_set_int32_create();
|
||||
hb_rule_whitespace_add_elems(hb_rule_whitespace_set);
|
||||
}
|
||||
|
||||
int hbr_whitespace_check(hb_char_t c) {
|
||||
return nh_set_int32_has(hbr_whitespace_set, c);
|
||||
int hb_rule_whitespace_check(hb_proc_char_t c) {
|
||||
return nh_set_int32_has(hb_rule_whitespace_set, c);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,80 +2,80 @@
|
|||
#include "../tag/mediatags.c"
|
||||
#include "../tag/sectioningtags.c"
|
||||
|
||||
static nh_map_str_strset_t hbr_blacklistchildren_map;
|
||||
static nh_map_str_strset_t hb_rule_blacklistchildren_map;
|
||||
|
||||
void hbr_blacklistchildren_init(void) {
|
||||
hbr_blacklistchildren_map = nh_map_str_strset_create();
|
||||
void hb_rule_blacklistchildren_init(void) {
|
||||
hb_rule_blacklistchildren_map = nh_map_str_strset_create();
|
||||
|
||||
// <address>
|
||||
nh_set_str_t address = nh_set_str_create();
|
||||
hbr_headingtags_add_elems(address);
|
||||
hbr_sectioningtags_add_elems(address);
|
||||
hb_rule_headingtags_add_elems(address);
|
||||
hb_rule_sectioningtags_add_elems(address);
|
||||
nh_set_str_add(address, "address");
|
||||
nh_set_str_add(address, "header");
|
||||
nh_set_str_add(address, "footer");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "address", address);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "address", address);
|
||||
|
||||
// <audio>
|
||||
nh_set_str_t audio = nh_set_str_create();
|
||||
hbr_mediatags_add_elems(audio);
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "audio", audio);
|
||||
hb_rule_mediatags_add_elems(audio);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "audio", audio);
|
||||
|
||||
// <dfn>
|
||||
nh_set_str_t dfn = nh_set_str_create();
|
||||
nh_set_str_add(dfn, "dfn");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "dfn", dfn);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "dfn", dfn);
|
||||
|
||||
// <dt>
|
||||
nh_set_str_t dt = nh_set_str_create();
|
||||
hbr_headingtags_add_elems(dt);
|
||||
hbr_sectioningtags_add_elems(dt);
|
||||
hb_rule_headingtags_add_elems(dt);
|
||||
hb_rule_sectioningtags_add_elems(dt);
|
||||
nh_set_str_add(dt, "header");
|
||||
nh_set_str_add(dt, "footer");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "dt", dt);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "dt", dt);
|
||||
|
||||
// <footer>
|
||||
nh_set_str_t footer = nh_set_str_create();
|
||||
nh_set_str_add(footer, "header");
|
||||
nh_set_str_add(footer, "footer");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "footer", footer);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "footer", footer);
|
||||
|
||||
// <form>
|
||||
nh_set_str_t form = nh_set_str_create();
|
||||
nh_set_str_add(form, "form");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "form", form);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "form", form);
|
||||
|
||||
// <header>
|
||||
nh_set_str_t header = nh_set_str_create();
|
||||
nh_set_str_add(header, "header");
|
||||
nh_set_str_add(header, "footer");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "header", header);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "header", header);
|
||||
|
||||
// <label>
|
||||
nh_set_str_t label = nh_set_str_create();
|
||||
nh_set_str_add(label, "label");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "label", label);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "label", label);
|
||||
|
||||
// <progress>
|
||||
nh_set_str_t progress = nh_set_str_create();
|
||||
nh_set_str_add(progress, "progress");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "progress", progress);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "progress", progress);
|
||||
|
||||
// <th>
|
||||
nh_set_str_t th = nh_set_str_create();
|
||||
hbr_headingtags_add_elems(th);
|
||||
hbr_sectioningtags_add_elems(th);
|
||||
hb_rule_headingtags_add_elems(th);
|
||||
hb_rule_sectioningtags_add_elems(th);
|
||||
nh_set_str_add(th, "header");
|
||||
nh_set_str_add(th, "footer");
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "th", th);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "th", th);
|
||||
|
||||
// <video>
|
||||
nh_set_str_t video = nh_set_str_create();
|
||||
hbr_mediatags_add_elems(video);
|
||||
nh_map_str_strset_set(hbr_blacklistchildren_map, "video", video);
|
||||
hb_rule_mediatags_add_elems(video);
|
||||
nh_map_str_strset_set(hb_rule_blacklistchildren_map, "video", video);
|
||||
}
|
||||
|
||||
int hbr_blacklistchildren_allowed(hb_char_t *parent, hb_char_t *child) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hbr_blacklistchildren_map, (char *) parent, NULL);
|
||||
int hb_rule_blacklistchildren_allowed(hb_proc_char_t *parent, hb_proc_char_t *child) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hb_rule_blacklistchildren_map, (char *) parent, NULL);
|
||||
return set == NULL || !nh_set_str_has(set, (char *) child);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
static nh_map_str_strset_t hbr_blacklistparents_map;
|
||||
static nh_map_str_strset_t hb_rule_blacklistparents_map;
|
||||
|
||||
void hbr_blacklistparents_init(void) {
|
||||
hbr_blacklistparents_map = nh_map_str_strset_create();
|
||||
void hb_rule_blacklistparents_init(void) {
|
||||
hb_rule_blacklistparents_map = nh_map_str_strset_create();
|
||||
}
|
||||
|
||||
int hbr_blacklistparents_allowed(hb_char_t *child, hb_char_t *parent) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hbr_blacklistparents_map, (char *) child, NULL);
|
||||
int hb_rule_blacklistparents_allowed(hb_proc_char_t *child, hb_proc_char_t *parent) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hb_rule_blacklistparents_map, (char *) child, NULL);
|
||||
return set == NULL || !nh_set_str_has(set, (char *) parent);
|
||||
}
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
#include "../tag/headingtags.c"
|
||||
|
||||
static nh_map_str_strset_t hbr_whitelistchildren_map;
|
||||
static nh_map_str_strset_t hb_rule_whitelistchildren_map;
|
||||
|
||||
void hbr_whitelistchildren_init(void) {
|
||||
hbr_whitelistchildren_map = nh_map_str_strset_create();
|
||||
void hb_rule_whitelistchildren_init(void) {
|
||||
hb_rule_whitelistchildren_map = nh_map_str_strset_create();
|
||||
|
||||
// <colgroup>
|
||||
nh_set_str_t colgroup = nh_set_str_create();
|
||||
nh_set_str_add(colgroup, "col");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "colgroup", colgroup);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "colgroup", colgroup);
|
||||
|
||||
// <datalist>
|
||||
nh_set_str_t datalist = nh_set_str_create();
|
||||
nh_set_str_add(datalist, "option");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "datalist", datalist);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "datalist", datalist);
|
||||
|
||||
// <dl>
|
||||
nh_set_str_t dl = nh_set_str_create();
|
||||
nh_set_str_add(dl, "dt");
|
||||
nh_set_str_add(dl, "dd");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "dl", dl);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "dl", dl);
|
||||
|
||||
// <hgroup>
|
||||
nh_set_str_t hgroup = nh_set_str_create();
|
||||
hbr_headingtags_add_elems(hgroup);
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "hgroup", hgroup);
|
||||
hb_rule_headingtags_add_elems(hgroup);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "hgroup", hgroup);
|
||||
|
||||
// <ol>
|
||||
nh_set_str_t ol = nh_set_str_create();
|
||||
nh_set_str_add(ol, "li");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "ol", ol);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "ol", ol);
|
||||
|
||||
// <optgroup>
|
||||
nh_set_str_t optgroup = nh_set_str_create();
|
||||
nh_set_str_add(optgroup, "option");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "optgroup", optgroup);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "optgroup", optgroup);
|
||||
|
||||
// <picture>
|
||||
nh_set_str_t picture = nh_set_str_create();
|
||||
nh_set_str_add(picture, "source");
|
||||
nh_set_str_add(picture, "img");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "picture", picture);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "picture", picture);
|
||||
|
||||
// <select>
|
||||
nh_set_str_t select = nh_set_str_create();
|
||||
nh_set_str_add(select, "optgroup");
|
||||
nh_set_str_add(select, "option");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "select", select);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "select", select);
|
||||
|
||||
// <table>
|
||||
nh_set_str_t table = nh_set_str_create();
|
||||
|
@ -57,22 +57,22 @@ void hbr_whitelistchildren_init(void) {
|
|||
nh_set_str_add(table, "tbody");
|
||||
nh_set_str_add(table, "tfoot");
|
||||
nh_set_str_add(table, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "table", table);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "table", table);
|
||||
|
||||
// <tbody>
|
||||
nh_set_str_t tbody = nh_set_str_create();
|
||||
nh_set_str_add(tbody, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "tbody", tbody);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "tbody", tbody);
|
||||
|
||||
// <tfoot>
|
||||
nh_set_str_t tfoot = nh_set_str_create();
|
||||
nh_set_str_add(tfoot, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "tfoot", tfoot);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "tfoot", tfoot);
|
||||
|
||||
// <thead>
|
||||
nh_set_str_t thead = nh_set_str_create();
|
||||
nh_set_str_add(thead, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "thead", thead);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "thead", thead);
|
||||
|
||||
// <tr>
|
||||
nh_set_str_t tr = nh_set_str_create();
|
||||
|
@ -80,15 +80,15 @@ void hbr_whitelistchildren_init(void) {
|
|||
nh_set_str_add(tr, "th");
|
||||
nh_set_str_add(tr, "template");
|
||||
nh_set_str_add(tr, "script");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "tr", tr);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "tr", tr);
|
||||
|
||||
// <ul>
|
||||
nh_set_str_t ul = nh_set_str_create();
|
||||
nh_set_str_add(ul, "li");
|
||||
nh_map_str_strset_set(hbr_whitelistchildren_map, "ul", ul);
|
||||
nh_map_str_strset_set(hb_rule_whitelistchildren_map, "ul", ul);
|
||||
}
|
||||
|
||||
int hbr_whitelistchildren_allowed(hb_char_t *parent, hb_char_t *child) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hbr_whitelistchildren_map, (char *) parent, NULL);
|
||||
int hb_rule_whitelistchildren_allowed(hb_proc_char_t *parent, hb_proc_char_t *child) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hb_rule_whitelistchildren_map, (char *) parent, NULL);
|
||||
return set == NULL || nh_set_str_has(set, (char *) child);
|
||||
}
|
||||
|
|
|
@ -1,125 +1,125 @@
|
|||
#include "../tag/mediatags.c"
|
||||
|
||||
static nh_map_str_strset_t hbr_whitelistparents_map;
|
||||
static nh_map_str_strset_t hb_rule_whitelistparents_map;
|
||||
|
||||
void hbr_whitelistparents_init(void) {
|
||||
hbr_whitelistparents_map = nh_map_str_strset_create();
|
||||
void hb_rule_whitelistparents_init(void) {
|
||||
hb_rule_whitelistparents_map = nh_map_str_strset_create();
|
||||
|
||||
// <caption>
|
||||
nh_set_str_t caption = nh_set_str_create();
|
||||
nh_set_str_add(caption, "table");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "caption", caption);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "caption", caption);
|
||||
|
||||
// <col>
|
||||
nh_set_str_t col = nh_set_str_create();
|
||||
nh_set_str_add(col, "table");
|
||||
nh_set_str_add(col, "colgroup");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "col", col);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "col", col);
|
||||
|
||||
// <colgroup>
|
||||
nh_set_str_t colgroup = nh_set_str_create();
|
||||
nh_set_str_add(colgroup, "table");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "colgroup", colgroup);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "colgroup", colgroup);
|
||||
|
||||
// <dd>
|
||||
nh_set_str_t dd = nh_set_str_create();
|
||||
nh_set_str_add(dd, "dl");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "dd", dd);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "dd", dd);
|
||||
|
||||
// <dt>
|
||||
nh_set_str_t dt = nh_set_str_create();
|
||||
nh_set_str_add(dt, "dl");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "dt", dt);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "dt", dt);
|
||||
|
||||
// <figcaption>
|
||||
nh_set_str_t figcaption = nh_set_str_create();
|
||||
nh_set_str_add(figcaption, "figure");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "figcaption", figcaption);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "figcaption", figcaption);
|
||||
|
||||
// <legend>
|
||||
nh_set_str_t legend = nh_set_str_create();
|
||||
nh_set_str_add(legend, "fieldset");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "legend", legend);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "legend", legend);
|
||||
|
||||
// <li>
|
||||
nh_set_str_t li = nh_set_str_create();
|
||||
nh_set_str_add(li, "ul");
|
||||
nh_set_str_add(li, "ol");
|
||||
nh_set_str_add(li, "menu");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "li", li);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "li", li);
|
||||
|
||||
// <optgroup>
|
||||
nh_set_str_t optgroup = nh_set_str_create();
|
||||
nh_set_str_add(optgroup, "select");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "optgroup", optgroup);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "optgroup", optgroup);
|
||||
|
||||
// <option>
|
||||
nh_set_str_t option = nh_set_str_create();
|
||||
nh_set_str_add(option, "select");
|
||||
nh_set_str_add(option, "optgroup");
|
||||
nh_set_str_add(option, "datalist");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "option", option);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "option", option);
|
||||
|
||||
// <param>
|
||||
nh_set_str_t param = nh_set_str_create();
|
||||
nh_set_str_add(param, "object");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "param", param);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "param", param);
|
||||
|
||||
// <rp>
|
||||
nh_set_str_t rp = nh_set_str_create();
|
||||
nh_set_str_add(rp, "ruby");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "rp", rp);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "rp", rp);
|
||||
|
||||
// <rt>
|
||||
nh_set_str_t rt = nh_set_str_create();
|
||||
nh_set_str_add(rt, "ruby");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "rt", rt);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "rt", rt);
|
||||
|
||||
// <rtc>
|
||||
nh_set_str_t rtc = nh_set_str_create();
|
||||
nh_set_str_add(rtc, "ruby");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "rtc", rtc);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "rtc", rtc);
|
||||
|
||||
// <summary>
|
||||
nh_set_str_t summary = nh_set_str_create();
|
||||
nh_set_str_add(summary, "details");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "summary", summary);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "summary", summary);
|
||||
|
||||
// <source>
|
||||
nh_set_str_t source = nh_set_str_create();
|
||||
hbr_mediatags_add_elems(source);
|
||||
hb_rule_mediatags_add_elems(source);
|
||||
nh_set_str_add(source, "picture");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "source", source);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "source", source);
|
||||
|
||||
// <track>
|
||||
nh_set_str_t track = nh_set_str_create();
|
||||
hbr_mediatags_add_elems(track);
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "track", track);
|
||||
hb_rule_mediatags_add_elems(track);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "track", track);
|
||||
|
||||
// <tbody>
|
||||
nh_set_str_t tbody = nh_set_str_create();
|
||||
nh_set_str_add(tbody, "table");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "tbody", tbody);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "tbody", tbody);
|
||||
|
||||
// <td>
|
||||
nh_set_str_t td = nh_set_str_create();
|
||||
nh_set_str_add(td, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "td", td);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "td", td);
|
||||
|
||||
// <tfoot>
|
||||
nh_set_str_t tfoot = nh_set_str_create();
|
||||
nh_set_str_add(tfoot, "table");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "tfoot", tfoot);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "tfoot", tfoot);
|
||||
|
||||
// <th>
|
||||
nh_set_str_t th = nh_set_str_create();
|
||||
nh_set_str_add(th, "tr");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "th", th);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "th", th);
|
||||
|
||||
// <thead>
|
||||
nh_set_str_t thead = nh_set_str_create();
|
||||
nh_set_str_add(thead, "table");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "thead", thead);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "thead", thead);
|
||||
|
||||
// <tr>
|
||||
nh_set_str_t tr = nh_set_str_create();
|
||||
|
@ -127,13 +127,13 @@ void hbr_whitelistparents_init(void) {
|
|||
nh_set_str_add(tr, "thead");
|
||||
nh_set_str_add(tr, "tbody");
|
||||
nh_set_str_add(tr, "tfoot");
|
||||
nh_map_str_strset_set(hbr_whitelistparents_map, "tr", tr);
|
||||
nh_map_str_strset_set(hb_rule_whitelistparents_map, "tr", tr);
|
||||
|
||||
// <template>
|
||||
// Should be <body>, <frameset>, <head>, <dl>, <colgroup>, but ignoring
|
||||
}
|
||||
|
||||
int hbr_whitelistparents_allowed(hb_char_t *child, hb_char_t *parent) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hbr_whitelistparents_map, (char *) child, NULL);
|
||||
int hb_rule_whitelistparents_allowed(hb_proc_char_t *child, hb_proc_char_t *parent) {
|
||||
nh_set_str_t set = nh_map_str_strset_get(hb_rule_whitelistparents_map, (char *) child, NULL);
|
||||
return set == NULL || nh_set_str_has(set, (char *) parent);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_str_t hbr_contentfirsttags_set;
|
||||
static nh_set_str_t hb_rule_contentfirsttags_set;
|
||||
|
||||
void hbr_contentfirsttags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_contentfirsttags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "dd");
|
||||
nh_set_str_add(set, "details");
|
||||
nh_set_str_add(set, "dt");
|
||||
|
@ -16,11 +16,11 @@ void hbr_contentfirsttags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "th");
|
||||
}
|
||||
|
||||
void hbr_contentfirsttags_init(void) {
|
||||
hbr_contentfirsttags_set = nh_set_str_create();
|
||||
hbr_contentfirsttags_add_elems(hbr_contentfirsttags_set);
|
||||
void hb_rule_contentfirsttags_init(void) {
|
||||
hb_rule_contentfirsttags_set = nh_set_str_create();
|
||||
hb_rule_contentfirsttags_add_elems(hb_rule_contentfirsttags_set);
|
||||
}
|
||||
|
||||
int hbr_contentfirsttags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_contentfirsttags_set, (char *) tag);
|
||||
int hb_rule_contentfirsttags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_contentfirsttags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_str_t hbr_contenttags_set;
|
||||
static nh_set_str_t hb_rule_contenttags_set;
|
||||
|
||||
void hbr_contenttags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_contenttags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "address");
|
||||
nh_set_str_add(set, "audio");
|
||||
nh_set_str_add(set, "button");
|
||||
|
@ -23,11 +23,11 @@ void hbr_contenttags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "video");
|
||||
}
|
||||
|
||||
void hbr_contenttags_init(void) {
|
||||
hbr_contenttags_set = nh_set_str_create();
|
||||
hbr_contenttags_add_elems(hbr_contenttags_set);
|
||||
void hb_rule_contenttags_init(void) {
|
||||
hb_rule_contenttags_set = nh_set_str_create();
|
||||
hb_rule_contenttags_add_elems(hb_rule_contenttags_set);
|
||||
}
|
||||
|
||||
int hbr_contenttags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_contenttags_set, (char *) tag);
|
||||
int hb_rule_contenttags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_contenttags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_str_t hbr_formattingtags_set;
|
||||
static nh_set_str_t hb_rule_formattingtags_set;
|
||||
|
||||
void hbr_formattingtags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_formattingtags_add_elems(nh_set_str_t set) {
|
||||
// Difference to MDN's inline text semantics list: -br, +del, +ins
|
||||
nh_set_str_add(set, "a");
|
||||
nh_set_str_add(set, "abbr");
|
||||
|
@ -34,11 +34,11 @@ void hbr_formattingtags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "wbr");
|
||||
}
|
||||
|
||||
void hbr_formattingtags_init(void) {
|
||||
hbr_formattingtags_set = nh_set_str_create();
|
||||
hbr_formattingtags_add_elems(hbr_formattingtags_set);
|
||||
void hb_rule_formattingtags_init(void) {
|
||||
hb_rule_formattingtags_set = nh_set_str_create();
|
||||
hb_rule_formattingtags_add_elems(hb_rule_formattingtags_set);
|
||||
}
|
||||
|
||||
int hbr_formattingtags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_formattingtags_set, (char *) tag);
|
||||
int hb_rule_formattingtags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_formattingtags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_str_t hbr_headingtags_set;
|
||||
static nh_set_str_t hb_rule_headingtags_set;
|
||||
|
||||
void hbr_headingtags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_headingtags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "hgroup");
|
||||
nh_set_str_add(set, "h1");
|
||||
nh_set_str_add(set, "h2");
|
||||
|
@ -10,11 +10,11 @@ void hbr_headingtags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "h6");
|
||||
}
|
||||
|
||||
void hbr_headingtags_init(void) {
|
||||
hbr_headingtags_set = nh_set_str_create();
|
||||
hbr_headingtags_add_elems(hbr_headingtags_set);
|
||||
void hb_rule_headingtags_init(void) {
|
||||
hb_rule_headingtags_set = nh_set_str_create();
|
||||
hb_rule_headingtags_add_elems(hb_rule_headingtags_set);
|
||||
}
|
||||
|
||||
int hbr_headingtags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_headingtags_set, (char *) tag);
|
||||
int hb_rule_headingtags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_headingtags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,162 +1,162 @@
|
|||
// Sourced from https://developer.mozilla.org/en-US/docs/Web/HTML/Element at 2018-07-01T05:55:00Z
|
||||
|
||||
static nh_set_str_t hbr_htmltags_set;
|
||||
static nh_set_str_t hb_rule_htmltags_set;
|
||||
|
||||
void hbr_htmltags_init(void) {
|
||||
hbr_htmltags_set = nh_set_str_create();
|
||||
nh_set_str_add(hbr_htmltags_set, "a");
|
||||
nh_set_str_add(hbr_htmltags_set, "abbr");
|
||||
nh_set_str_add(hbr_htmltags_set, "acronym");
|
||||
nh_set_str_add(hbr_htmltags_set, "address");
|
||||
nh_set_str_add(hbr_htmltags_set, "applet");
|
||||
nh_set_str_add(hbr_htmltags_set, "applet");
|
||||
nh_set_str_add(hbr_htmltags_set, "area");
|
||||
nh_set_str_add(hbr_htmltags_set, "article");
|
||||
nh_set_str_add(hbr_htmltags_set, "aside");
|
||||
nh_set_str_add(hbr_htmltags_set, "audio");
|
||||
nh_set_str_add(hbr_htmltags_set, "b");
|
||||
nh_set_str_add(hbr_htmltags_set, "basefont");
|
||||
nh_set_str_add(hbr_htmltags_set, "bdi");
|
||||
nh_set_str_add(hbr_htmltags_set, "bdo");
|
||||
nh_set_str_add(hbr_htmltags_set, "bgsound");
|
||||
nh_set_str_add(hbr_htmltags_set, "big");
|
||||
nh_set_str_add(hbr_htmltags_set, "blink");
|
||||
nh_set_str_add(hbr_htmltags_set, "blockquote");
|
||||
nh_set_str_add(hbr_htmltags_set, "body");
|
||||
nh_set_str_add(hbr_htmltags_set, "br");
|
||||
nh_set_str_add(hbr_htmltags_set, "button");
|
||||
nh_set_str_add(hbr_htmltags_set, "canvas");
|
||||
nh_set_str_add(hbr_htmltags_set, "caption");
|
||||
nh_set_str_add(hbr_htmltags_set, "center");
|
||||
nh_set_str_add(hbr_htmltags_set, "cite");
|
||||
nh_set_str_add(hbr_htmltags_set, "code");
|
||||
nh_set_str_add(hbr_htmltags_set, "col");
|
||||
nh_set_str_add(hbr_htmltags_set, "colgroup");
|
||||
nh_set_str_add(hbr_htmltags_set, "command");
|
||||
nh_set_str_add(hbr_htmltags_set, "content");
|
||||
nh_set_str_add(hbr_htmltags_set, "content");
|
||||
nh_set_str_add(hbr_htmltags_set, "data");
|
||||
nh_set_str_add(hbr_htmltags_set, "datalist");
|
||||
nh_set_str_add(hbr_htmltags_set, "dd");
|
||||
nh_set_str_add(hbr_htmltags_set, "del");
|
||||
nh_set_str_add(hbr_htmltags_set, "details");
|
||||
nh_set_str_add(hbr_htmltags_set, "dfn");
|
||||
nh_set_str_add(hbr_htmltags_set, "dialog");
|
||||
nh_set_str_add(hbr_htmltags_set, "dir");
|
||||
nh_set_str_add(hbr_htmltags_set, "dir");
|
||||
nh_set_str_add(hbr_htmltags_set, "div");
|
||||
nh_set_str_add(hbr_htmltags_set, "dl");
|
||||
nh_set_str_add(hbr_htmltags_set, "dt");
|
||||
nh_set_str_add(hbr_htmltags_set, "element");
|
||||
nh_set_str_add(hbr_htmltags_set, "element");
|
||||
nh_set_str_add(hbr_htmltags_set, "em");
|
||||
nh_set_str_add(hbr_htmltags_set, "embed");
|
||||
nh_set_str_add(hbr_htmltags_set, "fieldset");
|
||||
nh_set_str_add(hbr_htmltags_set, "figcaption");
|
||||
nh_set_str_add(hbr_htmltags_set, "figure");
|
||||
nh_set_str_add(hbr_htmltags_set, "font");
|
||||
nh_set_str_add(hbr_htmltags_set, "footer");
|
||||
nh_set_str_add(hbr_htmltags_set, "form");
|
||||
nh_set_str_add(hbr_htmltags_set, "frame");
|
||||
nh_set_str_add(hbr_htmltags_set, "frameset");
|
||||
nh_set_str_add(hbr_htmltags_set, "h1");
|
||||
nh_set_str_add(hbr_htmltags_set, "h2");
|
||||
nh_set_str_add(hbr_htmltags_set, "h3");
|
||||
nh_set_str_add(hbr_htmltags_set, "h4");
|
||||
nh_set_str_add(hbr_htmltags_set, "h5");
|
||||
nh_set_str_add(hbr_htmltags_set, "h6");
|
||||
nh_set_str_add(hbr_htmltags_set, "head");
|
||||
nh_set_str_add(hbr_htmltags_set, "header");
|
||||
nh_set_str_add(hbr_htmltags_set, "hgroup");
|
||||
nh_set_str_add(hbr_htmltags_set, "hr");
|
||||
nh_set_str_add(hbr_htmltags_set, "html");
|
||||
nh_set_str_add(hbr_htmltags_set, "i");
|
||||
nh_set_str_add(hbr_htmltags_set, "iframe");
|
||||
nh_set_str_add(hbr_htmltags_set, "image");
|
||||
nh_set_str_add(hbr_htmltags_set, "img");
|
||||
nh_set_str_add(hbr_htmltags_set, "input");
|
||||
nh_set_str_add(hbr_htmltags_set, "ins");
|
||||
nh_set_str_add(hbr_htmltags_set, "isindex");
|
||||
nh_set_str_add(hbr_htmltags_set, "kbd");
|
||||
nh_set_str_add(hbr_htmltags_set, "keygen");
|
||||
nh_set_str_add(hbr_htmltags_set, "label");
|
||||
nh_set_str_add(hbr_htmltags_set, "legend");
|
||||
nh_set_str_add(hbr_htmltags_set, "li");
|
||||
nh_set_str_add(hbr_htmltags_set, "link");
|
||||
nh_set_str_add(hbr_htmltags_set, "listing");
|
||||
nh_set_str_add(hbr_htmltags_set, "main");
|
||||
nh_set_str_add(hbr_htmltags_set, "map");
|
||||
nh_set_str_add(hbr_htmltags_set, "mark");
|
||||
nh_set_str_add(hbr_htmltags_set, "marquee");
|
||||
nh_set_str_add(hbr_htmltags_set, "menu");
|
||||
nh_set_str_add(hbr_htmltags_set, "menuitem");
|
||||
nh_set_str_add(hbr_htmltags_set, "menuitem");
|
||||
nh_set_str_add(hbr_htmltags_set, "meta");
|
||||
nh_set_str_add(hbr_htmltags_set, "meter");
|
||||
nh_set_str_add(hbr_htmltags_set, "multicol");
|
||||
nh_set_str_add(hbr_htmltags_set, "nav");
|
||||
nh_set_str_add(hbr_htmltags_set, "nextid");
|
||||
nh_set_str_add(hbr_htmltags_set, "nobr");
|
||||
nh_set_str_add(hbr_htmltags_set, "noembed");
|
||||
nh_set_str_add(hbr_htmltags_set, "noembed");
|
||||
nh_set_str_add(hbr_htmltags_set, "noframes");
|
||||
nh_set_str_add(hbr_htmltags_set, "noscript");
|
||||
nh_set_str_add(hbr_htmltags_set, "object");
|
||||
nh_set_str_add(hbr_htmltags_set, "ol");
|
||||
nh_set_str_add(hbr_htmltags_set, "optgroup");
|
||||
nh_set_str_add(hbr_htmltags_set, "option");
|
||||
nh_set_str_add(hbr_htmltags_set, "output");
|
||||
nh_set_str_add(hbr_htmltags_set, "p");
|
||||
nh_set_str_add(hbr_htmltags_set, "param");
|
||||
nh_set_str_add(hbr_htmltags_set, "picture");
|
||||
nh_set_str_add(hbr_htmltags_set, "plaintext");
|
||||
nh_set_str_add(hbr_htmltags_set, "pre");
|
||||
nh_set_str_add(hbr_htmltags_set, "progress");
|
||||
nh_set_str_add(hbr_htmltags_set, "q");
|
||||
nh_set_str_add(hbr_htmltags_set, "rp");
|
||||
nh_set_str_add(hbr_htmltags_set, "rt");
|
||||
nh_set_str_add(hbr_htmltags_set, "rtc");
|
||||
nh_set_str_add(hbr_htmltags_set, "ruby");
|
||||
nh_set_str_add(hbr_htmltags_set, "s");
|
||||
nh_set_str_add(hbr_htmltags_set, "samp");
|
||||
nh_set_str_add(hbr_htmltags_set, "script");
|
||||
nh_set_str_add(hbr_htmltags_set, "section");
|
||||
nh_set_str_add(hbr_htmltags_set, "select");
|
||||
nh_set_str_add(hbr_htmltags_set, "shadow");
|
||||
nh_set_str_add(hbr_htmltags_set, "shadow");
|
||||
nh_set_str_add(hbr_htmltags_set, "slot");
|
||||
nh_set_str_add(hbr_htmltags_set, "small");
|
||||
nh_set_str_add(hbr_htmltags_set, "source");
|
||||
nh_set_str_add(hbr_htmltags_set, "spacer");
|
||||
nh_set_str_add(hbr_htmltags_set, "span");
|
||||
nh_set_str_add(hbr_htmltags_set, "strike");
|
||||
nh_set_str_add(hbr_htmltags_set, "strong");
|
||||
nh_set_str_add(hbr_htmltags_set, "style");
|
||||
nh_set_str_add(hbr_htmltags_set, "sub");
|
||||
nh_set_str_add(hbr_htmltags_set, "summary");
|
||||
nh_set_str_add(hbr_htmltags_set, "sup");
|
||||
nh_set_str_add(hbr_htmltags_set, "table");
|
||||
nh_set_str_add(hbr_htmltags_set, "tbody");
|
||||
nh_set_str_add(hbr_htmltags_set, "td");
|
||||
nh_set_str_add(hbr_htmltags_set, "template");
|
||||
nh_set_str_add(hbr_htmltags_set, "textarea");
|
||||
nh_set_str_add(hbr_htmltags_set, "tfoot");
|
||||
nh_set_str_add(hbr_htmltags_set, "th");
|
||||
nh_set_str_add(hbr_htmltags_set, "thead");
|
||||
nh_set_str_add(hbr_htmltags_set, "time");
|
||||
nh_set_str_add(hbr_htmltags_set, "title");
|
||||
nh_set_str_add(hbr_htmltags_set, "tr");
|
||||
nh_set_str_add(hbr_htmltags_set, "track");
|
||||
nh_set_str_add(hbr_htmltags_set, "tt");
|
||||
nh_set_str_add(hbr_htmltags_set, "tt");
|
||||
nh_set_str_add(hbr_htmltags_set, "u");
|
||||
nh_set_str_add(hbr_htmltags_set, "ul");
|
||||
nh_set_str_add(hbr_htmltags_set, "var");
|
||||
nh_set_str_add(hbr_htmltags_set, "video");
|
||||
nh_set_str_add(hbr_htmltags_set, "wbr");
|
||||
nh_set_str_add(hbr_htmltags_set, "xmp");
|
||||
void hb_rule_htmltags_init(void) {
|
||||
hb_rule_htmltags_set = nh_set_str_create();
|
||||
nh_set_str_add(hb_rule_htmltags_set, "a");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "abbr");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "acronym");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "address");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "applet");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "applet");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "area");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "article");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "aside");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "audio");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "b");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "basefont");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "bdi");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "bdo");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "bgsound");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "big");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "blink");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "blockquote");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "body");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "br");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "button");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "canvas");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "caption");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "center");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "cite");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "code");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "col");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "colgroup");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "command");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "content");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "content");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "data");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "datalist");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dd");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "del");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "details");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dfn");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dialog");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dir");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dir");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "div");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dl");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "dt");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "element");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "element");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "em");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "embed");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "fieldset");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "figcaption");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "figure");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "font");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "footer");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "form");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "frame");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "frameset");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h1");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h2");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h3");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h4");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h5");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "h6");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "head");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "header");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "hgroup");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "hr");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "html");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "i");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "iframe");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "image");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "img");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "input");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "ins");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "isindex");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "kbd");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "keygen");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "label");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "legend");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "li");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "link");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "listing");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "main");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "map");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "mark");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "marquee");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "menu");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "menuitem");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "menuitem");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "meta");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "meter");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "multicol");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "nav");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "nextid");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "nobr");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "noembed");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "noembed");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "noframes");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "noscript");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "object");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "ol");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "optgroup");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "option");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "output");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "p");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "param");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "picture");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "plaintext");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "pre");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "progress");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "q");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "rp");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "rt");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "rtc");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "ruby");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "s");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "samp");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "script");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "section");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "select");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "shadow");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "shadow");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "slot");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "small");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "source");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "spacer");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "span");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "strike");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "strong");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "style");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "sub");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "summary");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "sup");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "table");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "tbody");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "td");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "template");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "textarea");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "tfoot");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "th");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "thead");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "time");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "title");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "tr");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "track");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "tt");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "tt");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "u");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "ul");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "var");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "video");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "wbr");
|
||||
nh_set_str_add(hb_rule_htmltags_set, "xmp");
|
||||
}
|
||||
|
||||
int hbr_htmltags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_htmltags_set, (char *) tag);
|
||||
int hb_rule_htmltags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_htmltags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "./sectioningtags.c"
|
||||
|
||||
static nh_set_str_t hbr_layouttags_set;
|
||||
static nh_set_str_t hb_rule_layouttags_set;
|
||||
|
||||
void hbr_layouttags_add_elems(nh_set_str_t set) {
|
||||
hbr_sectioningtags_add_elems(set);
|
||||
void hb_rule_layouttags_add_elems(nh_set_str_t set) {
|
||||
hb_rule_sectioningtags_add_elems(set);
|
||||
nh_set_str_add(set, "blockquote");
|
||||
nh_set_str_add(set, "body");
|
||||
nh_set_str_add(set, "colgroup");
|
||||
|
@ -36,11 +36,11 @@ void hbr_layouttags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "ul");
|
||||
}
|
||||
|
||||
void hbr_layouttags_init(void) {
|
||||
hbr_layouttags_set = nh_set_str_create();
|
||||
hbr_layouttags_add_elems(hbr_layouttags_set);
|
||||
void hb_rule_layouttags_init(void) {
|
||||
hb_rule_layouttags_set = nh_set_str_create();
|
||||
hb_rule_layouttags_add_elems(hb_rule_layouttags_set);
|
||||
}
|
||||
|
||||
int hbr_layouttags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_layouttags_set, (char *) tag);
|
||||
int hb_rule_layouttags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_layouttags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
static nh_set_str_t hbr_mediatags_set;
|
||||
static nh_set_str_t hb_rule_mediatags_set;
|
||||
|
||||
void hbr_mediatags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_mediatags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "audio");
|
||||
nh_set_str_add(set, "video");
|
||||
}
|
||||
|
||||
void hbr_mediatags_init(void) {
|
||||
hbr_mediatags_set = nh_set_str_create();
|
||||
hbr_mediatags_add_elems(hbr_mediatags_set);
|
||||
void hb_rule_mediatags_init(void) {
|
||||
hb_rule_mediatags_set = nh_set_str_create();
|
||||
hb_rule_mediatags_add_elems(hb_rule_mediatags_set);
|
||||
}
|
||||
|
||||
int hbr_mediatags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_mediatags_set, (char *) tag);
|
||||
int hb_rule_mediatags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_mediatags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
static nh_set_str_t hbr_sectioningtags_set;
|
||||
static nh_set_str_t hb_rule_sectioningtags_set;
|
||||
|
||||
void hbr_sectioningtags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_sectioningtags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "article");
|
||||
nh_set_str_add(set, "aside");
|
||||
nh_set_str_add(set, "nav");
|
||||
nh_set_str_add(set, "section");
|
||||
}
|
||||
|
||||
void hbr_sectioningtags_init(void) {
|
||||
hbr_sectioningtags_set = nh_set_str_create();
|
||||
hbr_sectioningtags_add_elems(hbr_sectioningtags_set);
|
||||
void hb_rule_sectioningtags_init(void) {
|
||||
hb_rule_sectioningtags_set = nh_set_str_create();
|
||||
hb_rule_sectioningtags_add_elems(hb_rule_sectioningtags_set);
|
||||
}
|
||||
|
||||
int hbr_sectioningtags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_sectioningtags_set, (char *) tag);
|
||||
int hb_rule_sectioningtags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_sectioningtags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "./sectioningtags.c"
|
||||
#include "./svgtags.c"
|
||||
|
||||
static nh_set_str_t hbr_specifictags_set;
|
||||
static nh_set_str_t hb_rule_specifictags_set;
|
||||
|
||||
void hbr_specifictags_add_elems(nh_set_str_t set) {
|
||||
hbr_svgtags_add_elems(set);
|
||||
void hb_rule_specifictags_add_elems(nh_set_str_t set) {
|
||||
hb_rule_svgtags_add_elems(set);
|
||||
nh_set_str_add(set, "area");
|
||||
nh_set_str_add(set, "base");
|
||||
nh_set_str_add(set, "br");
|
||||
|
@ -21,11 +21,11 @@ void hbr_specifictags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "track");
|
||||
}
|
||||
|
||||
void hbr_specifictags_init(void) {
|
||||
hbr_specifictags_set = nh_set_str_create();
|
||||
hbr_specifictags_add_elems(hbr_specifictags_set);
|
||||
void hb_rule_specifictags_init(void) {
|
||||
hb_rule_specifictags_set = nh_set_str_create();
|
||||
hb_rule_specifictags_add_elems(hb_rule_specifictags_set);
|
||||
}
|
||||
|
||||
int hbr_specifictags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_specifictags_set, (char *) tag);
|
||||
int hb_rule_specifictags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_specifictags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Sourced from https://developer.mozilla.org/en-US/docs/Web/SVG/Element at 2018-08-04T03:50:00Z
|
||||
|
||||
static nh_set_str_t hbr_svgtags_set;
|
||||
static nh_set_str_t hb_rule_svgtags_set;
|
||||
|
||||
void hbr_svgtags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_svgtags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "a");
|
||||
nh_set_str_add(set, "altGlyph");
|
||||
nh_set_str_add(set, "altGlyphDef");
|
||||
|
@ -95,11 +95,11 @@ void hbr_svgtags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "vkern");
|
||||
}
|
||||
|
||||
void hbr_svgtags_init(void) {
|
||||
hbr_svgtags_set = nh_set_str_create();
|
||||
hbr_svgtags_add_elems(hbr_svgtags_set);
|
||||
void hb_rule_svgtags_init(void) {
|
||||
hb_rule_svgtags_set = nh_set_str_create();
|
||||
hb_rule_svgtags_add_elems(hb_rule_svgtags_set);
|
||||
}
|
||||
|
||||
int hbr_svgtags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_svgtags_set, (char *) tag);
|
||||
int hb_rule_svgtags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_svgtags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "./htmltags.c"
|
||||
#include "./svgtags.c"
|
||||
|
||||
void hbr_tags_init(void) {
|
||||
void hb_rule_tags_init(void) {
|
||||
}
|
||||
|
||||
int hbr_tags_check(hb_char_t *tag) {
|
||||
return hbr_htmltags_check(tag) ||
|
||||
hbr_svgtags_check(tag);
|
||||
int hb_rule_tags_check(hb_proc_char_t *tag) {
|
||||
return hb_rule_htmltags_check(tag) ||
|
||||
hb_rule_svgtags_check(tag);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
static nh_set_str_t hbr_voidtags_set;
|
||||
static nh_set_str_t hb_rule_voidtags_set;
|
||||
|
||||
void hbr_voidtags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_voidtags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "area");
|
||||
nh_set_str_add(set, "base");
|
||||
nh_set_str_add(set, "br");
|
||||
|
@ -18,11 +18,11 @@ void hbr_voidtags_add_elems(nh_set_str_t set) {
|
|||
nh_set_str_add(set, "wbr");
|
||||
}
|
||||
|
||||
void hbr_voidtags_init(void) {
|
||||
hbr_voidtags_set = nh_set_str_create();
|
||||
hbr_voidtags_add_elems(hbr_voidtags_set);
|
||||
void hb_rule_voidtags_init(void) {
|
||||
hb_rule_voidtags_set = nh_set_str_create();
|
||||
hb_rule_voidtags_add_elems(hb_rule_voidtags_set);
|
||||
}
|
||||
|
||||
int hbr_voidtags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_voidtags_set, (char *) tag);
|
||||
int hb_rule_voidtags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_voidtags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
static nh_set_str_t hbr_wsstags_set;
|
||||
static nh_set_str_t hb_rule_wsstags_set;
|
||||
|
||||
void hbr_wsstags_add_elems(nh_set_str_t set) {
|
||||
void hb_rule_wsstags_add_elems(nh_set_str_t set) {
|
||||
nh_set_str_add(set, "code");
|
||||
nh_set_str_add(set, "pre");
|
||||
}
|
||||
|
||||
void hbr_wsstags_init(void) {
|
||||
hbr_wsstags_set = nh_set_str_create();
|
||||
hbr_wsstags_add_elems(hbr_wsstags_set);
|
||||
void hb_rule_wsstags_init(void) {
|
||||
hb_rule_wsstags_set = nh_set_str_create();
|
||||
hb_rule_wsstags_add_elems(hb_rule_wsstags_set);
|
||||
}
|
||||
|
||||
int hbr_wsstags_check(hb_char_t *tag) {
|
||||
return nh_set_str_has(hbr_wsstags_set, (char *) tag);
|
||||
int hb_rule_wsstags_check(hb_proc_char_t *tag) {
|
||||
return nh_set_str_has(hb_rule_wsstags_set, (char *) tag);
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
void hbs_bang(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "<!");
|
||||
|
||||
while (1) {
|
||||
hb_char_t next = HBE_CATCH_V(hbu_pipe_peek, pipe);
|
||||
if (next == '>') {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
void hbs_comment(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
||||
hbu_pipe_toggle_output_mask(pipe, so->remove_comments);
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "<!--");
|
||||
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hbu_pipe_accept_if_matches, pipe, "-->");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
|
||||
hbu_pipe_toggle_output_mask(pipe, 0);
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
static void _hbs_script_slcomment(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "//");
|
||||
|
||||
// Comment can end at closing </script>
|
||||
// NOTE: Closing tag must not contain whitespace
|
||||
while (1) {
|
||||
int line_term = HBE_CATCH_V(hbu_pipe_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
break;
|
||||
}
|
||||
|
||||
int end_tag = HBE_CATCH_V(hbu_pipe_matches_i, pipe, "</script>");
|
||||
if (end_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_mlcomment(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "/*");
|
||||
|
||||
// Comment can end at closing </script>
|
||||
// NOTE: Closing tag must not contain whitespace
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hbu_pipe_accept_if_matches, pipe, "*/");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int end_tag = HBE_CATCH_V(hbu_pipe_matches_i, pipe, "</script>");
|
||||
if (end_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_string(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_char_t delim = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (delim != '"' && delim != '\'') {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected JavaScript string delimiter");
|
||||
}
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_char_t c = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == delim && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
int line_term = HBE_CATCH_V(hbu_pipe_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
if (!escaping) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Unterminated JavaScript string");
|
||||
}
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_script_template(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "`");
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_char_t c = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '`' && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hbs_script(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hbu_pipe_matches, pipe, "</");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int sl_comment = HBE_CATCH_V(hbu_pipe_matches, pipe, "//");
|
||||
if (sl_comment) {
|
||||
HBE_CATCH_V(_hbs_script_slcomment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
int ml_comment = HBE_CATCH_V(hbu_pipe_matches, pipe, "/*");
|
||||
if (ml_comment) {
|
||||
HBE_CATCH_V(_hbs_script_mlcomment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_char_t next = HBE_CATCH_V(hbu_pipe_peek, pipe);
|
||||
if (next == '"' || next == '\'') {
|
||||
HBE_CATCH_V(_hbs_script_string, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next == '`') {
|
||||
HBE_CATCH_V(_hbs_script_template, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
static void _hbs_style_comment(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
HBE_CATCH_V(hbu_pipe_require_match, pipe, "/*");
|
||||
|
||||
// Unlike script tags, style comments do NOT end at closing tag
|
||||
while (1) {
|
||||
int is_end = HBE_CATCH_V(hbu_pipe_accept_if_matches, pipe, "*/");
|
||||
if (is_end) {
|
||||
break;
|
||||
}
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hbs_style_string(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_char_t delim = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (delim != '"' && delim != '\'') {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected CSS string delimiter");
|
||||
}
|
||||
|
||||
int escaping = 0;
|
||||
|
||||
while (1) {
|
||||
hb_char_t c = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (c == '\\') {
|
||||
escaping ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == delim && !escaping) {
|
||||
break;
|
||||
}
|
||||
|
||||
int line_term = HBE_CATCH_V(hbu_pipe_accept_if_matches_line_terminator, pipe);
|
||||
if (line_term) {
|
||||
if (!escaping) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Unterminated CSS string");
|
||||
}
|
||||
}
|
||||
|
||||
escaping = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void hbs_style(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
while (1) {
|
||||
int end = HBE_CATCH_V(hbu_pipe_matches, pipe, "</");
|
||||
if (end) {
|
||||
break;
|
||||
}
|
||||
|
||||
int is_comment = HBE_CATCH_V(hbu_pipe_matches, pipe, "/*");
|
||||
if (is_comment) {
|
||||
HBE_CATCH_V(_hbs_style_comment, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_char_t next = HBE_CATCH_V(hbu_pipe_peek, pipe);
|
||||
if (next == '"' || next == '\'') {
|
||||
HBE_CATCH_V(_hbs_style_string, pipe);
|
||||
continue;
|
||||
}
|
||||
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
// Declare first before content.c, as content.c depends on it
|
||||
void hbs_tag(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb_char_t *parent);
|
||||
|
||||
#include "./tagname.c"
|
||||
#include "../attr/attr.c"
|
||||
#include "../content/script.c"
|
||||
#include "../content/style.c"
|
||||
#include "../content/html.c"
|
||||
|
||||
// $parent could be NULL
|
||||
void hbs_tag(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe, hb_char_t *parent) {
|
||||
hbu_list_char_t opening_name = NULL;
|
||||
|
||||
int self_closing = 0;
|
||||
|
||||
HBE_CATCH_F(hbu_pipe_require, pipe, '<');
|
||||
opening_name = HBE_CATCH_F(hbs_tagname, so, pipe);
|
||||
|
||||
int last_attr_type = -1;
|
||||
|
||||
while (1) {
|
||||
// At the beginning of this loop, the last parsed unit was either the tag name
|
||||
// or an attribute (including its value, if it had one)
|
||||
size_t ws_accepted;
|
||||
if (so->remove_tag_whitespace) {
|
||||
ws_accepted = HBE_CATCH_F(hbu_pipe_skip_while_predicate, pipe, &hbr_whitespace_check);
|
||||
} else {
|
||||
ws_accepted = HBE_CATCH_F(hbu_pipe_accept_while_predicate, pipe, &hbr_whitespace_check);
|
||||
}
|
||||
|
||||
int end_of_tag = HBE_CATCH_F(hbu_pipe_accept_if, pipe, '>');
|
||||
if (end_of_tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
self_closing = HBE_CATCH_F(hbu_pipe_accept_if_matches, pipe, "/>");
|
||||
if (self_closing) {
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_SELF_CLOSING_TAG)) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_SELF_CLOSING_TAG, "Self-closing tag");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// HBE_PARSE_NO_SPACE_BEFORE_ATTR is not suppressable as then there would be difficulty
|
||||
// in determining what is the end of a tag/attribute name/attribute value
|
||||
if (!ws_accepted) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_NO_SPACE_BEFORE_ATTR, "No whitespace before attribute");
|
||||
}
|
||||
|
||||
if (so->remove_tag_whitespace) {
|
||||
if (last_attr_type != HBS_ATTR_QUOTED) {
|
||||
HBE_CATCH_F(hbu_pipe_write, pipe, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
last_attr_type = HBE_CATCH_F(hbs_attr, so, pipe);
|
||||
}
|
||||
|
||||
hb_char_t *tag_name = hbu_list_char_underlying(opening_name);
|
||||
|
||||
// Non-standard tag checking is done in hbs_tagname
|
||||
if (parent != NULL && (
|
||||
!hbr_whitelistparents_allowed(tag_name, parent) ||
|
||||
!hbr_whitelistchildren_allowed(parent, tag_name) ||
|
||||
!hbr_blacklistparents_allowed(tag_name, parent) ||
|
||||
!hbr_blacklistchildren_allowed(parent, tag_name))) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_ILLEGAL_CHILD, "Tag can't be a child there");
|
||||
}
|
||||
|
||||
// Self-closing or void tag
|
||||
if (self_closing || hbr_voidtags_check(tag_name)) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
if (hbu_list_char_compare_lit(opening_name, "script") == 0) {
|
||||
// Script tag
|
||||
HBE_CATCH_F(hbs_script, pipe);
|
||||
} else if (hbu_list_char_compare_lit(opening_name, "style") == 0) {
|
||||
// Style tag
|
||||
HBE_CATCH_F(hbs_style, pipe);
|
||||
} else {
|
||||
// Content
|
||||
HBE_CATCH_F(hbs_content, so, pipe, tag_name);
|
||||
}
|
||||
|
||||
// Closing tag for non-void
|
||||
HBE_CATCH_F(hbu_pipe_require, pipe, '<');
|
||||
HBE_CATCH_F(hbu_pipe_require, pipe, '/');
|
||||
hbu_list_char_t closing_name = HBE_CATCH_F(hbs_tagname, so, pipe);
|
||||
HBE_CATCH_F(hbu_pipe_require, pipe, '>');
|
||||
|
||||
if (!hbu_list_char_equal(opening_name, closing_name)) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_UNCLOSED_TAG, "Tag not closed (expected `%s` closing tag, got `%s`)", tag_name, hbu_list_char_underlying(closing_name));
|
||||
}
|
||||
|
||||
finally:
|
||||
if (opening_name) {
|
||||
hbu_list_char_destroy(opening_name);
|
||||
opening_name = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
hbu_list_char_t hbs_tagname(hbe_err_t *hbe_err, hbu_streamoptions_t so, hbu_pipe_t pipe) {
|
||||
hbu_list_char_t name = hbu_list_char_create();
|
||||
|
||||
while (1) {
|
||||
hb_char_t c = HBE_CATCH_F(hbu_pipe_peek, pipe);
|
||||
|
||||
if (!hbr_tagname_check(c)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (hbr_ucalpha_check(c)) {
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_UCASE_TAG)) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_UCASE_TAG, "Uppercase character in tag");
|
||||
}
|
||||
// Lowercase to normalise when checking against rules and closing tag
|
||||
hbu_list_char_append(name, c + 32);
|
||||
} else {
|
||||
hbu_list_char_append(name, c);
|
||||
}
|
||||
|
||||
HBE_CATCH_F(hbu_pipe_accept, pipe);
|
||||
}
|
||||
|
||||
if (!hbu_streamoptions_supressed_error(so, HBE_PARSE_NONSTANDARD_TAG) && !hbr_tags_check(hbu_list_char_underlying(name))) {
|
||||
HBU_PIPE_THROW_F(pipe, HBE_PARSE_NONSTANDARD_TAG, "Non-standard tag");
|
||||
}
|
||||
|
||||
finally:
|
||||
if (*hbe_err != NULL) {
|
||||
hbu_list_char_destroy(name);
|
||||
name = NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#include "./char/char.c"
|
||||
|
||||
#include "./config/streamoptions.c"
|
||||
|
||||
#include "./execution/error.c"
|
||||
#include "./execution/logging.c"
|
||||
|
||||
#include "./fstream/fstreamin.c"
|
||||
#include "./fstream/fstreamout.c"
|
||||
|
||||
#include "./list/char.c"
|
||||
#include "./list/charlist.c"
|
||||
|
||||
#include "./map/str-int32.c"
|
||||
#include "./map/str-strset.c"
|
||||
|
||||
#include "./math/math.c"
|
||||
|
||||
#include "./pipe/pipe.c"
|
|
@ -1,5 +0,0 @@
|
|||
typedef signed int hb_eod_char_t;
|
||||
typedef unsigned char hb_char_t;
|
||||
|
||||
#define HB_EOD -1 // End Of Data
|
||||
#define SIZEOF_CHAR sizeof(hb_char_t)
|
|
@ -1,224 +0,0 @@
|
|||
#include "../execution/error.c"
|
||||
#include "../execution/logging.c"
|
||||
#include "../char/char.c"
|
||||
#include "../list/char.c"
|
||||
#include "../list/charlist.c"
|
||||
#include "../../rule/tag/contentfirsttags.c"
|
||||
#include "../../rule/tag/contenttags.c"
|
||||
#include "../../rule/tag/formattingtags.c"
|
||||
#include "../../rule/tag/headingtags.c"
|
||||
#include "../../rule/tag/layouttags.c"
|
||||
#include "../../rule/tag/mediatags.c"
|
||||
#include "../../rule/tag/sectioningtags.c"
|
||||
#include "../../rule/tag/specifictags.c"
|
||||
#include "../../rule/tag/tags.c"
|
||||
#include "../../rule/tag/voidtags.c"
|
||||
#include "../../rule/tag/wsstags.c"
|
||||
|
||||
typedef struct hbu_streamoptions_s {
|
||||
nh_set_str_t ex_collapse_whitespace; // Could be NULL to represent the universal set (i.e. don't minify)
|
||||
nh_set_str_t ex_destroy_whole_whitespace; // Could be NULL to represent the universal set (i.e. don't minify)
|
||||
nh_set_str_t ex_trim_whitespace; // Could be NULL to represent the universal set (i.e. don't minify)
|
||||
nh_set_int32_t suppressed_errors;
|
||||
int trim_class_attr;
|
||||
int decode_entities;
|
||||
int min_conditional_comments;
|
||||
int remove_attr_quotes;
|
||||
int remove_comments;
|
||||
int remove_optional_tags;
|
||||
int remove_tag_whitespace;
|
||||
} *hbu_streamoptions_t;
|
||||
|
||||
static nh_set_str_t _hbu_streamoptions_default_ex_collapse_whitespace = NULL;
|
||||
nh_set_str_t hbu_streamoptions_default_ex_collapse_whitespace(void) {
|
||||
if (_hbu_streamoptions_default_ex_collapse_whitespace == NULL) {
|
||||
_hbu_streamoptions_default_ex_collapse_whitespace = nh_set_str_create();
|
||||
hbr_wsstags_add_elems(_hbu_streamoptions_default_ex_collapse_whitespace);
|
||||
}
|
||||
return _hbu_streamoptions_default_ex_collapse_whitespace;
|
||||
}
|
||||
|
||||
static nh_set_str_t _hbu_streamoptions_default_ex_destroy_whole_whitespace = NULL;
|
||||
nh_set_str_t hbu_streamoptions_default_ex_destroy_whole_whitespace(void) {
|
||||
if (_hbu_streamoptions_default_ex_destroy_whole_whitespace == NULL) {
|
||||
_hbu_streamoptions_default_ex_destroy_whole_whitespace = nh_set_str_create();
|
||||
hbr_wsstags_add_elems(_hbu_streamoptions_default_ex_destroy_whole_whitespace);
|
||||
hbr_contenttags_add_elems(_hbu_streamoptions_default_ex_destroy_whole_whitespace);
|
||||
hbr_formattingtags_add_elems(_hbu_streamoptions_default_ex_destroy_whole_whitespace);
|
||||
}
|
||||
return _hbu_streamoptions_default_ex_destroy_whole_whitespace;
|
||||
}
|
||||
|
||||
static nh_set_str_t _hbu_streamoptions_default_ex_trim_whitespace = NULL;
|
||||
nh_set_str_t hbu_streamoptions_default_ex_trim_whitespace(void) {
|
||||
if (_hbu_streamoptions_default_ex_trim_whitespace == NULL) {
|
||||
_hbu_streamoptions_default_ex_trim_whitespace = nh_set_str_create();
|
||||
hbr_wsstags_add_elems(_hbu_streamoptions_default_ex_trim_whitespace);
|
||||
hbr_formattingtags_add_elems(_hbu_streamoptions_default_ex_trim_whitespace);
|
||||
}
|
||||
return _hbu_streamoptions_default_ex_trim_whitespace;
|
||||
}
|
||||
|
||||
// WARNING: Rules must be initialised before calling this function
|
||||
hbu_streamoptions_t hbu_streamoptions_create(void) {
|
||||
hbu_streamoptions_t opt = malloc(sizeof(struct hbu_streamoptions_s));
|
||||
opt->ex_collapse_whitespace = NULL;
|
||||
opt->ex_destroy_whole_whitespace = NULL;
|
||||
opt->ex_trim_whitespace = NULL;
|
||||
opt->suppressed_errors = nh_set_int32_create();
|
||||
opt->trim_class_attr = 1;
|
||||
opt->decode_entities = 1;
|
||||
opt->min_conditional_comments = 1;
|
||||
opt->remove_attr_quotes = 1;
|
||||
opt->remove_comments = 1;
|
||||
opt->remove_optional_tags = 1;
|
||||
opt->remove_tag_whitespace = 1;
|
||||
return opt;
|
||||
}
|
||||
|
||||
// WARNING: Does not destroy ex_* members
|
||||
void hbu_streamoptions_destroy(hbu_streamoptions_t opt) {
|
||||
nh_set_int32_destroy(opt->suppressed_errors);
|
||||
free(opt);
|
||||
}
|
||||
|
||||
int hbu_streamoptions_in_tags_list(nh_set_str_t set, hb_char_t *query) {
|
||||
if (set == NULL) {
|
||||
return 1; // NULL represents the universal set
|
||||
}
|
||||
|
||||
if (query == NULL) {
|
||||
// When parent is #root
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nh_set_str_has(set, (char *) query);
|
||||
}
|
||||
|
||||
int hbu_streamoptions_supressed_error(hbu_streamoptions_t opt, hbe_errcode_t errcode) {
|
||||
return nh_set_int32_has(opt->suppressed_errors, errcode);
|
||||
}
|
||||
|
||||
void hbu_streamoptions_log(hbu_streamoptions_t opt) {
|
||||
hbl_info_kv_boolean("Trim `class` attributes", opt->trim_class_attr);
|
||||
hbl_info_kv_boolean("Decode entities", opt->decode_entities);
|
||||
hbl_info_kv_boolean("Minify conditional comments", opt->min_conditional_comments);
|
||||
hbl_info_kv_boolean("Remove attribute quotes", opt->remove_attr_quotes);
|
||||
hbl_info_kv_boolean("Remove comments", opt->remove_comments);
|
||||
hbl_info_kv_boolean("Remove optional tags", opt->remove_optional_tags);
|
||||
hbl_info_kv_boolean("Remove tag whitespace", opt->remove_tag_whitespace);
|
||||
}
|
||||
|
||||
void hbu_streamoptions_parse_and_add_tag_set(hbe_err_t *hbe_err, char *set_name, nh_set_str_t set) {
|
||||
if (strcmp(set_name, "content") == 0) {
|
||||
hbr_contenttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "contentfirst") == 0) {
|
||||
hbr_contentfirsttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "formatting") == 0) {
|
||||
hbr_formattingtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "layout") == 0) {
|
||||
hbr_layouttags_add_elems(set);
|
||||
} else if (strcmp(set_name, "specific") == 0) {
|
||||
hbr_specifictags_add_elems(set);
|
||||
} else if (strcmp(set_name, "heading") == 0) {
|
||||
hbr_headingtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "media") == 0) {
|
||||
hbr_mediatags_add_elems(set);
|
||||
} else if (strcmp(set_name, "sectioning") == 0) {
|
||||
hbr_sectioningtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "void") == 0) {
|
||||
hbr_voidtags_add_elems(set);
|
||||
} else if (strcmp(set_name, "wss") == 0) {
|
||||
hbr_wsstags_add_elems(set);
|
||||
} else {
|
||||
HBE_THROW_V(HBE_CLI_INVALID_TAG_SET, "Unrecognised tag set `%s`", set_name);
|
||||
}
|
||||
}
|
||||
|
||||
nh_set_str_t hbu_streamoptions_parse_list_of_tags(hbe_err_t *hbe_err, char *argv) {
|
||||
nh_set_str_t set = NULL;
|
||||
hbu_list_charlist_t list = NULL;
|
||||
|
||||
if (argv != NULL && strcmp(argv, "*")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
set = nh_set_str_create();
|
||||
|
||||
if (argv == NULL) {
|
||||
return set;
|
||||
}
|
||||
|
||||
list = hbu_list_charlist_create_from_split((hb_char_t *) argv, ',');
|
||||
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
hbu_list_char_t part = hbu_list_charlist_get(list, i);
|
||||
hb_char_t *part_c = hbu_list_char_underlying(part);
|
||||
|
||||
if (hbu_list_char_get(part, 0) == '$') {
|
||||
// Set of tags
|
||||
hbu_list_char_shift(part);
|
||||
HBE_CATCH_F(hbu_streamoptions_parse_and_add_tag_set, (char *) part_c, set);
|
||||
|
||||
} else {
|
||||
// Single tag
|
||||
if (!hbr_tags_check(part_c)) {
|
||||
HBE_THROW_F(HBE_CLI_INVALID_TAG, "%s is not a standard tag and was provided as part of an argument's value", part_c);
|
||||
}
|
||||
nh_set_str_add(set, (char *) hbu_list_char_underlying_copy(part));
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
if (list != NULL) {
|
||||
hbu_list_charlist_destroy_from_split(list);
|
||||
list = NULL;
|
||||
}
|
||||
if (*hbe_err != NULL) {
|
||||
if (set != NULL) {
|
||||
nh_set_str_destroy(set);
|
||||
set = NULL;
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
void hbu_streamoptions_parse_and_add_errors_to_suppress(hbe_err_t *hbe_err, nh_set_int32_t suppressed_errors, char *argv) {
|
||||
hbu_list_charlist_t list = NULL;
|
||||
|
||||
if (argv == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
list = hbu_list_charlist_create_from_split((hb_char_t *) argv, ',');
|
||||
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
hbu_list_char_t part = hbu_list_charlist_get(list, i);
|
||||
|
||||
if (hbu_list_char_compare_lit(part, "MALFORMED_ENTITY") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_MALFORMED_ENTITY);
|
||||
} else if (hbu_list_char_compare_lit(part, "BARE_AMPERSAND") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_BARE_AMPERSAND);
|
||||
} else if (hbu_list_char_compare_lit(part, "INVALID_ENTITY") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_INVALID_ENTITY);
|
||||
} else if (hbu_list_char_compare_lit(part, "NONSTANDARD_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_NONSTANDARD_TAG);
|
||||
} else if (hbu_list_char_compare_lit(part, "UCASE_ATTR") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UCASE_ATTR);
|
||||
} else if (hbu_list_char_compare_lit(part, "UCASE_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UCASE_TAG);
|
||||
} else if (hbu_list_char_compare_lit(part, "UNQUOTED_ATTR") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_UNQUOTED_ATTR);
|
||||
} else if (hbu_list_char_compare_lit(part, "SELF_CLOSING_TAG") == 0) {
|
||||
nh_set_int32_add(suppressed_errors, HBE_PARSE_SELF_CLOSING_TAG);
|
||||
} else {
|
||||
HBE_THROW_F(HBE_CLI_INVALID_SUPPRESSABLE_ERROR, "Unrecognised suppressable error `%s`", hbu_list_char_underlying(part));
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
if (list != NULL) {
|
||||
hbu_list_charlist_destroy_from_split(list);
|
||||
list = NULL;
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define HBE_COND if (*hbe_err != 0)
|
||||
#define HBE_THROW(code, format, ...) *hbe_err = hbe_err_create(code, format, ##__VA_ARGS__); return 0;
|
||||
#define HBE_THROW_V(code, format, ...) *hbe_err = hbe_err_create(code, format, ##__VA_ARGS__); return;
|
||||
#define HBE_THROW_F(code, format, ...) *hbe_err = hbe_err_create(code, format, ##__VA_ARGS__); goto finally;
|
||||
#define HBE_CATCH(fn, ...) fn(hbe_err, ##__VA_ARGS__); HBE_COND return 0;
|
||||
#define HBE_CATCH_V(fn, ...) fn(hbe_err, ##__VA_ARGS__); HBE_COND return;
|
||||
#define HBE_CATCH_F(fn, ...) fn(hbe_err, ##__VA_ARGS__); HBE_COND goto finally;
|
||||
#define HBE_PASS(fn, ...) fn(hbe_err, ##__VA_ARGS__); return 0;
|
||||
#define HBE_PASS_V(fn, ...) fn(hbe_err, ##__VA_ARGS__); return;
|
||||
#define HBE_PASS_F(fn, ...) fn(hbe_err, ##__VA_ARGS__); goto finally;
|
||||
#define HB_RETURN_F(v) rv = v; goto finally;
|
||||
|
||||
#define MAX_ERR_MSG_LEN 1024
|
||||
|
||||
typedef enum hbe_errcode_e {
|
||||
HBE_INTERR_UNKNOWN_ENTITY_TYPE = 2,
|
||||
HBE_INTERR_UNKNOWN_CONTENT_NEXT_STATE,
|
||||
HBE_INTERR_NOT_A_HB_DIR,
|
||||
|
||||
HBE_CLI_TOO_MANY_OPTIONS = 17,
|
||||
HBE_CLI_INVALID_TAG_SET,
|
||||
HBE_CLI_INVALID_TAG,
|
||||
HBE_CLI_INVALID_SUPPRESSABLE_ERROR,
|
||||
|
||||
HBE_IO_FOPEN_FAIL = 33,
|
||||
HBE_IO_FCLOSE_FAIL,
|
||||
HBE_IO_FREAD_FAIL,
|
||||
HBE_IO_FWRITE_FAIL,
|
||||
|
||||
HBE_PARSE_MALFORMED_ENTITY = 65,
|
||||
HBE_PARSE_BARE_AMPERSAND,
|
||||
HBE_PARSE_INVALID_ENTITY,
|
||||
HBE_PARSE_NONSTANDARD_TAG,
|
||||
HBE_PARSE_UCASE_TAG,
|
||||
HBE_PARSE_UCASE_ATTR,
|
||||
HBE_PARSE_UNQUOTED_ATTR,
|
||||
HBE_PARSE_ILLEGAL_CHILD,
|
||||
HBE_PARSE_UNCLOSED_TAG,
|
||||
HBE_PARSE_SELF_CLOSING_TAG,
|
||||
HBE_PARSE_NO_SPACE_BEFORE_ATTR,
|
||||
|
||||
HBE_PARSE_UNEXPECTED_END,
|
||||
HBE_PARSE_EXPECTED_NOT_FOUND,
|
||||
} hbe_errcode_t;
|
||||
|
||||
typedef struct hbe_err_s {
|
||||
hbe_errcode_t code;
|
||||
char *message;
|
||||
} *hbe_err_t;
|
||||
|
||||
hbe_err_t hbe_err_create(hbe_errcode_t code, char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char *message = calloc(MAX_ERR_MSG_LEN + 1, SIZEOF_CHAR);
|
||||
vsnprintf(message, MAX_ERR_MSG_LEN, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
hbe_err_t err = malloc(sizeof(struct hbe_err_s));
|
||||
err->code = code;
|
||||
err->message = message;
|
||||
return err;
|
||||
}
|
||||
|
||||
hbe_errcode_t hbe_err_code(hbe_err_t err) {
|
||||
return err->code;
|
||||
}
|
||||
|
||||
char *hbe_err_message(hbe_err_t err) {
|
||||
return err->message;
|
||||
}
|
||||
|
||||
void hbe_err_destroy(hbe_err_t err) {
|
||||
free(err->message);
|
||||
free(err);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#define PC_RED "\e[31m"
|
||||
#define PC_GRN "\e[32m"
|
||||
#define PC_YEL "\e[33m"
|
||||
#define PC_BLU "\e[34m"
|
||||
#define PC_MAG "\e[35m"
|
||||
#define PC_CYN "\e[36m"
|
||||
#define PC_WHT "\e[37m"
|
||||
#define PC_RESET "\e[0m"
|
||||
#define PC_BOLD "\e[1m"
|
||||
|
||||
#define HBL_LOG_DEBUG_PREFIX "[DEBUG] "
|
||||
#define HBL_LOG_INFO_PREFIX PC_MAG "[INFO] "
|
||||
#define HBL_LOG_WARN_PREFIX PC_BOLD PC_YEL "[WARN] "
|
||||
|
||||
#define HBL_KV_LOGLINE_LEFTWIDTH "35"
|
||||
|
||||
typedef enum hbl_log_level_e {
|
||||
HBL_LOG_DEBUG,
|
||||
HBL_LOG_INFO,
|
||||
HBL_LOG_WARN,
|
||||
} hbl_log_level_t;
|
||||
|
||||
void hbl_log(hbl_log_level_t level, char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
const char *prefix = level == HBL_LOG_INFO ? (HBL_LOG_INFO_PREFIX) :
|
||||
level == HBL_LOG_WARN ? (HBL_LOG_WARN_PREFIX) :
|
||||
HBL_LOG_DEBUG_PREFIX;
|
||||
|
||||
fprintf(stderr, "%s" PC_RESET, prefix);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void hbl_info_kv_boolean(char *name, int state) {
|
||||
const char *color = state ? (PC_BOLD PC_GRN) : PC_MAG;
|
||||
const char *label = state ? "ON" : "OFF";
|
||||
|
||||
hbl_log(HBL_LOG_INFO, "%-" HBL_KV_LOGLINE_LEFTWIDTH "s%s%s" PC_RESET, name, color, label);
|
||||
}
|
||||
|
||||
void hbl_info_kv_string(char *name, char *value) {
|
||||
hbl_log(HBL_LOG_INFO, "%-" HBL_KV_LOGLINE_LEFTWIDTH "s" PC_BOLD "%s" PC_RESET, name, value);
|
||||
}
|
||||
|
||||
void hbl_error(hbe_err_t err) {
|
||||
fprintf(stderr, PC_BOLD PC_RED "[FATAL]" PC_RESET PC_RED " Error %d: %s\n" PC_RESET, err->code, err->message);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include "../execution/error.c"
|
||||
|
||||
#define HBU_FSTREAM_BUILD_INFRA(type, mode, noun, verb, std) \
|
||||
typedef struct hbu_fstream##type##_s \
|
||||
{ \
|
||||
const char *name; \
|
||||
FILE *fd; \
|
||||
} * hbu_fstream##type##_t; \
|
||||
\
|
||||
hbu_fstream##type##_t hbu_fstream##type##_create(hbe_err_t *hbe_err, char *path) \
|
||||
{ \
|
||||
hbu_fstream##type##_t fstream = malloc(sizeof(struct hbu_fstream##type##_s)); \
|
||||
\
|
||||
if (path == NULL) \
|
||||
{ \
|
||||
fstream->name = #std; \
|
||||
fstream->fd = std; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fstream->name = path; \
|
||||
\
|
||||
FILE *fd = fopen(path, mode); \
|
||||
\
|
||||
if (fd == NULL) \
|
||||
{ \
|
||||
HBE_THROW(HBE_IO_FOPEN_FAIL, "Failed to open file %s for " verb " with error %d", fstream->name, errno); \
|
||||
} \
|
||||
\
|
||||
fstream->fd = fd; \
|
||||
} \
|
||||
\
|
||||
return fstream; \
|
||||
} \
|
||||
\
|
||||
void hbu_fstream##type##_destroy(hbe_err_t *hbe_err, hbu_fstream##type##_t fstream) \
|
||||
{ \
|
||||
if (fclose(fstream->fd) == EOF) \
|
||||
{ \
|
||||
HBE_THROW_V(HBE_IO_FCLOSE_FAIL, "Failed to close " noun " stream for file %s with error %d", fstream->name, errno); \
|
||||
} \
|
||||
\
|
||||
free(fstream); \
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include "../char/char.c"
|
||||
#include "../execution/error.c"
|
||||
#include "./__base__.c"
|
||||
|
||||
HBU_FSTREAM_BUILD_INFRA(in, "r", "read", "reading", stdin)
|
||||
|
||||
hb_eod_char_t hbu_fstreamin_read(hbe_err_t *hbe_err, hbu_fstreamin_t fstreamin) {
|
||||
hb_char_t c;
|
||||
|
||||
if (fread(&c, SIZEOF_CHAR, 1, fstreamin->fd) != SIZEOF_CHAR) {
|
||||
if (ferror(fstreamin->fd)) {
|
||||
HBE_THROW(HBE_IO_FREAD_FAIL, "Failed to read input file %s", fstreamin->name);
|
||||
}
|
||||
|
||||
// Must be EOF
|
||||
return HB_EOD;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include "../execution/error.c"
|
||||
#include "../list/char.c"
|
||||
#include "./__base__.c"
|
||||
|
||||
HBU_FSTREAM_BUILD_INFRA(out, "w", "write", "writing", stdout)
|
||||
|
||||
static void _hbu_fstreamout_fwrite(hbe_err_t *hbe_err, hbu_fstreamout_t fstreamout, hb_char_t *source, size_t length) {
|
||||
if (fwrite(source, SIZEOF_CHAR, length, fstreamout->fd) != SIZEOF_CHAR * length) {
|
||||
HBE_THROW_V(HBE_IO_FWRITE_FAIL, "Failed to write to output file %s", fstreamout->name);
|
||||
}
|
||||
}
|
||||
|
||||
void hbu_fstreamout_write_buffer(hbe_err_t *hbe_err, hbu_fstreamout_t fstreamout, hbu_list_char_t buffer) {
|
||||
HBE_CATCH_V(_hbu_fstreamout_fwrite, fstreamout, hbu_list_char_underlying(buffer), buffer->length);
|
||||
}
|
||||
|
||||
void hbu_fstreamout_write(hbe_err_t *hbe_err, hbu_fstreamout_t fstreamout, hb_char_t c) {
|
||||
HBE_CATCH_V(_hbu_fstreamout_fwrite, fstreamout, &c, 1);
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INITIAL_LIST_SIDE_SIZE 10
|
||||
#define LIST_GROWTH_RATE 1.5
|
||||
|
||||
#define HBU_LIST(name, elem_type, elem_size, invsafe_elem_type, invalid_value) \
|
||||
typedef struct name##_s \
|
||||
{ \
|
||||
elem_type *data; \
|
||||
size_t head; \
|
||||
size_t length; \
|
||||
size_t size; \
|
||||
size_t size_left; \
|
||||
size_t size_right; \
|
||||
} * name##_t; \
|
||||
\
|
||||
name##_t name##_create_size(size_t initial_size_left, size_t initial_size_right) \
|
||||
{ \
|
||||
size_t initial_size = initial_size_left + initial_size_right; \
|
||||
name##_t buf = malloc(sizeof(struct name##_s)); \
|
||||
buf->data = calloc(initial_size, elem_size); \
|
||||
buf->head = initial_size_left; \
|
||||
buf->length = 0; \
|
||||
buf->size = initial_size; \
|
||||
buf->size_left = initial_size_left; \
|
||||
buf->size_right = initial_size_right; \
|
||||
return buf; \
|
||||
} \
|
||||
\
|
||||
name##_t name##_create(void) \
|
||||
{ \
|
||||
return name##_create_size(INITIAL_LIST_SIDE_SIZE, INITIAL_LIST_SIDE_SIZE); \
|
||||
} \
|
||||
\
|
||||
void name##_destroy(name##_t buf) \
|
||||
{ \
|
||||
free(buf->data); \
|
||||
free(buf); \
|
||||
} \
|
||||
\
|
||||
void name##_destroy_shallow(name##_t buf) \
|
||||
{ \
|
||||
free(buf); \
|
||||
} \
|
||||
\
|
||||
elem_type *name##_underlying(name##_t buf) \
|
||||
{ \
|
||||
return &((buf->data)[buf->head]); \
|
||||
} \
|
||||
\
|
||||
elem_type *name##_underlying_copy(name##_t buf) \
|
||||
{ \
|
||||
elem_type *copy = calloc(buf->length + 1, elem_size); \
|
||||
memcpy(copy, name##_underlying(buf), buf->length *elem_size); \
|
||||
return copy; \
|
||||
} \
|
||||
\
|
||||
int name##_valid_index(name##_t buf, size_t idx) \
|
||||
{ \
|
||||
return idx < buf->length; \
|
||||
} \
|
||||
\
|
||||
invsafe_elem_type name##_get(name##_t buf, size_t idx) \
|
||||
{ \
|
||||
if (!name##_valid_index(buf, idx)) \
|
||||
{ \
|
||||
return invalid_value; \
|
||||
} \
|
||||
\
|
||||
return buf->data[buf->head + idx]; \
|
||||
} \
|
||||
\
|
||||
void name##_set(name##_t buf, size_t idx, elem_type c) \
|
||||
{ \
|
||||
if (!name##_valid_index(buf, idx)) \
|
||||
{ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
buf->data[buf->head + idx] = c; \
|
||||
} \
|
||||
\
|
||||
void name##_size_expand_left(name##_t buf, size_t new_size_left) \
|
||||
{ \
|
||||
size_t old_size_left = buf->size_left; \
|
||||
\
|
||||
if (old_size_left >= new_size_left) \
|
||||
{ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
size_t diff_size_left = new_size_left - old_size_left; \
|
||||
\
|
||||
size_t new_size = new_size_left + buf->size_right; \
|
||||
\
|
||||
elem_type *new_data = calloc(new_size, elem_size); \
|
||||
memcpy(&(new_data[diff_size_left]), buf->data, elem_size * buf->length); \
|
||||
free(buf->data); \
|
||||
\
|
||||
buf->data = new_data; \
|
||||
buf->head += old_size_left; \
|
||||
buf->size = new_size; \
|
||||
buf->size_left = new_size_left; \
|
||||
} \
|
||||
\
|
||||
void name##_size_expand_right(name##_t buf, size_t new_size_right) \
|
||||
{ \
|
||||
size_t old_size = buf->size; \
|
||||
size_t old_size_right = buf->size_right; \
|
||||
\
|
||||
if (old_size_right >= new_size_right) \
|
||||
{ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
size_t new_size = buf->size_left + new_size_right; \
|
||||
\
|
||||
elem_type *new_data = realloc(buf->data, elem_size * new_size); \
|
||||
for (size_t i = old_size; i < new_size; i++) \
|
||||
{ \
|
||||
new_data[i] = 0; \
|
||||
} \
|
||||
\
|
||||
buf->data = new_data; \
|
||||
buf->size = new_size; \
|
||||
buf->size_right = new_size_right; \
|
||||
} \
|
||||
\
|
||||
void name##_ensure_left(name##_t buf, size_t amount) \
|
||||
{ \
|
||||
size_t desired_size = amount + 1; \
|
||||
\
|
||||
if (buf->size_left < desired_size) \
|
||||
{ \
|
||||
name##_size_expand_left(buf, desired_size); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void name##_ensure_right(name##_t buf, size_t amount) \
|
||||
{ \
|
||||
size_t desired_size = amount + 1; \
|
||||
\
|
||||
if (buf->size_right < desired_size) \
|
||||
{ \
|
||||
name##_size_expand_right(buf, desired_size); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void name##_append(name##_t buf, elem_type tail) \
|
||||
{ \
|
||||
size_t next_idx = buf->head + buf->length; \
|
||||
\
|
||||
if (next_idx >= buf->size - 1) \
|
||||
{ \
|
||||
size_t old_size = buf->size_right; \
|
||||
size_t new_size = old_size * LIST_GROWTH_RATE + 1; /* +1 to always guarantee an increase */ \
|
||||
\
|
||||
name##_size_expand_right(buf, new_size); \
|
||||
} \
|
||||
\
|
||||
buf->data[next_idx] = tail; \
|
||||
buf->length++; \
|
||||
} \
|
||||
\
|
||||
void name##_extend_arr(name##_t buf, elem_type *ext, size_t ext_len) \
|
||||
{ \
|
||||
name##_ensure_right(buf, buf->length + ext_len); \
|
||||
for (size_t i = 0; i < ext_len; i++) \
|
||||
{ \
|
||||
name##_append(buf, ext[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void name##_extend_buf(name##_t buf, name##_t ext) \
|
||||
{ \
|
||||
name##_ensure_right(buf, buf->length + ext->length); \
|
||||
for (size_t i = 0; i < buf->length; i++) \
|
||||
{ \
|
||||
name##_append(buf, buf->data[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
invsafe_elem_type name##_shift(name##_t buf) \
|
||||
{ \
|
||||
if (buf->length == 0) \
|
||||
{ \
|
||||
return invalid_value; \
|
||||
} \
|
||||
\
|
||||
elem_type f = buf->data[buf->head]; \
|
||||
buf->data[buf->head] = 0; \
|
||||
buf->head++; \
|
||||
buf->length--; \
|
||||
\
|
||||
return f; \
|
||||
} \
|
||||
\
|
||||
void name##_unshift(name##_t buf, elem_type head) \
|
||||
{ \
|
||||
if (buf->head == 0) \
|
||||
{ \
|
||||
size_t old_size = buf->size_left; \
|
||||
size_t new_size = old_size * LIST_GROWTH_RATE + 1; /* +1 to always guarantee an increase */ \
|
||||
\
|
||||
name##_size_expand_left(buf, new_size); \
|
||||
} \
|
||||
\
|
||||
buf->head--; \
|
||||
buf->data[buf->head] = head; \
|
||||
buf->length++; \
|
||||
} \
|
||||
\
|
||||
invsafe_elem_type name##_pop(name##_t buf) \
|
||||
{ \
|
||||
if (buf->length == 0) \
|
||||
{ \
|
||||
return invalid_value; \
|
||||
} \
|
||||
\
|
||||
size_t idx = buf->head + buf->length - 1; \
|
||||
\
|
||||
elem_type l = buf->data[idx]; \
|
||||
\
|
||||
buf->data[idx] = 0; \
|
||||
buf->length--; \
|
||||
\
|
||||
return l; \
|
||||
} \
|
||||
\
|
||||
int name##_compare(name##_t a, name##_t b); \
|
||||
\
|
||||
int name##_equal(name##_t a, name##_t b) \
|
||||
{ \
|
||||
return a->length == b->length && \
|
||||
name##_compare(a, b) == 0; \
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "../char/char.c"
|
||||
#include "./__base__.c"
|
||||
|
||||
HBU_LIST(hbu_list_char, hb_char_t, SIZEOF_CHAR, hb_eod_char_t, HB_EOD);
|
||||
|
||||
int hbu_list_char_compare(hbu_list_char_t a, hbu_list_char_t b) {
|
||||
// All buffers have NULL-terminated underlying char arrays
|
||||
return strcmp((char *) hbu_list_char_underlying(a), (char *) hbu_list_char_underlying(b));
|
||||
}
|
||||
|
||||
int hbu_list_char_compare_lit(hbu_list_char_t a, const char *b) {
|
||||
return strcmp((char *) hbu_list_char_underlying(a), b);
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
#include "../math/math.c"
|
||||
#include "./__base__.c"
|
||||
#include "./char.c"
|
||||
|
||||
HBU_LIST(hbu_list_charlist, hbu_list_char_t, sizeof(hbu_list_char_t), hbu_list_char_t, NULL);
|
||||
|
||||
int hbu_list_charlist_compare(hbu_list_charlist_t a, hbu_list_charlist_t b)
|
||||
{
|
||||
size_t max = hbu_max(a->length, b->length);
|
||||
|
||||
for (size_t i = 0; i < max; i++)
|
||||
{
|
||||
hbu_list_char_t a1 = hbu_list_charlist_get(a, i);
|
||||
hbu_list_char_t b1 = hbu_list_charlist_get(b, i);
|
||||
|
||||
if (a1 == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b1 == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int subcmp = hbu_list_char_compare(a1, b1);
|
||||
if (subcmp != 0)
|
||||
{
|
||||
return subcmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hbu_list_charlist_t hbu_list_charlist_create_from_split(hb_char_t *source, hb_char_t delim)
|
||||
{
|
||||
hbu_list_charlist_t parts = hbu_list_charlist_create();
|
||||
hbu_list_char_t part = hbu_list_char_create();
|
||||
hbu_list_charlist_append(parts, part);
|
||||
|
||||
hb_char_t c;
|
||||
size_t i = 0;
|
||||
while ((c = source[i]))
|
||||
{
|
||||
if (c == delim)
|
||||
{
|
||||
part = hbu_list_char_create();
|
||||
hbu_list_charlist_append(parts, part);
|
||||
}
|
||||
else
|
||||
{
|
||||
hbu_list_char_append(part, c);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
void hbu_list_charlist_destroy_from_split(hbu_list_charlist_t list)
|
||||
{
|
||||
for (size_t i = 0; i < list->length; i++) {
|
||||
hbu_list_char_destroy(hbu_list_charlist_get(list, i));
|
||||
}
|
||||
hbu_list_charlist_destroy(list);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
NICEHASH_MAP_STR(int32, int32_t)
|
|
@ -1 +0,0 @@
|
|||
NICEHASH_MAP_STR(strset, nh_set_str_t)
|
|
@ -1,4 +0,0 @@
|
|||
#define hbu_max(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
|
@ -1,954 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "../../rule/char/ucalpha.c"
|
||||
#include "../char/char.c"
|
||||
#include "../execution/error.c"
|
||||
#include "../list/char.c"
|
||||
#include "../fstream/fstreamin.c"
|
||||
#include "../fstream/fstreamout.c"
|
||||
|
||||
#define HBU_PIPE_MAX_ERR_MSG_LEN 1024
|
||||
|
||||
// Use macro to prevent having to allocate (and therefore free/manage) memory
|
||||
#define HBU_FN_FORMAT_WITH_POS(fn, a, format, ...) fn(a, format " at %s [line %d, column %d]", __VA_ARGS__, pipe->input_name, pipe->line, pipe->column);
|
||||
|
||||
#define HBU_PIPE_THROW(pipe, errcode, format, ...) *hbe_err = hbu_pipe_error(pipe, errcode, format, ##__VA_ARGS__); return 0;
|
||||
#define HBU_PIPE_THROW_V(pipe, errcode, format, ...) *hbe_err = hbu_pipe_error(pipe, errcode, format, ##__VA_ARGS__); return;
|
||||
#define HBU_PIPE_THROW_F(pipe, errcode, format, ...) *hbe_err = hbu_pipe_error(pipe, errcode, format, ##__VA_ARGS__); goto finally;
|
||||
|
||||
typedef int (*hbu_pipe_predicate_t)(hb_char_t);
|
||||
|
||||
typedef hb_eod_char_t (*hbu_pipe_reader_cb_t)(hbe_err_t *hbe_err, void *);
|
||||
typedef void (*hbu_pipe_writer_cb_t)(hbe_err_t *hbe_err, void *, hb_char_t);
|
||||
|
||||
typedef struct hbu_pipe_s {
|
||||
void* input;
|
||||
hbu_pipe_reader_cb_t reader;
|
||||
void *output;
|
||||
hbu_pipe_writer_cb_t writer;
|
||||
|
||||
char *input_name;
|
||||
|
||||
int output_masked;
|
||||
hbu_list_char_t output_redirect;
|
||||
|
||||
hbu_list_char_t buffer;
|
||||
|
||||
int line;
|
||||
int column;
|
||||
int lastCharWasCR;
|
||||
int EOI;
|
||||
} *hbu_pipe_t;
|
||||
|
||||
/*
|
||||
*
|
||||
* MESSAGING
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Logs a debug message with the current position appended.
|
||||
*
|
||||
* @param pipe pipe
|
||||
* @param msg message
|
||||
*/
|
||||
void hbu_pipe_debug(hbu_pipe_t pipe, const char *msg) {
|
||||
HBU_FN_FORMAT_WITH_POS(hbl_log, HBL_LOG_DEBUG, "%s", msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message with the current position appended.
|
||||
*
|
||||
* @param pipe pipe
|
||||
* @param msg message
|
||||
*/
|
||||
void hbu_pipe_warn(hbu_pipe_t pipe, const char *msg) {
|
||||
HBU_FN_FORMAT_WITH_POS(hbl_log, HBL_LOG_WARN, "%s", msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error using a message with the current position appended.
|
||||
*
|
||||
* @param pipe pipe
|
||||
* @param errcode error code
|
||||
* @param reason message
|
||||
* @return error
|
||||
*/
|
||||
hbe_err_t hbu_pipe_error(hbu_pipe_t pipe, hbe_errcode_t errcode, const char *reason, ...) {
|
||||
va_list args;
|
||||
va_start(args, reason);
|
||||
|
||||
char *msg = calloc(HBU_PIPE_MAX_ERR_MSG_LEN + 1, SIZEOF_CHAR);
|
||||
vsnprintf(msg, HBU_PIPE_MAX_ERR_MSG_LEN, reason, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
hbe_err_t err = HBU_FN_FORMAT_WITH_POS(hbe_err_create, errcode, "%s", msg);
|
||||
free(msg);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* INTERNAL FUNCTIONS
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reads from input.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @throws on read error
|
||||
*/
|
||||
static hb_eod_char_t _hbu_pipe_read_from_input(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH((*pipe->reader), pipe->input);
|
||||
if (c == HB_EOD) {
|
||||
pipe->EOI = 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the buffer has loaded at least the next <code>offset</code> characters, or the remaining
|
||||
* characters from input if there are less than <code>offset</code> characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @throws on read error
|
||||
*/
|
||||
static void _hbu_pipe_ensure_buffer(hbe_err_t *hbe_err, hbu_pipe_t pipe, size_t offset) {
|
||||
if (pipe->EOI) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t current = pipe->buffer->length;
|
||||
|
||||
if (offset <= current) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t gap = offset - current;
|
||||
|
||||
for (size_t i = 0; i < gap; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH_V(_hbu_pipe_read_from_input, pipe);
|
||||
if (c == HB_EOD) {
|
||||
// EOI flag already set by _hbu_pipe_read_from_input
|
||||
return;
|
||||
}
|
||||
hbu_list_char_append(pipe->buffer, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next character, whether it's by shifting the buffer or reading from input.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @throws on read error
|
||||
*/
|
||||
static hb_eod_char_t _hbu_pipe_read_from_buffer_or_input(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
if (pipe->EOI) {
|
||||
return HB_EOD;
|
||||
}
|
||||
|
||||
if (pipe->buffer->length) {
|
||||
return hbu_list_char_shift(pipe->buffer);
|
||||
}
|
||||
|
||||
return HBE_CATCH(_hbu_pipe_read_from_input, pipe);
|
||||
}
|
||||
|
||||
static void _hbu_pipe_update_pos(hbu_pipe_t pipe, hb_char_t c) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
pipe->lastCharWasCR = 1;
|
||||
pipe->line++;
|
||||
pipe->column = 0;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if (!pipe->lastCharWasCR) {
|
||||
pipe->line++;
|
||||
pipe->column = 0;
|
||||
} else {
|
||||
pipe->lastCharWasCR = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pipe->column++;
|
||||
pipe->lastCharWasCR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided character is not @{link HB_EOD}, and causes an error otherwise.
|
||||
*
|
||||
* @param c character to test for <code>HB_EOD</code>
|
||||
* @throws HBE_PARSE_UNEXPECTED_END if <code>c</code> is <code>HB_EOD</code>
|
||||
*/
|
||||
static void _hbu_pipe_assert_not_eoi(hbe_err_t *hbe_err, hb_eod_char_t c) {
|
||||
if (c == HB_EOD) {
|
||||
HBE_THROW_V(HBE_PARSE_UNEXPECTED_END, "Unexpected end of input");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character to the redirect, if enabled, otherwise output, of a pipe,
|
||||
* unless the output is masked.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to write
|
||||
* @return a freshly-created pipe
|
||||
* @throws on write error
|
||||
*/
|
||||
static void _hbu_pipe_write_to_output(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
if (!pipe->output_masked) {
|
||||
hbu_list_char_t redirect = pipe->output_redirect;
|
||||
if (redirect != NULL) {
|
||||
hbu_list_char_append(redirect, c);
|
||||
} else {
|
||||
HBE_CATCH_V((*pipe->writer), pipe->output, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* INSTANCE MANAGEMENT FUNCTIONS
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocates memory for a pipe, and creates one with provided arguments.
|
||||
*
|
||||
* @param input input
|
||||
* @param reader reader
|
||||
* @param input_name input_name
|
||||
* @param output output
|
||||
* @param writer writer
|
||||
* @return a freshly-created pipe
|
||||
*/
|
||||
hbu_pipe_t hbu_pipe_create(void *input, hbu_pipe_reader_cb_t reader, char *input_name, void *output, hbu_pipe_writer_cb_t writer) {
|
||||
hbu_pipe_t pipe = malloc(sizeof(struct hbu_pipe_s));
|
||||
pipe->input = input;
|
||||
pipe->reader = reader;
|
||||
pipe->output = output;
|
||||
pipe->writer = writer;
|
||||
|
||||
pipe->input_name = input_name;
|
||||
|
||||
pipe->output_masked = 0;
|
||||
pipe->output_redirect = NULL;
|
||||
|
||||
pipe->buffer = hbu_list_char_create();
|
||||
|
||||
pipe->line = 1;
|
||||
pipe->column = 0;
|
||||
pipe->lastCharWasCR = 0;
|
||||
pipe->EOI = 0; // End Of Input
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all memory associated with a pipe.
|
||||
*
|
||||
* @param pipe pipe
|
||||
*/
|
||||
void hbu_pipe_destroy(hbu_pipe_t pipe) {
|
||||
hbu_list_char_destroy(pipe->buffer);
|
||||
free(pipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the output mask.
|
||||
* When the output mask is enabled, all writes are simply discarded and not actually written to output.
|
||||
*
|
||||
* @param pipe pipe
|
||||
* @param output_masked 1 to enable, 0 to disable
|
||||
* @return previous state
|
||||
*/
|
||||
int hbu_pipe_toggle_output_mask(hbu_pipe_t pipe, int output_masked) {
|
||||
int current = pipe->output_masked;
|
||||
pipe->output_masked = output_masked;
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the output redirect.
|
||||
* When the output redirect is enabled, all writes are written to a buffer instead of the output.
|
||||
*
|
||||
* @param pipe pipe
|
||||
* @param output_redirect buffer to redirect writes to, or NULL to disable
|
||||
*/
|
||||
void hbu_pipe_set_output_redirect(hbu_pipe_t pipe, hbu_list_char_t output_redirect) {
|
||||
pipe->output_redirect = output_redirect;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* BUILDER FUNCTIONS
|
||||
*
|
||||
*/
|
||||
|
||||
hbu_pipe_t hbu_pipe_create_blank(char *input_name) {
|
||||
return hbu_pipe_create(NULL, NULL, input_name, NULL, NULL);
|
||||
}
|
||||
|
||||
void hbu_pipe_blank_set_input_fstreamin(hbu_pipe_t pipe, hbu_fstreamin_t fstreamin) {
|
||||
pipe->input = fstreamin;
|
||||
pipe->reader = (hbu_pipe_reader_cb_t) &hbu_fstreamin_read;
|
||||
}
|
||||
|
||||
// Wrapper function for hbu_list_char_shift to make it compatible with hbu_pipe_reader_cb_t
|
||||
hb_eod_char_t hbu_pipe_read_from_list_char_input(hbe_err_t *hbe_err, hbu_list_char_t input) {
|
||||
(void) hbe_err;
|
||||
return hbu_list_char_shift(input);
|
||||
}
|
||||
|
||||
void hbu_pipe_blank_set_input_buffer(hbu_pipe_t pipe, hbu_list_char_t buf) {
|
||||
pipe->input = buf;
|
||||
pipe->reader = (hbu_pipe_reader_cb_t) &hbu_pipe_read_from_list_char_input;
|
||||
}
|
||||
|
||||
void hbu_pipe_blank_set_output_fstreamout(hbu_pipe_t pipe, hbu_fstreamout_t fstreamout) {
|
||||
pipe->output = fstreamout;
|
||||
pipe->writer = (hbu_pipe_writer_cb_t) &hbu_fstreamout_write;
|
||||
}
|
||||
|
||||
// Wrapper function for hbu_list_char_append to make it compatible with hbu_pipe_writer_cb_t
|
||||
void hbu_pipe_write_to_list_char_output(hbe_err_t *hbe_err, hbu_list_char_t output, hb_char_t c) {
|
||||
(void) hbe_err;
|
||||
hbu_list_char_append(output, c);
|
||||
}
|
||||
|
||||
void hbu_pipe_blank_set_output_buffer(hbu_pipe_t pipe, hbu_list_char_t buf) {
|
||||
pipe->output = buf;
|
||||
pipe->writer = (hbu_pipe_writer_cb_t) &hbu_pipe_write_to_list_char_output;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* CONSUMERS AND PRODUCERS
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the next character.
|
||||
* If it's the end, {@link HB_EOD} is returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return character or {@link HB_EOD}
|
||||
* @throws on read error
|
||||
*/
|
||||
hb_eod_char_t hbu_pipe_peek_eoi(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
// OPTIMISATION: Read directly from buffer if available (no need to unshift later)
|
||||
if (pipe->buffer->length) {
|
||||
return hbu_list_char_get(pipe->buffer, 0);
|
||||
}
|
||||
|
||||
hb_eod_char_t c = HBE_CATCH(_hbu_pipe_read_from_buffer_or_input, pipe);
|
||||
|
||||
if (c != HB_EOD) {
|
||||
hbu_list_char_unshift(pipe->buffer, c);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next character.
|
||||
* Will cause an error if it's the end and there is no next character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_char_t hbu_pipe_peek(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi, pipe);
|
||||
|
||||
HBE_CATCH(_hbu_pipe_assert_not_eoi, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <i>n</i>th character from current, where <i>n</i> is <code>offset</code>.
|
||||
* When <code>offset</code> is 1, the next character is returned (equivalent to {@link hbu_pipe_peek_eoi_offset}).
|
||||
* If <code>offset</code> is after the last character, {@link HB_EOD} is returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param offset position of character to get
|
||||
* @return character or {@link HB_EOD}
|
||||
* @throws on read error
|
||||
*/
|
||||
hb_eod_char_t hbu_pipe_peek_eoi_offset(hbe_err_t *hbe_err, hbu_pipe_t pipe, size_t offset) {
|
||||
HBE_CATCH(_hbu_pipe_ensure_buffer, pipe, offset);
|
||||
|
||||
hb_eod_char_t c = hbu_list_char_get(pipe->buffer, offset - 1);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <i>n</i>th character from current, where <i>n</i> is <code>offset</code>.
|
||||
* When <code>offset</code> is 1, the next character is returned (equivalent to {@link hbu_pipe_peek_offset}).
|
||||
* An error will be caused if <code>offset</code> is after the last character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param offset position of character to get
|
||||
* @return character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_char_t hbu_pipe_peek_offset(hbe_err_t *hbe_err, hbu_pipe_t pipe, size_t offset) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi_offset, pipe, offset);
|
||||
|
||||
HBE_CATCH(_hbu_pipe_assert_not_eoi, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the next sequence of characters is the null-terminated character array <code>match</code>.
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match
|
||||
* @return amount of characters matched, which should be equal to <code>strlen(match)</code>
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hbu_pipe_matches(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
size_t matchlen = strlen(match);
|
||||
|
||||
for (size_t i = 0; i < matchlen; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi_offset, pipe, i + 1);
|
||||
if (c == HB_EOD || c != match[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the next sequence of characters matches the null-terminated character array <code>match</code>
|
||||
* of lowercase characters case-insensitively.
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match case-insensitively
|
||||
* @return amount of characters matched, which should be equal to <code>strlen(match)</code>
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hbu_pipe_matches_i(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
size_t matchlen = strlen(match);
|
||||
|
||||
for (size_t i = 0; i < matchlen; i++) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi_offset, pipe, i + 1);
|
||||
if (!(
|
||||
c != HB_EOD &&
|
||||
(
|
||||
c == match[i] ||
|
||||
(hbr_ucalpha_check(c) && (c + 32) == match[i])
|
||||
)
|
||||
)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return matchlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the next sequence of characters is "\r", "\n", or "\r\n".
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return amount of characters matched
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hbu_pipe_matches_line_terminator(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
// Can't chain into HBE_CATCH(...) || HBE_CATCH(...) || ...
|
||||
// as HBE_CATCH needs auxiliary statement
|
||||
|
||||
// `\r\n` must be before `\r`
|
||||
size_t crlf = HBE_CATCH(hbu_pipe_matches, pipe, "\r\n");
|
||||
if (crlf) return crlf;
|
||||
|
||||
size_t cr = HBE_CATCH(hbu_pipe_matches, pipe, "\r");
|
||||
if (cr) return cr;
|
||||
|
||||
return HBE_CATCH(hbu_pipe_matches, pipe, "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the next character.
|
||||
* Will cause an error if already at end.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return next character
|
||||
* @throws on read/write error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_char_t hbu_pipe_accept(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(_hbu_pipe_read_from_buffer_or_input, pipe);
|
||||
|
||||
HBE_CATCH(_hbu_pipe_assert_not_eoi, c);
|
||||
|
||||
_hbu_pipe_update_pos(pipe, c);
|
||||
|
||||
HBE_CATCH(_hbu_pipe_write_to_output, pipe, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the next <code>count</code> characters.
|
||||
* Requires at least <code>count</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param count amount of characters
|
||||
* @throws on read/write error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
void hbu_pipe_accept_count(hbe_err_t *hbe_err, hbu_pipe_t pipe, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following character if it is <code>c</code>.
|
||||
* Won't match or cause an error if there are no characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hbu_pipe_accept_if(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
hb_eod_char_t n = HBE_CATCH(hbu_pipe_peek_eoi, pipe);
|
||||
|
||||
if (n == HB_EOD || n != c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hbu_pipe_accept, pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following characters if they match <code>match</code>.
|
||||
* Won't match or cause an error if there are not enough characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match characters to match
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hbu_pipe_accept_if_matches(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
size_t matchedlen = HBE_CATCH(hbu_pipe_matches, pipe, match);
|
||||
|
||||
int matched = matchedlen > 0;
|
||||
|
||||
if (matched) {
|
||||
HBE_CATCH(hbu_pipe_accept_count, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following characters if they are either "\r", "\r\n", or "\n".
|
||||
* Won't cause an error if insufficient amount of characters left.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return amount of characters matched
|
||||
* @throws on read/write error
|
||||
*/
|
||||
size_t hbu_pipe_accept_if_matches_line_terminator(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
size_t matchedlen = HBE_CATCH(hbu_pipe_matches_line_terminator, pipe);
|
||||
|
||||
if (matchedlen) {
|
||||
HBE_CATCH(hbu_pipe_accept_count, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matchedlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the following character if it satisfies the predicate <code>pred</code>.
|
||||
* Won't do anything if already at the end.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return 0 if nothing was accepted, 1 otherwise
|
||||
* @throws on read/write error
|
||||
*/
|
||||
int hbu_pipe_accept_if_predicate(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_pipe_predicate_t pred) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi, pipe);
|
||||
|
||||
if (c == HB_EOD || !(*pred)(c)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hbu_pipe_accept, pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts every following character until one dissatisfies the predicate <code>pred</code>,
|
||||
* or the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return amount of characters accepted
|
||||
* @throws on read/write error
|
||||
*/
|
||||
size_t hbu_pipe_accept_while_predicate(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_pipe_predicate_t pred) {
|
||||
size_t count = 0;
|
||||
|
||||
while (1) {
|
||||
int matched = HBE_CATCH(hbu_pipe_accept_if_predicate, pipe, pred);
|
||||
if (!matched) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the next character.
|
||||
* Requires that the file has at least one character remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @return skipped character
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
hb_char_t hbu_pipe_skip(hbe_err_t *hbe_err, hbu_pipe_t pipe) {
|
||||
hb_eod_char_t c = HBE_CATCH(_hbu_pipe_read_from_buffer_or_input, pipe);
|
||||
|
||||
HBE_CATCH(_hbu_pipe_assert_not_eoi, c);
|
||||
|
||||
_hbu_pipe_update_pos(pipe, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the next <code>amount</code> characters.
|
||||
* Requires that the file has at least <code>amount</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param amount amount of characters to skip
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
void hbu_pipe_skip_amount(hbe_err_t *hbe_err, hbu_pipe_t pipe, size_t amount) {
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
HBE_CATCH_V(hbu_pipe_skip, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the following character if it is <code>c</code>.
|
||||
* Won't cause an error if the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to skip if next
|
||||
* @return 1 if skipped, 0 otherwise
|
||||
* @throws on read error
|
||||
*/
|
||||
int hbu_pipe_skip_if(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
hb_eod_char_t n = HBE_CATCH(hbu_pipe_peek_eoi, pipe);
|
||||
|
||||
if (n == HB_EOD || n != c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HBE_CATCH(hbu_pipe_skip, pipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over every following character until one dissatisfies the predicate <code>pred</code>,
|
||||
* or the end is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @return amount of characters skipped
|
||||
* @throws on read error
|
||||
*/
|
||||
size_t hbu_pipe_skip_while_predicate(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_pipe_predicate_t pred) {
|
||||
size_t count = 0;
|
||||
|
||||
while (1) {
|
||||
hb_eod_char_t c = HBE_CATCH(hbu_pipe_peek_eoi, pipe);
|
||||
|
||||
if (c == HB_EOD || !(*pred)(c)) {
|
||||
break;
|
||||
}
|
||||
|
||||
HBE_CATCH(hbu_pipe_skip, pipe);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over the next sequence of characters if they are <code>match</code>.
|
||||
* Requires that the file has at least the length of <code>match</code> characters remaining.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to match
|
||||
* @return 0 if not matched, 1 otherwise
|
||||
* @throws on read error or HBE_PARSE_UNEXPECTED_END
|
||||
*/
|
||||
int hbu_pipe_skip_if_matches(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
size_t matchedlen = HBE_CATCH(hbu_pipe_matches, pipe, match);
|
||||
|
||||
int matched = matchedlen > 0;
|
||||
|
||||
if (matched) {
|
||||
HBE_CATCH(hbu_pipe_skip_amount, pipe, matchedlen);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to be <code>c</code>.
|
||||
* The matched character is written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hbu_pipe_require(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
hb_char_t n = HBE_CATCH_V(hbu_pipe_accept, pipe);
|
||||
|
||||
if (c != n) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%c` (0x%x), got `%c` (0x%x)", c, c, n, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to be <code>c</code>.
|
||||
* The matched character is skipped over and NOT written to output, and also returned.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character to match
|
||||
* @return matched character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_char_t hbu_pipe_require_skip(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
hb_char_t n = HBE_CATCH(hbu_pipe_skip, pipe);
|
||||
|
||||
if (c != n) {
|
||||
HBU_PIPE_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%c` (0x%x), got `%c` (0x%x) at %s", c, c, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to satisfy the predicate <code>pred</code>.
|
||||
* The matched character is written to output.
|
||||
* If not matched, the error message will describe the expected output using <code>name</code>.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @param name what to output in the error message to describe the requirement
|
||||
* @return required character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_char_t hbu_pipe_require_predicate(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_pipe_predicate_t pred, const char *name) {
|
||||
hb_char_t n = HBE_CATCH(hbu_pipe_accept, pipe);
|
||||
|
||||
if (!(*pred)(n)) {
|
||||
HBU_PIPE_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected %s, got `%c` (0x%x)", name, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next character to satisfy the predicate <code>pred</code>.
|
||||
* The matched character is skipped over and NOT written to output.
|
||||
* If not matched, the error message will describe the expected output using <code>name</code>.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param pred predicate
|
||||
* @param name what to output in the error message to describe the requirement
|
||||
* @return required character
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
hb_char_t hbu_pipe_require_skip_predicate(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_pipe_predicate_t pred, const char *name) {
|
||||
hb_char_t n = HBE_CATCH(hbu_pipe_skip, pipe);
|
||||
|
||||
if (!(*pred)(n)) {
|
||||
HBU_PIPE_THROW(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected %s, got `%c` (0x%x)", name, n, n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next sequence of characters to be equal to <code>match</code>.
|
||||
* Matched characters are written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to require
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hbu_pipe_require_match(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
int matches = HBE_CATCH_V(hbu_pipe_accept_if_matches, pipe, match);
|
||||
if (!matches) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%s`", match);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the next sequence of characters to be equal to <code>match</code>.
|
||||
* Matched characters are skipped over and NOT written to output.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param match sequence of characters to require
|
||||
* @throws on read/write error, HBE_PARSE_UNEXPECTED_END, or HBE_PARSE_EXPECTED_NOT_FOUND
|
||||
*/
|
||||
void hbu_pipe_require_skip_match(hbe_err_t *hbe_err, hbu_pipe_t pipe, const char *match) {
|
||||
int matches = HBE_CATCH_V(hbu_pipe_skip_if_matches, pipe, match);
|
||||
if (!matches) {
|
||||
HBU_PIPE_THROW_V(pipe, HBE_PARSE_EXPECTED_NOT_FOUND, "Expected `%s`", match);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param c character
|
||||
* @throws on write error
|
||||
*/
|
||||
void hbu_pipe_write(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t c) {
|
||||
HBE_CATCH_V(_hbu_pipe_write_to_output, pipe, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character array until a NUL character is reached.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param str null-terminated character array
|
||||
* @throws on write error
|
||||
*/
|
||||
void hbu_pipe_write_str(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t *str) {
|
||||
hb_char_t c;
|
||||
for (size_t i = 0; (c = str[i]); i++) {
|
||||
HBE_CATCH_V(_hbu_pipe_write_to_output, pipe, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes <code>len</code> characters from the beginning of a character array.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param str character array
|
||||
* @param len amount of characters to write
|
||||
* @throws on write error
|
||||
*/
|
||||
void hbu_pipe_write_str_len(hbe_err_t *hbe_err, hbu_pipe_t pipe, hb_char_t *str, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
HBE_CATCH_V(_hbu_pipe_write_to_output, pipe, str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a buffer.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param buffer buffer
|
||||
* @throws on write error
|
||||
*/
|
||||
void hbu_pipe_write_buffer(hbe_err_t *hbe_err, hbu_pipe_t pipe, hbu_list_char_t buffer) {
|
||||
for (size_t i = 0; i < buffer->length; i++) {
|
||||
HBE_CATCH_V(_hbu_pipe_write_to_output, pipe, hbu_list_char_get(buffer, i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character from its Unicode code point in UTF-8 encoding, which may be multiple bytes.
|
||||
*
|
||||
* @param hbe_err pointer to hbe_err_t
|
||||
* @param pipe pipe
|
||||
* @param code_point Unicode code point
|
||||
* @return amount of bytes written (0 if invalid code point)
|
||||
* @throws on write error
|
||||
*/
|
||||
// Logic copied from https://gist.github.com/MightyPork/52eda3e5677b4b03524e40c9f0ab1da5
|
||||
int hbu_pipe_write_unicode(hbe_err_t *hbe_err, hbu_pipe_t pipe, uint32_t code_point) {
|
||||
if (code_point <= 0x7F) {
|
||||
// Plain ASCII
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) code_point);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (code_point <= 0x07FF) {
|
||||
// 2-byte unicode
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 6) & 0x1F) | 0xC0));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (code_point <= 0xFFFF) {
|
||||
// 3-byte unicode
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 12) & 0x0F) | 0xE0));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 6) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (code_point <= 0x10FFFF) {
|
||||
// 4-byte unicode
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 18) & 0x07) | 0xF0));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 12) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 6) & 0x3F) | 0x80));
|
||||
HBE_CATCH(hbu_pipe_write, pipe, (hb_char_t) (((code_point >> 0) & 0x3F) | 0x80));
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue