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