Home | History | Annotate | Line # | Download | only in dist
cmd-parse.y revision 1.7
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 %{
     20 
     21 #include <sys/types.h>
     22 
     23 #include <ctype.h>
     24 #include <errno.h>
     25 #include <pwd.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 #include <wchar.h>
     30 
     31 #include "tmux.h"
     32 
     33 static int			 yylex(void);
     34 static int			 yyparse(void);
     35 static int printflike(1,2)	 yyerror(const char *, ...);
     36 
     37 static char			*yylex_token(int);
     38 static char			*yylex_format(void);
     39 
     40 struct cmd_parse_scope {
     41 	int				 flag;
     42 	TAILQ_ENTRY (cmd_parse_scope)	 entry;
     43 };
     44 
     45 enum cmd_parse_argument_type {
     46 	CMD_PARSE_STRING,
     47 	CMD_PARSE_COMMANDS,
     48 	CMD_PARSE_PARSED_COMMANDS
     49 };
     50 
     51 struct cmd_parse_argument {
     52 	enum cmd_parse_argument_type	 type;
     53 	char				*string;
     54 	struct cmd_parse_commands	*commands;
     55 	struct cmd_list			*cmdlist;
     56 
     57 	TAILQ_ENTRY(cmd_parse_argument)	 entry;
     58 };
     59 TAILQ_HEAD(cmd_parse_arguments, cmd_parse_argument);
     60 
     61 struct cmd_parse_command {
     62 	u_int				 line;
     63 	struct cmd_parse_arguments	 arguments;
     64 
     65 	TAILQ_ENTRY(cmd_parse_command)	 entry;
     66 };
     67 TAILQ_HEAD(cmd_parse_commands, cmd_parse_command);
     68 
     69 struct cmd_parse_state {
     70 	FILE				*f;
     71 
     72 	const char			*buf;
     73 	size_t				 len;
     74 	size_t				 off;
     75 
     76 	int				 condition;
     77 	int				 eol;
     78 	int				 eof;
     79 	struct cmd_parse_input		*input;
     80 	u_int				 escapes;
     81 
     82 	char				*error;
     83 	struct cmd_parse_commands	*commands;
     84 
     85 	struct cmd_parse_scope		*scope;
     86 	TAILQ_HEAD(, cmd_parse_scope)	 stack;
     87 };
     88 static struct cmd_parse_state parse_state;
     89 
     90 static char	*cmd_parse_get_error(const char *, u_int, const char *);
     91 static void	 cmd_parse_free_command(struct cmd_parse_command *);
     92 static struct cmd_parse_commands *cmd_parse_new_commands(void);
     93 static void	 cmd_parse_free_commands(struct cmd_parse_commands *);
     94 static void	 cmd_parse_build_commands(struct cmd_parse_commands *,
     95 		     struct cmd_parse_input *, struct cmd_parse_result *);
     96 static void	 cmd_parse_print_commands(struct cmd_parse_input *,
     97 		     struct cmd_list *);
     98 
     99 %}
    100 
    101 %union
    102 {
    103 	char					 *token;
    104 	struct cmd_parse_arguments		 *arguments;
    105 	struct cmd_parse_argument		 *argument;
    106 	int					  flag;
    107 	struct {
    108 		int				  flag;
    109 		struct cmd_parse_commands	 *commands;
    110 	} elif;
    111 	struct cmd_parse_commands		 *commands;
    112 	struct cmd_parse_command		 *command;
    113 }
    114 
    115 %token ERROR
    116 %token HIDDEN
    117 %token IF
    118 %token ELSE
    119 %token ELIF
    120 %token ENDIF
    121 %token <token> FORMAT TOKEN EQUALS
    122 
    123 %type <token> expanded format
    124 %type <arguments> arguments
    125 %type <argument> argument
    126 %type <flag> if_open if_elif
    127 %type <elif> elif elif1
    128 %type <commands> argument_statements statements statement
    129 %type <commands> commands condition condition1
    130 %type <command> command
    131 
    132 %%
    133 
    134 lines		: /* empty */
    135 		| statements
    136 		{
    137 			struct cmd_parse_state	*ps = &parse_state;
    138 
    139 			ps->commands = $1;
    140 		}
    141 
    142 statements	: statement '\n'
    143 		{
    144 			$$ = $1;
    145 		}
    146 		| statements statement '\n'
    147 		{
    148 			$$ = $1;
    149 			TAILQ_CONCAT($$, $2, entry);
    150 			free($2);
    151 		}
    152 
    153 statement	: /* empty */
    154 		{
    155 			$$ = xmalloc (sizeof *$$);
    156 			TAILQ_INIT($$);
    157 		}
    158 		| hidden_assignment
    159 		{
    160 			$$ = xmalloc (sizeof *$$);
    161 			TAILQ_INIT($$);
    162 		}
    163 		| condition
    164 		{
    165 			struct cmd_parse_state	*ps = &parse_state;
    166 
    167 			if (ps->scope == NULL || ps->scope->flag)
    168 				$$ = $1;
    169 			else {
    170 				$$ = cmd_parse_new_commands();
    171 				cmd_parse_free_commands($1);
    172 			}
    173 		}
    174 		| commands
    175 		{
    176 			struct cmd_parse_state	*ps = &parse_state;
    177 
    178 			if (ps->scope == NULL || ps->scope->flag)
    179 				$$ = $1;
    180 			else {
    181 				$$ = cmd_parse_new_commands();
    182 				cmd_parse_free_commands($1);
    183 			}
    184 		}
    185 
    186 format		: FORMAT
    187 		{
    188 			$$ = $1;
    189 		}
    190 		| TOKEN
    191 		{
    192 			$$ = $1;
    193 		}
    194 
    195 expanded	: format
    196 		{
    197 			struct cmd_parse_state	*ps = &parse_state;
    198 			struct cmd_parse_input	*pi = ps->input;
    199 			struct format_tree	*ft;
    200 			struct client		*c = pi->c;
    201 			struct cmd_find_state	*fsp;
    202 			struct cmd_find_state	 fs;
    203 			int			 flags = FORMAT_NOJOBS;
    204 
    205 			if (cmd_find_valid_state(&pi->fs))
    206 				fsp = &pi->fs;
    207 			else {
    208 				cmd_find_from_client(&fs, c, 0);
    209 				fsp = &fs;
    210 			}
    211 			ft = format_create(NULL, pi->item, FORMAT_NONE, flags);
    212 			format_defaults(ft, c, fsp->s, fsp->wl, fsp->wp);
    213 
    214 			$$ = format_expand(ft, $1);
    215 			format_free(ft);
    216 			free($1);
    217 		}
    218 
    219 optional_assignment	: /* empty */
    220 			| assignment
    221 
    222 assignment	: EQUALS
    223 		{
    224 			struct cmd_parse_state	*ps = &parse_state;
    225 			int			 flags = ps->input->flags;
    226 
    227 			if ((~flags & CMD_PARSE_PARSEONLY) &&
    228 			    (ps->scope == NULL || ps->scope->flag))
    229 				environ_put(global_environ, $1, 0);
    230 			free($1);
    231 		}
    232 
    233 hidden_assignment : HIDDEN EQUALS
    234 		{
    235 			struct cmd_parse_state	*ps = &parse_state;
    236 			int			 flags = ps->input->flags;
    237 
    238 			if ((~flags & CMD_PARSE_PARSEONLY) &&
    239 			    (ps->scope == NULL || ps->scope->flag))
    240 				environ_put(global_environ, $2, ENVIRON_HIDDEN);
    241 			free($2);
    242 		}
    243 
    244 if_open		: IF expanded
    245 		{
    246 			struct cmd_parse_state	*ps = &parse_state;
    247 			struct cmd_parse_scope	*scope;
    248 
    249 			scope = xmalloc(sizeof *scope);
    250 			$$ = scope->flag = format_true($2);
    251 			free($2);
    252 
    253 			if (ps->scope != NULL)
    254 				TAILQ_INSERT_HEAD(&ps->stack, ps->scope, entry);
    255 			ps->scope = scope;
    256 		}
    257 
    258 if_else		: ELSE
    259 		{
    260 			struct cmd_parse_state	*ps = &parse_state;
    261 			struct cmd_parse_scope	*scope;
    262 
    263 			scope = xmalloc(sizeof *scope);
    264 			scope->flag = !ps->scope->flag;
    265 
    266 			free(ps->scope);
    267 			ps->scope = scope;
    268 		}
    269 
    270 if_elif		: ELIF expanded
    271 		{
    272 			struct cmd_parse_state	*ps = &parse_state;
    273 			struct cmd_parse_scope	*scope;
    274 
    275 			scope = xmalloc(sizeof *scope);
    276 			$$ = scope->flag = format_true($2);
    277 			free($2);
    278 
    279 			free(ps->scope);
    280 			ps->scope = scope;
    281 		}
    282 
    283 if_close	: ENDIF
    284 		{
    285 			struct cmd_parse_state	*ps = &parse_state;
    286 
    287 			free(ps->scope);
    288 			ps->scope = TAILQ_FIRST(&ps->stack);
    289 			if (ps->scope != NULL)
    290 				TAILQ_REMOVE(&ps->stack, ps->scope, entry);
    291 		}
    292 
    293 condition	: if_open '\n' statements if_close
    294 		{
    295 			if ($1)
    296 				$$ = $3;
    297 			else {
    298 				$$ = cmd_parse_new_commands();
    299 				cmd_parse_free_commands($3);
    300 			}
    301 		}
    302 		| if_open '\n' statements if_else '\n' statements if_close
    303 		{
    304 			if ($1) {
    305 				$$ = $3;
    306 				cmd_parse_free_commands($6);
    307 			} else {
    308 				$$ = $6;
    309 				cmd_parse_free_commands($3);
    310 			}
    311 		}
    312 		| if_open '\n' statements elif if_close
    313 		{
    314 			if ($1) {
    315 				$$ = $3;
    316 				cmd_parse_free_commands($4.commands);
    317 			} else if ($4.flag) {
    318 				$$ = $4.commands;
    319 				cmd_parse_free_commands($3);
    320 			} else {
    321 				$$ = cmd_parse_new_commands();
    322 				cmd_parse_free_commands($3);
    323 				cmd_parse_free_commands($4.commands);
    324 			}
    325 		}
    326 		| if_open '\n' statements elif if_else '\n' statements if_close
    327 		{
    328 			if ($1) {
    329 				$$ = $3;
    330 				cmd_parse_free_commands($4.commands);
    331 				cmd_parse_free_commands($7);
    332 			} else if ($4.flag) {
    333 				$$ = $4.commands;
    334 				cmd_parse_free_commands($3);
    335 				cmd_parse_free_commands($7);
    336 			} else {
    337 				$$ = $7;
    338 				cmd_parse_free_commands($3);
    339 				cmd_parse_free_commands($4.commands);
    340 			}
    341 		}
    342 
    343 elif		: if_elif '\n' statements
    344 		{
    345 			if ($1) {
    346 				$$.flag = 1;
    347 				$$.commands = $3;
    348 			} else {
    349 				$$.flag = 0;
    350 				$$.commands = cmd_parse_new_commands();
    351 				cmd_parse_free_commands($3);
    352 			}
    353 		}
    354 		| if_elif '\n' statements elif
    355 		{
    356 			if ($1) {
    357 				$$.flag = 1;
    358 				$$.commands = $3;
    359 				cmd_parse_free_commands($4.commands);
    360 			} else if ($4.flag) {
    361 				$$.flag = 1;
    362 				$$.commands = $4.commands;
    363 				cmd_parse_free_commands($3);
    364 			} else {
    365 				$$.flag = 0;
    366 				$$.commands = cmd_parse_new_commands();
    367 				cmd_parse_free_commands($3);
    368 				cmd_parse_free_commands($4.commands);
    369 			}
    370 		}
    371 
    372 commands	: command
    373 		{
    374 			struct cmd_parse_state	*ps = &parse_state;
    375 
    376 			$$ = cmd_parse_new_commands();
    377 			if (!TAILQ_EMPTY(&$1->arguments) &&
    378 			    (ps->scope == NULL || ps->scope->flag))
    379 				TAILQ_INSERT_TAIL($$, $1, entry);
    380 			else
    381 				cmd_parse_free_command($1);
    382 		}
    383 		| commands ';'
    384 		{
    385 			$$ = $1;
    386 		}
    387 		| commands ';' condition1
    388 		{
    389 			$$ = $1;
    390 			TAILQ_CONCAT($$, $3, entry);
    391 			free($3);
    392 		}
    393 		| commands ';' command
    394 		{
    395 			struct cmd_parse_state	*ps = &parse_state;
    396 
    397 			if (!TAILQ_EMPTY(&$3->arguments) &&
    398 			    (ps->scope == NULL || ps->scope->flag)) {
    399 				$$ = $1;
    400 				TAILQ_INSERT_TAIL($$, $3, entry);
    401 			} else {
    402 				$$ = cmd_parse_new_commands();
    403 				cmd_parse_free_commands($1);
    404 				cmd_parse_free_command($3);
    405 			}
    406 		}
    407 		| condition1
    408 		{
    409 			$$ = $1;
    410 		}
    411 
    412 command		: assignment
    413 		{
    414 			struct cmd_parse_state	*ps = &parse_state;
    415 
    416 			$$ = xcalloc(1, sizeof *$$);
    417 			$$->line = ps->input->line;
    418 			TAILQ_INIT(&$$->arguments);
    419 		}
    420 		| optional_assignment TOKEN
    421 		{
    422 			struct cmd_parse_state		*ps = &parse_state;
    423 			struct cmd_parse_argument	*arg;
    424 
    425 			$$ = xcalloc(1, sizeof *$$);
    426 			$$->line = ps->input->line;
    427 			TAILQ_INIT(&$$->arguments);
    428 
    429 			arg = xcalloc(1, sizeof *arg);
    430 			arg->type = CMD_PARSE_STRING;
    431 			arg->string = $2;
    432 			TAILQ_INSERT_HEAD(&$$->arguments, arg, entry);
    433 		}
    434 		| optional_assignment TOKEN arguments
    435 		{
    436 			struct cmd_parse_state		*ps = &parse_state;
    437 			struct cmd_parse_argument	*arg;
    438 
    439 			$$ = xcalloc(1, sizeof *$$);
    440 			$$->line = ps->input->line;
    441 			TAILQ_INIT(&$$->arguments);
    442 
    443 			TAILQ_CONCAT(&$$->arguments, $3, entry);
    444 			free($3);
    445 
    446 			arg = xcalloc(1, sizeof *arg);
    447 			arg->type = CMD_PARSE_STRING;
    448 			arg->string = $2;
    449 			TAILQ_INSERT_HEAD(&$$->arguments, arg, entry);
    450 		}
    451 
    452 condition1	: if_open commands if_close
    453 		{
    454 			if ($1)
    455 				$$ = $2;
    456 			else {
    457 				$$ = cmd_parse_new_commands();
    458 				cmd_parse_free_commands($2);
    459 			}
    460 		}
    461 		| if_open commands if_else commands if_close
    462 		{
    463 			if ($1) {
    464 				$$ = $2;
    465 				cmd_parse_free_commands($4);
    466 			} else {
    467 				$$ = $4;
    468 				cmd_parse_free_commands($2);
    469 			}
    470 		}
    471 		| if_open commands elif1 if_close
    472 		{
    473 			if ($1) {
    474 				$$ = $2;
    475 				cmd_parse_free_commands($3.commands);
    476 			} else if ($3.flag) {
    477 				$$ = $3.commands;
    478 				cmd_parse_free_commands($2);
    479 			} else {
    480 				$$ = cmd_parse_new_commands();
    481 				cmd_parse_free_commands($2);
    482 				cmd_parse_free_commands($3.commands);
    483 			}
    484 		}
    485 		| if_open commands elif1 if_else commands if_close
    486 		{
    487 			if ($1) {
    488 				$$ = $2;
    489 				cmd_parse_free_commands($3.commands);
    490 				cmd_parse_free_commands($5);
    491 			} else if ($3.flag) {
    492 				$$ = $3.commands;
    493 				cmd_parse_free_commands($2);
    494 				cmd_parse_free_commands($5);
    495 			} else {
    496 				$$ = $5;
    497 				cmd_parse_free_commands($2);
    498 				cmd_parse_free_commands($3.commands);
    499 			}
    500 		}
    501 
    502 elif1		: if_elif commands
    503 		{
    504 			if ($1) {
    505 				$$.flag = 1;
    506 				$$.commands = $2;
    507 			} else {
    508 				$$.flag = 0;
    509 				$$.commands = cmd_parse_new_commands();
    510 				cmd_parse_free_commands($2);
    511 			}
    512 		}
    513 		| if_elif commands elif1
    514 		{
    515 			if ($1) {
    516 				$$.flag = 1;
    517 				$$.commands = $2;
    518 				cmd_parse_free_commands($3.commands);
    519 			} else if ($3.flag) {
    520 				$$.flag = 1;
    521 				$$.commands = $3.commands;
    522 				cmd_parse_free_commands($2);
    523 			} else {
    524 				$$.flag = 0;
    525 				$$.commands = cmd_parse_new_commands();
    526 				cmd_parse_free_commands($2);
    527 				cmd_parse_free_commands($3.commands);
    528 			}
    529 		}
    530 
    531 arguments	: argument
    532 		{
    533 			$$ = xcalloc(1, sizeof *$$);
    534 			TAILQ_INIT($$);
    535 
    536 			TAILQ_INSERT_HEAD($$, $1, entry);
    537 		}
    538 		| argument arguments
    539 		{
    540 			TAILQ_INSERT_HEAD($2, $1, entry);
    541 			$$ = $2;
    542 		}
    543 
    544 argument	: TOKEN
    545 		{
    546 			$$ = xcalloc(1, sizeof *$$);
    547 			$$->type = CMD_PARSE_STRING;
    548 			$$->string = $1;
    549 		}
    550 		| EQUALS
    551 		{
    552 			$$ = xcalloc(1, sizeof *$$);
    553 			$$->type = CMD_PARSE_STRING;
    554 			$$->string = $1;
    555 		}
    556 		| '{' argument_statements
    557 		{
    558 			$$ = xcalloc(1, sizeof *$$);
    559 			$$->type = CMD_PARSE_COMMANDS;
    560 			$$->commands = $2;
    561 		}
    562 
    563 argument_statements	: statement '}'
    564 			{
    565 				$$ = $1;
    566 			}
    567 			| statements statement '}'
    568 			{
    569 				$$ = $1;
    570 				TAILQ_CONCAT($$, $2, entry);
    571 				free($2);
    572 			}
    573 
    574 %%
    575 
    576 static char *
    577 cmd_parse_get_error(const char *file, u_int line, const char *error)
    578 {
    579 	char	*s;
    580 
    581 	if (file == NULL)
    582 		s = xstrdup(error);
    583 	else
    584 		xasprintf(&s, "%s:%u: %s", file, line, error);
    585 	return (s);
    586 }
    587 
    588 static void
    589 cmd_parse_print_commands(struct cmd_parse_input *pi, struct cmd_list *cmdlist)
    590 {
    591 	char	*s;
    592 
    593 	if (pi->item == NULL || (~pi->flags & CMD_PARSE_VERBOSE))
    594 		return;
    595 	s = cmd_list_print(cmdlist, 0);
    596 	if (pi->file != NULL)
    597 		cmdq_print(pi->item, "%s:%u: %s", pi->file, pi->line, s);
    598 	else
    599 		cmdq_print(pi->item, "%u: %s", pi->line, s);
    600 	free(s);
    601 }
    602 
    603 static void
    604 cmd_parse_free_argument(struct cmd_parse_argument *arg)
    605 {
    606 	switch (arg->type) {
    607 	case CMD_PARSE_STRING:
    608 		free(arg->string);
    609 		break;
    610 	case CMD_PARSE_COMMANDS:
    611 		cmd_parse_free_commands(arg->commands);
    612 		break;
    613 	case CMD_PARSE_PARSED_COMMANDS:
    614 		cmd_list_free(arg->cmdlist);
    615 		break;
    616 	}
    617 	free(arg);
    618 }
    619 
    620 static void
    621 cmd_parse_free_arguments(struct cmd_parse_arguments *args)
    622 {
    623 	struct cmd_parse_argument	*arg, *arg1;
    624 
    625 	TAILQ_FOREACH_SAFE(arg, args, entry, arg1) {
    626 		TAILQ_REMOVE(args, arg, entry);
    627 		cmd_parse_free_argument(arg);
    628 	}
    629 }
    630 
    631 static void
    632 cmd_parse_free_command(struct cmd_parse_command *cmd)
    633 {
    634 	cmd_parse_free_arguments(&cmd->arguments);
    635 	free(cmd);
    636 }
    637 
    638 static struct cmd_parse_commands *
    639 cmd_parse_new_commands(void)
    640 {
    641 	struct cmd_parse_commands	*cmds;
    642 
    643 	cmds = xmalloc(sizeof *cmds);
    644 	TAILQ_INIT(cmds);
    645 	return (cmds);
    646 }
    647 
    648 static void
    649 cmd_parse_free_commands(struct cmd_parse_commands *cmds)
    650 {
    651 	struct cmd_parse_command	*cmd, *cmd1;
    652 
    653 	TAILQ_FOREACH_SAFE(cmd, cmds, entry, cmd1) {
    654 		TAILQ_REMOVE(cmds, cmd, entry);
    655 		cmd_parse_free_command(cmd);
    656 	}
    657 	free(cmds);
    658 }
    659 
    660 static struct cmd_parse_commands *
    661 cmd_parse_run_parser(char **cause)
    662 {
    663 	struct cmd_parse_state	*ps = &parse_state;
    664 	struct cmd_parse_scope	*scope, *scope1;
    665 	int			 retval;
    666 
    667 	ps->commands = NULL;
    668 	TAILQ_INIT(&ps->stack);
    669 
    670 	retval = yyparse();
    671 	TAILQ_FOREACH_SAFE(scope, &ps->stack, entry, scope1) {
    672 		TAILQ_REMOVE(&ps->stack, scope, entry);
    673 		free(scope);
    674 	}
    675 	if (retval != 0) {
    676 		*cause = ps->error;
    677 		return (NULL);
    678 	}
    679 
    680 	if (ps->commands == NULL)
    681 		return (cmd_parse_new_commands());
    682 	return (ps->commands);
    683 }
    684 
    685 static struct cmd_parse_commands *
    686 cmd_parse_do_file(FILE *f, struct cmd_parse_input *pi, char **cause)
    687 {
    688 	struct cmd_parse_state	*ps = &parse_state;
    689 
    690 	memset(ps, 0, sizeof *ps);
    691 	ps->input = pi;
    692 	ps->f = f;
    693 	return (cmd_parse_run_parser(cause));
    694 }
    695 
    696 static struct cmd_parse_commands *
    697 cmd_parse_do_buffer(const char *buf, size_t len, struct cmd_parse_input *pi,
    698     char **cause)
    699 {
    700 	struct cmd_parse_state	*ps = &parse_state;
    701 
    702 	memset(ps, 0, sizeof *ps);
    703 	ps->input = pi;
    704 	ps->buf = buf;
    705 	ps->len = len;
    706 	return (cmd_parse_run_parser(cause));
    707 }
    708 
    709 static void
    710 cmd_parse_log_commands(struct cmd_parse_commands *cmds, const char *prefix)
    711 {
    712 	struct cmd_parse_command	*cmd;
    713 	struct cmd_parse_argument	*arg;
    714 	u_int				 i, j;
    715 	char				*s;
    716 
    717 	i = 0;
    718 	TAILQ_FOREACH(cmd, cmds, entry) {
    719 		j = 0;
    720 		TAILQ_FOREACH(arg, &cmd->arguments, entry) {
    721 			switch (arg->type) {
    722 			case CMD_PARSE_STRING:
    723 				log_debug("%s %u:%u: %s", prefix, i, j,
    724 				    arg->string);
    725 				break;
    726 			case CMD_PARSE_COMMANDS:
    727 				xasprintf(&s, "%s %u:%u", prefix, i, j);
    728 				cmd_parse_log_commands(arg->commands, s);
    729 				free(s);
    730 				break;
    731 			case CMD_PARSE_PARSED_COMMANDS:
    732 				s = cmd_list_print(arg->cmdlist, 0);
    733 				log_debug("%s %u:%u: %s", prefix, i, j, s);
    734 				free(s);
    735 				break;
    736 			}
    737 			j++;
    738 		}
    739 		i++;
    740 	}
    741 }
    742 
    743 static int
    744 cmd_parse_expand_alias(struct cmd_parse_command *cmd,
    745     struct cmd_parse_input *pi, struct cmd_parse_result *pr)
    746 {
    747 	struct cmd_parse_argument	*arg, *arg1, *first;
    748 	struct cmd_parse_commands	*cmds;
    749 	struct cmd_parse_command	*last;
    750 	char				*alias, *name, *cause;
    751 
    752 	if (pi->flags & CMD_PARSE_NOALIAS)
    753 		return (0);
    754 	memset(pr, 0, sizeof *pr);
    755 
    756 	first = TAILQ_FIRST(&cmd->arguments);
    757 	if (first == NULL || first->type != CMD_PARSE_STRING) {
    758 		pr->status = CMD_PARSE_SUCCESS;
    759 		pr->cmdlist = cmd_list_new();
    760 		return (1);
    761 	}
    762 	name = first->string;
    763 
    764 	alias = cmd_get_alias(name);
    765 	if (alias == NULL)
    766 		return (0);
    767 	log_debug("%s: %u alias %s = %s", __func__, pi->line, name, alias);
    768 
    769 	cmds = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
    770 	free(alias);
    771 	if (cmds == NULL) {
    772 		pr->status = CMD_PARSE_ERROR;
    773 		pr->error = cause;
    774 		return (1);
    775 	}
    776 
    777 	last = TAILQ_LAST(cmds, cmd_parse_commands);
    778 	if (last == NULL) {
    779 		pr->status = CMD_PARSE_SUCCESS;
    780 		pr->cmdlist = cmd_list_new();
    781 		return (1);
    782 	}
    783 
    784 	TAILQ_REMOVE(&cmd->arguments, first, entry);
    785 	cmd_parse_free_argument(first);
    786 
    787 	TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) {
    788 		TAILQ_REMOVE(&cmd->arguments, arg, entry);
    789 		TAILQ_INSERT_TAIL(&last->arguments, arg, entry);
    790 	}
    791 	cmd_parse_log_commands(cmds, __func__);
    792 
    793 	pi->flags |= CMD_PARSE_NOALIAS;
    794 	cmd_parse_build_commands(cmds, pi, pr);
    795 	pi->flags &= ~CMD_PARSE_NOALIAS;
    796 	return (1);
    797 }
    798 
    799 static void
    800 cmd_parse_build_command(struct cmd_parse_command *cmd,
    801     struct cmd_parse_input *pi, struct cmd_parse_result *pr)
    802 {
    803 	struct cmd_parse_argument	*arg;
    804 	struct cmd			*add;
    805 	char				*cause;
    806 	struct args_value		*values = NULL;
    807 	u_int				 count = 0, idx;
    808 
    809 	memset(pr, 0, sizeof *pr);
    810 
    811 	if (cmd_parse_expand_alias(cmd, pi, pr))
    812 		return;
    813 
    814 	TAILQ_FOREACH(arg, &cmd->arguments, entry) {
    815 		values = xrecallocarray(values, count, count + 1,
    816 		    sizeof *values);
    817 		switch (arg->type) {
    818 		case CMD_PARSE_STRING:
    819 			values[count].type = ARGS_STRING;
    820 			values[count].string = xstrdup(arg->string);
    821 			break;
    822 		case CMD_PARSE_COMMANDS:
    823 			cmd_parse_build_commands(arg->commands, pi, pr);
    824 			if (pr->status != CMD_PARSE_SUCCESS)
    825 				goto out;
    826 			values[count].type = ARGS_COMMANDS;
    827 			values[count].cmdlist = pr->cmdlist;
    828 			break;
    829 		case CMD_PARSE_PARSED_COMMANDS:
    830 			values[count].type = ARGS_COMMANDS;
    831 			values[count].cmdlist = arg->cmdlist;
    832 			values[count].cmdlist->references++;
    833 			break;
    834 		}
    835 		count++;
    836 	}
    837 
    838 	add = cmd_parse(values, count, pi->file, pi->line, &cause);
    839 	if (add == NULL) {
    840 		pr->status = CMD_PARSE_ERROR;
    841 		pr->error = cmd_parse_get_error(pi->file, pi->line, cause);
    842 		free(cause);
    843 		goto out;
    844 	}
    845 	pr->status = CMD_PARSE_SUCCESS;
    846 	pr->cmdlist = cmd_list_new();
    847 	cmd_list_append(pr->cmdlist, add);
    848 
    849 out:
    850 	for (idx = 0; idx < count; idx++)
    851 		args_free_value(&values[idx]);
    852 	free(values);
    853 }
    854 
    855 static void
    856 cmd_parse_build_commands(struct cmd_parse_commands *cmds,
    857     struct cmd_parse_input *pi, struct cmd_parse_result *pr)
    858 {
    859 	struct cmd_parse_command	*cmd;
    860 	u_int				 line = UINT_MAX;
    861 	struct cmd_list			*current = NULL, *result;
    862 	char				*s;
    863 
    864 	memset(pr, 0, sizeof *pr);
    865 
    866 	/* Check for an empty list. */
    867 	if (TAILQ_EMPTY(cmds)) {
    868 		pr->status = CMD_PARSE_SUCCESS;
    869 		pr->cmdlist = cmd_list_new();
    870 		return;
    871 	}
    872 	cmd_parse_log_commands(cmds, __func__);
    873 
    874 	/*
    875 	 * Parse each command into a command list. Create a new command list
    876 	 * for each line (unless the flag is set) so they get a new group (so
    877 	 * the queue knows which ones to remove if a command fails when
    878 	 * executed).
    879 	 */
    880 	result = cmd_list_new();
    881 	TAILQ_FOREACH(cmd, cmds, entry) {
    882 		if (((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
    883 			if (current != NULL) {
    884 				cmd_parse_print_commands(pi, current);
    885 				cmd_list_move(result, current);
    886 				cmd_list_free(current);
    887 			}
    888 			current = cmd_list_new();
    889 		}
    890 		if (current == NULL)
    891 			current = cmd_list_new();
    892 		line = pi->line = cmd->line;
    893 
    894 		cmd_parse_build_command(cmd, pi, pr);
    895 		if (pr->status != CMD_PARSE_SUCCESS) {
    896 			cmd_list_free(result);
    897 			cmd_list_free(current);
    898 			return;
    899 		}
    900 		cmd_list_append_all(current, pr->cmdlist);
    901 		cmd_list_free(pr->cmdlist);
    902 	}
    903 	if (current != NULL) {
    904 		cmd_parse_print_commands(pi, current);
    905 		cmd_list_move(result, current);
    906 		cmd_list_free(current);
    907 	}
    908 
    909 	s = cmd_list_print(result, 0);
    910 	log_debug("%s: %s", __func__, s);
    911 	free(s);
    912 
    913 	pr->status = CMD_PARSE_SUCCESS;
    914 	pr->cmdlist = result;
    915 }
    916 
    917 struct cmd_parse_result *
    918 cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi)
    919 {
    920 	static struct cmd_parse_result	 pr;
    921 	struct cmd_parse_input		 input;
    922 	struct cmd_parse_commands	*cmds;
    923 	char				*cause;
    924 
    925 	if (pi == NULL) {
    926 		memset(&input, 0, sizeof input);
    927 		pi = &input;
    928 	}
    929 	memset(&pr, 0, sizeof pr);
    930 
    931 	cmds = cmd_parse_do_file(f, pi, &cause);
    932 	if (cmds == NULL) {
    933 		pr.status = CMD_PARSE_ERROR;
    934 		pr.error = cause;
    935 		return (&pr);
    936 	}
    937 	cmd_parse_build_commands(cmds, pi, &pr);
    938 	cmd_parse_free_commands(cmds);
    939 	return (&pr);
    940 
    941 }
    942 
    943 struct cmd_parse_result *
    944 cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
    945 {
    946 	struct cmd_parse_input	input;
    947 
    948 	if (pi == NULL) {
    949 		memset(&input, 0, sizeof input);
    950 		pi = &input;
    951 	}
    952 
    953 	/*
    954 	 * When parsing a string, put commands in one group even if there are
    955 	 * multiple lines. This means { a \n b } is identical to "a ; b" when
    956 	 * given as an argument to another command.
    957 	 */
    958 	pi->flags |= CMD_PARSE_ONEGROUP;
    959 	return (cmd_parse_from_buffer(s, strlen(s), pi));
    960 }
    961 
    962 enum cmd_parse_status
    963 cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi,
    964     struct cmdq_item *after, struct cmdq_state *state, char **error)
    965 {
    966 	struct cmd_parse_result	*pr;
    967 	struct cmdq_item	*item;
    968 
    969 	pr = cmd_parse_from_string(s, pi);
    970 	switch (pr->status) {
    971 	case CMD_PARSE_ERROR:
    972 		if (error != NULL)
    973 			*error = pr->error;
    974 		else
    975 			free(pr->error);
    976 		break;
    977 	case CMD_PARSE_SUCCESS:
    978 		item = cmdq_get_command(pr->cmdlist, state);
    979 		cmdq_insert_after(after, item);
    980 		cmd_list_free(pr->cmdlist);
    981 		break;
    982 	}
    983 	return (pr->status);
    984 }
    985 
    986 enum cmd_parse_status
    987 cmd_parse_and_append(const char *s, struct cmd_parse_input *pi,
    988     struct client *c, struct cmdq_state *state, char **error)
    989 {
    990 	struct cmd_parse_result	*pr;
    991 	struct cmdq_item	*item;
    992 
    993 	pr = cmd_parse_from_string(s, pi);
    994 	switch (pr->status) {
    995 	case CMD_PARSE_ERROR:
    996 		if (error != NULL)
    997 			*error = pr->error;
    998 		else
    999 			free(pr->error);
   1000 		break;
   1001 	case CMD_PARSE_SUCCESS:
   1002 		item = cmdq_get_command(pr->cmdlist, state);
   1003 		cmdq_append(c, item);
   1004 		cmd_list_free(pr->cmdlist);
   1005 		break;
   1006 	}
   1007 	return (pr->status);
   1008 }
   1009 
   1010 struct cmd_parse_result *
   1011 cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
   1012 {
   1013 	static struct cmd_parse_result	 pr;
   1014 	struct cmd_parse_input		 input;
   1015 	struct cmd_parse_commands	*cmds;
   1016 	char				*cause;
   1017 
   1018 	if (pi == NULL) {
   1019 		memset(&input, 0, sizeof input);
   1020 		pi = &input;
   1021 	}
   1022 	memset(&pr, 0, sizeof pr);
   1023 
   1024 	if (len == 0) {
   1025 		pr.status = CMD_PARSE_SUCCESS;
   1026 		pr.cmdlist = cmd_list_new();
   1027 		return (&pr);
   1028 	}
   1029 
   1030 	cmds = cmd_parse_do_buffer(buf, len, pi, &cause);
   1031 	if (cmds == NULL) {
   1032 		pr.status = CMD_PARSE_ERROR;
   1033 		pr.error = cause;
   1034 		return (&pr);
   1035 	}
   1036 	cmd_parse_build_commands(cmds, pi, &pr);
   1037 	cmd_parse_free_commands(cmds);
   1038 	return (&pr);
   1039 }
   1040 
   1041 struct cmd_parse_result *
   1042 cmd_parse_from_arguments(struct args_value *values, u_int count,
   1043     struct cmd_parse_input *pi)
   1044 {
   1045 	static struct cmd_parse_result	 pr;
   1046 	struct cmd_parse_input		 input;
   1047 	struct cmd_parse_commands	*cmds;
   1048 	struct cmd_parse_command	*cmd;
   1049 	struct cmd_parse_argument	*arg;
   1050 	u_int				 i;
   1051 	char				*copy;
   1052 	size_t				 size;
   1053 	int				 end;
   1054 
   1055 	/*
   1056 	 * The commands are already split up into arguments, so just separate
   1057 	 * into a set of commands by ';'.
   1058 	 */
   1059 
   1060 	if (pi == NULL) {
   1061 		memset(&input, 0, sizeof input);
   1062 		pi = &input;
   1063 	}
   1064 	memset(&pr, 0, sizeof pr);
   1065 
   1066 	cmds = cmd_parse_new_commands();
   1067 
   1068 	cmd = xcalloc(1, sizeof *cmd);
   1069 	cmd->line = pi->line;
   1070 	TAILQ_INIT(&cmd->arguments);
   1071 
   1072 	for (i = 0; i < count; i++) {
   1073 		end = 0;
   1074 		if (values[i].type == ARGS_STRING) {
   1075 			copy = xstrdup(values[i].string);
   1076 			size = strlen(copy);
   1077 			if (size != 0 && copy[size - 1] == ';') {
   1078 				copy[--size] = '\0';
   1079 				if (size > 0 && copy[size - 1] == '\\')
   1080 					copy[size - 1] = ';';
   1081 				else
   1082 					end = 1;
   1083 			}
   1084 			if (!end || size != 0) {
   1085 				arg = xcalloc(1, sizeof *arg);
   1086 				arg->type = CMD_PARSE_STRING;
   1087 				arg->string = copy;
   1088 				TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
   1089 			} else
   1090 				free(copy);
   1091 		} else if (values[i].type == ARGS_COMMANDS) {
   1092 			arg = xcalloc(1, sizeof *arg);
   1093 			arg->type = CMD_PARSE_PARSED_COMMANDS;
   1094 			arg->cmdlist = values[i].cmdlist;
   1095 			arg->cmdlist->references++;
   1096 			TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
   1097 		} else
   1098 			fatalx("unknown argument type");
   1099 		if (end) {
   1100 			TAILQ_INSERT_TAIL(cmds, cmd, entry);
   1101 			cmd = xcalloc(1, sizeof *cmd);
   1102 			cmd->line = pi->line;
   1103 			TAILQ_INIT(&cmd->arguments);
   1104 		}
   1105 	}
   1106 	if (!TAILQ_EMPTY(&cmd->arguments))
   1107 		TAILQ_INSERT_TAIL(cmds, cmd, entry);
   1108 	else
   1109 		free(cmd);
   1110 
   1111 	cmd_parse_build_commands(cmds, pi, &pr);
   1112 	cmd_parse_free_commands(cmds);
   1113 	return (&pr);
   1114 }
   1115 
   1116 static int printflike(1, 2)
   1117 yyerror(const char *fmt, ...)
   1118 {
   1119 	struct cmd_parse_state	*ps = &parse_state;
   1120 	struct cmd_parse_input	*pi = ps->input;
   1121 	va_list			 ap;
   1122 	char			*error;
   1123 
   1124 	if (ps->error != NULL)
   1125 		return (0);
   1126 
   1127 	va_start(ap, fmt);
   1128 	xvasprintf(&error, fmt, ap);
   1129 	va_end(ap);
   1130 
   1131 	ps->error = cmd_parse_get_error(pi->file, pi->line, error);
   1132 	free(error);
   1133 	return (0);
   1134 }
   1135 
   1136 static int
   1137 yylex_is_var(char ch, int first)
   1138 {
   1139 	if (ch == '=')
   1140 		return (0);
   1141 	if (first && isdigit((u_char)ch))
   1142 		return (0);
   1143 	return (isalnum((u_char)ch) || ch == '_');
   1144 }
   1145 
   1146 static void
   1147 yylex_append(char **buf, size_t *len, const char *add, size_t addlen)
   1148 {
   1149 	if (addlen > SIZE_MAX - 1 || *len > SIZE_MAX - 1 - addlen)
   1150 		fatalx("buffer is too big");
   1151 	*buf = xrealloc(*buf, (*len) + 1 + addlen);
   1152 	memcpy((*buf) + *len, add, addlen);
   1153 	(*len) += addlen;
   1154 }
   1155 
   1156 static void
   1157 yylex_append1(char **buf, size_t *len, char add)
   1158 {
   1159 	yylex_append(buf, len, &add, 1);
   1160 }
   1161 
   1162 static int
   1163 yylex_getc1(void)
   1164 {
   1165 	struct cmd_parse_state	*ps = &parse_state;
   1166 	int			 ch;
   1167 
   1168 	if (ps->f != NULL)
   1169 		ch = getc(ps->f);
   1170 	else {
   1171 		if (ps->off == ps->len)
   1172 			ch = EOF;
   1173 		else
   1174 			ch = ps->buf[ps->off++];
   1175 	}
   1176 	return (ch);
   1177 }
   1178 
   1179 static void
   1180 yylex_ungetc(int ch)
   1181 {
   1182 	struct cmd_parse_state	*ps = &parse_state;
   1183 
   1184 	if (ps->f != NULL)
   1185 		ungetc(ch, ps->f);
   1186 	else if (ps->off > 0 && ch != EOF)
   1187 		ps->off--;
   1188 }
   1189 
   1190 static int
   1191 yylex_getc(void)
   1192 {
   1193 	struct cmd_parse_state	*ps = &parse_state;
   1194 	int			 ch;
   1195 
   1196 	if (ps->escapes != 0) {
   1197 		ps->escapes--;
   1198 		return ('\\');
   1199 	}
   1200 	for (;;) {
   1201 		ch = yylex_getc1();
   1202 		if (ch == '\\') {
   1203 			ps->escapes++;
   1204 			continue;
   1205 		}
   1206 		if (ch == '\n' && (ps->escapes % 2) == 1) {
   1207 			ps->input->line++;
   1208 			ps->escapes--;
   1209 			continue;
   1210 		}
   1211 
   1212 		if (ps->escapes != 0) {
   1213 			yylex_ungetc(ch);
   1214 			ps->escapes--;
   1215 			return ('\\');
   1216 		}
   1217 		return (ch);
   1218 	}
   1219 }
   1220 
   1221 static char *
   1222 yylex_get_word(int ch)
   1223 {
   1224 	char	*buf;
   1225 	size_t	 len;
   1226 
   1227 	len = 0;
   1228 	buf = xmalloc(1);
   1229 
   1230 	do
   1231 		yylex_append1(&buf, &len, ch);
   1232 	while ((ch = yylex_getc()) != EOF && strchr(" \t\n", ch) == NULL);
   1233 	yylex_ungetc(ch);
   1234 
   1235 	buf[len] = '\0';
   1236 	log_debug("%s: %s", __func__, buf);
   1237 	return (buf);
   1238 }
   1239 
   1240 static int
   1241 yylex(void)
   1242 {
   1243 	struct cmd_parse_state	*ps = &parse_state;
   1244 	char			*token, *cp;
   1245 	int			 ch, next, condition;
   1246 
   1247 	if (ps->eol)
   1248 		ps->input->line++;
   1249 	ps->eol = 0;
   1250 
   1251 	condition = ps->condition;
   1252 	ps->condition = 0;
   1253 
   1254 	for (;;) {
   1255 		ch = yylex_getc();
   1256 
   1257 		if (ch == EOF) {
   1258 			/*
   1259 			 * Ensure every file or string is terminated by a
   1260 			 * newline. This keeps the parser simpler and avoids
   1261 			 * having to add a newline to each string.
   1262 			 */
   1263 			if (ps->eof)
   1264 				break;
   1265 			ps->eof = 1;
   1266 			return ('\n');
   1267 		}
   1268 
   1269 		if (ch == ' ' || ch == '\t') {
   1270 			/*
   1271 			 * Ignore whitespace.
   1272 			 */
   1273 			continue;
   1274 		}
   1275 
   1276 		if (ch == '\r') {
   1277 			/*
   1278 			 * Treat \r\n as \n.
   1279 			 */
   1280 			ch = yylex_getc();
   1281 			if (ch != '\n') {
   1282 				yylex_ungetc(ch);
   1283 				ch = '\r';
   1284 			}
   1285 		}
   1286 		if (ch == '\n') {
   1287 			/*
   1288 			 * End of line. Update the line number.
   1289 			 */
   1290 			ps->eol = 1;
   1291 			return ('\n');
   1292 		}
   1293 
   1294 		if (ch == ';' || ch == '{' || ch == '}') {
   1295 			/*
   1296 			 * A semicolon or { or } is itself.
   1297 			 */
   1298 			return (ch);
   1299 		}
   1300 
   1301 		if (ch == '#') {
   1302 			/*
   1303 			 * #{ after a condition opens a format; anything else
   1304 			 * is a comment, ignore up to the end of the line.
   1305 			 */
   1306 			next = yylex_getc();
   1307 			if (condition && next == '{') {
   1308 				yylval.token = yylex_format();
   1309 				if (yylval.token == NULL)
   1310 					return (ERROR);
   1311 				return (FORMAT);
   1312 			}
   1313 			while (next != '\n' && next != EOF)
   1314 				next = yylex_getc();
   1315 			if (next == '\n') {
   1316 				ps->input->line++;
   1317 				return ('\n');
   1318 			}
   1319 			continue;
   1320 		}
   1321 
   1322 		if (ch == '%') {
   1323 			/*
   1324 			 * % is a condition unless it is all % or all numbers,
   1325 			 * then it is a token.
   1326 			 */
   1327 			yylval.token = yylex_get_word('%');
   1328 			for (cp = yylval.token; *cp != '\0'; cp++) {
   1329 				if (*cp != '%' && !isdigit((u_char)*cp))
   1330 					break;
   1331 			}
   1332 			if (*cp == '\0')
   1333 				return (TOKEN);
   1334 			ps->condition = 1;
   1335 			if (strcmp(yylval.token, "%hidden") == 0) {
   1336 				free(yylval.token);
   1337 				return (HIDDEN);
   1338 			}
   1339 			if (strcmp(yylval.token, "%if") == 0) {
   1340 				free(yylval.token);
   1341 				return (IF);
   1342 			}
   1343 			if (strcmp(yylval.token, "%else") == 0) {
   1344 				free(yylval.token);
   1345 				return (ELSE);
   1346 			}
   1347 			if (strcmp(yylval.token, "%elif") == 0) {
   1348 				free(yylval.token);
   1349 				return (ELIF);
   1350 			}
   1351 			if (strcmp(yylval.token, "%endif") == 0) {
   1352 				free(yylval.token);
   1353 				return (ENDIF);
   1354 			}
   1355 			free(yylval.token);
   1356 			return (ERROR);
   1357 		}
   1358 
   1359 		/*
   1360 		 * Otherwise this is a token.
   1361 		 */
   1362 		token = yylex_token(ch);
   1363 		if (token == NULL)
   1364 			return (ERROR);
   1365 		yylval.token = token;
   1366 
   1367 		if (strchr(token, '=') != NULL && yylex_is_var(*token, 1)) {
   1368 			for (cp = token + 1; *cp != '='; cp++) {
   1369 				if (!yylex_is_var(*cp, 0))
   1370 					break;
   1371 			}
   1372 			if (*cp == '=')
   1373 				return (EQUALS);
   1374 		}
   1375 		return (TOKEN);
   1376 	}
   1377 	return (0);
   1378 }
   1379 
   1380 static char *
   1381 yylex_format(void)
   1382 {
   1383 	char	*buf;
   1384 	size_t	 len;
   1385 	int	 ch, brackets = 1;
   1386 
   1387 	len = 0;
   1388 	buf = xmalloc(1);
   1389 
   1390 	yylex_append(&buf, &len, "#{", 2);
   1391 	for (;;) {
   1392 		if ((ch = yylex_getc()) == EOF || ch == '\n')
   1393 			goto error;
   1394 		if (ch == '#') {
   1395 			if ((ch = yylex_getc()) == EOF || ch == '\n')
   1396 				goto error;
   1397 			if (ch == '{')
   1398 				brackets++;
   1399 			yylex_append1(&buf, &len, '#');
   1400 		} else if (ch == '}') {
   1401 			if (brackets != 0 && --brackets == 0) {
   1402 				yylex_append1(&buf, &len, ch);
   1403 				break;
   1404 			}
   1405 		}
   1406 		yylex_append1(&buf, &len, ch);
   1407 	}
   1408 	if (brackets != 0)
   1409 		goto error;
   1410 
   1411 	buf[len] = '\0';
   1412 	log_debug("%s: %s", __func__, buf);
   1413 	return (buf);
   1414 
   1415 error:
   1416 	free(buf);
   1417 	return (NULL);
   1418 }
   1419 
   1420 static int
   1421 yylex_token_escape(char **buf, size_t *len)
   1422 {
   1423 	int	 ch, type, o2, o3, mlen;
   1424 	u_int	 size, i, tmp;
   1425 	char	 s[9], m[MB_LEN_MAX];
   1426 
   1427 	ch = yylex_getc();
   1428 
   1429 	if (ch >= '4' && ch <= '7') {
   1430 		yyerror("invalid octal escape");
   1431 		return (0);
   1432 	}
   1433 	if (ch >= '0' && ch <= '3') {
   1434 		o2 = yylex_getc();
   1435 		if (o2 >= '0' && o2 <= '7') {
   1436 			o3 = yylex_getc();
   1437 			if (o3 >= '0' && o3 <= '7') {
   1438 				ch = 64 * (ch - '0') +
   1439 				      8 * (o2 - '0') +
   1440 					  (o3 - '0');
   1441 				yylex_append1(buf, len, ch);
   1442 				return (1);
   1443 			}
   1444 		}
   1445 		yyerror("invalid octal escape");
   1446 		return (0);
   1447 	}
   1448 
   1449 	switch (ch) {
   1450 	case EOF:
   1451 		return (0);
   1452 	case 'a':
   1453 		ch = '\a';
   1454 		break;
   1455 	case 'b':
   1456 		ch = '\b';
   1457 		break;
   1458 	case 'e':
   1459 		ch = '\033';
   1460 		break;
   1461 	case 'f':
   1462 		ch = '\f';
   1463 		break;
   1464 	case 's':
   1465 		ch = ' ';
   1466 		break;
   1467 	case 'v':
   1468 		ch = '\v';
   1469 		break;
   1470 	case 'r':
   1471 		ch = '\r';
   1472 		break;
   1473 	case 'n':
   1474 		ch = '\n';
   1475 		break;
   1476 	case 't':
   1477 		ch = '\t';
   1478 		break;
   1479 	case 'u':
   1480 		type = 'u';
   1481 		size = 4;
   1482 		goto unicode;
   1483 	case 'U':
   1484 		type = 'U';
   1485 		size = 8;
   1486 		goto unicode;
   1487 	}
   1488 
   1489 	yylex_append1(buf, len, ch);
   1490 	return (1);
   1491 
   1492 unicode:
   1493 	for (i = 0; i < size; i++) {
   1494 		ch = yylex_getc();
   1495 		if (ch == EOF || ch == '\n')
   1496 			return (0);
   1497 		if (!isxdigit((u_char)ch)) {
   1498 			yyerror("invalid \\%c argument", type);
   1499 			return (0);
   1500 		}
   1501 		s[i] = ch;
   1502 	}
   1503 	s[i] = '\0';
   1504 
   1505 	if ((size == 4 && sscanf(s, "%4x", &tmp) != 1) ||
   1506 	    (size == 8 && sscanf(s, "%8x", &tmp) != 1)) {
   1507 		yyerror("invalid \\%c argument", type);
   1508 		return (0);
   1509 	}
   1510 	mlen = wctomb(m, tmp);
   1511 	if (mlen <= 0 || mlen > (int)sizeof m) {
   1512 		yyerror("invalid \\%c argument", type);
   1513 		return (0);
   1514 	}
   1515 	yylex_append(buf, len, m, mlen);
   1516 	return (1);
   1517 }
   1518 
   1519 static int
   1520 yylex_token_variable(char **buf, size_t *len)
   1521 {
   1522 	struct environ_entry	*envent;
   1523 	int			 ch, brackets = 0;
   1524 	char			 name[1024];
   1525 	size_t			 namelen = 0;
   1526 	const char		*value;
   1527 
   1528 	ch = yylex_getc();
   1529 	if (ch == EOF)
   1530 		return (0);
   1531 	if (ch == '{')
   1532 		brackets = 1;
   1533 	else {
   1534 		if (!yylex_is_var(ch, 1)) {
   1535 			yylex_append1(buf, len, '$');
   1536 			yylex_ungetc(ch);
   1537 			return (1);
   1538 		}
   1539 		name[namelen++] = ch;
   1540 	}
   1541 
   1542 	for (;;) {
   1543 		ch = yylex_getc();
   1544 		if (brackets && ch == '}')
   1545 			break;
   1546 		if (ch == EOF || !yylex_is_var(ch, 0)) {
   1547 			if (!brackets) {
   1548 				yylex_ungetc(ch);
   1549 				break;
   1550 			}
   1551 			yyerror("invalid environment variable");
   1552 			return (0);
   1553 		}
   1554 		if (namelen == (sizeof name) - 2) {
   1555 			yyerror("environment variable is too long");
   1556 			return (0);
   1557 		}
   1558 		name[namelen++] = ch;
   1559 	}
   1560 	name[namelen] = '\0';
   1561 
   1562 	envent = environ_find(global_environ, name);
   1563 	if (envent != NULL && envent->value != NULL) {
   1564 		value = envent->value;
   1565 		log_debug("%s: %s -> %s", __func__, name, value);
   1566 		yylex_append(buf, len, value, strlen(value));
   1567 	}
   1568 	return (1);
   1569 }
   1570 
   1571 static int
   1572 yylex_token_tilde(char **buf, size_t *len)
   1573 {
   1574 	struct environ_entry	*envent;
   1575 	int			 ch;
   1576 	char			 name[1024];
   1577 	size_t			 namelen = 0;
   1578 	struct passwd		*pw;
   1579 	const char		*home = NULL;
   1580 
   1581 	for (;;) {
   1582 		ch = yylex_getc();
   1583 		if (ch == EOF || strchr("/ \t\n\"'", ch) != NULL) {
   1584 			yylex_ungetc(ch);
   1585 			break;
   1586 		}
   1587 		if (namelen == (sizeof name) - 2) {
   1588 			yyerror("user name is too long");
   1589 			return (0);
   1590 		}
   1591 		name[namelen++] = ch;
   1592 	}
   1593 	name[namelen] = '\0';
   1594 
   1595 	if (*name == '\0') {
   1596 		envent = environ_find(global_environ, "HOME");
   1597 		if (envent != NULL && *envent->value != '\0')
   1598 			home = envent->value;
   1599 		else if ((pw = getpwuid(getuid())) != NULL)
   1600 			home = pw->pw_dir;
   1601 	} else {
   1602 		if ((pw = getpwnam(name)) != NULL)
   1603 			home = pw->pw_dir;
   1604 	}
   1605 	if (home == NULL)
   1606 		return (0);
   1607 
   1608 	log_debug("%s: ~%s -> %s", __func__, name, home);
   1609 	yylex_append(buf, len, home, strlen(home));
   1610 	return (1);
   1611 }
   1612 
   1613 static char *
   1614 yylex_token(int ch)
   1615 {
   1616 	char			*buf;
   1617 	size_t			 len;
   1618 	enum { START,
   1619 	       NONE,
   1620 	       DOUBLE_QUOTES,
   1621 	       SINGLE_QUOTES }	 state = NONE, last = START;
   1622 
   1623 	len = 0;
   1624 	buf = xmalloc(1);
   1625 
   1626 	for (;;) {
   1627 		/* EOF or \n are always the end of the token. */
   1628 		if (ch == EOF) {
   1629 			log_debug("%s: end at EOF", __func__);
   1630 			break;
   1631 		}
   1632 		if (state == NONE && ch == '\r') {
   1633 			ch = yylex_getc();
   1634 			if (ch != '\n') {
   1635 				yylex_ungetc(ch);
   1636 				ch = '\r';
   1637 			}
   1638 		}
   1639 		if (state == NONE && ch == '\n') {
   1640 			log_debug("%s: end at EOL", __func__);
   1641 			break;
   1642 		}
   1643 
   1644 		/* Whitespace or ; or } ends a token unless inside quotes. */
   1645 		if (state == NONE && (ch == ' ' || ch == '\t')) {
   1646 			log_debug("%s: end at WS", __func__);
   1647 			break;
   1648 		}
   1649 		if (state == NONE && (ch == ';' || ch == '}')) {
   1650 			log_debug("%s: end at %c", __func__, ch);
   1651 			break;
   1652 		}
   1653 
   1654 		/*
   1655 		 * Spaces and comments inside quotes after \n are removed but
   1656 		 * the \n is left.
   1657 		 */
   1658 		if (ch == '\n' && state != NONE) {
   1659 			yylex_append1(&buf, &len, '\n');
   1660 			while ((ch = yylex_getc()) == ' ' || ch == '\t')
   1661 				/* nothing */;
   1662 			if (ch != '#')
   1663 				continue;
   1664 			ch = yylex_getc();
   1665 			if (strchr(",#{}:", ch) != NULL) {
   1666 				yylex_ungetc(ch);
   1667 				ch = '#';
   1668 			} else {
   1669 				while ((ch = yylex_getc()) != '\n' && ch != EOF)
   1670 					/* nothing */;
   1671 			}
   1672 			continue;
   1673 		}
   1674 
   1675 		/* \ ~ and $ are expanded except in single quotes. */
   1676 		if (ch == '\\' && state != SINGLE_QUOTES) {
   1677 			if (!yylex_token_escape(&buf, &len))
   1678 				goto error;
   1679 			goto skip;
   1680 		}
   1681 		if (ch == '~' && last != state && state != SINGLE_QUOTES) {
   1682 			if (!yylex_token_tilde(&buf, &len))
   1683 				goto error;
   1684 			goto skip;
   1685 		}
   1686 		if (ch == '$' && state != SINGLE_QUOTES) {
   1687 			if (!yylex_token_variable(&buf, &len))
   1688 				goto error;
   1689 			goto skip;
   1690 		}
   1691 		if (ch == '}' && state == NONE)
   1692 			goto error;  /* unmatched (matched ones were handled) */
   1693 
   1694 		/* ' and " starts or end quotes (and is consumed). */
   1695 		if (ch == '\'') {
   1696 			if (state == NONE) {
   1697 				state = SINGLE_QUOTES;
   1698 				goto next;
   1699 			}
   1700 			if (state == SINGLE_QUOTES) {
   1701 				state = NONE;
   1702 				goto next;
   1703 			}
   1704 		}
   1705 		if (ch == '"') {
   1706 			if (state == NONE) {
   1707 				state = DOUBLE_QUOTES;
   1708 				goto next;
   1709 			}
   1710 			if (state == DOUBLE_QUOTES) {
   1711 				state = NONE;
   1712 				goto next;
   1713 			}
   1714 		}
   1715 
   1716 		/* Otherwise add the character to the buffer. */
   1717 		yylex_append1(&buf, &len, ch);
   1718 
   1719 	skip:
   1720 		last = state;
   1721 
   1722 	next:
   1723 		ch = yylex_getc();
   1724 	}
   1725 	yylex_ungetc(ch);
   1726 
   1727 	buf[len] = '\0';
   1728 	log_debug("%s: %s", __func__, buf);
   1729 	return (buf);
   1730 
   1731 error:
   1732 	free(buf);
   1733 	return (NULL);
   1734 }
   1735