xref: /openbsd/usr.bin/tmux/cmd-parse.y (revision 771fbea0)
1 /* $OpenBSD: cmd-parse.y,v 1.32 2020/12/01 10:48:03 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 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