aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-11-27 21:09:44 +0100
committerMarc André Tanner <mat@brain-dump.org>2016-11-27 21:09:44 +0100
commit6a566b9cf5aa38f5f0d4e03c98c84e3a86961e9c (patch)
tree06ab86bc8a9944c477f2c82d523a4130e20f79b5
parentce66ec2833143cc14eb6cffc6f16b736df9d1f31 (diff)
downloadvis-6a566b9cf5aa38f5f0d4e03c98c84e3a86961e9c.tar.gz
vis-6a566b9cf5aa38f5f0d4e03c98c84e3a86961e9c.tar.xz
sam: stricter command parsing
Properly detect unbalanced curly braces and spurious output at the end of a group.
-rw-r--r--sam.c25
-rw-r--r--sam.h1
-rw-r--r--vis-core.h1
3 files changed, 22 insertions, 5 deletions
diff --git a/sam.c b/sam.c
index 594de1c..7499242 100644
--- a/sam.c
+++ b/sam.c
@@ -404,6 +404,7 @@ const char *sam_error(enum SamError err) {
[SAM_ERR_SHELL] = "Shell command expected",
[SAM_ERR_COMMAND] = "Unknown command",
[SAM_ERR_EXECUTE] = "Error executing command",
+ [SAM_ERR_NEWLINE] = "Newline expected",
};
return err < LENGTH(error_msg) ? error_msg[err] : NULL;
@@ -695,7 +696,7 @@ static const CommandDef *command_lookup(Vis *vis, const char *name) {
return map_closest(vis->cmds, name);
}
-static Command *command_parse(Vis *vis, const char **s, int level, enum SamError *err) {
+static Command *command_parse(Vis *vis, const char **s, enum SamError *err) {
if (!**s) {
*err = SAM_ERR_COMMAND;
return NULL;
@@ -727,17 +728,22 @@ static Command *command_parse(Vis *vis, const char **s, int level, enum SamError
if (strcmp(cmd->argv[0], "{") == 0) {
Command *prev = NULL, *next;
+ int level = vis->nesting_level++;
do {
while (**s == ' ' || **s == '\t' || **s == '\n')
(*s)++;
- next = command_parse(vis, s, level+1, err);
+ next = command_parse(vis, s, err);
if (prev)
prev->next = next;
else
cmd->cmd = next;
} while ((prev = next));
+ if (level != vis->nesting_level) {
+ *err = SAM_ERR_UNMATCHED_BRACE;
+ goto fail;
+ }
} else if (strcmp(cmd->argv[0], "}") == 0) {
- if (level == 0) {
+ if (vis->nesting_level-- == 0) {
*err = SAM_ERR_UNMATCHED_BRACE;
goto fail;
}
@@ -791,7 +797,7 @@ static Command *command_parse(Vis *vis, const char **s, int level, enum SamError
goto fail;
cmd->cmd->cmddef = command_lookup(vis, cmddef->defcmd);
} else {
- if (!(cmd->cmd = command_parse(vis, s, level, err)))
+ if (!(cmd->cmd = command_parse(vis, s, err)))
goto fail;
if (strcmp(cmd->argv[0], "X") == 0 || strcmp(cmd->argv[0], "Y") == 0) {
Command *sel = command_new("s");
@@ -811,10 +817,19 @@ fail:
}
static Command *sam_parse(Vis *vis, const char *cmd, enum SamError *err) {
+ vis->nesting_level = 0;
const char **s = &cmd;
- Command *c = command_parse(vis, s, 0, err);
+ Command *c = command_parse(vis, s, err);
if (!c)
return NULL;
+ while (**s == ' ' || **s == '\t' || **s == '\n')
+ (*s)++;
+ if (**s) {
+ *err = SAM_ERR_NEWLINE;
+ command_free(c);
+ return NULL;
+ }
+
Command *sel = command_new("s");
if (!sel) {
command_free(c);
diff --git a/sam.h b/sam.h
index de7e910..7d063f4 100644
--- a/sam.h
+++ b/sam.h
@@ -14,6 +14,7 @@ enum SamError {
SAM_ERR_SHELL,
SAM_ERR_COMMAND,
SAM_ERR_EXECUTE,
+ SAM_ERR_NEWLINE,
};
bool sam_init(Vis*);
diff --git a/vis-core.h b/vis-core.h
index 79270f6..842c753 100644
--- a/vis-core.h
+++ b/vis-core.h
@@ -174,6 +174,7 @@ struct Vis {
Mode *mode; /* currently active mode, used to search for keybindings */
Mode *mode_prev; /* previsouly active user mode */
bool initialized; /* whether UI and Lua integration has been initialized */
+ int nesting_level; /* parsing state to hold keep track of { } nesting level */
volatile bool running; /* exit main loop once this becomes false */
int exit_status; /* exit status when terminating main loop */
volatile sig_atomic_t cancel_filter; /* abort external command/filter (SIGINT occured) */