aff5a58f0f9901940af1cf443b44dd0007c76a34 — Simon Ser 5 months ago 51d24f3
parser: handle `$` followed by invalid char more gracefully

e.g. `$ ` and `$\n`

POSIX says it's undefined behaviour.

Closes: https://github.com/emersion/mrsh/issues/13
1 files changed, 32 insertions(+), 3 deletions(-)

M parser/word.c
M parser/word.c => parser/word.c +32 -3
@@ 383,8 383,9 @@
 	assert(c == '$');
 
 	struct mrsh_word_parameter *wp;
-	switch (parser_peek_char(state)) {
-	case '{':; // Parameter expansion in the form `${expression}`
+	c = parser_peek_char(state);
+	switch (c) {
+	case '{': // Parameter expansion in the form `${expression}`
 		wp = expect_parameter_expression(state);
 		if (wp == NULL) {
 			return NULL;


@@ 414,7 415,35 @@
 	default:; // Parameter expansion in the form `$parameter`
 		size_t name_len = peek_name(state, false);
 		if (name_len == 0) {
-			name_len = 1;
+			bool ok = false;
+			switch (c) {
+			case '@':
+			case '*':
+			case '#':
+			case '?':
+			case '-':
+			case '$':
+			case '!':
+				ok = true;
+				break;
+			default:
+				ok = isdigit(c);
+			}
+			if (ok) {
+				name_len = 1;
+			} else {
+				// 2.6. If an unquoted '$' is followed by a character that is
+				// not one of the following […] the result is unspecified.
+				char str[] = {'$', c, '\0'};
+				struct mrsh_word_string *ws =
+					mrsh_word_string_create(strdup(str), false);
+				if (ws == NULL) {
+					return NULL;
+				}
+				ws->range.begin = dollar_pos;
+				ws->range.end = state->pos;
+				return &ws->word;
+			}
 		}
 
 		struct mrsh_range name_range;