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