diff options
Diffstat (limited to 'cmd-parse.c')
-rw-r--r-- | cmd-parse.c | 2229 |
1 files changed, 2229 insertions, 0 deletions
diff --git a/cmd-parse.c b/cmd-parse.c new file mode 100644 index 0000000..309c6fe --- /dev/null +++ b/cmd-parse.c @@ -0,0 +1,2229 @@ +#include <stdlib.h> +#include <string.h> +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +#define YYPREFIX "yy" +#line 20 "cmd-parse.y" + +#include <sys/types.h> + +#include <ctype.h> +#include <errno.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> + +#include "tmux.h" + +static int yylex(void); +static int yyparse(void); +static int printflike(1,2) yyerror(const char *, ...); + +static char *yylex_token(int); +static char *yylex_format(void); + +struct cmd_parse_scope { + int flag; + TAILQ_ENTRY (cmd_parse_scope) entry; +}; + +enum cmd_parse_argument_type { + CMD_PARSE_STRING, + CMD_PARSE_COMMANDS, + CMD_PARSE_PARSED_COMMANDS +}; + +struct cmd_parse_argument { + enum cmd_parse_argument_type type; + char *string; + struct cmd_parse_commands *commands; + struct cmd_list *cmdlist; + + TAILQ_ENTRY(cmd_parse_argument) entry; +}; +TAILQ_HEAD(cmd_parse_arguments, cmd_parse_argument); + +struct cmd_parse_command { + u_int line; + struct cmd_parse_arguments arguments; + + TAILQ_ENTRY(cmd_parse_command) entry; +}; +TAILQ_HEAD(cmd_parse_commands, cmd_parse_command); + +struct cmd_parse_state { + FILE *f; + + const char *buf; + size_t len; + size_t off; + + int condition; + int eol; + int eof; + struct cmd_parse_input *input; + u_int escapes; + + char *error; + struct cmd_parse_commands *commands; + + struct cmd_parse_scope *scope; + TAILQ_HEAD(, cmd_parse_scope) stack; +}; +static struct cmd_parse_state parse_state; + +static char *cmd_parse_get_error(const char *, u_int, const char *); +static void cmd_parse_free_command(struct cmd_parse_command *); +static struct cmd_parse_commands *cmd_parse_new_commands(void); +static void cmd_parse_free_commands(struct cmd_parse_commands *); +static void cmd_parse_build_commands(struct cmd_parse_commands *, + struct cmd_parse_input *, struct cmd_parse_result *); +static void cmd_parse_print_commands(struct cmd_parse_input *, + struct cmd_list *); + +#line 101 "cmd-parse.y" +#ifndef YYSTYPE_DEFINED +#define YYSTYPE_DEFINED +typedef union +{ + char *token; + struct cmd_parse_arguments *arguments; + struct cmd_parse_argument *argument; + int flag; + struct { + int flag; + struct cmd_parse_commands *commands; + } elif; + struct cmd_parse_commands *commands; + struct cmd_parse_command *command; +} YYSTYPE; +#endif /* YYSTYPE_DEFINED */ +#line 110 "cmd-parse.c" +#define ERROR 257 +#define HIDDEN 258 +#define IF 259 +#define ELSE 260 +#define ELIF 261 +#define ENDIF 262 +#define FORMAT 263 +#define TOKEN 264 +#define EQUALS 265 +#define YYERRCODE 256 +const short yylhs[] = + { -1, + 0, 0, 10, 10, 11, 11, 11, 11, 2, 2, + 1, 17, 17, 18, 16, 5, 19, 6, 20, 13, + 13, 13, 13, 7, 7, 12, 12, 12, 12, 12, + 15, 15, 15, 14, 14, 14, 14, 8, 8, 3, + 3, 4, 4, 4, 9, 9, +}; +const short yylen[] = + { 2, + 0, 1, 2, 3, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 2, 2, 1, 2, 1, 4, + 7, 5, 8, 3, 4, 1, 2, 3, 3, 1, + 1, 2, 3, 3, 5, 4, 6, 2, 3, 1, + 2, 1, 1, 2, 2, 3, +}; +const short yydefred[] = + { 0, + 0, 0, 14, 0, 0, 0, 0, 0, 7, 30, + 26, 6, 0, 0, 15, 9, 10, 16, 11, 0, + 0, 0, 0, 3, 0, 0, 0, 17, 0, 19, + 0, 0, 0, 34, 4, 28, 29, 42, 43, 0, + 33, 0, 0, 0, 0, 20, 18, 0, 0, 36, + 0, 44, 0, 0, 41, 0, 0, 22, 0, 39, + 0, 35, 0, 45, 0, 0, 0, 37, 46, 25, + 0, 21, 23, +}; +const short yydgoto[] = + { 4, + 18, 19, 41, 42, 5, 31, 44, 32, 52, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 33, 34, +}; +const short yysindex[] = + { -175, + -227, -172, 0, 0, -10, -175, 46, 10, 0, 0, + 0, 0, -205, 0, 0, 0, 0, 0, 0, -175, + -238, -56, 53, 0, -238, -118, -228, 0, -172, 0, + -238, -234, -238, 0, 0, 0, 0, 0, 0, -175, + 0, -118, 63, -234, 66, 0, 0, -52, -238, 0, + -55, 0, -175, 3, 0, -175, 68, 0, -175, 0, + -55, 0, 4, 0, -208, -175, -219, 0, 0, 0, + -219, 0, 0,}; +const short yyrindex[] = + { 1, + 0, 0, 0, 0, -184, 2, 0, 5, 0, 0, + 0, 0, 0, -4, 0, 0, 0, 0, 0, 6, + -184, 0, 0, 0, 7, 12, 6, 0, 0, 0, + -184, 0, -184, 0, 0, 0, 0, 0, 0, -2, + 0, 15, 0, 0, 0, 0, 0, -215, -184, 0, + 0, 0, -2, 0, 0, 6, 0, 0, 6, 0, + 0, 0, 0, 0, -1, 6, 6, 0, 0, 0, + 6, 0, 0,}; +const short yygindex[] = + { 0, + 57, 0, 40, 0, 39, -17, 28, 47, 0, 9, + 14, 56, 0, 69, 71, 0, 0, 0, -8, -9, +}; +#define YYTABLESIZE 277 +const short yytable[] = + { 20, + 1, 2, 25, 25, 40, 31, 25, 5, 5, 43, + 5, 5, 24, 35, 8, 5, 27, 46, 45, 23, + 2, 32, 50, 49, 40, 28, 3, 30, 27, 1, + 2, 28, 29, 30, 58, 57, 3, 15, 1, 2, + 23, 62, 30, 21, 38, 3, 38, 43, 53, 1, + 2, 68, 29, 54, 31, 24, 3, 72, 26, 21, + 22, 73, 35, 21, 65, 27, 63, 67, 25, 21, + 32, 21, 56, 40, 71, 59, 22, 66, 23, 12, + 23, 55, 1, 2, 23, 47, 48, 21, 51, 3, + 16, 17, 70, 36, 60, 37, 0, 0, 0, 0, + 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 31, 0, 5, 0, 0, 0, 0, 64, 69, 8, + 0, 27, 0, 0, 0, 0, 32, 0, 0, 40, + 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 28, 29, 30, 30, 0, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 3, 31, 31, 31, 24, 13, + 24, 12, 12, 0, 12, 12, 27, 27, 27, 12, + 12, 32, 32, 32, 40, 40, 40, +}; +const short yycheck[] = + { 10, + 0, 0, 59, 59, 123, 10, 59, 10, 10, 27, + 10, 10, 10, 10, 10, 10, 10, 27, 27, 6, + 259, 10, 32, 32, 10, 260, 265, 262, 20, 258, + 259, 260, 261, 262, 44, 44, 265, 265, 258, 259, + 27, 51, 262, 5, 260, 265, 262, 65, 40, 258, + 259, 61, 261, 40, 59, 10, 265, 67, 264, 21, + 5, 71, 10, 25, 56, 59, 53, 59, 59, 31, + 59, 33, 10, 59, 66, 10, 21, 10, 65, 264, + 67, 42, 258, 259, 71, 29, 31, 49, 33, 265, + 263, 264, 65, 25, 48, 25, -1, -1, -1, -1, + -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 125, -1, 125, -1, -1, -1, -1, 125, 125, 125, + -1, 125, -1, -1, -1, -1, 125, -1, -1, 125, + -1, -1, -1, -1, -1, 264, 265, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 260, 261, 262, 262, -1, 261, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 259, -1, + -1, -1, -1, -1, 265, 260, 261, 262, 260, 264, + 262, 264, 264, -1, 264, 264, 260, 261, 262, 264, + 264, 260, 261, 262, 260, 261, 262, +}; +#define YYFINAL 4 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 265 +#if YYDEBUG +const char * const yyname[] = + { +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"ERROR", +"HIDDEN","IF","ELSE","ELIF","ENDIF","FORMAT","TOKEN","EQUALS", +}; +const char * const yyrule[] = + {"$accept : lines", +"lines :", +"lines : statements", +"statements : statement '\\n'", +"statements : statements statement '\\n'", +"statement :", +"statement : hidden_assignment", +"statement : condition", +"statement : commands", +"format : FORMAT", +"format : TOKEN", +"expanded : format", +"optional_assignment :", +"optional_assignment : assignment", +"assignment : EQUALS", +"hidden_assignment : HIDDEN EQUALS", +"if_open : IF expanded", +"if_else : ELSE", +"if_elif : ELIF expanded", +"if_close : ENDIF", +"condition : if_open '\\n' statements if_close", +"condition : if_open '\\n' statements if_else '\\n' statements if_close", +"condition : if_open '\\n' statements elif if_close", +"condition : if_open '\\n' statements elif if_else '\\n' statements if_close", +"elif : if_elif '\\n' statements", +"elif : if_elif '\\n' statements elif", +"commands : command", +"commands : commands ';'", +"commands : commands ';' condition1", +"commands : commands ';' command", +"commands : condition1", +"command : assignment", +"command : optional_assignment TOKEN", +"command : optional_assignment TOKEN arguments", +"condition1 : if_open commands if_close", +"condition1 : if_open commands if_else commands if_close", +"condition1 : if_open commands elif1 if_close", +"condition1 : if_open commands elif1 if_else commands if_close", +"elif1 : if_elif commands", +"elif1 : if_elif commands elif1", +"arguments : argument", +"arguments : argument arguments", +"argument : TOKEN", +"argument : EQUALS", +"argument : '{' argument_statements", +"argument_statements : statement '}'", +"argument_statements : statements statement '}'", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +/* LINTUSED */ +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +unsigned int yystacksize; +int yyparse(void); +#line 575 "cmd-parse.y" + +static char * +cmd_parse_get_error(const char *file, u_int line, const char *error) +{ + char *s; + + if (file == NULL) + s = xstrdup(error); + else + xasprintf(&s, "%s:%u: %s", file, line, error); + return (s); +} + +static void +cmd_parse_print_commands(struct cmd_parse_input *pi, struct cmd_list *cmdlist) +{ + char *s; + + if (pi->item == NULL || (~pi->flags & CMD_PARSE_VERBOSE)) + return; + s = cmd_list_print(cmdlist, 0); + if (pi->file != NULL) + cmdq_print(pi->item, "%s:%u: %s", pi->file, pi->line, s); + else + cmdq_print(pi->item, "%u: %s", pi->line, s); + free(s); +} + +static void +cmd_parse_free_argument(struct cmd_parse_argument *arg) +{ + switch (arg->type) { + case CMD_PARSE_STRING: + free(arg->string); + break; + case CMD_PARSE_COMMANDS: + cmd_parse_free_commands(arg->commands); + break; + case CMD_PARSE_PARSED_COMMANDS: + cmd_list_free(arg->cmdlist); + break; + } + free(arg); +} + +static void +cmd_parse_free_arguments(struct cmd_parse_arguments *args) +{ + struct cmd_parse_argument *arg, *arg1; + + TAILQ_FOREACH_SAFE(arg, args, entry, arg1) { + TAILQ_REMOVE(args, arg, entry); + cmd_parse_free_argument(arg); + } +} + +static void +cmd_parse_free_command(struct cmd_parse_command *cmd) +{ + cmd_parse_free_arguments(&cmd->arguments); + free(cmd); +} + +static struct cmd_parse_commands * +cmd_parse_new_commands(void) +{ + struct cmd_parse_commands *cmds; + + cmds = xmalloc(sizeof *cmds); + TAILQ_INIT(cmds); + return (cmds); +} + +static void +cmd_parse_free_commands(struct cmd_parse_commands *cmds) +{ + struct cmd_parse_command *cmd, *cmd1; + + TAILQ_FOREACH_SAFE(cmd, cmds, entry, cmd1) { + TAILQ_REMOVE(cmds, cmd, entry); + cmd_parse_free_command(cmd); + } + free(cmds); +} + +static struct cmd_parse_commands * +cmd_parse_run_parser(char **cause) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_scope *scope, *scope1; + int retval; + + ps->commands = NULL; + TAILQ_INIT(&ps->stack); + + retval = yyparse(); + TAILQ_FOREACH_SAFE(scope, &ps->stack, entry, scope1) { + TAILQ_REMOVE(&ps->stack, scope, entry); + free(scope); + } + if (retval != 0) { + *cause = ps->error; + return (NULL); + } + + if (ps->commands == NULL) + return (cmd_parse_new_commands()); + return (ps->commands); +} + +static struct cmd_parse_commands * +cmd_parse_do_file(FILE *f, struct cmd_parse_input *pi, char **cause) +{ + struct cmd_parse_state *ps = &parse_state; + + memset(ps, 0, sizeof *ps); + ps->input = pi; + ps->f = f; + return (cmd_parse_run_parser(cause)); +} + +static struct cmd_parse_commands * +cmd_parse_do_buffer(const char *buf, size_t len, struct cmd_parse_input *pi, + char **cause) +{ + struct cmd_parse_state *ps = &parse_state; + + memset(ps, 0, sizeof *ps); + ps->input = pi; + ps->buf = buf; + ps->len = len; + return (cmd_parse_run_parser(cause)); +} + +static void +cmd_parse_log_commands(struct cmd_parse_commands *cmds, const char *prefix) +{ + struct cmd_parse_command *cmd; + struct cmd_parse_argument *arg; + u_int i, j; + char *s; + + i = 0; + TAILQ_FOREACH(cmd, cmds, entry) { + j = 0; + TAILQ_FOREACH(arg, &cmd->arguments, entry) { + switch (arg->type) { + case CMD_PARSE_STRING: + log_debug("%s %u:%u: %s", prefix, i, j, + arg->string); + break; + case CMD_PARSE_COMMANDS: + xasprintf(&s, "%s %u:%u", prefix, i, j); + cmd_parse_log_commands(arg->commands, s); + free(s); + break; + case CMD_PARSE_PARSED_COMMANDS: + s = cmd_list_print(arg->cmdlist, 0); + log_debug("%s %u:%u: %s", prefix, i, j, s); + free(s); + break; + } + j++; + } + i++; + } +} + +static int +cmd_parse_expand_alias(struct cmd_parse_command *cmd, + struct cmd_parse_input *pi, struct cmd_parse_result *pr) +{ + struct cmd_parse_argument *arg, *arg1, *first; + struct cmd_parse_commands *cmds; + struct cmd_parse_command *last; + char *alias, *name, *cause; + + if (pi->flags & CMD_PARSE_NOALIAS) + return (0); + memset(pr, 0, sizeof *pr); + + first = TAILQ_FIRST(&cmd->arguments); + if (first == NULL || first->type != CMD_PARSE_STRING) { + pr->status = CMD_PARSE_SUCCESS; + pr->cmdlist = cmd_list_new(); + return (1); + } + name = first->string; + + alias = cmd_get_alias(name); + if (alias == NULL) + return (0); + log_debug("%s: %u alias %s = %s", __func__, pi->line, name, alias); + + cmds = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause); + free(alias); + if (cmds == NULL) { + pr->status = CMD_PARSE_ERROR; + pr->error = cause; + return (1); + } + + last = TAILQ_LAST(cmds, cmd_parse_commands); + if (last == NULL) { + pr->status = CMD_PARSE_SUCCESS; + pr->cmdlist = cmd_list_new(); + return (1); + } + + TAILQ_REMOVE(&cmd->arguments, first, entry); + cmd_parse_free_argument(first); + + TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) { + TAILQ_REMOVE(&cmd->arguments, arg, entry); + TAILQ_INSERT_TAIL(&last->arguments, arg, entry); + } + cmd_parse_log_commands(cmds, __func__); + + pi->flags |= CMD_PARSE_NOALIAS; + cmd_parse_build_commands(cmds, pi, pr); + pi->flags &= ~CMD_PARSE_NOALIAS; + return (1); +} + +static void +cmd_parse_build_command(struct cmd_parse_command *cmd, + struct cmd_parse_input *pi, struct cmd_parse_result *pr) +{ + struct cmd_parse_argument *arg; + struct cmd *add; + char *cause; + struct args_value *values = NULL; + u_int count = 0, idx; + + memset(pr, 0, sizeof *pr); + + if (cmd_parse_expand_alias(cmd, pi, pr)) + return; + + TAILQ_FOREACH(arg, &cmd->arguments, entry) { + values = xrecallocarray(values, count, count + 1, + sizeof *values); + switch (arg->type) { + case CMD_PARSE_STRING: + values[count].type = ARGS_STRING; + values[count].string = xstrdup(arg->string); + break; + case CMD_PARSE_COMMANDS: + cmd_parse_build_commands(arg->commands, pi, pr); + if (pr->status != CMD_PARSE_SUCCESS) + goto out; + values[count].type = ARGS_COMMANDS; + values[count].cmdlist = pr->cmdlist; + break; + case CMD_PARSE_PARSED_COMMANDS: + values[count].type = ARGS_COMMANDS; + values[count].cmdlist = arg->cmdlist; + values[count].cmdlist->references++; + break; + } + count++; + } + + add = cmd_parse(values, count, pi->file, pi->line, &cause); + if (add == NULL) { + pr->status = CMD_PARSE_ERROR; + pr->error = cmd_parse_get_error(pi->file, pi->line, cause); + free(cause); + goto out; + } + pr->status = CMD_PARSE_SUCCESS; + pr->cmdlist = cmd_list_new(); + cmd_list_append(pr->cmdlist, add); + +out: + for (idx = 0; idx < count; idx++) + args_free_value(&values[idx]); + free(values); +} + +static void +cmd_parse_build_commands(struct cmd_parse_commands *cmds, + struct cmd_parse_input *pi, struct cmd_parse_result *pr) +{ + struct cmd_parse_command *cmd; + u_int line = UINT_MAX; + struct cmd_list *current = NULL, *result; + char *s; + + memset(pr, 0, sizeof *pr); + + /* Check for an empty list. */ + if (TAILQ_EMPTY(cmds)) { + pr->status = CMD_PARSE_SUCCESS; + pr->cmdlist = cmd_list_new(); + return; + } + cmd_parse_log_commands(cmds, __func__); + + /* + * Parse each command into a command list. Create a new command list + * for each line (unless the flag is set) so they get a new group (so + * the queue knows which ones to remove if a command fails when + * executed). + */ + result = cmd_list_new(); + TAILQ_FOREACH(cmd, cmds, entry) { + if (((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) { + if (current != NULL) { + cmd_parse_print_commands(pi, current); + cmd_list_move(result, current); + cmd_list_free(current); + } + current = cmd_list_new(); + } + if (current == NULL) + current = cmd_list_new(); + line = pi->line = cmd->line; + + cmd_parse_build_command(cmd, pi, pr); + if (pr->status != CMD_PARSE_SUCCESS) { + cmd_list_free(result); + cmd_list_free(current); + return; + } + cmd_list_append_all(current, pr->cmdlist); + cmd_list_free(pr->cmdlist); + } + if (current != NULL) { + cmd_parse_print_commands(pi, current); + cmd_list_move(result, current); + cmd_list_free(current); + } + + s = cmd_list_print(result, 0); + log_debug("%s: %s", __func__, s); + free(s); + + pr->status = CMD_PARSE_SUCCESS; + pr->cmdlist = result; +} + +struct cmd_parse_result * +cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi) +{ + static struct cmd_parse_result pr; + struct cmd_parse_input input; + struct cmd_parse_commands *cmds; + char *cause; + + if (pi == NULL) { + memset(&input, 0, sizeof input); + pi = &input; + } + memset(&pr, 0, sizeof pr); + + cmds = cmd_parse_do_file(f, pi, &cause); + if (cmds == NULL) { + pr.status = CMD_PARSE_ERROR; + pr.error = cause; + return (&pr); + } + cmd_parse_build_commands(cmds, pi, &pr); + cmd_parse_free_commands(cmds); + return (&pr); + +} + +struct cmd_parse_result * +cmd_parse_from_string(const char *s, struct cmd_parse_input *pi) +{ + struct cmd_parse_input input; + + if (pi == NULL) { + memset(&input, 0, sizeof input); + pi = &input; + } + + /* + * When parsing a string, put commands in one group even if there are + * multiple lines. This means { a \n b } is identical to "a ; b" when + * given as an argument to another command. + */ + pi->flags |= CMD_PARSE_ONEGROUP; + return (cmd_parse_from_buffer(s, strlen(s), pi)); +} + +enum cmd_parse_status +cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi, + struct cmdq_item *after, struct cmdq_state *state, char **error) +{ + struct cmd_parse_result *pr; + struct cmdq_item *item; + + pr = cmd_parse_from_string(s, pi); + switch (pr->status) { + case CMD_PARSE_ERROR: + if (error != NULL) + *error = pr->error; + else + free(pr->error); + break; + case CMD_PARSE_SUCCESS: + item = cmdq_get_command(pr->cmdlist, state); + cmdq_insert_after(after, item); + cmd_list_free(pr->cmdlist); + break; + } + return (pr->status); +} + +enum cmd_parse_status +cmd_parse_and_append(const char *s, struct cmd_parse_input *pi, + struct client *c, struct cmdq_state *state, char **error) +{ + struct cmd_parse_result *pr; + struct cmdq_item *item; + + pr = cmd_parse_from_string(s, pi); + switch (pr->status) { + case CMD_PARSE_ERROR: + if (error != NULL) + *error = pr->error; + else + free(pr->error); + break; + case CMD_PARSE_SUCCESS: + item = cmdq_get_command(pr->cmdlist, state); + cmdq_append(c, item); + cmd_list_free(pr->cmdlist); + break; + } + return (pr->status); +} + +struct cmd_parse_result * +cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi) +{ + static struct cmd_parse_result pr; + struct cmd_parse_input input; + struct cmd_parse_commands *cmds; + char *cause; + + if (pi == NULL) { + memset(&input, 0, sizeof input); + pi = &input; + } + memset(&pr, 0, sizeof pr); + + if (len == 0) { + pr.status = CMD_PARSE_SUCCESS; + pr.cmdlist = cmd_list_new(); + return (&pr); + } + + cmds = cmd_parse_do_buffer(buf, len, pi, &cause); + if (cmds == NULL) { + pr.status = CMD_PARSE_ERROR; + pr.error = cause; + return (&pr); + } + cmd_parse_build_commands(cmds, pi, &pr); + cmd_parse_free_commands(cmds); + return (&pr); +} + +struct cmd_parse_result * +cmd_parse_from_arguments(struct args_value *values, u_int count, + struct cmd_parse_input *pi) +{ + static struct cmd_parse_result pr; + struct cmd_parse_input input; + struct cmd_parse_commands *cmds; + struct cmd_parse_command *cmd; + struct cmd_parse_argument *arg; + u_int i; + char *copy; + size_t size; + int end; + + /* + * The commands are already split up into arguments, so just separate + * into a set of commands by ';'. + */ + + if (pi == NULL) { + memset(&input, 0, sizeof input); + pi = &input; + } + memset(&pr, 0, sizeof pr); + + cmds = cmd_parse_new_commands(); + + cmd = xcalloc(1, sizeof *cmd); + cmd->line = pi->line; + TAILQ_INIT(&cmd->arguments); + + for (i = 0; i < count; i++) { + end = 0; + if (values[i].type == ARGS_STRING) { + copy = xstrdup(values[i].string); + size = strlen(copy); + if (size != 0 && copy[size - 1] == ';') { + copy[--size] = '\0'; + if (size > 0 && copy[size - 1] == '\\') + copy[size - 1] = ';'; + else + end = 1; + } + if (!end || size != 0) { + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_STRING; + arg->string = copy; + TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); + } + } else if (values[i].type == ARGS_COMMANDS) { + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_PARSED_COMMANDS; + arg->cmdlist = values[i].cmdlist; + arg->cmdlist->references++; + TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); + } else + fatalx("unknown argument type"); + if (end) { + TAILQ_INSERT_TAIL(cmds, cmd, entry); + cmd = xcalloc(1, sizeof *cmd); + cmd->line = pi->line; + TAILQ_INIT(&cmd->arguments); + } + } + if (!TAILQ_EMPTY(&cmd->arguments)) + TAILQ_INSERT_TAIL(cmds, cmd, entry); + else + free(cmd); + + cmd_parse_build_commands(cmds, pi, &pr); + cmd_parse_free_commands(cmds); + return (&pr); +} + +static int printflike(1, 2) +yyerror(const char *fmt, ...) +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_input *pi = ps->input; + va_list ap; + char *error; + + if (ps->error != NULL) + return (0); + + va_start(ap, fmt); + xvasprintf(&error, fmt, ap); + va_end(ap); + + ps->error = cmd_parse_get_error(pi->file, pi->line, error); + free(error); + return (0); +} + +static int +yylex_is_var(char ch, int first) +{ + if (ch == '=') + return (0); + if (first && isdigit((u_char)ch)) + return (0); + return (isalnum((u_char)ch) || ch == '_'); +} + +static void +yylex_append(char **buf, size_t *len, const char *add, size_t addlen) +{ + if (addlen > SIZE_MAX - 1 || *len > SIZE_MAX - 1 - addlen) + fatalx("buffer is too big"); + *buf = xrealloc(*buf, (*len) + 1 + addlen); + memcpy((*buf) + *len, add, addlen); + (*len) += addlen; +} + +static void +yylex_append1(char **buf, size_t *len, char add) +{ + yylex_append(buf, len, &add, 1); +} + +static int +yylex_getc1(void) +{ + struct cmd_parse_state *ps = &parse_state; + int ch; + + if (ps->f != NULL) + ch = getc(ps->f); + else { + if (ps->off == ps->len) + ch = EOF; + else + ch = ps->buf[ps->off++]; + } + return (ch); +} + +static void +yylex_ungetc(int ch) +{ + struct cmd_parse_state *ps = &parse_state; + + if (ps->f != NULL) + ungetc(ch, ps->f); + else if (ps->off > 0 && ch != EOF) + ps->off--; +} + +static int +yylex_getc(void) +{ + struct cmd_parse_state *ps = &parse_state; + int ch; + + if (ps->escapes != 0) { + ps->escapes--; + return ('\\'); + } + for (;;) { + ch = yylex_getc1(); + if (ch == '\\') { + ps->escapes++; + continue; + } + if (ch == '\n' && (ps->escapes % 2) == 1) { + ps->input->line++; + ps->escapes--; + continue; + } + + if (ps->escapes != 0) { + yylex_ungetc(ch); + ps->escapes--; + return ('\\'); + } + return (ch); + } +} + +static char * +yylex_get_word(int ch) +{ + char *buf; + size_t len; + + len = 0; + buf = xmalloc(1); + + do + yylex_append1(&buf, &len, ch); + while ((ch = yylex_getc()) != EOF && strchr(" \t\n", ch) == NULL); + yylex_ungetc(ch); + + buf[len] = '\0'; + log_debug("%s: %s", __func__, buf); + return (buf); +} + +static int +yylex(void) +{ + struct cmd_parse_state *ps = &parse_state; + char *token, *cp; + int ch, next, condition; + + if (ps->eol) + ps->input->line++; + ps->eol = 0; + + condition = ps->condition; + ps->condition = 0; + + for (;;) { + ch = yylex_getc(); + + if (ch == EOF) { + /* + * Ensure every file or string is terminated by a + * newline. This keeps the parser simpler and avoids + * having to add a newline to each string. + */ + if (ps->eof) + break; + ps->eof = 1; + return ('\n'); + } + + if (ch == ' ' || ch == '\t') { + /* + * Ignore whitespace. + */ + continue; + } + + if (ch == '\n') { + /* + * End of line. Update the line number. + */ + ps->eol = 1; + return ('\n'); + } + + if (ch == ';' || ch == '{' || ch == '}') { + /* + * A semicolon or { or } is itself. + */ + return (ch); + } + + if (ch == '#') { + /* + * #{ after a condition opens a format; anything else + * is a comment, ignore up to the end of the line. + */ + next = yylex_getc(); + if (condition && next == '{') { + yylval.token = yylex_format(); + if (yylval.token == NULL) + return (ERROR); + return (FORMAT); + } + while (next != '\n' && next != EOF) + next = yylex_getc(); + if (next == '\n') { + ps->input->line++; + return ('\n'); + } + continue; + } + + if (ch == '%') { + /* + * % is a condition unless it is all % or all numbers, + * then it is a token. + */ + yylval.token = yylex_get_word('%'); + for (cp = yylval.token; *cp != '\0'; cp++) { + if (*cp != '%' && !isdigit((u_char)*cp)) + break; + } + if (*cp == '\0') + return (TOKEN); + ps->condition = 1; + if (strcmp(yylval.token, "%hidden") == 0) { + free(yylval.token); + return (HIDDEN); + } + if (strcmp(yylval.token, "%if") == 0) { + free(yylval.token); + return (IF); + } + if (strcmp(yylval.token, "%else") == 0) { + free(yylval.token); + return (ELSE); + } + if (strcmp(yylval.token, "%elif") == 0) { + free(yylval.token); + return (ELIF); + } + if (strcmp(yylval.token, "%endif") == 0) { + free(yylval.token); + return (ENDIF); + } + free(yylval.token); + return (ERROR); + } + + /* + * Otherwise this is a token. + */ + token = yylex_token(ch); + if (token == NULL) + return (ERROR); + yylval.token = token; + + if (strchr(token, '=') != NULL && yylex_is_var(*token, 1)) { + for (cp = token + 1; *cp != '='; cp++) { + if (!yylex_is_var(*cp, 0)) + break; + } + if (*cp == '=') + return (EQUALS); + } + return (TOKEN); + } + return (0); +} + +static char * +yylex_format(void) +{ + char *buf; + size_t len; + int ch, brackets = 1; + + len = 0; + buf = xmalloc(1); + + yylex_append(&buf, &len, "#{", 2); + for (;;) { + if ((ch = yylex_getc()) == EOF || ch == '\n') + goto error; + if (ch == '#') { + if ((ch = yylex_getc()) == EOF || ch == '\n') + goto error; + if (ch == '{') + brackets++; + yylex_append1(&buf, &len, '#'); + } else if (ch == '}') { + if (brackets != 0 && --brackets == 0) { + yylex_append1(&buf, &len, ch); + break; + } + } + yylex_append1(&buf, &len, ch); + } + if (brackets != 0) + goto error; + + buf[len] = '\0'; + log_debug("%s: %s", __func__, buf); + return (buf); + +error: + free(buf); + return (NULL); +} + +static int +yylex_token_escape(char **buf, size_t *len) +{ + int ch, type, o2, o3, mlen; + u_int size, i, tmp; + char s[9], m[MB_LEN_MAX]; + + ch = yylex_getc(); + + if (ch >= '4' && ch <= '7') { + yyerror("invalid octal escape"); + return (0); + } + if (ch >= '0' && ch <= '3') { + o2 = yylex_getc(); + if (o2 >= '0' && o2 <= '7') { + o3 = yylex_getc(); + if (o3 >= '0' && o3 <= '7') { + ch = 64 * (ch - '0') + + 8 * (o2 - '0') + + (o3 - '0'); + yylex_append1(buf, len, ch); + return (1); + } + } + yyerror("invalid octal escape"); + return (0); + } + + switch (ch) { + case EOF: + return (0); + case 'a': + ch = '\a'; + break; + case 'b': + ch = '\b'; + break; + case 'e': + ch = '\033'; + break; + case 'f': + ch = '\f'; + break; + case 's': + ch = ' '; + break; + case 'v': + ch = '\v'; + break; + case 'r': + ch = '\r'; + break; + case 'n': + ch = '\n'; + break; + case 't': + ch = '\t'; + break; + case 'u': + type = 'u'; + size = 4; + goto unicode; + case 'U': + type = 'U'; + size = 8; + goto unicode; + } + + yylex_append1(buf, len, ch); + return (1); + +unicode: + for (i = 0; i < size; i++) { + ch = yylex_getc(); + if (ch == EOF || ch == '\n') + return (0); + if (!isxdigit((u_char)ch)) { + yyerror("invalid \\%c argument", type); + return (0); + } + s[i] = ch; + } + s[i] = '\0'; + + if ((size == 4 && sscanf(s, "%4x", &tmp) != 1) || + (size == 8 && sscanf(s, "%8x", &tmp) != 1)) { + yyerror("invalid \\%c argument", type); + return (0); + } + mlen = wctomb(m, tmp); + if (mlen <= 0 || mlen > (int)sizeof m) { + yyerror("invalid \\%c argument", type); + return (0); + } + yylex_append(buf, len, m, mlen); + return (1); +} + +static int +yylex_token_variable(char **buf, size_t *len) +{ + struct environ_entry *envent; + int ch, brackets = 0; + char name[1024]; + size_t namelen = 0; + const char *value; + + ch = yylex_getc(); + if (ch == EOF) + return (0); + if (ch == '{') + brackets = 1; + else { + if (!yylex_is_var(ch, 1)) { + yylex_append1(buf, len, '$'); + yylex_ungetc(ch); + return (1); + } + name[namelen++] = ch; + } + + for (;;) { + ch = yylex_getc(); + if (brackets && ch == '}') + break; + if (ch == EOF || !yylex_is_var(ch, 0)) { + if (!brackets) { + yylex_ungetc(ch); + break; + } + yyerror("invalid environment variable"); + return (0); + } + if (namelen == (sizeof name) - 2) { + yyerror("environment variable is too long"); + return (0); + } + name[namelen++] = ch; + } + name[namelen] = '\0'; + + envent = environ_find(global_environ, name); + if (envent != NULL && envent->value != NULL) { + value = envent->value; + log_debug("%s: %s -> %s", __func__, name, value); + yylex_append(buf, len, value, strlen(value)); + } + return (1); +} + +static int +yylex_token_tilde(char **buf, size_t *len) +{ + struct environ_entry *envent; + int ch; + char name[1024]; + size_t namelen = 0; + struct passwd *pw; + const char *home = NULL; + + for (;;) { + ch = yylex_getc(); + if (ch == EOF || strchr("/ \t\n\"'", ch) != NULL) { + yylex_ungetc(ch); + break; + } + if (namelen == (sizeof name) - 2) { + yyerror("user name is too long"); + return (0); + } + name[namelen++] = ch; + } + name[namelen] = '\0'; + + if (*name == '\0') { + envent = environ_find(global_environ, "HOME"); + if (envent != NULL && *envent->value != '\0') + home = envent->value; + else if ((pw = getpwuid(getuid())) != NULL) + home = pw->pw_dir; + } else { + if ((pw = getpwnam(name)) != NULL) + home = pw->pw_dir; + } + if (home == NULL) + return (0); + + log_debug("%s: ~%s -> %s", __func__, name, home); + yylex_append(buf, len, home, strlen(home)); + return (1); +} + +static char * +yylex_token(int ch) +{ + char *buf; + size_t len; + enum { START, + NONE, + DOUBLE_QUOTES, + SINGLE_QUOTES } state = NONE, last = START; + + len = 0; + buf = xmalloc(1); + + for (;;) { + /* EOF or \n are always the end of the token. */ + if (ch == EOF || (state == NONE && ch == '\n')) + break; + + /* Whitespace or ; or } ends a token unless inside quotes. */ + if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') && + state == NONE) + break; + + /* + * Spaces and comments inside quotes after \n are removed but + * the \n is left. + */ + if (ch == '\n' && state != NONE) { + yylex_append1(&buf, &len, '\n'); + while ((ch = yylex_getc()) == ' ' || ch == '\t') + /* nothing */; + if (ch != '#') + continue; + ch = yylex_getc(); + if (strchr(",#{}:", ch) != NULL) { + yylex_ungetc(ch); + ch = '#'; + } else { + while ((ch = yylex_getc()) != '\n' && ch != EOF) + /* nothing */; + } + continue; + } + + /* \ ~ and $ are expanded except in single quotes. */ + if (ch == '\\' && state != SINGLE_QUOTES) { + if (!yylex_token_escape(&buf, &len)) + goto error; + goto skip; + } + if (ch == '~' && last != state && state != SINGLE_QUOTES) { + if (!yylex_token_tilde(&buf, &len)) + goto error; + goto skip; + } + if (ch == '$' && state != SINGLE_QUOTES) { + if (!yylex_token_variable(&buf, &len)) + goto error; + goto skip; + } + if (ch == '}' && state == NONE) + goto error; /* unmatched (matched ones were handled) */ + + /* ' and " starts or end quotes (and is consumed). */ + if (ch == '\'') { + if (state == NONE) { + state = SINGLE_QUOTES; + goto next; + } + if (state == SINGLE_QUOTES) { + state = NONE; + goto next; + } + } + if (ch == '"') { + if (state == NONE) { + state = DOUBLE_QUOTES; + goto next; + } + if (state == DOUBLE_QUOTES) { + state = NONE; + goto next; + } + } + + /* Otherwise add the character to the buffer. */ + yylex_append1(&buf, &len, ch); + + skip: + last = state; + + next: + ch = yylex_getc(); + } + yylex_ungetc(ch); + + buf[len] = '\0'; + log_debug("%s: %s", __func__, buf); + return (buf); + +error: + free(buf); + return (NULL); +} +#line 1458 "cmd-parse.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack(void) +{ + unsigned int newsize; + long sslen; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + sslen = yyssp - yyss; +#ifdef SIZE_MAX +#define YY_SIZE_MAX SIZE_MAX +#else +#define YY_SIZE_MAX 0xffffffffU +#endif + if (newsize && YY_SIZE_MAX / newsize < sizeof *newss) + goto bail; + newss = (short *)realloc(yyss, newsize * sizeof *newss); + if (newss == NULL) + goto bail; + yyss = newss; + yyssp = newss + sslen; + if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs) + goto bail; + newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs); + if (newvs == NULL) + goto bail; + yyvs = newvs; + yyvsp = newvs + sslen; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +bail: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return -1; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse(void) +{ + int yym, yyn, yystate; +#if YYDEBUG + const char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif /* YYDEBUG */ + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yyvsp[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 2: +#line 136 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + ps->commands = yyvsp[0].commands; + } +break; +case 3: +#line 143 "cmd-parse.y" +{ + yyval.commands = yyvsp[-1].commands; + } +break; +case 4: +#line 147 "cmd-parse.y" +{ + yyval.commands = yyvsp[-2].commands; + TAILQ_CONCAT(yyval.commands, yyvsp[-1].commands, entry); + free(yyvsp[-1].commands); + } +break; +case 5: +#line 154 "cmd-parse.y" +{ + yyval.commands = xmalloc (sizeof *yyval.commands); + TAILQ_INIT(yyval.commands); + } +break; +case 6: +#line 159 "cmd-parse.y" +{ + yyval.commands = xmalloc (sizeof *yyval.commands); + TAILQ_INIT(yyval.commands); + } +break; +case 7: +#line 164 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + if (ps->scope == NULL || ps->scope->flag) + yyval.commands = yyvsp[0].commands; + else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[0].commands); + } + } +break; +case 8: +#line 175 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + if (ps->scope == NULL || ps->scope->flag) + yyval.commands = yyvsp[0].commands; + else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[0].commands); + } + } +break; +case 9: +#line 187 "cmd-parse.y" +{ + yyval.token = yyvsp[0].token; + } +break; +case 10: +#line 191 "cmd-parse.y" +{ + yyval.token = yyvsp[0].token; + } +break; +case 11: +#line 196 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_input *pi = ps->input; + struct format_tree *ft; + struct client *c = pi->c; + struct cmd_find_state *fsp; + struct cmd_find_state fs; + int flags = FORMAT_NOJOBS; + + if (cmd_find_valid_state(&pi->fs)) + fsp = &pi->fs; + else { + cmd_find_from_client(&fs, c, 0); + fsp = &fs; + } + ft = format_create(NULL, pi->item, FORMAT_NONE, flags); + format_defaults(ft, c, fsp->s, fsp->wl, fsp->wp); + + yyval.token = format_expand(ft, yyvsp[0].token); + format_free(ft); + free(yyvsp[0].token); + } +break; +case 14: +#line 223 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + int flags = ps->input->flags; + + if ((~flags & CMD_PARSE_PARSEONLY) && + (ps->scope == NULL || ps->scope->flag)) + environ_put(global_environ, yyvsp[0].token, 0); + free(yyvsp[0].token); + } +break; +case 15: +#line 234 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + int flags = ps->input->flags; + + if ((~flags & CMD_PARSE_PARSEONLY) && + (ps->scope == NULL || ps->scope->flag)) + environ_put(global_environ, yyvsp[0].token, ENVIRON_HIDDEN); + free(yyvsp[0].token); + } +break; +case 16: +#line 245 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_scope *scope; + + scope = xmalloc(sizeof *scope); + yyval.flag = scope->flag = format_true(yyvsp[0].token); + free(yyvsp[0].token); + + if (ps->scope != NULL) + TAILQ_INSERT_HEAD(&ps->stack, ps->scope, entry); + ps->scope = scope; + } +break; +case 17: +#line 259 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_scope *scope; + + scope = xmalloc(sizeof *scope); + scope->flag = !ps->scope->flag; + + free(ps->scope); + ps->scope = scope; + } +break; +case 18: +#line 271 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_scope *scope; + + scope = xmalloc(sizeof *scope); + yyval.flag = scope->flag = format_true(yyvsp[0].token); + free(yyvsp[0].token); + + free(ps->scope); + ps->scope = scope; + } +break; +case 19: +#line 284 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + free(ps->scope); + ps->scope = TAILQ_FIRST(&ps->stack); + if (ps->scope != NULL) + TAILQ_REMOVE(&ps->stack, ps->scope, entry); + } +break; +case 20: +#line 294 "cmd-parse.y" +{ + if (yyvsp[-3].flag) + yyval.commands = yyvsp[-1].commands; + else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-1].commands); + } + } +break; +case 21: +#line 303 "cmd-parse.y" +{ + if (yyvsp[-6].flag) { + yyval.commands = yyvsp[-4].commands; + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[-4].commands); + } + } +break; +case 22: +#line 313 "cmd-parse.y" +{ + if (yyvsp[-4].flag) { + yyval.commands = yyvsp[-2].commands; + cmd_parse_free_commands(yyvsp[-1].elif.commands); + } else if (yyvsp[-1].elif.flag) { + yyval.commands = yyvsp[-1].elif.commands; + cmd_parse_free_commands(yyvsp[-2].commands); + } else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-2].commands); + cmd_parse_free_commands(yyvsp[-1].elif.commands); + } + } +break; +case 23: +#line 327 "cmd-parse.y" +{ + if (yyvsp[-7].flag) { + yyval.commands = yyvsp[-5].commands; + cmd_parse_free_commands(yyvsp[-4].elif.commands); + cmd_parse_free_commands(yyvsp[-1].commands); + } else if (yyvsp[-4].elif.flag) { + yyval.commands = yyvsp[-4].elif.commands; + cmd_parse_free_commands(yyvsp[-5].commands); + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[-5].commands); + cmd_parse_free_commands(yyvsp[-4].elif.commands); + } + } +break; +case 24: +#line 344 "cmd-parse.y" +{ + if (yyvsp[-2].flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[0].commands; + } else { + yyval.elif.flag = 0; + yyval.elif.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[0].commands); + } + } +break; +case 25: +#line 355 "cmd-parse.y" +{ + if (yyvsp[-3].flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[0].elif.commands); + } else if (yyvsp[0].elif.flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[0].elif.commands; + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.elif.flag = 0; + yyval.elif.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-1].commands); + cmd_parse_free_commands(yyvsp[0].elif.commands); + } + } +break; +case 26: +#line 373 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + yyval.commands = cmd_parse_new_commands(); + if (!TAILQ_EMPTY(&yyvsp[0].command->arguments) && + (ps->scope == NULL || ps->scope->flag)) + TAILQ_INSERT_TAIL(yyval.commands, yyvsp[0].command, entry); + else + cmd_parse_free_command(yyvsp[0].command); + } +break; +case 27: +#line 384 "cmd-parse.y" +{ + yyval.commands = yyvsp[-1].commands; + } +break; +case 28: +#line 388 "cmd-parse.y" +{ + yyval.commands = yyvsp[-2].commands; + TAILQ_CONCAT(yyval.commands, yyvsp[0].commands, entry); + free(yyvsp[0].commands); + } +break; +case 29: +#line 394 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + if (!TAILQ_EMPTY(&yyvsp[0].command->arguments) && + (ps->scope == NULL || ps->scope->flag)) { + yyval.commands = yyvsp[-2].commands; + TAILQ_INSERT_TAIL(yyval.commands, yyvsp[0].command, entry); + } else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-2].commands); + cmd_parse_free_command(yyvsp[0].command); + } + } +break; +case 30: +#line 408 "cmd-parse.y" +{ + yyval.commands = yyvsp[0].commands; + } +break; +case 31: +#line 413 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + + yyval.command = xcalloc(1, sizeof *yyval.command); + yyval.command->line = ps->input->line; + TAILQ_INIT(&yyval.command->arguments); + } +break; +case 32: +#line 421 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_argument *arg; + + yyval.command = xcalloc(1, sizeof *yyval.command); + yyval.command->line = ps->input->line; + TAILQ_INIT(&yyval.command->arguments); + + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_STRING; + arg->string = yyvsp[0].token; + TAILQ_INSERT_HEAD(&yyval.command->arguments, arg, entry); + } +break; +case 33: +#line 435 "cmd-parse.y" +{ + struct cmd_parse_state *ps = &parse_state; + struct cmd_parse_argument *arg; + + yyval.command = xcalloc(1, sizeof *yyval.command); + yyval.command->line = ps->input->line; + TAILQ_INIT(&yyval.command->arguments); + + TAILQ_CONCAT(&yyval.command->arguments, yyvsp[0].arguments, entry); + free(yyvsp[0].arguments); + + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_STRING; + arg->string = yyvsp[-1].token; + TAILQ_INSERT_HEAD(&yyval.command->arguments, arg, entry); + } +break; +case 34: +#line 453 "cmd-parse.y" +{ + if (yyvsp[-2].flag) + yyval.commands = yyvsp[-1].commands; + else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-1].commands); + } + } +break; +case 35: +#line 462 "cmd-parse.y" +{ + if (yyvsp[-4].flag) { + yyval.commands = yyvsp[-3].commands; + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[-3].commands); + } + } +break; +case 36: +#line 472 "cmd-parse.y" +{ + if (yyvsp[-3].flag) { + yyval.commands = yyvsp[-2].commands; + cmd_parse_free_commands(yyvsp[-1].elif.commands); + } else if (yyvsp[-1].elif.flag) { + yyval.commands = yyvsp[-1].elif.commands; + cmd_parse_free_commands(yyvsp[-2].commands); + } else { + yyval.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-2].commands); + cmd_parse_free_commands(yyvsp[-1].elif.commands); + } + } +break; +case 37: +#line 486 "cmd-parse.y" +{ + if (yyvsp[-5].flag) { + yyval.commands = yyvsp[-4].commands; + cmd_parse_free_commands(yyvsp[-3].elif.commands); + cmd_parse_free_commands(yyvsp[-1].commands); + } else if (yyvsp[-3].elif.flag) { + yyval.commands = yyvsp[-3].elif.commands; + cmd_parse_free_commands(yyvsp[-4].commands); + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[-4].commands); + cmd_parse_free_commands(yyvsp[-3].elif.commands); + } + } +break; +case 38: +#line 503 "cmd-parse.y" +{ + if (yyvsp[-1].flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[0].commands; + } else { + yyval.elif.flag = 0; + yyval.elif.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[0].commands); + } + } +break; +case 39: +#line 514 "cmd-parse.y" +{ + if (yyvsp[-2].flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[-1].commands; + cmd_parse_free_commands(yyvsp[0].elif.commands); + } else if (yyvsp[0].elif.flag) { + yyval.elif.flag = 1; + yyval.elif.commands = yyvsp[0].elif.commands; + cmd_parse_free_commands(yyvsp[-1].commands); + } else { + yyval.elif.flag = 0; + yyval.elif.commands = cmd_parse_new_commands(); + cmd_parse_free_commands(yyvsp[-1].commands); + cmd_parse_free_commands(yyvsp[0].elif.commands); + } + } +break; +case 40: +#line 532 "cmd-parse.y" +{ + yyval.arguments = xcalloc(1, sizeof *yyval.arguments); + TAILQ_INIT(yyval.arguments); + + TAILQ_INSERT_HEAD(yyval.arguments, yyvsp[0].argument, entry); + } +break; +case 41: +#line 539 "cmd-parse.y" +{ + TAILQ_INSERT_HEAD(yyvsp[0].arguments, yyvsp[-1].argument, entry); + yyval.arguments = yyvsp[0].arguments; + } +break; +case 42: +#line 545 "cmd-parse.y" +{ + yyval.argument = xcalloc(1, sizeof *yyval.argument); + yyval.argument->type = CMD_PARSE_STRING; + yyval.argument->string = yyvsp[0].token; + } +break; +case 43: +#line 551 "cmd-parse.y" +{ + yyval.argument = xcalloc(1, sizeof *yyval.argument); + yyval.argument->type = CMD_PARSE_STRING; + yyval.argument->string = yyvsp[0].token; + } +break; +case 44: +#line 557 "cmd-parse.y" +{ + yyval.argument = xcalloc(1, sizeof *yyval.argument); + yyval.argument->type = CMD_PARSE_COMMANDS; + yyval.argument->commands = yyvsp[0].commands; + } +break; +case 45: +#line 564 "cmd-parse.y" +{ + yyval.commands = yyvsp[-1].commands; + } +break; +case 46: +#line 568 "cmd-parse.y" +{ + yyval.commands = yyvsp[-2].commands; + TAILQ_CONCAT(yyval.commands, yyvsp[-1].commands, entry); + free(yyvsp[-1].commands); + } +break; +#line 2152 "cmd-parse.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (1); +yyaccept: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (0); +} |