Various mostly safety fixes
This commit is contained in:
parent
5963b99c3e
commit
365d6e69e1
|
@ -47,7 +47,7 @@ Runtime
|
||||||
-------
|
-------
|
||||||
All variables are put in a single global namespace with no further scoping.
|
All variables are put in a single global namespace with no further scoping.
|
||||||
When calling a command (which is a list of lists), all arguments are
|
When calling a command (which is a list of lists), all arguments are
|
||||||
automatically stored in variables named 1, 2, 3, ... n. They are however
|
automatically stored in variables named 0, 1, 2, 3, ... n. They are however
|
||||||
effectively inaccessible and you must rename them first using the `arg` special
|
effectively inaccessible and you must rename them first using the `arg` special
|
||||||
form.
|
form.
|
||||||
|
|
||||||
|
|
58
ell.c
58
ell.c
|
@ -270,8 +270,10 @@ lexer_free (struct lexer *self) {
|
||||||
free (self->string.s);
|
free (self->string.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: other isspace() stuff is missing
|
static bool lexer_is_ignored (int c) { return c == ' ' || c == '\t'; }
|
||||||
static bool lexer_is_word_char (int c) { return !strchr ("()[]{}\n@#' ", c); }
|
static bool lexer_is_word_char (int c) {
|
||||||
|
return !lexer_is_ignored (c) && !strchr ("()[]{}\n@#' ", c);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lexer_advance (struct lexer *self) {
|
lexer_advance (struct lexer *self) {
|
||||||
|
@ -286,11 +288,10 @@ lexer_advance (struct lexer *self) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lexer_error (struct lexer *self, char **e, const char *fmt, ...)
|
static bool lexer_error (struct lexer *self, char **e, const char *fmt, ...)
|
||||||
ATTRIBUTE_PRINTF (3, 4);
|
ATTRIBUTE_PRINTF (3, 4);
|
||||||
|
|
||||||
// TODO: see "script", we can just use error constants to avoid allocation
|
static bool
|
||||||
static void
|
|
||||||
lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
|
lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, fmt);
|
va_start (ap, fmt);
|
||||||
|
@ -300,11 +301,12 @@ lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
|
||||||
*e = format ("near line %u, column %u: %s",
|
*e = format ("near line %u, column %u: %s",
|
||||||
self->line + 1, self->column + 1, description);
|
self->line + 1, self->column + 1, description);
|
||||||
|
|
||||||
// TODO: see above, we should be able to indicate error without allocation
|
// TODO: see "script", we can just use error constants to avoid allocation
|
||||||
if (!*e)
|
if (!*e)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
free (description);
|
free (description);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -333,10 +335,8 @@ lexer_hexa_escape (struct lexer *self, struct buffer *output) {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
|
lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
|
||||||
if (!self->len) {
|
if (!self->len)
|
||||||
lexer_error (self, e, "premature end of escape sequence");
|
return lexer_error (self, e, "premature end of escape sequence");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char c = *self->p;
|
unsigned char c = *self->p;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -356,12 +356,10 @@ lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
|
||||||
if (lexer_hexa_escape (self, output))
|
if (lexer_hexa_escape (self, output))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
lexer_error (self, e, "invalid hexadecimal escape");
|
return lexer_error (self, e, "invalid hexadecimal escape");
|
||||||
return false;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
lexer_error (self, e, "unknown escape sequence");
|
return lexer_error (self, e, "unknown escape sequence");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_append_c (output, c);
|
buffer_append_c (output, c);
|
||||||
|
@ -380,14 +378,13 @@ lexer_string (struct lexer *self, struct buffer *output, char **e) {
|
||||||
else if (!lexer_escape_sequence (self, output, e))
|
else if (!lexer_escape_sequence (self, output, e))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lexer_error (self, e, "premature end of string");
|
return lexer_error (self, e, "premature end of string");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum token
|
static enum token
|
||||||
lexer_next (struct lexer *self, char **e) {
|
lexer_next (struct lexer *self, char **e) {
|
||||||
// Skip over any whitespace between tokens
|
// Skip over any whitespace between tokens
|
||||||
while (self->len && isspace (*self->p) && *self->p != '\n')
|
while (self->len && lexer_is_ignored (*self->p))
|
||||||
lexer_advance (self);
|
lexer_advance (self);
|
||||||
if (!self->len)
|
if (!self->len)
|
||||||
return T_ABORT;
|
return T_ABORT;
|
||||||
|
@ -428,6 +425,8 @@ lexer_next (struct lexer *self, char **e) {
|
||||||
|
|
||||||
// --- Parsing -----------------------------------------------------------------
|
// --- Parsing -----------------------------------------------------------------
|
||||||
|
|
||||||
|
// FIXME: the parser generally ignores memory allocation errors
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_string (const char *s) {
|
print_string (const char *s) {
|
||||||
putc ('\'', stdout);
|
putc ('\'', stdout);
|
||||||
|
@ -675,6 +674,9 @@ register_native (const char *name, handler_fn handler) {
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
// TODO: fill in "error_is_fatal"
|
||||||
|
// TODO: probably add new_*() methods that set "memory_failure"
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
struct item *variables; ///< List of variables
|
struct item *variables; ///< List of variables
|
||||||
|
|
||||||
|
@ -704,7 +706,6 @@ get (struct context *ctx, const char *name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: cloning and removing
|
|
||||||
static bool
|
static bool
|
||||||
set (struct context *ctx, const char *name, struct item *value) {
|
set (struct context *ctx, const char *name, struct item *value) {
|
||||||
struct item *iter, *key = NULL, *pair = NULL;
|
struct item *iter, *key = NULL, *pair = NULL;
|
||||||
|
@ -713,12 +714,19 @@ set (struct context *ctx, const char *name, struct item *value) {
|
||||||
break;
|
break;
|
||||||
if (iter) {
|
if (iter) {
|
||||||
item_free (iter->head->next);
|
item_free (iter->head->next);
|
||||||
iter->head->next = value;
|
if (!(iter->head->next = new_clone (value))) {
|
||||||
|
ctx->memory_failure = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((key = new_string (name, strlen (name)))
|
if ((key = new_string (name, strlen (name)))
|
||||||
&& (pair = new_list (NULL))) {
|
&& (pair = new_list (NULL))) {
|
||||||
(pair->head = key)->next = value;
|
if (!((pair->head = key)->next = new_clone (value))) {
|
||||||
|
item_free (pair);
|
||||||
|
ctx->memory_failure = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
pair->next = ctx->variables;
|
pair->next = ctx->variables;
|
||||||
ctx->variables = pair;
|
ctx->variables = pair;
|
||||||
return true;
|
return true;
|
||||||
|
@ -756,10 +764,12 @@ rename_arguments (struct context *ctx, struct item *names) {
|
||||||
|
|
||||||
if (names->type != ITEM_STRING)
|
if (names->type != ITEM_STRING)
|
||||||
continue;
|
continue;
|
||||||
if (value)
|
if (value && !(value = new_clone (value))) {
|
||||||
set (ctx, names->value, new_clone (value));
|
ctx->memory_failure = true;
|
||||||
else
|
return false;
|
||||||
set (ctx, names->value, NULL);
|
}
|
||||||
|
if (!set (ctx, names->value, value))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue