diff options
Diffstat (limited to '')
-rw-r--r-- | doc/info/mds.texinfo | 4 | ||||
-rw-r--r-- | src/mds-kbdc/make-tree.c | 29 | ||||
-rw-r--r-- | src/mds-kbdc/process-includes.c | 30 | ||||
-rw-r--r-- | src/mds-kbdc/raw-data.c | 104 | ||||
-rw-r--r-- | src/mds-kbdc/raw-data.h | 9 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/invalid/_error | 2 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/invalid/include_error | 31 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/invalid/include_nonexisting | 11 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/valid/_empty | 0 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/valid/_mapping | 2 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/valid/include_empty_file | 11 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/valid/include_include_empty_file | 18 | ||||
-rw-r--r-- | test-files/mds-kbdc/process-includes/valid/include_mapping | 16 |
13 files changed, 256 insertions, 11 deletions
diff --git a/doc/info/mds.texinfo b/doc/info/mds.texinfo index a4bb672..d2da0c4 100644 --- a/doc/info/mds.texinfo +++ b/doc/info/mds.texinfo @@ -5900,6 +5900,10 @@ two zeroes, you do not write `\100' as that would expand to the value of the hundredth variable. Instead you write `\1.00'. +Use of function calls and variables inside +@code{include}-statments invokes undefined behaviour. +Escaped numerals greater than or equal to the 31th +power of 2 also invoke undefined behaviour. @node Builtin Functions diff --git a/src/mds-kbdc/make-tree.c b/src/mds-kbdc/make-tree.c index fab402b..5c644b4 100644 --- a/src/mds-kbdc/make-tree.c +++ b/src/mds-kbdc/make-tree.c @@ -662,6 +662,9 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res size_t line_i, line_n; const char** keyword_stack = NULL; mds_kbdc_tree_t*** tree_stack = NULL; + char* cwd = NULL; + char* old = NULL; + size_t cwd_size = 4096 >> 1; size_t stack_ptr = 0; int saved_errno, in_array = 0; @@ -672,7 +675,29 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res * can be misleading as the program can have changed working * directory to be able to resolve filenames. */ result->pathname = realpath(filename, NULL); /* XXX use absolute path */ - fail_if (result->pathname == NULL); + if (result->pathname == NULL) + { + fail_if (errno != ENOENT); + saved_errno = errno; + + /* 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); + } + + result->pathname = strdup(filename); + fail_if (result->pathname == NULL); + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); + free(cwd); + return 0; + } /* Check that the file exists and can be read. */ if (access(result->pathname, R_OK) < 0) @@ -1043,6 +1068,8 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res saved_errno = errno; free(keyword_stack); free(tree_stack); + free(cwd); + free(old); return errno = saved_errno, -1; } diff --git a/src/mds-kbdc/process-includes.c b/src/mds-kbdc/process-includes.c index 9677671..8c4bbbf 100644 --- a/src/mds-kbdc/process-includes.c +++ b/src/mds-kbdc/process-includes.c @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "process-includes.h" +/* TODO we need to deal with mutually recursive includes */ #include "make-tree.h" #include "simplify-tree.h" @@ -68,26 +69,34 @@ static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_ { mds_kbdc_parse_error_t** errors = NULL; mds_kbdc_parse_error_t* suberror; - size_t errors_ptr = 0, i; + size_t errors_ptr = 0; int saved_errno; - /* List errors backwards, so that we can easily insert “included from here”-notes. */ + /* Allocate temporary list for errors. */ + if (subresult->errors_ptr == 0) + return 0; fail_if (xmalloc(errors, subresult->errors_ptr * 2, mds_kbdc_parse_error_t*)); + + /* List errors backwards, so that we can easily handle errors and add “included from here”-note. */ while (subresult->errors_ptr--) { suberror = subresult->errors[subresult->errors_ptr]; + + /* If it is more severe than a note, we want to say there it was included. */ if (suberror->severity > MDS_KBDC_PARSE_ERROR_NOTE) { NEW_ERROR(tree, NOTE, "included from here"); errors[errors_ptr++] = error; result->errors[--(result->errors_ptr)] = NULL; } + + /* Include error. */ errors[errors_ptr++] = suberror; subresult->errors[subresult->errors_ptr] = NULL; } /* Append errors. */ - for (i = 0; i < errors_ptr; errors[i++] = NULL) + for (; errors_ptr--; errors[errors_ptr] = NULL) { if (result->errors_ptr + 1 >= result->errors_size) { @@ -98,8 +107,8 @@ static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_ result->errors = new_errors; result->errors_size = new_errors_size; } - - result->errors[result->errors_ptr++] = errors[i]; + + result->errors[result->errors_ptr++] = errors[errors_ptr]; result->errors[result->errors_ptr] = NULL; } @@ -108,10 +117,7 @@ static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_ pfail: saved_errno = errno; while (errors_ptr--) - if (errors[errors_ptr] == NULL) - break; - else - mds_kbdc_parse_error_free(errors[errors_ptr]); + mds_kbdc_parse_error_free(errors[errors_ptr]); free(errors); return errno = saved_errno, -1; } @@ -150,7 +156,7 @@ static int process_include(mds_kbdc_tree_include_t* restrict tree) * but we will not assume that glibc is used here. */ for (;;) { - fail_if (!xxrealloc(old, cwd, cwd_size <<= 1, char)); + fail_if (xxrealloc(old, cwd, cwd_size <<= 1, char)); if (getcwd(cwd, cwd_size)) break; else @@ -165,6 +171,10 @@ static int process_include(mds_kbdc_tree_include_t* restrict tree) our_result = result; /* Process include. */ + old = tree->filename, tree->filename = NULL; + tree->filename = parse_raw_string(old); + fail_if (tree->filename == NULL); + free(old), old = NULL; process (parse_to_tree(tree->filename, &subresult)); process (simplify_tree(&subresult)); process (process_includes(&subresult)); diff --git a/src/mds-kbdc/raw-data.c b/src/mds-kbdc/raw-data.c index b0985fe..1803cd5 100644 --- a/src/mds-kbdc/raw-data.c +++ b/src/mds-kbdc/raw-data.c @@ -18,6 +18,7 @@ #include "raw-data.h" #include "globals.h" +#include "string.h" #include <libmdsserver/macros.h> @@ -29,6 +30,7 @@ #include <unistd.h> #include <stdio.h> #include <string.h> +#include <stdint.h> @@ -54,6 +56,8 @@ void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this) */ void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) { + if (this == NULL) + return; free(this->lines), this->lines = NULL; free(this->real_lines), this->real_lines = NULL; free(this->content), this->content = NULL; @@ -68,6 +72,8 @@ void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) */ void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this) { + if (this == NULL) + return; free(this->lines); free(this->real_lines); free(this->content); @@ -371,3 +377,101 @@ int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* res return -1; } + +/** + * Encode a character in UTF-8 + * + * @param buffer The buffer where the character should be stored + * @param character The character + * @return The of the character in `buffer`, `NULL` on error + */ +static char* encode_utf8(char* buffer, char32_t character) +{ + char32_t text[2]; + char* restrict str; + char* restrict str_; + + text[0] = character; + text[1] = -1; + + if (str_ = str = string_encode(text), str == NULL) + return NULL; + + while (*str) + *buffer++ = *str++; + + free(str_); + return buffer; +} + + +/** + * Parse a quoted and escaped string that may not include function calls or variable dereferences + * + * @param string The string + * @return The string in machine-readable format, `NULL` on error + */ +char* parse_raw_string(const char* restrict string) +{ +#define r(lower, upper) (((lower) <= c) && (c <= (upper))) + + char* rc; + char* p; + int escape = 0; + char32_t buf; + + /* We know that the output string can only be shorter because + * it is surrounded by 2 quotes and escape can only be longer + * then what they escape, for example \uA0, is four characters, + * but when parsed it generateds 2 bytes in UTF-8, and their + * is not code point whose UTF-8 encoding is longer than its + * hexadecimal representation. */ + p = rc = malloc(strlen(string) * sizeof(char)); + if (rc == NULL) + return NULL; + + while (*string) + { + char c = *string++; + + if (escape > 1) + { + if ((escape == 8) && r('0', '7')) buf = (buf << 3) | (c & 15); + else if ((escape == 16) && r('0', '9')) buf = (buf << 4) | (c & 15); + else if ((escape == 16) && r('a', 'f')) buf = (buf << 4) | ((c & 15) + 9); + else if ((escape == 16) && r('A', 'F')) buf = (buf << 4) | ((c & 15) + 9); + else + goto end_of_escape; + continue; + end_of_escape: + escape = 0; + p = encode_utf8(p, buf); + if (p == NULL) + goto fail; + if (c != '.') + *p++ = c; + } + else if (escape == 1) + { + escape = 0, buf = 0; + switch (c) + { + case '0': escape = 8; break; + case 'u': escape = 16; break; + default: *p++ = c; break; + } + } + else if (c == '\\') + escape = 1; + else if (c != '\"') + *p++ = c; + } + + *p = '\0'; + return rc; + fail: + free(rc); + return NULL; +#undef r +} + diff --git a/src/mds-kbdc/raw-data.h b/src/mds-kbdc/raw-data.h index 4bc7355..a2f1edc 100644 --- a/src/mds-kbdc/raw-data.h +++ b/src/mds-kbdc/raw-data.h @@ -104,5 +104,14 @@ size_t get_end_of_call(char* restrict content, size_t offset, size_t size) __att int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* restrict source_code); +/** + * Parse a quoted and escaped string that may not include function calls or variable dereferences + * + * @param string The string + * @return The string in machine-readable format, `NULL` on error + */ +char* parse_raw_string(const char* restrict string); + + #endif diff --git a/test-files/mds-kbdc/process-includes/invalid/_error b/test-files/mds-kbdc/process-includes/invalid/_error new file mode 100644 index 0000000..aa42b42 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/invalid/_error @@ -0,0 +1,2 @@ +[.] + diff --git a/test-files/mds-kbdc/process-includes/invalid/include_error b/test-files/mds-kbdc/process-includes/invalid/include_error new file mode 100644 index 0000000..cec9385 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/invalid/include_error @@ -0,0 +1,31 @@ +include "_error" + +# (include (@ 1 0-7) ‘/home/mattias/git/mds/test-files/mds-kbdc/process-includes/invalid/_error’ +# (.inner +# (map (@ 1 0-0) +# (.sequence +# (nothing (@ 1 1-2)) +# ) +# (.result nil) +# ) +# ) +# ) +# .../test-files/mds-kbdc/process-includes/invalid/_error:1:0–1: warning: alternated value statement is undefined unless the alternatives are identical +# [.] +# ^ +# .../test-files/mds-kbdc/process-includes/invalid/include_error:1:0–7: note: included from here +# include "_error" +# ^^^^^^^ +# .../test-files/mds-kbdc/process-includes/invalid/_error:1:0–1: warning: singleton alternation +# [.] +# ^ +# .../test-files/mds-kbdc/process-includes/invalid/include_error:1:0–7: note: included from here +# include "_error" +# ^^^^^^^ +# .../test-files/mds-kbdc/process-includes/invalid/_error:1:1–2: error: nothing in value statement +# [.] +# ^ +# .../test-files/mds-kbdc/process-includes/invalid/include_error:1:0–7: note: included from here +# include "_error" +# ^^^^^^^ + diff --git a/test-files/mds-kbdc/process-includes/invalid/include_nonexisting b/test-files/mds-kbdc/process-includes/invalid/include_nonexisting new file mode 100644 index 0000000..9ff0f5c --- /dev/null +++ b/test-files/mds-kbdc/process-includes/invalid/include_nonexisting @@ -0,0 +1,11 @@ +include "this file does not exist" + +# (include (@ 1 0-7) ‘this file does not exist’ +# (.inner nil) +# ) +# this file does not exist: error: no such file or directory in ‘.../test-files/mds-kbdc/process-includes/invalid’ +# +# .../test-files/mds-kbdc/process-includes/invalid/include_nonexisting:1:0–7: note: included from here +# include "this file does not exist" +# ^^^^^^^ + diff --git a/test-files/mds-kbdc/process-includes/valid/_empty b/test-files/mds-kbdc/process-includes/valid/_empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/valid/_empty diff --git a/test-files/mds-kbdc/process-includes/valid/_mapping b/test-files/mds-kbdc/process-includes/valid/_mapping new file mode 100644 index 0000000..6026f43 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/valid/_mapping @@ -0,0 +1,2 @@ +<dead letter ´> "e" : "é" + diff --git a/test-files/mds-kbdc/process-includes/valid/include_empty_file b/test-files/mds-kbdc/process-includes/valid/include_empty_file new file mode 100644 index 0000000..c784768 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/valid/include_empty_file @@ -0,0 +1,11 @@ +include "_empty" + +# (include (@ 1 0-7) ‘.../test-files/mds-kbdc/process-includes/valid/_empty’ +# (.inner nil) +# ) +# .../test-files/mds-kbdc/process-includes/valid/_empty: warning: file is empty +# +# .../test-files/mds-kbdc/process-includes/valid/include_empty_file:1:0–7: note: included from here +# include "_empty" +# ^^^^^^^ + diff --git a/test-files/mds-kbdc/process-includes/valid/include_include_empty_file b/test-files/mds-kbdc/process-includes/valid/include_include_empty_file new file mode 100644 index 0000000..9b8e1c1 --- /dev/null +++ b/test-files/mds-kbdc/process-includes/valid/include_include_empty_file @@ -0,0 +1,18 @@ +include "include_empty_file" + +# (include (@ 1 0-7) ‘.../test-files/mds-kbdc/process-includes/valid/include_empty_file’ +# (.inner +# (include (@ 1 0-7) ‘.../test-files/mds-kbdc/process-includes/valid/_empty’ +# (.inner nil) +# ) +# ) +# ) +# .../test-files/mds-kbdc/process-includes/valid/_empty: warning: file is empty +# +# .../test-files/mds-kbdc/process-includes/valid/include_include_empty_file:1:0–7: note: included from here +# include "include_empty_file" +# ^^^^^^^ +# .../test-files/mds-kbdc/process-includes/valid/include_empty_file:1:0–7: note: included from here +# include "_empty" +# ^^^^^^^ + diff --git a/test-files/mds-kbdc/process-includes/valid/include_mapping b/test-files/mds-kbdc/process-includes/valid/include_mapping new file mode 100644 index 0000000..e9d531f --- /dev/null +++ b/test-files/mds-kbdc/process-includes/valid/include_mapping @@ -0,0 +1,16 @@ +include "_mapping" + +# (include (@ 1 0-7) ‘/home/mattias/git/mds/test-files/mds-kbdc/process-includes/valid/_mapping’ +# (.inner +# (map (@ 1 0-0) +# (.sequence +# (keys (@ 1 0-16) ‘<dead letter ´>’) +# (string (@ 1 17-20) ‘"e"’) +# ) +# (.result +# (string (@ 1 23-27) ‘"é"’) +# ) +# ) +# ) +# ) + |