diff options
Diffstat (limited to '')
-rw-r--r-- | src/mds-kbdc/process-includes.c | 149 |
1 files changed, 145 insertions, 4 deletions
diff --git a/src/mds-kbdc/process-includes.c b/src/mds-kbdc/process-includes.c index 0b068f1..1e9c5ff 100644 --- a/src/mds-kbdc/process-includes.c +++ b/src/mds-kbdc/process-includes.c @@ -17,7 +17,20 @@ */ #include "process-includes.h" +#include "make-tree.h" +#include "simplify-tree.h" +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + + + +/** + * Tree type constant shortener + */ +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error the to error list @@ -38,20 +51,148 @@ */ static mds_kbdc_parse_error_t* error; +/** + * The parameter of `process_includes` + */ +static mds_kbdc_parsed_t* restrict result; + /** - * Include included files and process them upto this level + * Process an include-statement * - * @param result `result` from `simplify_tree`, will be updated - * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise + * @param tree The include-statement + * @return Zero on success, -1 on error */ -int process_includes(mds_kbdc_parsed_t* restrict result) +static int process_include(mds_kbdc_tree_include_t* restrict tree) { +#define process(expr) \ + fail_if ((expr) < 0); \ + if (mds_kbdc_parsed_is_fatal(&subresult)) \ + goto stop; + + mds_kbdc_parsed_t subresult; + mds_kbdc_parsed_t* our_result; + char* dirname = NULL; + char* cwd = NULL; + char* old = NULL; + size_t cwd_size = 4096 >> 1; + int saved_errno; + + /* Initialise result structure for the included file. */ + mds_kbdc_parsed_initialise(&subresult); + + /* Get dirname of current file. */ + fail_if ((dirname = strdup(result->pathname)) == NULL); + *(strrchr(dirname, '/')) = '\0'; + + /* Get the current working directory. */ + /* glibc offers ways to do this in just one function call, + * but we will not assume that glibc is used here. */ + for (;;) + { + fail_if (!xxrealloc(old, cwd, cwd_size <<= 1, char)); + if (getcwd(cwd, cwd_size)) + break; + else + fail_if (errno != ERANGE); + } + + /* Switch working directory. */ + fail_if (chdir(dirname)); + free(dirname), dirname = NULL; + + /* Store `result` as it will be switched by the inner `process_includes`. */ + our_result = result; + + /* Process include. */ + process (parse_to_tree(tree->filename, &subresult)); + process (simplify_tree(&subresult)); + process (process_includes(&subresult)); + stop: + + /* Switch back `result`. */ + result = our_result; + + /* Switch back to the old working directory. */ + fail_if (chdir(cwd)); + free(cwd), cwd = NULL; + + /* Move over data to our result. */ + free(tree->filename); + tree->filename = subresult.pathname, subresult.pathname = NULL; + tree->inner = subresult.tree, subresult.tree = NULL; + if (result->severest_error_level < subresult.severest_error_level) + result->severest_error_level = subresult.severest_error_level; + + /* Move over errors. */ + /* TODO */ + + /* Release resources. */ + mds_kbdc_parsed_destroy(&subresult); + return 0; + pfail: + saved_errno = errno; + free(dirname); + free(cwd); + free(old); + mds_kbdc_parsed_destroy(&subresult); + return errno = saved_errno, -1; +#undef process +} + + +/** + * Process a subtree + * + * @param tree The tree + * @return Zero on success, -1 on error + */ +static int process_includes_in_tree(mds_kbdc_tree_t* restrict tree) +{ +#define p(expr) if ((r = process_includes_in_tree(tree->expr))) return r + int r; + again: + if (tree == NULL) + return 0; + + switch (tree->type) + { + case C(INFORMATION): p (information.inner); break; + case C(FUNCTION): p (function.inner); break; + case C(MACRO): p (macro.inner); break; + case C(ASSUMPTION): p (assumption.inner); break; + case C(FOR): p (for_.inner); break; + case C(IF): p (if_.inner); p (if_.otherwise); break; + case C(INCLUDE): + if ((r = process_include(&(tree->include)))) + return r; + break; + default: + break; + } + + tree = tree->next; + goto again; +#undef p +} + + +/** + * Include included files and process them upto this level + * + * @param result_ `result` from `simplify_tree`, will be updated + * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise + */ +int process_includes(mds_kbdc_parsed_t* restrict result_) +{ + result = result_; + return process_includes_in_tree(result_->tree); } #undef NEW_ERROR +#undef C |