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