diff --git a/src/commands_parser.c b/src/commands_parser.c index af0afe02..1bb9f0c2 100644 --- a/src/commands_parser.c +++ b/src/commands_parser.c @@ -214,8 +214,9 @@ char *parse_command(const char *input) { /* The "<=" operator is intentional: We also handle the terminating 0-byte * explicitly by looking for an 'end' token. */ while ((walk - input) <= len) { - /* skip whitespace before every token */ - while ((*walk == ' ' || *walk == '\t') && *walk != '\0') + /* skip whitespace and newlines before every token */ + while ((*walk == ' ' || *walk == '\t' || + *walk == '\r' || *walk == '\n') && *walk != '\0') walk++; DLOG("remaining input = %s\n", walk); @@ -255,15 +256,20 @@ char *parse_command(const char *input) { if (token->name[0] == 's') { /* For a string (starting with 's'), the delimiters are * comma (,) and semicolon (;) which introduce a new - * operation or command, respectively. */ - while (*walk != ';' && *walk != ',' && *walk != '\0') + * operation or command, respectively. Also, newlines + * end a command. */ + while (*walk != ';' && *walk != ',' && + *walk != '\0' && *walk != '\r' && + *walk != '\n') walk++; } else { /* For a word, the delimiters are white space (' ' or * '\t'), closing square bracket (]), comma (,) and * semicolon (;). */ - while (*walk != ' ' && *walk != '\t' && *walk != ']' && - *walk != ',' && *walk != ';' && *walk != '\0') + while (*walk != ' ' && *walk != '\t' && + *walk != ']' && *walk != ',' && + *walk != ';' && *walk != '\r' && + *walk != '\n' && *walk != '\0') walk++; } } @@ -382,8 +388,8 @@ void debuglog(uint64_t lev, char *fmt, ...) { va_list args; va_start(args, fmt); - fprintf(stdout, "# "); - vfprintf(stdout, fmt, args); + fprintf(stderr, "# "); + vfprintf(stderr, fmt, args); va_end(args); } diff --git a/testcases/t/187-commands-parser.t b/testcases/t/187-commands-parser.t index 35eaef73..1a11068b 100644 --- a/testcases/t/187-commands-parser.t +++ b/testcases/t/187-commands-parser.t @@ -12,7 +12,7 @@ sub parser_calls { # TODO: use a timeout, so that we can error out if it doesn’t terminate # TODO: better way of passing arguments - my $stdout = qx(../test.commands_parser '$command'); + my $stdout = qx(../test.commands_parser '$command' 2>&-); # Filter out all debugging output. my @lines = split("\n", $stdout); @@ -129,6 +129,17 @@ is(parser_calls('[con_mark="yay"] focus'), "cmd_focus()", 'quoted criteria focus ok'); +# Make sure trailing whitespace is stripped off: While this is not an issue for +# commands being parsed due to the configuration, people might send IPC +# commands with leading or trailing newlines. +is(parser_calls("workspace test\n"), + 'cmd_workspace_name(test)', + 'trailing whitespace stripped off ok'); + +is(parser_calls("\nworkspace test"), + 'cmd_workspace_name(test)', + 'trailing whitespace stripped off ok'); + ################################################################################ # 2: Verify that the parser spits out the right error message on commands which # are not ok.