xref: /openbsd-src/usr.bin/tmux/cmd-parse.y (revision a2d98599e3c69439489c0bfafa67f0ebef23661b)
1 /* $OpenBSD: cmd-parse.y,v 1.47 2021/09/09 06:57:48 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@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 	memset(pr, 0, sizeof *pr);
753 
754 	first = TAILQ_FIRST(&cmd->arguments);
755 	if (first == NULL || first->type != CMD_PARSE_STRING) {
756 		pr->status = CMD_PARSE_SUCCESS;
757 		pr->cmdlist = cmd_list_new();
758 		return (1);
759 	}
760 	name = first->string;
761 
762 	alias = cmd_get_alias(name);
763 	if (alias == NULL)
764 		return (0);
765 	log_debug("%s: %u alias %s = %s", __func__, pi->line, name, alias);
766 
767 	cmds = cmd_parse_do_buffer(alias, strlen(alias), pi, &cause);
768 	free(alias);
769 	if (cmds == NULL) {
770 		pr->status = CMD_PARSE_ERROR;
771 		pr->error = cause;
772 		return (1);
773 	}
774 
775 	last = TAILQ_LAST(cmds, cmd_parse_commands);
776 	if (last == NULL) {
777 		pr->status = CMD_PARSE_SUCCESS;
778 		pr->cmdlist = cmd_list_new();
779 		return (1);
780 	}
781 
782 	TAILQ_REMOVE(&cmd->arguments, first, entry);
783 	cmd_parse_free_argument(first);
784 
785 	TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) {
786 		TAILQ_REMOVE(&cmd->arguments, arg, entry);
787 		TAILQ_INSERT_TAIL(&last->arguments, arg, entry);
788 	}
789  	cmd_parse_log_commands(cmds, __func__);
790 
791 	cmd_parse_build_commands(cmds, pi, pr);
792 	return (1);
793 }
794 
795 static void
796 cmd_parse_build_command(struct cmd_parse_command *cmd,
797     struct cmd_parse_input *pi, struct cmd_parse_result *pr)
798 {
799 	struct cmd_parse_argument	*arg;
800 	struct cmd			*add;
801 	char				*cause;
802 	struct args_value		*values = NULL;
803 	u_int				 count = 0, idx;
804 
805 	memset(pr, 0, sizeof *pr);
806 
807 	if (cmd_parse_expand_alias(cmd, pi, pr))
808 		return;
809 
810 	TAILQ_FOREACH(arg, &cmd->arguments, entry) {
811 		values = xrecallocarray(values, count, count + 1,
812 		    sizeof *values);
813 		switch (arg->type) {
814 		case CMD_PARSE_STRING:
815 			values[count].type = ARGS_STRING;
816 			values[count].string = xstrdup(arg->string);
817 			break;
818 		case CMD_PARSE_COMMANDS:
819 			cmd_parse_build_commands(arg->commands, pi, pr);
820 			if (pr->status != CMD_PARSE_SUCCESS)
821 				goto out;
822 			values[count].type = ARGS_COMMANDS;
823 			values[count].cmdlist = pr->cmdlist;
824 			break;
825 		case CMD_PARSE_PARSED_COMMANDS:
826 			values[count].type = ARGS_COMMANDS;
827 			values[count].cmdlist = arg->cmdlist;
828 			values[count].cmdlist->references++;
829 			break;
830 		}
831 		count++;
832 	}
833 
834 	add = cmd_parse(values, count, pi->file, pi->line, &cause);
835 	if (add == NULL) {
836 		pr->status = CMD_PARSE_ERROR;
837 		pr->error = cmd_parse_get_error(pi->file, pi->line, cause);
838 		free(cause);
839 		goto out;
840 	}
841 	pr->status = CMD_PARSE_SUCCESS;
842 	pr->cmdlist = cmd_list_new();
843 	cmd_list_append(pr->cmdlist, add);
844 
845 out:
846 	for (idx = 0; idx < count; idx++)
847 		args_free_value(&values[idx]);
848 	free(values);
849 }
850 
851 static void
852 cmd_parse_build_commands(struct cmd_parse_commands *cmds,
853     struct cmd_parse_input *pi, struct cmd_parse_result *pr)
854 {
855 	struct cmd_parse_command	*cmd;
856 	u_int				 line = UINT_MAX;
857 	struct cmd_list			*current = NULL, *result;
858 	char				*s;
859 
860 	memset(pr, 0, sizeof *pr);
861 
862 	/* Check for an empty list. */
863 	if (TAILQ_EMPTY(cmds)) {
864 		pr->status = CMD_PARSE_SUCCESS;
865 		pr->cmdlist = cmd_list_new();
866 		return;
867 	}
868  	cmd_parse_log_commands(cmds, __func__);
869 
870 	/*
871 	 * Parse each command into a command list. Create a new command list
872 	 * for each line (unless the flag is set) so they get a new group (so
873 	 * the queue knows which ones to remove if a command fails when
874 	 * executed).
875 	 */
876 	result = cmd_list_new();
877 	TAILQ_FOREACH(cmd, cmds, entry) {
878 		if (((~pi->flags & CMD_PARSE_ONEGROUP) && cmd->line != line)) {
879 			if (current != NULL) {
880 				cmd_parse_print_commands(pi, current);
881 				cmd_list_move(result, current);
882 				cmd_list_free(current);
883 			}
884 			current = cmd_list_new();
885 		}
886 		if (current == NULL)
887 			current = cmd_list_new();
888 		line = pi->line = cmd->line;
889 
890 		cmd_parse_build_command(cmd, pi, pr);
891 		if (pr->status != CMD_PARSE_SUCCESS) {
892 			cmd_list_free(result);
893 			cmd_list_free(current);
894 			return;
895 		}
896 		cmd_list_append_all(current, pr->cmdlist);
897 		cmd_list_free(pr->cmdlist);
898 	}
899 	if (current != NULL) {
900 		cmd_parse_print_commands(pi, current);
901 		cmd_list_move(result, current);
902 		cmd_list_free(current);
903 	}
904 
905 	s = cmd_list_print(result, 0);
906 	log_debug("%s: %s", __func__, s);
907 	free(s);
908 
909 	pr->status = CMD_PARSE_SUCCESS;
910 	pr->cmdlist = result;
911 }
912 
913 struct cmd_parse_result *
914 cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi)
915 {
916 	static struct cmd_parse_result	 pr;
917 	struct cmd_parse_input		 input;
918 	struct cmd_parse_commands	*cmds;
919 	char				*cause;
920 
921 	if (pi == NULL) {
922 		memset(&input, 0, sizeof input);
923 		pi = &input;
924 	}
925 	memset(&pr, 0, sizeof pr);
926 
927 	cmds = cmd_parse_do_file(f, pi, &cause);
928 	if (cmds == NULL) {
929 		pr.status = CMD_PARSE_ERROR;
930 		pr.error = cause;
931 		return (&pr);
932 	}
933 	cmd_parse_build_commands(cmds, pi, &pr);
934 	cmd_parse_free_commands(cmds);
935 	return (&pr);
936 
937 }
938 
939 struct cmd_parse_result *
940 cmd_parse_from_string(const char *s, struct cmd_parse_input *pi)
941 {
942 	struct cmd_parse_input	input;
943 
944 	if (pi == NULL) {
945 		memset(&input, 0, sizeof input);
946 		pi = &input;
947 	}
948 
949 	/*
950 	 * When parsing a string, put commands in one group even if there are
951 	 * multiple lines. This means { a \n b } is identical to "a ; b" when
952 	 * given as an argument to another command.
953 	 */
954 	pi->flags |= CMD_PARSE_ONEGROUP;
955 	return (cmd_parse_from_buffer(s, strlen(s), pi));
956 }
957 
958 enum cmd_parse_status
959 cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi,
960     struct cmdq_item *after, struct cmdq_state *state, char **error)
961 {
962 	struct cmd_parse_result	*pr;
963 	struct cmdq_item	*item;
964 
965 	pr = cmd_parse_from_string(s, pi);
966 	switch (pr->status) {
967 	case CMD_PARSE_ERROR:
968 		if (error != NULL)
969 			*error = pr->error;
970 		else
971 			free(pr->error);
972 		break;
973 	case CMD_PARSE_SUCCESS:
974 		item = cmdq_get_command(pr->cmdlist, state);
975 		cmdq_insert_after(after, item);
976 		cmd_list_free(pr->cmdlist);
977 		break;
978 	}
979 	return (pr->status);
980 }
981 
982 enum cmd_parse_status
983 cmd_parse_and_append(const char *s, struct cmd_parse_input *pi,
984     struct client *c, struct cmdq_state *state, char **error)
985 {
986 	struct cmd_parse_result	*pr;
987 	struct cmdq_item	*item;
988 
989 	pr = cmd_parse_from_string(s, pi);
990 	switch (pr->status) {
991 	case CMD_PARSE_ERROR:
992 		if (error != NULL)
993 			*error = pr->error;
994 		else
995 			free(pr->error);
996 		break;
997 	case CMD_PARSE_SUCCESS:
998 		item = cmdq_get_command(pr->cmdlist, state);
999 		cmdq_append(c, item);
1000 		cmd_list_free(pr->cmdlist);
1001 		break;
1002 	}
1003 	return (pr->status);
1004 }
1005 
1006 struct cmd_parse_result *
1007 cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
1008 {
1009 	static struct cmd_parse_result	 pr;
1010 	struct cmd_parse_input		 input;
1011 	struct cmd_parse_commands	*cmds;
1012 	char				*cause;
1013 
1014 	if (pi == NULL) {
1015 		memset(&input, 0, sizeof input);
1016 		pi = &input;
1017 	}
1018 	memset(&pr, 0, sizeof pr);
1019 
1020 	if (len == 0) {
1021 		pr.status = CMD_PARSE_SUCCESS;
1022 		pr.cmdlist = cmd_list_new();
1023 		return (&pr);
1024 	}
1025 
1026 	cmds = cmd_parse_do_buffer(buf, len, pi, &cause);
1027 	if (cmds == NULL) {
1028 		pr.status = CMD_PARSE_ERROR;
1029 		pr.error = cause;
1030 		return (&pr);
1031 	}
1032 	cmd_parse_build_commands(cmds, pi, &pr);
1033 	cmd_parse_free_commands(cmds);
1034 	return (&pr);
1035 }
1036 
1037 struct cmd_parse_result *
1038 cmd_parse_from_arguments(struct args_value *values, u_int count,
1039     struct cmd_parse_input *pi)
1040 {
1041 	static struct cmd_parse_result	 pr;
1042 	struct cmd_parse_input		 input;
1043 	struct cmd_parse_commands	*cmds;
1044 	struct cmd_parse_command	*cmd;
1045 	struct cmd_parse_argument	*arg;
1046 	u_int				 i;
1047 	char				*copy;
1048 	size_t				 size;
1049 	int				 end;
1050 
1051 	/*
1052 	 * The commands are already split up into arguments, so just separate
1053 	 * into a set of commands by ';'.
1054 	 */
1055 
1056 	if (pi == NULL) {
1057 		memset(&input, 0, sizeof input);
1058 		pi = &input;
1059 	}
1060 	memset(&pr, 0, sizeof pr);
1061 
1062 	cmds = cmd_parse_new_commands();
1063 
1064 	cmd = xcalloc(1, sizeof *cmd);
1065 	cmd->line = pi->line;
1066 	TAILQ_INIT(&cmd->arguments);
1067 
1068 	for (i = 0; i < count; i++) {
1069 		end = 0;
1070 		if (values[i].type == ARGS_STRING) {
1071 			copy = xstrdup(values[i].string);
1072 			size = strlen(copy);
1073 			if (size != 0 && copy[size - 1] == ';') {
1074 				copy[--size] = '\0';
1075 				if (size > 0 && copy[size - 1] == '\\')
1076 					copy[size - 1] = ';';
1077 				else
1078 					end = 1;
1079 			}
1080 			if (!end || size != 0) {
1081 				arg = xcalloc(1, sizeof *arg);
1082 				arg->type = CMD_PARSE_STRING;
1083 				arg->string = copy;
1084 				TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
1085 			}
1086 		} else if (values[i].type == ARGS_COMMANDS) {
1087 			arg = xcalloc(1, sizeof *arg);
1088 			arg->type = CMD_PARSE_PARSED_COMMANDS;
1089 			arg->cmdlist = values[i].cmdlist;
1090 			arg->cmdlist->references++;
1091 			TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
1092 		} else
1093 			fatalx("unknown argument type");
1094 		if (end) {
1095 			TAILQ_INSERT_TAIL(cmds, cmd, entry);
1096 			cmd = xcalloc(1, sizeof *cmd);
1097 			cmd->line = pi->line;
1098 			TAILQ_INIT(&cmd->arguments);
1099 		}
1100 	}
1101 	if (!TAILQ_EMPTY(&cmd->arguments))
1102 		TAILQ_INSERT_TAIL(cmds, cmd, entry);
1103 	else
1104 		free(cmd);
1105 
1106 	cmd_parse_build_commands(cmds, pi, &pr);
1107 	cmd_parse_free_commands(cmds);
1108 	return (&pr);
1109 }
1110 
1111 static int printflike(1, 2)
1112 yyerror(const char *fmt, ...)
1113 {
1114 	struct cmd_parse_state	*ps = &parse_state;
1115 	struct cmd_parse_input	*pi = ps->input;
1116 	va_list			 ap;
1117 	char			*error;
1118 
1119 	if (ps->error != NULL)
1120 		return (0);
1121 
1122 	va_start(ap, fmt);
1123 	xvasprintf(&error, fmt, ap);
1124 	va_end(ap);
1125 
1126 	ps->error = cmd_parse_get_error(pi->file, pi->line, error);
1127 	free(error);
1128 	return (0);
1129 }
1130 
1131 static int
1132 yylex_is_var(char ch, int first)
1133 {
1134 	if (ch == '=')
1135 		return (0);
1136 	if (first && isdigit((u_char)ch))
1137 		return (0);
1138 	return (isalnum((u_char)ch) || ch == '_');
1139 }
1140 
1141 static void
1142 yylex_append(char **buf, size_t *len, const char *add, size_t addlen)
1143 {
1144 	if (addlen > SIZE_MAX - 1 || *len > SIZE_MAX - 1 - addlen)
1145 		fatalx("buffer is too big");
1146 	*buf = xrealloc(*buf, (*len) + 1 + addlen);
1147 	memcpy((*buf) + *len, add, addlen);
1148 	(*len) += addlen;
1149 }
1150 
1151 static void
1152 yylex_append1(char **buf, size_t *len, char add)
1153 {
1154 	yylex_append(buf, len, &add, 1);
1155 }
1156 
1157 static int
1158 yylex_getc1(void)
1159 {
1160 	struct cmd_parse_state	*ps = &parse_state;
1161 	int			 ch;
1162 
1163 	if (ps->f != NULL)
1164 		ch = getc(ps->f);
1165 	else {
1166 		if (ps->off == ps->len)
1167 			ch = EOF;
1168 		else
1169 			ch = ps->buf[ps->off++];
1170 	}
1171 	return (ch);
1172 }
1173 
1174 static void
1175 yylex_ungetc(int ch)
1176 {
1177 	struct cmd_parse_state	*ps = &parse_state;
1178 
1179 	if (ps->f != NULL)
1180 		ungetc(ch, ps->f);
1181 	else if (ps->off > 0 && ch != EOF)
1182 		ps->off--;
1183 }
1184 
1185 static int
1186 yylex_getc(void)
1187 {
1188 	struct cmd_parse_state	*ps = &parse_state;
1189 	int			 ch;
1190 
1191 	if (ps->escapes != 0) {
1192 		ps->escapes--;
1193 		return ('\\');
1194 	}
1195 	for (;;) {
1196 		ch = yylex_getc1();
1197 		if (ch == '\\') {
1198 			ps->escapes++;
1199 			continue;
1200 		}
1201 		if (ch == '\n' && (ps->escapes % 2) == 1) {
1202 			ps->input->line++;
1203 			ps->escapes--;
1204 			continue;
1205 		}
1206 
1207 		if (ps->escapes != 0) {
1208 			yylex_ungetc(ch);
1209 			ps->escapes--;
1210 			return ('\\');
1211 		}
1212 		return (ch);
1213 	}
1214 }
1215 
1216 static char *
1217 yylex_get_word(int ch)
1218 {
1219 	char	*buf;
1220 	size_t	 len;
1221 
1222 	len = 0;
1223 	buf = xmalloc(1);
1224 
1225 	do
1226 		yylex_append1(&buf, &len, ch);
1227 	while ((ch = yylex_getc()) != EOF && strchr(" \t\n", ch) == NULL);
1228 	yylex_ungetc(ch);
1229 
1230 	buf[len] = '\0';
1231 	log_debug("%s: %s", __func__, buf);
1232 	return (buf);
1233 }
1234 
1235 static int
1236 yylex(void)
1237 {
1238 	struct cmd_parse_state	*ps = &parse_state;
1239 	char			*token, *cp;
1240 	int			 ch, next, condition;
1241 
1242 	if (ps->eol)
1243 		ps->input->line++;
1244 	ps->eol = 0;
1245 
1246 	condition = ps->condition;
1247 	ps->condition = 0;
1248 
1249 	for (;;) {
1250 		ch = yylex_getc();
1251 
1252 		if (ch == EOF) {
1253 			/*
1254 			 * Ensure every file or string is terminated by a
1255 			 * newline. This keeps the parser simpler and avoids
1256 			 * having to add a newline to each string.
1257 			 */
1258 			if (ps->eof)
1259 				break;
1260 			ps->eof = 1;
1261 			return ('\n');
1262 		}
1263 
1264 		if (ch == ' ' || ch == '\t') {
1265 			/*
1266 			 * Ignore whitespace.
1267 			 */
1268 			continue;
1269 		}
1270 
1271 		if (ch == '\n') {
1272 			/*
1273 			 * End of line. Update the line number.
1274 			 */
1275 			ps->eol = 1;
1276 			return ('\n');
1277 		}
1278 
1279 		if (ch == ';' || ch == '{' || ch == '}') {
1280 			/*
1281 			 * A semicolon or { or } is itself.
1282 			 */
1283 			return (ch);
1284 		}
1285 
1286 		if (ch == '#') {
1287 			/*
1288 			 * #{ after a condition opens a format; anything else
1289 			 * is a comment, ignore up to the end of the line.
1290 			 */
1291 			next = yylex_getc();
1292 			if (condition && next == '{') {
1293 				yylval.token = yylex_format();
1294 				if (yylval.token == NULL)
1295 					return (ERROR);
1296 				return (FORMAT);
1297 			}
1298 			while (next != '\n' && next != EOF)
1299 				next = yylex_getc();
1300 			if (next == '\n') {
1301 				ps->input->line++;
1302 				return ('\n');
1303 			}
1304 			continue;
1305 		}
1306 
1307 		if (ch == '%') {
1308 			/*
1309 			 * % is a condition unless it is all % or all numbers,
1310 			 * then it is a token.
1311 			 */
1312 			yylval.token = yylex_get_word('%');
1313 			for (cp = yylval.token; *cp != '\0'; cp++) {
1314 				if (*cp != '%' && !isdigit((u_char)*cp))
1315 					break;
1316 			}
1317 			if (*cp == '\0')
1318 				return (TOKEN);
1319 			ps->condition = 1;
1320 			if (strcmp(yylval.token, "%hidden") == 0) {
1321 				free(yylval.token);
1322 				return (HIDDEN);
1323 			}
1324 			if (strcmp(yylval.token, "%if") == 0) {
1325 				free(yylval.token);
1326 				return (IF);
1327 			}
1328 			if (strcmp(yylval.token, "%else") == 0) {
1329 				free(yylval.token);
1330 				return (ELSE);
1331 			}
1332 			if (strcmp(yylval.token, "%elif") == 0) {
1333 				free(yylval.token);
1334 				return (ELIF);
1335 			}
1336 			if (strcmp(yylval.token, "%endif") == 0) {
1337 				free(yylval.token);
1338 				return (ENDIF);
1339 			}
1340 			free(yylval.token);
1341 			return (ERROR);
1342 		}
1343 
1344 		/*
1345 		 * Otherwise this is a token.
1346 		 */
1347 		token = yylex_token(ch);
1348 		if (token == NULL)
1349 			return (ERROR);
1350 		yylval.token = token;
1351 
1352 		if (strchr(token, '=') != NULL && yylex_is_var(*token, 1)) {
1353 			for (cp = token + 1; *cp != '='; cp++) {
1354 				if (!yylex_is_var(*cp, 0))
1355 					break;
1356 			}
1357 			if (*cp == '=')
1358 				return (EQUALS);
1359 		}
1360 		return (TOKEN);
1361 	}
1362 	return (0);
1363 }
1364 
1365 static char *
1366 yylex_format(void)
1367 {
1368 	char	*buf;
1369 	size_t	 len;
1370 	int	 ch, brackets = 1;
1371 
1372 	len = 0;
1373 	buf = xmalloc(1);
1374 
1375 	yylex_append(&buf, &len, "#{", 2);
1376 	for (;;) {
1377 		if ((ch = yylex_getc()) == EOF || ch == '\n')
1378 			goto error;
1379 		if (ch == '#') {
1380 			if ((ch = yylex_getc()) == EOF || ch == '\n')
1381 				goto error;
1382 			if (ch == '{')
1383 				brackets++;
1384 			yylex_append1(&buf, &len, '#');
1385 		} else if (ch == '}') {
1386 			if (brackets != 0 && --brackets == 0) {
1387 				yylex_append1(&buf, &len, ch);
1388 				break;
1389 			}
1390 		}
1391 		yylex_append1(&buf, &len, ch);
1392 	}
1393 	if (brackets != 0)
1394 		goto error;
1395 
1396 	buf[len] = '\0';
1397 	log_debug("%s: %s", __func__, buf);
1398 	return (buf);
1399 
1400 error:
1401 	free(buf);
1402 	return (NULL);
1403 }
1404 
1405 static int
1406 yylex_token_escape(char **buf, size_t *len)
1407 {
1408 	int	 ch, type, o2, o3, mlen;
1409 	u_int	 size, i, tmp;
1410 	char	 s[9], m[MB_LEN_MAX];
1411 
1412 	ch = yylex_getc();
1413 
1414 	if (ch >= '4' && ch <= '7') {
1415 		yyerror("invalid octal escape");
1416 		return (0);
1417 	}
1418 	if (ch >= '0' && ch <= '3') {
1419 		o2 = yylex_getc();
1420 		if (o2 >= '0' && o2 <= '7') {
1421 			o3 = yylex_getc();
1422 			if (o3 >= '0' && o3 <= '7') {
1423 				ch = 64 * (ch - '0') +
1424 				      8 * (o2 - '0') +
1425 				          (o3 - '0');
1426 				yylex_append1(buf, len, ch);
1427 				return (1);
1428 			}
1429 		}
1430 		yyerror("invalid octal escape");
1431 		return (0);
1432 	}
1433 
1434 	switch (ch) {
1435 	case EOF:
1436 		return (0);
1437 	case 'a':
1438 		ch = '\a';
1439 		break;
1440 	case 'b':
1441 		ch = '\b';
1442 		break;
1443 	case 'e':
1444 		ch = '\033';
1445 		break;
1446 	case 'f':
1447 		ch = '\f';
1448 		break;
1449 	case 's':
1450 		ch = ' ';
1451 		break;
1452 	case 'v':
1453 		ch = '\v';
1454 		break;
1455 	case 'r':
1456 		ch = '\r';
1457 		break;
1458 	case 'n':
1459 		ch = '\n';
1460 		break;
1461 	case 't':
1462 		ch = '\t';
1463 		break;
1464 	case 'u':
1465 		type = 'u';
1466 		size = 4;
1467 		goto unicode;
1468 	case 'U':
1469 		type = 'U';
1470 		size = 8;
1471 		goto unicode;
1472 	}
1473 
1474 	yylex_append1(buf, len, ch);
1475 	return (1);
1476 
1477 unicode:
1478 	for (i = 0; i < size; i++) {
1479 		ch = yylex_getc();
1480 		if (ch == EOF || ch == '\n')
1481 			return (0);
1482 		if (!isxdigit((u_char)ch)) {
1483 			yyerror("invalid \\%c argument", type);
1484 			return (0);
1485 		}
1486 		s[i] = ch;
1487 	}
1488 	s[i] = '\0';
1489 
1490 	if ((size == 4 && sscanf(s, "%4x", &tmp) != 1) ||
1491 	    (size == 8 && sscanf(s, "%8x", &tmp) != 1)) {
1492 		yyerror("invalid \\%c argument", type);
1493 		return (0);
1494 	}
1495 	mlen = wctomb(m, tmp);
1496 	if (mlen <= 0 || mlen > (int)sizeof m) {
1497 		yyerror("invalid \\%c argument", type);
1498 		return (0);
1499 	}
1500 	yylex_append(buf, len, m, mlen);
1501 	return (1);
1502 }
1503 
1504 static int
1505 yylex_token_variable(char **buf, size_t *len)
1506 {
1507 	struct environ_entry	*envent;
1508 	int			 ch, brackets = 0;
1509 	char			 name[1024];
1510 	size_t			 namelen = 0;
1511 	const char		*value;
1512 
1513 	ch = yylex_getc();
1514 	if (ch == EOF)
1515 		return (0);
1516 	if (ch == '{')
1517 		brackets = 1;
1518 	else {
1519 		if (!yylex_is_var(ch, 1)) {
1520 			yylex_append1(buf, len, '$');
1521 			yylex_ungetc(ch);
1522 			return (1);
1523 		}
1524 		name[namelen++] = ch;
1525 	}
1526 
1527 	for (;;) {
1528 		ch = yylex_getc();
1529 		if (brackets && ch == '}')
1530 			break;
1531 		if (ch == EOF || !yylex_is_var(ch, 0)) {
1532 			if (!brackets) {
1533 				yylex_ungetc(ch);
1534 				break;
1535 			}
1536 			yyerror("invalid environment variable");
1537 			return (0);
1538 		}
1539 		if (namelen == (sizeof name) - 2) {
1540 			yyerror("environment variable is too long");
1541 			return (0);
1542 		}
1543 		name[namelen++] = ch;
1544 	}
1545 	name[namelen] = '\0';
1546 
1547 	envent = environ_find(global_environ, name);
1548 	if (envent != NULL && envent->value != NULL) {
1549 		value = envent->value;
1550 		log_debug("%s: %s -> %s", __func__, name, value);
1551 		yylex_append(buf, len, value, strlen(value));
1552 	}
1553 	return (1);
1554 }
1555 
1556 static int
1557 yylex_token_tilde(char **buf, size_t *len)
1558 {
1559 	struct environ_entry	*envent;
1560 	int			 ch;
1561 	char			 name[1024];
1562 	size_t			 namelen = 0;
1563 	struct passwd		*pw;
1564 	const char		*home = NULL;
1565 
1566 	for (;;) {
1567 		ch = yylex_getc();
1568 		if (ch == EOF || strchr("/ \t\n\"'", ch) != NULL) {
1569 			yylex_ungetc(ch);
1570 			break;
1571 		}
1572 		if (namelen == (sizeof name) - 2) {
1573 			yyerror("user name is too long");
1574 			return (0);
1575 		}
1576 		name[namelen++] = ch;
1577 	}
1578 	name[namelen] = '\0';
1579 
1580 	if (*name == '\0') {
1581 		envent = environ_find(global_environ, "HOME");
1582 		if (envent != NULL && *envent->value != '\0')
1583 			home = envent->value;
1584 		else if ((pw = getpwuid(getuid())) != NULL)
1585 			home = pw->pw_dir;
1586 	} else {
1587 		if ((pw = getpwnam(name)) != NULL)
1588 			home = pw->pw_dir;
1589 	}
1590 	if (home == NULL)
1591 		return (0);
1592 
1593 	log_debug("%s: ~%s -> %s", __func__, name, home);
1594 	yylex_append(buf, len, home, strlen(home));
1595 	return (1);
1596 }
1597 
1598 static char *
1599 yylex_token(int ch)
1600 {
1601 	char			*buf;
1602 	size_t			 len;
1603 	enum { START,
1604 	       NONE,
1605 	       DOUBLE_QUOTES,
1606 	       SINGLE_QUOTES }	 state = NONE, last = START;
1607 
1608 	len = 0;
1609 	buf = xmalloc(1);
1610 
1611 	for (;;) {
1612 		/* EOF or \n are always the end of the token. */
1613 		if (ch == EOF || (state == NONE && ch == '\n'))
1614 			break;
1615 
1616 		/* Whitespace or ; or } ends a token unless inside quotes. */
1617 		if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') &&
1618 		    state == NONE)
1619 			break;
1620 
1621 		/*
1622 		 * Spaces and comments inside quotes after \n are removed but
1623 		 * the \n is left.
1624 		 */
1625 		if (ch == '\n' && state != NONE) {
1626 			yylex_append1(&buf, &len, '\n');
1627 			while ((ch = yylex_getc()) == ' ' || ch == '\t')
1628 				/* nothing */;
1629 			if (ch != '#')
1630 				continue;
1631 			ch = yylex_getc();
1632 			if (strchr(",#{}:", ch) != NULL) {
1633 				yylex_ungetc(ch);
1634 				ch = '#';
1635 			} else {
1636 				while ((ch = yylex_getc()) != '\n' && ch != EOF)
1637 					/* nothing */;
1638 			}
1639 			continue;
1640 		}
1641 
1642 		/* \ ~ and $ are expanded except in single quotes. */
1643 		if (ch == '\\' && state != SINGLE_QUOTES) {
1644 			if (!yylex_token_escape(&buf, &len))
1645 				goto error;
1646 			goto skip;
1647 		}
1648 		if (ch == '~' && last != state && state != SINGLE_QUOTES) {
1649 			if (!yylex_token_tilde(&buf, &len))
1650 				goto error;
1651 			goto skip;
1652 		}
1653 		if (ch == '$' && state != SINGLE_QUOTES) {
1654 			if (!yylex_token_variable(&buf, &len))
1655 				goto error;
1656 			goto skip;
1657 		}
1658 		if (ch == '}' && state == NONE)
1659 			goto error;  /* unmatched (matched ones were handled) */
1660 
1661 		/* ' and " starts or end quotes (and is consumed). */
1662 		if (ch == '\'') {
1663 			if (state == NONE) {
1664 				state = SINGLE_QUOTES;
1665 				goto next;
1666 			}
1667 			if (state == SINGLE_QUOTES) {
1668 				state = NONE;
1669 				goto next;
1670 			}
1671 		}
1672 		if (ch == '"') {
1673 			if (state == NONE) {
1674 				state = DOUBLE_QUOTES;
1675 				goto next;
1676 			}
1677 			if (state == DOUBLE_QUOTES) {
1678 				state = NONE;
1679 				goto next;
1680 			}
1681 		}
1682 
1683 		/* Otherwise add the character to the buffer. */
1684 		yylex_append1(&buf, &len, ch);
1685 
1686 	skip:
1687 		last = state;
1688 
1689 	next:
1690 		ch = yylex_getc();
1691 	}
1692 	yylex_ungetc(ch);
1693 
1694 	buf[len] = '\0';
1695 	log_debug("%s: %s", __func__, buf);
1696 	return (buf);
1697 
1698 error:
1699 	free(buf);
1700 	return (NULL);
1701 }
1702