xref: /freebsd/contrib/netbsd-tests/lib/libcurses/director/testlang_parse.y (revision c22165b4f1f5d38b681921797a44b3ba8c13b7e0)
157718be8SEnji Cooper %{
2*640235e2SEnji Cooper /*	$NetBSD: testlang_parse.y,v 1.14 2015/01/04 20:19:46 christos Exp $	*/
357718be8SEnji Cooper 
457718be8SEnji Cooper /*-
557718be8SEnji Cooper  * Copyright 2009 Brett Lymn <blymn@NetBSD.org>
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * All rights reserved.
857718be8SEnji Cooper  *
957718be8SEnji Cooper  * This code has been donated to The NetBSD Foundation by the Author.
1057718be8SEnji Cooper  *
1157718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
1257718be8SEnji Cooper  * modification, are permitted provided that the following conditions
1357718be8SEnji Cooper  * are met:
1457718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1557718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1657718be8SEnji Cooper  * 2. The name of the author may not be used to endorse or promote products
1757718be8SEnji Cooper  *    derived from this software withough specific prior written permission
1857718be8SEnji Cooper  *
1957718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2057718be8SEnji Cooper  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2157718be8SEnji Cooper  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2257718be8SEnji Cooper  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2357718be8SEnji Cooper  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2457718be8SEnji Cooper  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2557718be8SEnji Cooper  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2657718be8SEnji Cooper  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2757718be8SEnji Cooper  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2857718be8SEnji Cooper  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2957718be8SEnji Cooper  *
3057718be8SEnji Cooper  *
3157718be8SEnji Cooper  */
3257718be8SEnji Cooper #include <assert.h>
3357718be8SEnji Cooper #include <curses.h>
3457718be8SEnji Cooper #include <errno.h>
3557718be8SEnji Cooper #include <fcntl.h>
3657718be8SEnji Cooper #include <err.h>
3757718be8SEnji Cooper #include <unistd.h>
3857718be8SEnji Cooper #include <poll.h>
3957718be8SEnji Cooper #include <stdbool.h>
4057718be8SEnji Cooper #include <stdio.h>
4157718be8SEnji Cooper #include <string.h>
42*640235e2SEnji Cooper #include <stdlib.h>
43*640235e2SEnji Cooper #include <limits.h>
4457718be8SEnji Cooper #include <time.h>
4557718be8SEnji Cooper #include <vis.h>
4657718be8SEnji Cooper #include <stdint.h>
4757718be8SEnji Cooper #include "returns.h"
4857718be8SEnji Cooper 
4957718be8SEnji Cooper #define YYDEBUG 1
5057718be8SEnji Cooper 
5157718be8SEnji Cooper extern int verbose;
5257718be8SEnji Cooper extern int cmdpipe[2];
5357718be8SEnji Cooper extern int slvpipe[2];
5457718be8SEnji Cooper extern int master;
5557718be8SEnji Cooper extern struct pollfd readfd;
5657718be8SEnji Cooper extern char *check_path;
5757718be8SEnji Cooper extern char *cur_file;		/* from director.c */
5857718be8SEnji Cooper 
5957718be8SEnji Cooper int yylex(void);
6057718be8SEnji Cooper 
6157718be8SEnji Cooper size_t line;
6257718be8SEnji Cooper 
6357718be8SEnji Cooper static int input_delay;
6457718be8SEnji Cooper 
6557718be8SEnji Cooper /* time delay between inputs chars - default to 0.1ms minimum to prevent
6657718be8SEnji Cooper  * problems with input tests
6757718be8SEnji Cooper  */
6857718be8SEnji Cooper #define DELAY_MIN 0.1
6957718be8SEnji Cooper 
7057718be8SEnji Cooper /* time delay after a function call - allows the slave time to
7157718be8SEnji Cooper  * run the function and output data before we do other actions.
7257718be8SEnji Cooper  * Set this to 50ms.
7357718be8SEnji Cooper  */
7457718be8SEnji Cooper #define POST_CALL_DELAY 50
7557718be8SEnji Cooper 
7657718be8SEnji Cooper static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
7757718be8SEnji Cooper static struct timespec delay_post_call = {0, 1000 * POST_CALL_DELAY};
7857718be8SEnji Cooper 
7957718be8SEnji Cooper static char *input_str;	/* string to feed in as input */
8057718be8SEnji Cooper static bool no_input;	/* don't need more input */
8157718be8SEnji Cooper 
8257718be8SEnji Cooper #define READ_PIPE  0
8357718be8SEnji Cooper #define WRITE_PIPE 1
8457718be8SEnji Cooper 
8557718be8SEnji Cooper const char *returns_enum_names[] = {
8657718be8SEnji Cooper 	"unused", "numeric", "string", "byte", "ERR", "OK", "NULL", "not NULL",
8757718be8SEnji Cooper 	"variable", "reference", "returns count", "slave error"
8857718be8SEnji Cooper };
8957718be8SEnji Cooper 
9057718be8SEnji Cooper typedef enum {
9157718be8SEnji Cooper 	arg_static,
9257718be8SEnji Cooper 	arg_byte,
9357718be8SEnji Cooper 	arg_var,
9457718be8SEnji Cooper 	arg_null
9557718be8SEnji Cooper } args_state_t;
9657718be8SEnji Cooper 
9757718be8SEnji Cooper static const char *args_enum_names[] = {
9857718be8SEnji Cooper 	"static", "byte", "var", "NULL"
9957718be8SEnji Cooper };
10057718be8SEnji Cooper 
10157718be8SEnji Cooper typedef struct {
10257718be8SEnji Cooper 	args_state_t	arg_type;
10357718be8SEnji Cooper 	size_t		arg_len;
10457718be8SEnji Cooper 	char		*arg_string;
10557718be8SEnji Cooper 	int		var_index;
10657718be8SEnji Cooper } args_t;
10757718be8SEnji Cooper 
10857718be8SEnji Cooper typedef struct {
10957718be8SEnji Cooper 	char		*function;
11057718be8SEnji Cooper 	int		nrets;		/* number of returns */
11157718be8SEnji Cooper 	returns_t	*returns;	/* array of expected returns */
11257718be8SEnji Cooper 	int		nargs;		/* number of arguments */
11357718be8SEnji Cooper 	args_t		*args;		/* arguments for the call */
11457718be8SEnji Cooper } cmd_line_t;
11557718be8SEnji Cooper 
11657718be8SEnji Cooper static cmd_line_t	command;
11757718be8SEnji Cooper 
11857718be8SEnji Cooper typedef struct {
11957718be8SEnji Cooper 	char *name;
12057718be8SEnji Cooper 	size_t len;
12157718be8SEnji Cooper 	returns_enum_t type;
12257718be8SEnji Cooper 	void *value;
12357718be8SEnji Cooper } var_t;
12457718be8SEnji Cooper 
12557718be8SEnji Cooper static size_t nvars; 		/* Number of declared variables */
12657718be8SEnji Cooper static var_t *vars; 		/* Variables defined during the test. */
12757718be8SEnji Cooper 
12857718be8SEnji Cooper static int	check_function_table(char *, const char *[], int);
12957718be8SEnji Cooper static int	find_var_index(const char *);
13057718be8SEnji Cooper static void 	assign_arg(args_state_t, void *);
13157718be8SEnji Cooper static int	assign_var(char *);
13257718be8SEnji Cooper void		init_parse_variables(int);
13357718be8SEnji Cooper static void	validate(int, void *);
13457718be8SEnji Cooper static void	validate_return(const char *, const char *, int);
13557718be8SEnji Cooper static void	validate_variable(int, returns_enum_t, const void *, int, int);
13657718be8SEnji Cooper static void	validate_byte(returns_t *, returns_t *, int);
13757718be8SEnji Cooper static void	write_cmd_pipe(char *);
13857718be8SEnji Cooper static void	write_cmd_pipe_args(args_state_t, void *);
13957718be8SEnji Cooper static void	read_cmd_pipe(returns_t *);
14057718be8SEnji Cooper static void	write_func_and_args(void);
14157718be8SEnji Cooper static void	compare_streams(char *, bool);
14257718be8SEnji Cooper static void	do_function_call(size_t);
14357718be8SEnji Cooper static void	save_slave_output(bool);
14457718be8SEnji Cooper static void	validate_type(returns_enum_t, returns_t *, int);
14557718be8SEnji Cooper static void	set_var(returns_enum_t, char *, void *);
14657718be8SEnji Cooper static void	validate_reference(int, void *);
14757718be8SEnji Cooper static char	*numeric_or(char *, char *);
14857718be8SEnji Cooper static char	*get_numeric_var(const char *);
14957718be8SEnji Cooper static void	perform_delay(struct timespec *);
15057718be8SEnji Cooper 
15157718be8SEnji Cooper static const char *input_functions[] = {
15257718be8SEnji Cooper 	"getch", "getnstr", "getstr", "mvgetnstr", "mvgetstr", "mvgetnstr",
15357718be8SEnji Cooper 	"mvgetstr", "mvscanw", "mvwscanw", "scanw", "wgetch", "wgetnstr",
15457718be8SEnji Cooper 	"wgetstr"
15557718be8SEnji Cooper };
15657718be8SEnji Cooper 
15757718be8SEnji Cooper static const unsigned ninput_functions =
15857718be8SEnji Cooper 	sizeof(input_functions) / sizeof(char *);
15957718be8SEnji Cooper 
16057718be8SEnji Cooper saved_data_t saved_output;
16157718be8SEnji Cooper 
16257718be8SEnji Cooper %}
16357718be8SEnji Cooper 
16457718be8SEnji Cooper %union {
16557718be8SEnji Cooper 	char *string;
16657718be8SEnji Cooper 	returns_t *retval;
16757718be8SEnji Cooper }
16857718be8SEnji Cooper 
16957718be8SEnji Cooper %token <string> PATH
17057718be8SEnji Cooper %token <string> STRING
17157718be8SEnji Cooper %token <retval> BYTE
17257718be8SEnji Cooper %token <string> VARNAME
17357718be8SEnji Cooper %token <string> FILENAME
17457718be8SEnji Cooper %token <string> VARIABLE
17557718be8SEnji Cooper %token <string> REFERENCE
17657718be8SEnji Cooper %token <string> NULL_RET
17757718be8SEnji Cooper %token <string> NON_NULL
17857718be8SEnji Cooper %token <string> ERR_RET
17957718be8SEnji Cooper %token <string> OK_RET
18057718be8SEnji Cooper %token <string> numeric
18157718be8SEnji Cooper %token <string> DELAY
18257718be8SEnji Cooper %token <string> INPUT
18357718be8SEnji Cooper %token <string> COMPARE
18457718be8SEnji Cooper %token <string> COMPAREND
18557718be8SEnji Cooper %token <string> ASSIGN
18657718be8SEnji Cooper %token EOL CALL CHECK NOINPUT OR LHB RHB
18757718be8SEnji Cooper %token CALL2 CALL3 CALL4 DRAIN
18857718be8SEnji Cooper 
18957718be8SEnji Cooper %nonassoc OR
19057718be8SEnji Cooper 
19157718be8SEnji Cooper %%
19257718be8SEnji Cooper 
19357718be8SEnji Cooper statement	:	/* empty */
19457718be8SEnji Cooper 		| assign statement
19557718be8SEnji Cooper 		| call statement
19657718be8SEnji Cooper 		| call2 statement
19757718be8SEnji Cooper 		| call3 statement
19857718be8SEnji Cooper 		| call4 statement
19957718be8SEnji Cooper 		| check statement
20057718be8SEnji Cooper 		| delay statement
20157718be8SEnji Cooper 		| input statement
20257718be8SEnji Cooper 		| noinput statement
20357718be8SEnji Cooper 		| compare statement
20457718be8SEnji Cooper 		| comparend statement
20557718be8SEnji Cooper 		| eol statement
20657718be8SEnji Cooper 		;
20757718be8SEnji Cooper 
20857718be8SEnji Cooper assign		: ASSIGN VARNAME numeric {set_var(ret_number, $2, $3);} eol
20957718be8SEnji Cooper 		| ASSIGN VARNAME LHB expr RHB {set_var(ret_number, $2, $<string>4);} eol
21057718be8SEnji Cooper 		| ASSIGN VARNAME STRING {set_var(ret_string, $2, $3);} eol
21157718be8SEnji Cooper 		| ASSIGN VARNAME BYTE {set_var(ret_byte, $2, $3);} eol
21257718be8SEnji Cooper 		;
21357718be8SEnji Cooper 
21457718be8SEnji Cooper call		: CALL result fn_name args eol {
21557718be8SEnji Cooper 	do_function_call(1);
21657718be8SEnji Cooper }
21757718be8SEnji Cooper 		;
21857718be8SEnji Cooper 
21957718be8SEnji Cooper call2		: CALL2 result result fn_name args eol {
22057718be8SEnji Cooper 	do_function_call(2);
22157718be8SEnji Cooper }
22257718be8SEnji Cooper 		;
22357718be8SEnji Cooper 
22457718be8SEnji Cooper call3		: CALL3 result result result fn_name args eol {
22557718be8SEnji Cooper 	do_function_call(3);
22657718be8SEnji Cooper }
22757718be8SEnji Cooper 		;
22857718be8SEnji Cooper 
22957718be8SEnji Cooper call4		: CALL4 result result result result fn_name args eol {
23057718be8SEnji Cooper 	do_function_call(4);
23157718be8SEnji Cooper  }
23257718be8SEnji Cooper 		;
23357718be8SEnji Cooper 
23457718be8SEnji Cooper check		: CHECK var returns eol {
23557718be8SEnji Cooper 	returns_t retvar;
23657718be8SEnji Cooper 	var_t *vptr;
23757718be8SEnji Cooper 	if (command.returns[0].return_index == -1)
23857718be8SEnji Cooper 		err(1, "Undefined variable in check statement, line %zu"
23957718be8SEnji Cooper 		    " of file %s", line, cur_file);
24057718be8SEnji Cooper 
24157718be8SEnji Cooper 	if (verbose) {
24257718be8SEnji Cooper 		fprintf(stderr, "Checking contents of variable %s for %s\n",
24357718be8SEnji Cooper 		    vars[command.returns[0].return_index].name,
24457718be8SEnji Cooper 		    returns_enum_names[command.returns[1].return_type]);
24557718be8SEnji Cooper 	}
24657718be8SEnji Cooper 
24757718be8SEnji Cooper 	if (((command.returns[1].return_type == ret_byte) &&
24857718be8SEnji Cooper 	     (vars[command.returns[0].return_index].type != ret_byte)) ||
24957718be8SEnji Cooper 	    vars[command.returns[0].return_index].type != ret_string)
25057718be8SEnji Cooper 		err(1, "Var type %s (%d) does not match return type %s (%d)",
25157718be8SEnji Cooper 		    returns_enum_names[
25257718be8SEnji Cooper 		    vars[command.returns[0].return_index].type],
25357718be8SEnji Cooper 		    vars[command.returns[0].return_index].type,
25457718be8SEnji Cooper 		    returns_enum_names[command.returns[1].return_type],
25557718be8SEnji Cooper 		    command.returns[1].return_type);
25657718be8SEnji Cooper 
25757718be8SEnji Cooper 	switch (command.returns[1].return_type) {
25857718be8SEnji Cooper 	case ret_err:
25957718be8SEnji Cooper 		validate_variable(0, ret_string, "ERR",
26057718be8SEnji Cooper 				  command.returns[0].return_index, 0);
26157718be8SEnji Cooper 		break;
26257718be8SEnji Cooper 
26357718be8SEnji Cooper 	case ret_ok:
26457718be8SEnji Cooper 		validate_variable(0, ret_string, "OK",
26557718be8SEnji Cooper 				  command.returns[0].return_index, 0);
26657718be8SEnji Cooper 		break;
26757718be8SEnji Cooper 
26857718be8SEnji Cooper 	case ret_null:
26957718be8SEnji Cooper 		validate_variable(0, ret_string, "NULL",
27057718be8SEnji Cooper 				  command.returns[0].return_index, 0);
27157718be8SEnji Cooper 		break;
27257718be8SEnji Cooper 
27357718be8SEnji Cooper 	case ret_nonnull:
27457718be8SEnji Cooper 		validate_variable(0, ret_string, "NULL",
27557718be8SEnji Cooper 				  command.returns[0].return_index, 1);
27657718be8SEnji Cooper 		break;
27757718be8SEnji Cooper 
27857718be8SEnji Cooper 	case ret_string:
27957718be8SEnji Cooper 	case ret_number:
28057718be8SEnji Cooper 		if (verbose) {
28157718be8SEnji Cooper 			fprintf(stderr, " %s == returned %s\n",
28257718be8SEnji Cooper 			    (const char *)command.returns[1].return_value,
28357718be8SEnji Cooper 			    (const char *)
28457718be8SEnji Cooper 			    vars[command.returns[0].return_index].value);
28557718be8SEnji Cooper 		}
28657718be8SEnji Cooper 		validate_variable(0, ret_string,
28757718be8SEnji Cooper 		    command.returns[1].return_value,
28857718be8SEnji Cooper 		    command.returns[0].return_index, 0);
28957718be8SEnji Cooper 		break;
29057718be8SEnji Cooper 
29157718be8SEnji Cooper 	case ret_byte:
29257718be8SEnji Cooper 		vptr = &vars[command.returns[0].return_index];
29357718be8SEnji Cooper 		retvar.return_len = vptr->len;
29457718be8SEnji Cooper 		retvar.return_type = vptr->type;
29557718be8SEnji Cooper 		retvar.return_value = vptr->value;
29657718be8SEnji Cooper 		validate_byte(&retvar, &command.returns[1], 0);
29757718be8SEnji Cooper 		break;
29857718be8SEnji Cooper 
29957718be8SEnji Cooper 	default:
30057718be8SEnji Cooper 		err(1, "Malformed check statement at line %zu "
30157718be8SEnji Cooper 		    "of file %s", line, cur_file);
30257718be8SEnji Cooper 		break;
30357718be8SEnji Cooper 	}
30457718be8SEnji Cooper 
30557718be8SEnji Cooper 	init_parse_variables(0);
30657718be8SEnji Cooper  }
30757718be8SEnji Cooper 		;
30857718be8SEnji Cooper 
30957718be8SEnji Cooper delay		: DELAY numeric eol {
31057718be8SEnji Cooper 	/* set the inter-character delay */
31157718be8SEnji Cooper 	if (sscanf($2, "%d", &input_delay) == 0)
31257718be8SEnji Cooper 		err(1, "delay specification %s could not be converted to "
31357718be8SEnji Cooper 		    "numeric at line %zu of file %s", $2, line, cur_file);
31457718be8SEnji Cooper 	if (verbose) {
31557718be8SEnji Cooper 		fprintf(stderr, "Set input delay to %d ms\n", input_delay);
31657718be8SEnji Cooper 	}
31757718be8SEnji Cooper 
31857718be8SEnji Cooper 	if (input_delay < DELAY_MIN)
31957718be8SEnji Cooper 		input_delay = DELAY_MIN;
32057718be8SEnji Cooper 	/*
32157718be8SEnji Cooper 	 * Fill in the timespec structure now ready for use later.
32257718be8SEnji Cooper 	 * The delay is specified in milliseconds so convert to timespec
32357718be8SEnji Cooper 	 * values
32457718be8SEnji Cooper 	 */
32557718be8SEnji Cooper 	delay_spec.tv_sec = input_delay / 1000;
32657718be8SEnji Cooper 	delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
32757718be8SEnji Cooper 	if (verbose) {
32857718be8SEnji Cooper 		fprintf(stderr, "set delay to %jd.%jd\n",
32957718be8SEnji Cooper 		    (intmax_t)delay_spec.tv_sec,
33057718be8SEnji Cooper 		    (intmax_t)delay_spec.tv_nsec);
33157718be8SEnji Cooper 	}
33257718be8SEnji Cooper 
33357718be8SEnji Cooper 	init_parse_variables(0);
33457718be8SEnji Cooper  }
33557718be8SEnji Cooper 	;
33657718be8SEnji Cooper 
33757718be8SEnji Cooper input		: INPUT STRING eol {
33857718be8SEnji Cooper 	if (input_str != NULL) {
33957718be8SEnji Cooper 		warnx("%s, %zu: Discarding unused input string",
34057718be8SEnji Cooper 		    cur_file, line);
34157718be8SEnji Cooper 		free(input_str);
34257718be8SEnji Cooper 	}
34357718be8SEnji Cooper 
34457718be8SEnji Cooper 	if ((input_str = malloc(strlen($2) + 1)) == NULL)
34557718be8SEnji Cooper 		err(2, "Cannot allocate memory for input string");
34657718be8SEnji Cooper 
34757718be8SEnji Cooper 	strlcpy(input_str, $2, strlen($2) + 1);
34857718be8SEnji Cooper }
34957718be8SEnji Cooper 	;
35057718be8SEnji Cooper 
35157718be8SEnji Cooper 
35257718be8SEnji Cooper noinput		: NOINPUT eol {
35357718be8SEnji Cooper 	if (input_str != NULL) {
35457718be8SEnji Cooper 		warnx("%s, %zu: Discarding unused input string",
35557718be8SEnji Cooper 		    cur_file, line);
35657718be8SEnji Cooper 		free(input_str);
35757718be8SEnji Cooper 	}
35857718be8SEnji Cooper 
35957718be8SEnji Cooper 	no_input = true;
36057718be8SEnji Cooper  }
36157718be8SEnji Cooper 
36257718be8SEnji Cooper compare		: COMPARE PATH eol
36357718be8SEnji Cooper 		| COMPARE FILENAME eol
36457718be8SEnji Cooper {
36557718be8SEnji Cooper 	compare_streams($2, true);
36657718be8SEnji Cooper }
36757718be8SEnji Cooper 	;
36857718be8SEnji Cooper 
36957718be8SEnji Cooper 
37057718be8SEnji Cooper comparend	: COMPAREND PATH eol
37157718be8SEnji Cooper 		| COMPAREND FILENAME eol
37257718be8SEnji Cooper {
37357718be8SEnji Cooper 	compare_streams($2, false);
37457718be8SEnji Cooper }
37557718be8SEnji Cooper 	;
37657718be8SEnji Cooper 
37757718be8SEnji Cooper 
37857718be8SEnji Cooper result		: returns
37957718be8SEnji Cooper 		| var
38057718be8SEnji Cooper 		| reference
38157718be8SEnji Cooper 		;
38257718be8SEnji Cooper 
38357718be8SEnji Cooper returns		: numeric { assign_rets(ret_number, $1); }
38457718be8SEnji Cooper 		| LHB expr RHB { assign_rets(ret_number, $<string>2); }
38557718be8SEnji Cooper 		| STRING { assign_rets(ret_string, $1); }
38657718be8SEnji Cooper 		| BYTE { assign_rets(ret_byte, (void *) $1); }
38757718be8SEnji Cooper 		| ERR_RET { assign_rets(ret_err, NULL); }
38857718be8SEnji Cooper 		| OK_RET { assign_rets(ret_ok, NULL); }
38957718be8SEnji Cooper 		| NULL_RET { assign_rets(ret_null, NULL); }
39057718be8SEnji Cooper 		| NON_NULL { assign_rets(ret_nonnull, NULL); }
39157718be8SEnji Cooper 		;
39257718be8SEnji Cooper 
39357718be8SEnji Cooper var		: VARNAME {
39457718be8SEnji Cooper 	assign_rets(ret_var, $1);
39557718be8SEnji Cooper  }
39657718be8SEnji Cooper 		;
39757718be8SEnji Cooper 
39857718be8SEnji Cooper reference	: VARIABLE {
39957718be8SEnji Cooper 	assign_rets(ret_ref, $1);
40057718be8SEnji Cooper  }
40157718be8SEnji Cooper 
40257718be8SEnji Cooper fn_name		: VARNAME {
40357718be8SEnji Cooper 	if (command.function != NULL)
40457718be8SEnji Cooper 		free(command.function);
40557718be8SEnji Cooper 
40657718be8SEnji Cooper 	command.function = malloc(strlen($1) + 1);
40757718be8SEnji Cooper 	if (command.function == NULL)
40857718be8SEnji Cooper 		err(1, "Could not allocate memory for function name");
40957718be8SEnji Cooper 	strcpy(command.function, $1);
41057718be8SEnji Cooper  }
41157718be8SEnji Cooper 		;
41257718be8SEnji Cooper 
41357718be8SEnji Cooper expr		: numeric
41457718be8SEnji Cooper 		| VARIABLE
41557718be8SEnji Cooper 			{ $<string>$ = get_numeric_var($1); }
41657718be8SEnji Cooper 		| expr OR expr
41757718be8SEnji Cooper 			{ $<string>$ = numeric_or($<string>1, $<string>3); }
41857718be8SEnji Cooper 		;
41957718be8SEnji Cooper 
42057718be8SEnji Cooper args		: /* empty */
42157718be8SEnji Cooper 		| LHB expr RHB { assign_arg(arg_static, $<string>2); } args
42257718be8SEnji Cooper 		| numeric { assign_arg(arg_static, $1); } args
42357718be8SEnji Cooper 		| STRING { assign_arg(arg_static, $1); } args
42457718be8SEnji Cooper 		| BYTE { assign_arg(arg_byte, $1); } args
42557718be8SEnji Cooper 		| PATH { assign_arg(arg_static, $1); } args
42657718be8SEnji Cooper 		| FILENAME { assign_arg(arg_static, $1); } args
42757718be8SEnji Cooper 		| VARNAME { assign_arg(arg_static, $1); } args
42857718be8SEnji Cooper 		| VARIABLE  { assign_arg(arg_var, $1); } args
42957718be8SEnji Cooper 		| NULL_RET { assign_arg(arg_null, $1); } args
43057718be8SEnji Cooper 		;
43157718be8SEnji Cooper 
43257718be8SEnji Cooper eol		: EOL
43357718be8SEnji Cooper 		;
43457718be8SEnji Cooper 
43557718be8SEnji Cooper %%
43657718be8SEnji Cooper 
43757718be8SEnji Cooper static void
43857718be8SEnji Cooper excess(const char *fname, size_t lineno, const char *func, const char *comment,
43957718be8SEnji Cooper     const void *data, size_t datalen)
44057718be8SEnji Cooper {
44157718be8SEnji Cooper 	size_t dstlen = datalen * 4 + 1;
44257718be8SEnji Cooper 	char *dst = malloc(dstlen);
44357718be8SEnji Cooper 
44457718be8SEnji Cooper 	if (dst == NULL)
44557718be8SEnji Cooper 		err(1, "malloc");
44657718be8SEnji Cooper 
44757718be8SEnji Cooper 	if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
44857718be8SEnji Cooper 		err(1, "strnvisx");
44957718be8SEnji Cooper 
45057718be8SEnji Cooper 	warnx("%s, %zu: [%s] Excess %zu bytes%s [%s]",
45157718be8SEnji Cooper 	    fname, lineno, func, datalen, comment, dst);
45257718be8SEnji Cooper 	free(dst);
45357718be8SEnji Cooper }
45457718be8SEnji Cooper 
45557718be8SEnji Cooper /*
45657718be8SEnji Cooper  * Get the value of a variable, error if the variable has not been set or
45757718be8SEnji Cooper  * is not a numeric type.
45857718be8SEnji Cooper  */
45957718be8SEnji Cooper static char *
get_numeric_var(const char * var)46057718be8SEnji Cooper get_numeric_var(const char *var)
46157718be8SEnji Cooper {
46257718be8SEnji Cooper 	int i;
46357718be8SEnji Cooper 
46457718be8SEnji Cooper 	if ((i = find_var_index(var)) < 0)
46557718be8SEnji Cooper 		err(1, "Variable %s is undefined", var);
46657718be8SEnji Cooper 
46757718be8SEnji Cooper 	if (vars[i].type != ret_number)
46857718be8SEnji Cooper 		err(1, "Variable %s is not a numeric type", var);
46957718be8SEnji Cooper 
47057718be8SEnji Cooper 	return vars[i].value;
47157718be8SEnji Cooper }
47257718be8SEnji Cooper 
47357718be8SEnji Cooper /*
47457718be8SEnji Cooper  * Perform a bitwise OR on two numbers and return the result.
47557718be8SEnji Cooper  */
47657718be8SEnji Cooper static char *
numeric_or(char * n1,char * n2)47757718be8SEnji Cooper numeric_or(char *n1, char *n2)
47857718be8SEnji Cooper {
47957718be8SEnji Cooper 	unsigned long i1, i2, result;
48057718be8SEnji Cooper 	char *ret;
48157718be8SEnji Cooper 
48257718be8SEnji Cooper 	i1 = strtoul(n1, NULL, 10);
48357718be8SEnji Cooper 	i2 = strtoul(n2, NULL, 10);
48457718be8SEnji Cooper 
48557718be8SEnji Cooper 	result = i1 | i2;
48657718be8SEnji Cooper 	asprintf(&ret, "%lu", result);
48757718be8SEnji Cooper 
48857718be8SEnji Cooper 	if (verbose) {
48957718be8SEnji Cooper 		fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
49057718be8SEnji Cooper 		    " results in 0x%lx (%s)\n",
49157718be8SEnji Cooper 		    i1, n1, i2, n2, result, ret);
49257718be8SEnji Cooper 	}
49357718be8SEnji Cooper 
49457718be8SEnji Cooper 	return ret;
49557718be8SEnji Cooper }
49657718be8SEnji Cooper 
49757718be8SEnji Cooper /*
49857718be8SEnji Cooper  * Sleep for the specified time, handle the sleep getting interrupted
49957718be8SEnji Cooper  * by a signal.
50057718be8SEnji Cooper  */
50157718be8SEnji Cooper static void
perform_delay(struct timespec * ts)50257718be8SEnji Cooper perform_delay(struct timespec *ts)
50357718be8SEnji Cooper {
50457718be8SEnji Cooper 	struct timespec delay_copy, delay_remainder;
50557718be8SEnji Cooper 
50657718be8SEnji Cooper 	delay_copy = *ts;
50757718be8SEnji Cooper 	while (nanosleep(&delay_copy, &delay_remainder) < 0) {
50857718be8SEnji Cooper 		if (errno != EINTR)
50957718be8SEnji Cooper 			err(2, "nanosleep returned error");
51057718be8SEnji Cooper 		delay_copy = delay_remainder;
51157718be8SEnji Cooper 	}
51257718be8SEnji Cooper }
51357718be8SEnji Cooper 
51457718be8SEnji Cooper /*
51557718be8SEnji Cooper  * Assign the value given to the named variable.
51657718be8SEnji Cooper  */
51757718be8SEnji Cooper static void
set_var(returns_enum_t type,char * name,void * value)51857718be8SEnji Cooper set_var(returns_enum_t type, char *name, void *value)
51957718be8SEnji Cooper {
52057718be8SEnji Cooper 	int i;
52157718be8SEnji Cooper 	char *number;
52257718be8SEnji Cooper 	returns_t *ret;
52357718be8SEnji Cooper 
52457718be8SEnji Cooper 	i = find_var_index(name);
52557718be8SEnji Cooper 	if (i < 0)
52657718be8SEnji Cooper 		i = assign_var(name);
52757718be8SEnji Cooper 
52857718be8SEnji Cooper 	vars[i].type = type;
52957718be8SEnji Cooper 	if ((type == ret_number) || (type == ret_string)) {
53057718be8SEnji Cooper 		number = value;
53157718be8SEnji Cooper 		vars[i].len = strlen(number) + 1;
53257718be8SEnji Cooper 		vars[i].value = malloc(vars[i].len + 1);
53357718be8SEnji Cooper 		if (vars[i].value == NULL)
53457718be8SEnji Cooper 			err(1, "Could not malloc memory for assign string");
53557718be8SEnji Cooper 		strcpy(vars[i].value, number);
53657718be8SEnji Cooper 	} else {
53757718be8SEnji Cooper 		/* can only be a byte value */
53857718be8SEnji Cooper 		ret = value;
53957718be8SEnji Cooper 		vars[i].len = ret->return_len;
54057718be8SEnji Cooper 		vars[i].value = malloc(vars[i].len);
54157718be8SEnji Cooper 		if (vars[i].value == NULL)
54257718be8SEnji Cooper 			err(1, "Could not malloc memory to assign byte string");
54357718be8SEnji Cooper 		memcpy(vars[i].value, ret->return_value, vars[i].len);
54457718be8SEnji Cooper 	}
54557718be8SEnji Cooper }
54657718be8SEnji Cooper 
54757718be8SEnji Cooper /*
54857718be8SEnji Cooper  * Add a new variable to the vars array, the value will be assigned later,
54957718be8SEnji Cooper  * when a test function call returns.
55057718be8SEnji Cooper  */
55157718be8SEnji Cooper static int
assign_var(char * varname)55257718be8SEnji Cooper assign_var(char *varname)
55357718be8SEnji Cooper {
55457718be8SEnji Cooper 	var_t *temp;
55557718be8SEnji Cooper 	char *name;
55657718be8SEnji Cooper 
55757718be8SEnji Cooper 	if ((name = malloc(strlen(varname) + 1)) == NULL)
55857718be8SEnji Cooper 		err(1, "Alloc of varname failed");
55957718be8SEnji Cooper 
56057718be8SEnji Cooper 	if ((temp = realloc(vars, sizeof(*temp) * (nvars + 1))) == NULL) {
56157718be8SEnji Cooper 		free(name);
56257718be8SEnji Cooper 		err(1, "Realloc of vars array failed");
56357718be8SEnji Cooper 	}
56457718be8SEnji Cooper 
56557718be8SEnji Cooper 	strcpy(name, varname);
56657718be8SEnji Cooper 	vars = temp;
56757718be8SEnji Cooper 	vars[nvars].name = name;
56857718be8SEnji Cooper 	vars[nvars].len = 0;
56957718be8SEnji Cooper 	vars[nvars].value = NULL;
57057718be8SEnji Cooper 	nvars++;
57157718be8SEnji Cooper 
57257718be8SEnji Cooper 	return (nvars - 1);
57357718be8SEnji Cooper }
57457718be8SEnji Cooper 
57557718be8SEnji Cooper /*
57657718be8SEnji Cooper  * Allocate and assign a new argument of the given type.
57757718be8SEnji Cooper  */
57857718be8SEnji Cooper static void
assign_arg(args_state_t arg_type,void * arg)57957718be8SEnji Cooper assign_arg(args_state_t arg_type, void *arg)
58057718be8SEnji Cooper {
58157718be8SEnji Cooper 	args_t *temp, cur;
58257718be8SEnji Cooper 	char *str = arg;
58357718be8SEnji Cooper 	returns_t *ret;
58457718be8SEnji Cooper 
58557718be8SEnji Cooper 	if (verbose) {
58657718be8SEnji Cooper 		fprintf(stderr, "function is >%s<, adding arg >%s< type %s\n",
58757718be8SEnji Cooper 		       command.function, str, args_enum_names[arg_type]);
58857718be8SEnji Cooper 	}
58957718be8SEnji Cooper 
59057718be8SEnji Cooper 	cur.arg_type = arg_type;
59157718be8SEnji Cooper 	switch (arg_type) {
59257718be8SEnji Cooper 	case arg_var:
59357718be8SEnji Cooper 		cur.var_index = find_var_index(arg);
59457718be8SEnji Cooper 		if (cur.var_index < 0)
59557718be8SEnji Cooper 			err(1, "Invalid variable %s at line %zu of file %s",
59657718be8SEnji Cooper 			    str, line, cur_file);
59757718be8SEnji Cooper 		cur.arg_type = ret_string;
59857718be8SEnji Cooper 		break;
59957718be8SEnji Cooper 
60057718be8SEnji Cooper 	case arg_byte:
60157718be8SEnji Cooper 		ret = arg;
60257718be8SEnji Cooper 		cur.arg_len = ret->return_len;
60357718be8SEnji Cooper 		cur.arg_string = malloc(cur.arg_len);
60457718be8SEnji Cooper 		if (cur.arg_string == NULL)
60557718be8SEnji Cooper 			err(1, "Could not malloc memory for arg bytes");
60657718be8SEnji Cooper 		memcpy(cur.arg_string, ret->return_value, cur.arg_len);
60757718be8SEnji Cooper 		break;
60857718be8SEnji Cooper 
60957718be8SEnji Cooper 	case arg_null:
61057718be8SEnji Cooper 		cur.arg_len = 0;
61157718be8SEnji Cooper 		cur.arg_string = NULL;
61257718be8SEnji Cooper 		break;
61357718be8SEnji Cooper 
61457718be8SEnji Cooper 	default:
61557718be8SEnji Cooper 		cur.arg_len = strlen(str);
61657718be8SEnji Cooper 		cur.arg_string = malloc(cur.arg_len + 1);
61757718be8SEnji Cooper 		if (cur.arg_string == NULL)
61857718be8SEnji Cooper 			err(1, "Could not malloc memory for arg string");
61957718be8SEnji Cooper 		strcpy(cur.arg_string, arg);
62057718be8SEnji Cooper 	}
62157718be8SEnji Cooper 
62257718be8SEnji Cooper 	temp = realloc(command.args, sizeof(*temp) * (command.nargs + 1));
62357718be8SEnji Cooper 	if (temp == NULL)
62457718be8SEnji Cooper 		err(1, "Failed to reallocate args");
62557718be8SEnji Cooper 	command.args = temp;
62657718be8SEnji Cooper 	memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
62757718be8SEnji Cooper 	command.nargs++;
62857718be8SEnji Cooper }
62957718be8SEnji Cooper 
63057718be8SEnji Cooper /*
63157718be8SEnji Cooper  * Allocate and assign a new return.
63257718be8SEnji Cooper  */
63357718be8SEnji Cooper static void
assign_rets(returns_enum_t ret_type,void * ret)63457718be8SEnji Cooper assign_rets(returns_enum_t ret_type, void *ret)
63557718be8SEnji Cooper {
63657718be8SEnji Cooper 	returns_t *temp, cur;
63757718be8SEnji Cooper 	char *ret_str;
63857718be8SEnji Cooper 	returns_t *ret_ret;
63957718be8SEnji Cooper 
64057718be8SEnji Cooper 	cur.return_type = ret_type;
64157718be8SEnji Cooper 	if (ret_type != ret_var) {
64257718be8SEnji Cooper 		if ((ret_type == ret_number) || (ret_type == ret_string)) {
64357718be8SEnji Cooper 			ret_str = ret;
64457718be8SEnji Cooper 			cur.return_len = strlen(ret_str) + 1;
64557718be8SEnji Cooper 			cur.return_value = malloc(cur.return_len + 1);
64657718be8SEnji Cooper 			if (cur.return_value == NULL)
64757718be8SEnji Cooper 				err(1,
64857718be8SEnji Cooper 				    "Could not malloc memory for arg string");
64957718be8SEnji Cooper 			strcpy(cur.return_value, ret_str);
65057718be8SEnji Cooper 		} else if (ret_type == ret_byte) {
65157718be8SEnji Cooper 			ret_ret = ret;
65257718be8SEnji Cooper 			cur.return_len = ret_ret->return_len;
65357718be8SEnji Cooper 			cur.return_value = malloc(cur.return_len);
65457718be8SEnji Cooper 			if (cur.return_value == NULL)
65557718be8SEnji Cooper 				err(1,
65657718be8SEnji Cooper 				    "Could not malloc memory for byte string");
65757718be8SEnji Cooper 			memcpy(cur.return_value, ret_ret->return_value,
65857718be8SEnji Cooper 			       cur.return_len);
65957718be8SEnji Cooper 		} else if (ret_type == ret_ref) {
66057718be8SEnji Cooper 			if ((cur.return_index = find_var_index(ret)) < 0)
66157718be8SEnji Cooper 				err(1, "Undefined variable reference");
66257718be8SEnji Cooper 		}
66357718be8SEnji Cooper 	} else {
66457718be8SEnji Cooper 		cur.return_index = find_var_index(ret);
66557718be8SEnji Cooper 		if (cur.return_index < 0)
66657718be8SEnji Cooper 			cur.return_index = assign_var(ret);
66757718be8SEnji Cooper 	}
66857718be8SEnji Cooper 
66957718be8SEnji Cooper 	temp = realloc(command.returns, sizeof(*temp) * (command.nrets + 1));
67057718be8SEnji Cooper 	if (temp == NULL)
67157718be8SEnji Cooper 		err(1, "Failed to reallocate returns");
67257718be8SEnji Cooper 	command.returns = temp;
67357718be8SEnji Cooper 	memcpy(&command.returns[command.nrets], &cur, sizeof(returns_t));
67457718be8SEnji Cooper 	command.nrets++;
67557718be8SEnji Cooper }
67657718be8SEnji Cooper 
67757718be8SEnji Cooper /*
67857718be8SEnji Cooper  * Find the given variable name in the var array and return the i
67957718be8SEnji Cooper  * return -1 if var is not found.
68057718be8SEnji Cooper  */
68157718be8SEnji Cooper static int
find_var_index(const char * var_name)68257718be8SEnji Cooper find_var_index(const char *var_name)
68357718be8SEnji Cooper {
68457718be8SEnji Cooper 	int result;
68557718be8SEnji Cooper 	size_t i;
68657718be8SEnji Cooper 
68757718be8SEnji Cooper 	result = -1;
68857718be8SEnji Cooper 
68957718be8SEnji Cooper 	for (i = 0; i < nvars; i++) {
69057718be8SEnji Cooper 		if (strcmp(var_name, vars[i].name) == 0) {
69157718be8SEnji Cooper 			result = i;
69257718be8SEnji Cooper 			break;
69357718be8SEnji Cooper 		}
69457718be8SEnji Cooper 	}
69557718be8SEnji Cooper 
69657718be8SEnji Cooper 	return result;
69757718be8SEnji Cooper }
69857718be8SEnji Cooper 
69957718be8SEnji Cooper /*
70057718be8SEnji Cooper  * Check the given function name in the given table of names, return 1 if
70157718be8SEnji Cooper  * there is a match.
70257718be8SEnji Cooper  */
check_function_table(char * function,const char * table[],int nfunctions)70357718be8SEnji Cooper static int check_function_table(char *function, const char *table[],
70457718be8SEnji Cooper 				int nfunctions)
70557718be8SEnji Cooper {
70657718be8SEnji Cooper 	int i;
70757718be8SEnji Cooper 
70857718be8SEnji Cooper 	for (i = 0; i < nfunctions; i++) {
70957718be8SEnji Cooper 		if ((strlen(function) == strlen(table[i])) &&
71057718be8SEnji Cooper 		    (strcmp(function, table[i]) == 0))
71157718be8SEnji Cooper 			return 1;
71257718be8SEnji Cooper 	}
71357718be8SEnji Cooper 
71457718be8SEnji Cooper 	return 0;
71557718be8SEnji Cooper }
71657718be8SEnji Cooper 
71757718be8SEnji Cooper /*
71857718be8SEnji Cooper  * Compare the output from the slave against the given file and report
71957718be8SEnji Cooper  * any differences.
72057718be8SEnji Cooper  */
72157718be8SEnji Cooper static void
compare_streams(char * filename,bool discard)72257718be8SEnji Cooper compare_streams(char *filename, bool discard)
72357718be8SEnji Cooper {
72457718be8SEnji Cooper 	char check_file[PATH_MAX], drain[100], ref, data;
72557718be8SEnji Cooper 	struct pollfd fds[2];
72657718be8SEnji Cooper 	int nfd, check_fd;
72757718be8SEnji Cooper 	ssize_t result;
72857718be8SEnji Cooper 	size_t offs;
72957718be8SEnji Cooper 
73057718be8SEnji Cooper 	/*
73157718be8SEnji Cooper 	 * Don't prepend check path iff check file has an absolute
73257718be8SEnji Cooper 	 * path.
73357718be8SEnji Cooper 	 */
73457718be8SEnji Cooper 	if (filename[0] != '/') {
73557718be8SEnji Cooper 		if (strlcpy(check_file, check_path, sizeof(check_file))
73657718be8SEnji Cooper 		    >= sizeof(check_file))
73757718be8SEnji Cooper 			err(2, "CHECK_PATH too long");
73857718be8SEnji Cooper 
73957718be8SEnji Cooper 		if (strlcat(check_file, "/", sizeof(check_file))
74057718be8SEnji Cooper 		    >= sizeof(check_file))
74157718be8SEnji Cooper 			err(2, "Could not append / to check file path");
74257718be8SEnji Cooper 	} else {
74357718be8SEnji Cooper 		check_file[0] = '\0';
74457718be8SEnji Cooper 	}
74557718be8SEnji Cooper 
74657718be8SEnji Cooper 	if (strlcat(check_file, filename, sizeof(check_file))
74757718be8SEnji Cooper 	    >= sizeof(check_file))
74857718be8SEnji Cooper 		err(2, "Path to check file path overflowed");
74957718be8SEnji Cooper 
75057718be8SEnji Cooper 	if ((check_fd = open(check_file, O_RDONLY, 0)) < 0)
75157718be8SEnji Cooper 		err(2, "failed to open file %s line %zu of file %s",
75257718be8SEnji Cooper 		    check_file, line, cur_file);
75357718be8SEnji Cooper 
75457718be8SEnji Cooper 	fds[0].fd = check_fd;
75557718be8SEnji Cooper 	fds[0].events = POLLIN;
75657718be8SEnji Cooper 	fds[1].fd = master;
75757718be8SEnji Cooper 	fds[1].events = POLLIN;
75857718be8SEnji Cooper 
75957718be8SEnji Cooper 	nfd = 2;
76057718be8SEnji Cooper 	/*
76157718be8SEnji Cooper 	 * if we have saved output then only check for data in the
76257718be8SEnji Cooper 	 * reference file since the slave data may already be drained.
76357718be8SEnji Cooper 	 */
76457718be8SEnji Cooper 	if (saved_output.count > 0)
76557718be8SEnji Cooper 		nfd = 1;
76657718be8SEnji Cooper 
76757718be8SEnji Cooper 	offs = 0;
76857718be8SEnji Cooper 	while (poll(fds, nfd, 500) == nfd) {
76957718be8SEnji Cooper 		if (fds[0].revents & POLLIN) {
77057718be8SEnji Cooper 			if ((result = read(check_fd, &ref, 1)) < 1) {
77157718be8SEnji Cooper 				if (result != 0) {
77257718be8SEnji Cooper 					err(2,
77357718be8SEnji Cooper 					    "Bad read on file %s", check_file);
77457718be8SEnji Cooper 				} else {
77557718be8SEnji Cooper 					break;
77657718be8SEnji Cooper 				}
77757718be8SEnji Cooper 			}
77857718be8SEnji Cooper 		}
77957718be8SEnji Cooper 
78057718be8SEnji Cooper 		if (saved_output.count > 0) {
78157718be8SEnji Cooper 			data = saved_output.data[saved_output.readp];
78257718be8SEnji Cooper 			saved_output.count--;
78357718be8SEnji Cooper 			saved_output.readp++;
78457718be8SEnji Cooper 			/* run out of saved data, switch to file */
78557718be8SEnji Cooper 			if (saved_output.count == 0)
78657718be8SEnji Cooper 				nfd = 2;
78757718be8SEnji Cooper 		} else {
78857718be8SEnji Cooper 			if (fds[0].revents & POLLIN) {
78957718be8SEnji Cooper 				if (read(master, &data, 1) < 1)
79057718be8SEnji Cooper 					err(2, "Bad read on slave pty");
79157718be8SEnji Cooper 			} else
79257718be8SEnji Cooper 				continue;
79357718be8SEnji Cooper 		}
79457718be8SEnji Cooper 
79557718be8SEnji Cooper 		if (verbose) {
79657718be8SEnji Cooper 			fprintf(stderr, "Comparing reference byte 0x%x (%c)"
79757718be8SEnji Cooper 				" against slave byte 0x%x (%c)\n",
79857718be8SEnji Cooper 				ref, (ref >= ' ') ? ref : '-',
79957718be8SEnji Cooper 				data, (data >= ' ' )? data : '-');
80057718be8SEnji Cooper 		}
80157718be8SEnji Cooper 
80257718be8SEnji Cooper 		if (ref != data) {
80357718be8SEnji Cooper 			errx(2, "%s, %zu: refresh data from slave does "
80457718be8SEnji Cooper 			    "not match expected from file %s offs %zu "
80557718be8SEnji Cooper 			    "[reference 0x%x (%c) != slave 0x%x (%c)]",
80657718be8SEnji Cooper 			    cur_file, line, check_file, offs,
80757718be8SEnji Cooper 			    ref, (ref >= ' ') ? ref : '-',
80857718be8SEnji Cooper 			    data, (data >= ' ') ? data : '-');
80957718be8SEnji Cooper 		}
81057718be8SEnji Cooper 
81157718be8SEnji Cooper 		offs++;
81257718be8SEnji Cooper 	}
81357718be8SEnji Cooper 
81457718be8SEnji Cooper 
81557718be8SEnji Cooper 	if (saved_output.count > 0)
81657718be8SEnji Cooper 		excess(cur_file, line, __func__, " from slave",
81757718be8SEnji Cooper 		    &saved_output.data[saved_output.readp], saved_output.count);
81857718be8SEnji Cooper 
81957718be8SEnji Cooper 	/* discard any excess saved output if required */
82057718be8SEnji Cooper 	if (discard) {
82157718be8SEnji Cooper 		saved_output.count = 0;
82257718be8SEnji Cooper 		saved_output.readp = 0;
82357718be8SEnji Cooper 	}
82457718be8SEnji Cooper 
82557718be8SEnji Cooper 	if ((result = poll(&fds[0], 2, 0)) != 0) {
82657718be8SEnji Cooper 		if (result == -1)
82757718be8SEnji Cooper 			err(2, "poll of file descriptors failed");
82857718be8SEnji Cooper 
82957718be8SEnji Cooper 		if ((fds[1].revents & POLLIN) == POLLIN) {
83057718be8SEnji Cooper 			save_slave_output(true);
83157718be8SEnji Cooper 		} else if ((fds[0].revents & POLLIN) == POLLIN) {
83257718be8SEnji Cooper 			/*
83357718be8SEnji Cooper 			 * handle excess in file if it exists.  Poll
83457718be8SEnji Cooper 			 * says there is data until EOF is read.
83557718be8SEnji Cooper 			 * Check next read is EOF, if it is not then
83657718be8SEnji Cooper 			 * the file really has more data than the
83757718be8SEnji Cooper 			 * slave produced so flag this as a warning.
83857718be8SEnji Cooper 			 */
83957718be8SEnji Cooper 			result = read(check_fd, drain, sizeof(drain));
84057718be8SEnji Cooper 			if (result == -1)
84157718be8SEnji Cooper 				err(1, "read of data file failed");
84257718be8SEnji Cooper 
84357718be8SEnji Cooper 			if (result > 0) {
84457718be8SEnji Cooper 				excess(check_file, 0, __func__, "", drain,
84557718be8SEnji Cooper 				    result);
84657718be8SEnji Cooper 			}
84757718be8SEnji Cooper 		}
84857718be8SEnji Cooper 	}
84957718be8SEnji Cooper 
85057718be8SEnji Cooper 	close(check_fd);
85157718be8SEnji Cooper }
85257718be8SEnji Cooper 
85357718be8SEnji Cooper /*
85457718be8SEnji Cooper  * Pass a function call and arguments to the slave and wait for the
85557718be8SEnji Cooper  * results.  The variable nresults determines how many returns we expect
85657718be8SEnji Cooper  * back from the slave.  These results will be validated against the
85757718be8SEnji Cooper  * expected returns or assigned to variables.
85857718be8SEnji Cooper  */
85957718be8SEnji Cooper static void
do_function_call(size_t nresults)86057718be8SEnji Cooper do_function_call(size_t nresults)
86157718be8SEnji Cooper {
86257718be8SEnji Cooper #define MAX_RESULTS 4
86357718be8SEnji Cooper 	char *p;
86457718be8SEnji Cooper 	int do_input;
86557718be8SEnji Cooper 	size_t i;
86657718be8SEnji Cooper 	struct pollfd fds[3];
86757718be8SEnji Cooper 	returns_t response[MAX_RESULTS], returns_count;
86857718be8SEnji Cooper 	assert(nresults <= MAX_RESULTS);
86957718be8SEnji Cooper 
87057718be8SEnji Cooper 	do_input = check_function_table(command.function, input_functions,
87157718be8SEnji Cooper 	    ninput_functions);
87257718be8SEnji Cooper 
87357718be8SEnji Cooper 	write_func_and_args();
87457718be8SEnji Cooper 
87557718be8SEnji Cooper 	/*
87657718be8SEnji Cooper 	 * We should get the number of returns back here, grab it before
87757718be8SEnji Cooper 	 * doing input otherwise it will confuse the input poll
87857718be8SEnji Cooper 	 */
87957718be8SEnji Cooper 	read_cmd_pipe(&returns_count);
88057718be8SEnji Cooper 	if (returns_count.return_type != ret_count)
88157718be8SEnji Cooper 		err(2, "expected return type of ret_count but received %s",
88257718be8SEnji Cooper 		    returns_enum_names[returns_count.return_type]);
88357718be8SEnji Cooper 
88457718be8SEnji Cooper 	perform_delay(&delay_post_call); /* let slave catch up */
88557718be8SEnji Cooper 
88657718be8SEnji Cooper 	if (verbose) {
88757718be8SEnji Cooper 		fprintf(stderr, "Expect %zu results from slave, slave "
88857718be8SEnji Cooper 		    "reported %zu\n", nresults, returns_count.return_len);
88957718be8SEnji Cooper 	}
89057718be8SEnji Cooper 
89157718be8SEnji Cooper 	if ((no_input == false) && (do_input == 1)) {
89257718be8SEnji Cooper 		if (verbose) {
89357718be8SEnji Cooper 			fprintf(stderr, "doing input with inputstr >%s<\n",
89457718be8SEnji Cooper 			    input_str);
89557718be8SEnji Cooper 		}
89657718be8SEnji Cooper 
89757718be8SEnji Cooper 		if (input_str == NULL)
89857718be8SEnji Cooper 			errx(2, "%s, %zu: Call to input function "
89957718be8SEnji Cooper 			    "but no input defined", cur_file, line);
90057718be8SEnji Cooper 
90157718be8SEnji Cooper 		fds[0].fd = slvpipe[READ_PIPE];
90257718be8SEnji Cooper 		fds[0].events = POLLIN;
90357718be8SEnji Cooper 		fds[1].fd = master;
90457718be8SEnji Cooper 		fds[1].events = POLLOUT;
90557718be8SEnji Cooper  		p = input_str;
90657718be8SEnji Cooper 		save_slave_output(false);
90757718be8SEnji Cooper 		while(*p != '\0') {
90857718be8SEnji Cooper 			perform_delay(&delay_spec);
90957718be8SEnji Cooper 
91057718be8SEnji Cooper 			if (poll(fds, 2, 0) < 0)
91157718be8SEnji Cooper 				err(2, "poll failed");
91257718be8SEnji Cooper 			if (fds[0].revents & POLLIN) {
91357718be8SEnji Cooper 				warnx("%s, %zu: Slave function "
91457718be8SEnji Cooper 				    "returned before end of input string",
91557718be8SEnji Cooper 				    cur_file, line);
91657718be8SEnji Cooper 				break;
91757718be8SEnji Cooper 			}
91857718be8SEnji Cooper 			if ((fds[1].revents & POLLOUT) == 0)
91957718be8SEnji Cooper 				continue;
92057718be8SEnji Cooper 			if (verbose) {
92157718be8SEnji Cooper 				fprintf(stderr, "Writing char >%c< to slave\n",
92257718be8SEnji Cooper 				    *p);
92357718be8SEnji Cooper 			}
92457718be8SEnji Cooper 			if (write(master, p, 1) != 1) {
92557718be8SEnji Cooper 				warn("%s, %zu: Slave function write error",
92657718be8SEnji Cooper 				    cur_file, line);
92757718be8SEnji Cooper 				break;
92857718be8SEnji Cooper 			}
92957718be8SEnji Cooper 			p++;
93057718be8SEnji Cooper 
93157718be8SEnji Cooper 		}
93257718be8SEnji Cooper 		save_slave_output(false);
93357718be8SEnji Cooper 
93457718be8SEnji Cooper 		if (verbose) {
93557718be8SEnji Cooper 			fprintf(stderr, "Input done.\n");
93657718be8SEnji Cooper 		}
93757718be8SEnji Cooper 
93857718be8SEnji Cooper 		/* done with the input string, free the resources */
93957718be8SEnji Cooper 		free(input_str);
94057718be8SEnji Cooper 		input_str = NULL;
94157718be8SEnji Cooper 	}
94257718be8SEnji Cooper 
94357718be8SEnji Cooper 	if (verbose) {
94457718be8SEnji Cooper 		fds[0].fd = slvpipe[READ_PIPE];
94557718be8SEnji Cooper 		fds[0].events = POLLIN;
94657718be8SEnji Cooper 
94757718be8SEnji Cooper 		fds[1].fd = slvpipe[WRITE_PIPE];
94857718be8SEnji Cooper 		fds[1].events = POLLOUT;
94957718be8SEnji Cooper 
95057718be8SEnji Cooper 		fds[2].fd = master;
95157718be8SEnji Cooper 		fds[2].events = POLLIN | POLLOUT;
95257718be8SEnji Cooper 
95357718be8SEnji Cooper 		i = poll(&fds[0], 3, 1000);
95457718be8SEnji Cooper 		fprintf(stderr, "Poll returned %zu\n", i);
95557718be8SEnji Cooper 		for (i = 0; i < 3; i++) {
95657718be8SEnji Cooper 			fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
95757718be8SEnji Cooper 				i, fds[i].revents);
95857718be8SEnji Cooper 		}
95957718be8SEnji Cooper 	}
96057718be8SEnji Cooper 
96157718be8SEnji Cooper 	/* drain any trailing output */
96257718be8SEnji Cooper 	save_slave_output(false);
96357718be8SEnji Cooper 
96457718be8SEnji Cooper 	for (i = 0; i < returns_count.return_len; i++) {
96557718be8SEnji Cooper 		read_cmd_pipe(&response[i]);
96657718be8SEnji Cooper 	}
96757718be8SEnji Cooper 
96857718be8SEnji Cooper 	/*
96957718be8SEnji Cooper 	 * Check for a slave error in the first return slot, if the
97057718be8SEnji Cooper 	 * slave errored then we may not have the number of returns we
97157718be8SEnji Cooper 	 * expect but in this case we should report the slave error
97257718be8SEnji Cooper 	 * instead of a return count mismatch.
97357718be8SEnji Cooper 	 */
97457718be8SEnji Cooper 	if ((returns_count.return_len > 0) &&
97557718be8SEnji Cooper 	    (response[0].return_type == ret_slave_error))
97657718be8SEnji Cooper 		err(2, "Slave returned error: %s",
97757718be8SEnji Cooper 		    (const char *)response[0].return_value);
97857718be8SEnji Cooper 
97957718be8SEnji Cooper 	if (returns_count.return_len != nresults)
98057718be8SEnji Cooper 		err(2, "Incorrect number of returns from slave, expected %zu "
98157718be8SEnji Cooper 		    "but received %zu", nresults, returns_count.return_len);
98257718be8SEnji Cooper 
98357718be8SEnji Cooper 	if (verbose) {
98457718be8SEnji Cooper 		for (i = 0; i < nresults; i++) {
98557718be8SEnji Cooper 			if ((response[i].return_type != ret_byte) &&
98657718be8SEnji Cooper 			    (response[i].return_type != ret_err) &&
98757718be8SEnji Cooper 			    (response[i].return_type != ret_ok))
98857718be8SEnji Cooper 				fprintf(stderr,
98957718be8SEnji Cooper 					"received response >%s< "
99057718be8SEnji Cooper 					"expected",
99157718be8SEnji Cooper 					(const char *)response[i].return_value);
99257718be8SEnji Cooper 			else
99357718be8SEnji Cooper 				fprintf(stderr, "received");
99457718be8SEnji Cooper 
99557718be8SEnji Cooper 			fprintf(stderr, " return_type %s\n",
99657718be8SEnji Cooper 			    returns_enum_names[command.returns[i].return_type]);
99757718be8SEnji Cooper 		}
99857718be8SEnji Cooper 	}
99957718be8SEnji Cooper 
100057718be8SEnji Cooper 	for (i = 0; i < nresults; i++) {
100157718be8SEnji Cooper 		if (command.returns[i].return_type != ret_var) {
100257718be8SEnji Cooper 			validate(i, &response[i]);
100357718be8SEnji Cooper 		} else {
100457718be8SEnji Cooper 			vars[command.returns[i].return_index].len =
100557718be8SEnji Cooper 				response[i].return_len;
100657718be8SEnji Cooper 			vars[command.returns[i].return_index].value =
100757718be8SEnji Cooper 				response[i].return_value;
100857718be8SEnji Cooper 			vars[command.returns[i].return_index].type =
100957718be8SEnji Cooper 				response[i].return_type;
101057718be8SEnji Cooper 		}
101157718be8SEnji Cooper 	}
101257718be8SEnji Cooper 
101357718be8SEnji Cooper 	if (verbose && (saved_output.count > 0))
101457718be8SEnji Cooper 		excess(cur_file, line, __func__, " from slave",
101557718be8SEnji Cooper 		    &saved_output.data[saved_output.readp], saved_output.count);
101657718be8SEnji Cooper 
101757718be8SEnji Cooper 	init_parse_variables(0);
101857718be8SEnji Cooper }
101957718be8SEnji Cooper 
102057718be8SEnji Cooper /*
102157718be8SEnji Cooper  * Write the function and command arguments to the command pipe.
102257718be8SEnji Cooper  */
102357718be8SEnji Cooper static void
write_func_and_args(void)102457718be8SEnji Cooper write_func_and_args(void)
102557718be8SEnji Cooper {
102657718be8SEnji Cooper 	int i;
102757718be8SEnji Cooper 
102857718be8SEnji Cooper 	if (verbose) {
102957718be8SEnji Cooper 		fprintf(stderr, "calling function >%s<\n", command.function);
103057718be8SEnji Cooper 	}
103157718be8SEnji Cooper 
103257718be8SEnji Cooper 	write_cmd_pipe(command.function);
103357718be8SEnji Cooper 	for (i = 0; i < command.nargs; i++) {
103457718be8SEnji Cooper 		if (command.args[i].arg_type == arg_var)
103557718be8SEnji Cooper 			write_cmd_pipe_args(command.args[i].arg_type,
103657718be8SEnji Cooper 					    &vars[command.args[i].var_index]);
103757718be8SEnji Cooper 		else
103857718be8SEnji Cooper 			write_cmd_pipe_args(command.args[i].arg_type,
103957718be8SEnji Cooper 					    &command.args[i]);
104057718be8SEnji Cooper 	}
104157718be8SEnji Cooper 
104257718be8SEnji Cooper 	write_cmd_pipe(NULL); /* signal end of arguments */
104357718be8SEnji Cooper }
104457718be8SEnji Cooper 
104557718be8SEnji Cooper /*
104657718be8SEnji Cooper  * Initialise the command structure - if initial is non-zero then just set
104757718be8SEnji Cooper  * everything to sane values otherwise free any memory that was allocated
104857718be8SEnji Cooper  * when building the structure.
104957718be8SEnji Cooper  */
105057718be8SEnji Cooper void
init_parse_variables(int initial)105157718be8SEnji Cooper init_parse_variables(int initial)
105257718be8SEnji Cooper {
105357718be8SEnji Cooper 	int i, result;
105457718be8SEnji Cooper 	struct pollfd slave_pty;
105557718be8SEnji Cooper 
105657718be8SEnji Cooper 	if (initial == 0) {
105757718be8SEnji Cooper 		free(command.function);
105857718be8SEnji Cooper 		for (i = 0; i < command.nrets; i++) {
105957718be8SEnji Cooper 			if (command.returns[i].return_type == ret_number)
106057718be8SEnji Cooper 				free(command.returns[i].return_value);
106157718be8SEnji Cooper 		}
106257718be8SEnji Cooper 		free(command.returns);
106357718be8SEnji Cooper 
106457718be8SEnji Cooper 		for (i = 0; i < command.nargs; i++) {
106557718be8SEnji Cooper 			if (command.args[i].arg_type != arg_var)
106657718be8SEnji Cooper 				free(command.args[i].arg_string);
106757718be8SEnji Cooper 		}
106857718be8SEnji Cooper 		free(command.args);
106957718be8SEnji Cooper 	} else {
107057718be8SEnji Cooper 		line = 0;
107157718be8SEnji Cooper 		input_delay = 0;
107257718be8SEnji Cooper 		vars = NULL;
107357718be8SEnji Cooper 		nvars = 0;
107457718be8SEnji Cooper 		input_str = NULL;
107557718be8SEnji Cooper 		saved_output.allocated = 0;
107657718be8SEnji Cooper 		saved_output.count = 0;
107757718be8SEnji Cooper 		saved_output.readp = 0;
107857718be8SEnji Cooper 		saved_output.data = NULL;
107957718be8SEnji Cooper 	}
108057718be8SEnji Cooper 
108157718be8SEnji Cooper 	no_input = false;
108257718be8SEnji Cooper 	command.function = NULL;
108357718be8SEnji Cooper 	command.nargs = 0;
108457718be8SEnji Cooper 	command.args = NULL;
108557718be8SEnji Cooper 	command.nrets = 0;
108657718be8SEnji Cooper 	command.returns = NULL;
108757718be8SEnji Cooper 
108857718be8SEnji Cooper 	/*
108957718be8SEnji Cooper 	 * Check the slave pty for stray output from the slave, at this
109057718be8SEnji Cooper 	 * point we should not see any data as it should have been
109157718be8SEnji Cooper 	 * consumed by the test functions.  If we see data then we have
109257718be8SEnji Cooper 	 * either a bug or are not handling an output generating function
109357718be8SEnji Cooper 	 * correctly.
109457718be8SEnji Cooper 	 */
109557718be8SEnji Cooper 	slave_pty.fd = master;
109657718be8SEnji Cooper 	slave_pty.events = POLLIN;
109757718be8SEnji Cooper 	result = poll(&slave_pty, 1, 0);
109857718be8SEnji Cooper 
109957718be8SEnji Cooper 	if (result < 0)
110057718be8SEnji Cooper 		err(2, "Poll of slave pty failed");
110157718be8SEnji Cooper 	else if (result > 0)
110257718be8SEnji Cooper 		warnx("%s, %zu: Unexpected data from slave", cur_file, line);
110357718be8SEnji Cooper }
110457718be8SEnji Cooper 
110557718be8SEnji Cooper /*
110657718be8SEnji Cooper  * Validate the response against the expected return.  The variable
110757718be8SEnji Cooper  * i is the i into the rets array in command.
110857718be8SEnji Cooper  */
110957718be8SEnji Cooper static void
validate(int i,void * data)111057718be8SEnji Cooper validate(int i, void *data)
111157718be8SEnji Cooper {
111257718be8SEnji Cooper 	char *response;
111357718be8SEnji Cooper 	returns_t *byte_response;
111457718be8SEnji Cooper 
111557718be8SEnji Cooper 	byte_response = data;
111657718be8SEnji Cooper 	if ((command.returns[i].return_type != ret_byte) &&
111757718be8SEnji Cooper 	    (command.returns[i].return_type != ret_err) &&
111857718be8SEnji Cooper 	    (command.returns[i].return_type != ret_ok)) {
111957718be8SEnji Cooper 		if ((byte_response->return_type == ret_byte) ||
112057718be8SEnji Cooper 		    (byte_response->return_type == ret_err) ||
112157718be8SEnji Cooper 		    (byte_response->return_type == ret_ok))
112257718be8SEnji Cooper 			err(1, "%s: expecting type %s, received type %s"
112357718be8SEnji Cooper 			    " at line %zu of file %s", __func__,
112457718be8SEnji Cooper 			    returns_enum_names[command.returns[i].return_type],
112557718be8SEnji Cooper 			    returns_enum_names[byte_response->return_type],
112657718be8SEnji Cooper 			    line, cur_file);
112757718be8SEnji Cooper 
112857718be8SEnji Cooper 		response = byte_response->return_value;
112957718be8SEnji Cooper 	}
113057718be8SEnji Cooper 
113157718be8SEnji Cooper 	switch (command.returns[i].return_type) {
113257718be8SEnji Cooper 	case ret_err:
113357718be8SEnji Cooper 		validate_type(ret_err, byte_response, 0);
113457718be8SEnji Cooper 		break;
113557718be8SEnji Cooper 
113657718be8SEnji Cooper 	case ret_ok:
113757718be8SEnji Cooper 		validate_type(ret_ok, byte_response, 0);
113857718be8SEnji Cooper 		break;
113957718be8SEnji Cooper 
114057718be8SEnji Cooper 	case ret_null:
114157718be8SEnji Cooper 		validate_return("NULL", response, 0);
114257718be8SEnji Cooper 		break;
114357718be8SEnji Cooper 
114457718be8SEnji Cooper 	case ret_nonnull:
114557718be8SEnji Cooper 		validate_return("NULL", response, 1);
114657718be8SEnji Cooper 		break;
114757718be8SEnji Cooper 
114857718be8SEnji Cooper 	case ret_string:
114957718be8SEnji Cooper 	case ret_number:
115057718be8SEnji Cooper 		validate_return(command.returns[i].return_value,
115157718be8SEnji Cooper 				response, 0);
115257718be8SEnji Cooper 		break;
115357718be8SEnji Cooper 
115457718be8SEnji Cooper 	case ret_ref:
115557718be8SEnji Cooper 		validate_reference(i, response);
115657718be8SEnji Cooper 		break;
115757718be8SEnji Cooper 
115857718be8SEnji Cooper 	case ret_byte:
115957718be8SEnji Cooper 		validate_byte(&command.returns[i], byte_response, 0);
116057718be8SEnji Cooper 		break;
116157718be8SEnji Cooper 
116257718be8SEnji Cooper 	default:
116357718be8SEnji Cooper 		err(1, "Malformed statement at line %zu of file %s",
116457718be8SEnji Cooper 		    line, cur_file);
116557718be8SEnji Cooper 		break;
116657718be8SEnji Cooper 	}
116757718be8SEnji Cooper }
116857718be8SEnji Cooper 
116957718be8SEnji Cooper /*
117057718be8SEnji Cooper  * Validate the return against the contents of a variable.
117157718be8SEnji Cooper  */
117257718be8SEnji Cooper static void
validate_reference(int i,void * data)117357718be8SEnji Cooper validate_reference(int i, void *data)
117457718be8SEnji Cooper {
117557718be8SEnji Cooper 	char *response;
117657718be8SEnji Cooper 	returns_t *byte_response;
117757718be8SEnji Cooper 	var_t *varp;
117857718be8SEnji Cooper 
117957718be8SEnji Cooper 	varp = &vars[command.returns[i].return_index];
118057718be8SEnji Cooper 
118157718be8SEnji Cooper 	byte_response = data;
118257718be8SEnji Cooper 	if (command.returns[i].return_type != ret_byte)
118357718be8SEnji Cooper 		response = data;
118457718be8SEnji Cooper 
118557718be8SEnji Cooper 	if (verbose) {
118657718be8SEnji Cooper 		fprintf(stderr,
118757718be8SEnji Cooper 		    "%s: return type of %s, value %s \n", __func__,
118857718be8SEnji Cooper 		    returns_enum_names[varp->type],
118957718be8SEnji Cooper 		    (const char *)varp->value);
119057718be8SEnji Cooper 	}
119157718be8SEnji Cooper 
119257718be8SEnji Cooper 	switch (varp->type) {
119357718be8SEnji Cooper 	case ret_string:
119457718be8SEnji Cooper 	case ret_number:
119557718be8SEnji Cooper 		validate_return(varp->value, response, 0);
119657718be8SEnji Cooper 		break;
119757718be8SEnji Cooper 
119857718be8SEnji Cooper 	case ret_byte:
119957718be8SEnji Cooper 		validate_byte(varp->value, byte_response, 0);
120057718be8SEnji Cooper 		break;
120157718be8SEnji Cooper 
120257718be8SEnji Cooper 	default:
120357718be8SEnji Cooper 		err(1,
120457718be8SEnji Cooper 		    "Invalid return type for reference at line %zu of file %s",
120557718be8SEnji Cooper 		    line, cur_file);
120657718be8SEnji Cooper 		break;
120757718be8SEnji Cooper 	}
120857718be8SEnji Cooper }
120957718be8SEnji Cooper 
121057718be8SEnji Cooper /*
121157718be8SEnji Cooper  * Validate the return type against the expected type, throw an error
121257718be8SEnji Cooper  * if they don't match.
121357718be8SEnji Cooper  */
121457718be8SEnji Cooper static void
validate_type(returns_enum_t expected,returns_t * value,int check)121557718be8SEnji Cooper validate_type(returns_enum_t expected, returns_t *value, int check)
121657718be8SEnji Cooper {
121757718be8SEnji Cooper 	if (((check == 0) && (expected != value->return_type)) ||
121857718be8SEnji Cooper 	    ((check == 1) && (expected == value->return_type)))
121957718be8SEnji Cooper 		err(1, "Validate expected type %s %s %s line %zu of file %s",
122057718be8SEnji Cooper 		    returns_enum_names[expected],
122157718be8SEnji Cooper 		    (check == 0)? "matching" : "not matching",
122257718be8SEnji Cooper 		    returns_enum_names[value->return_type], line, cur_file);
122357718be8SEnji Cooper 
122457718be8SEnji Cooper 	if (verbose) {
122557718be8SEnji Cooper 		fprintf(stderr, "Validate expected type %s %s %s line %zu"
122657718be8SEnji Cooper 		    " of file %s\n",
122757718be8SEnji Cooper 		    returns_enum_names[expected],
122857718be8SEnji Cooper 		    (check == 0)? "matching" : "not matching",
122957718be8SEnji Cooper 		    returns_enum_names[value->return_type], line, cur_file);
123057718be8SEnji Cooper 	}
123157718be8SEnji Cooper }
123257718be8SEnji Cooper 
123357718be8SEnji Cooper /*
123457718be8SEnji Cooper  * Validate the return value against the expected value, throw an error
123557718be8SEnji Cooper  * if they don't match.
123657718be8SEnji Cooper  */
123757718be8SEnji Cooper static void
validate_return(const char * expected,const char * value,int check)123857718be8SEnji Cooper validate_return(const char *expected, const char *value, int check)
123957718be8SEnji Cooper {
124057718be8SEnji Cooper 	if (((check == 0) && strcmp(expected, value) != 0) ||
124157718be8SEnji Cooper 	    ((check == 1) && strcmp(expected, value) == 0))
124257718be8SEnji Cooper 		errx(1, "Validate expected %s %s %s line %zu of file %s",
124357718be8SEnji Cooper 		    expected,
124457718be8SEnji Cooper 		    (check == 0)? "matching" : "not matching", value,
124557718be8SEnji Cooper 		    line, cur_file);
124657718be8SEnji Cooper 	if (verbose) {
124757718be8SEnji Cooper 		fprintf(stderr, "Validated expected value %s %s %s "
124857718be8SEnji Cooper 		    "at line %zu of file %s\n", expected,
124957718be8SEnji Cooper 		    (check == 0)? "matches" : "does not match",
125057718be8SEnji Cooper 		    value, line, cur_file);
125157718be8SEnji Cooper 	}
125257718be8SEnji Cooper }
125357718be8SEnji Cooper 
125457718be8SEnji Cooper /*
125557718be8SEnji Cooper  * Validate the return value against the expected value, throw an error
125657718be8SEnji Cooper  * if they don't match expectations.
125757718be8SEnji Cooper  */
125857718be8SEnji Cooper static void
validate_byte(returns_t * expected,returns_t * value,int check)125957718be8SEnji Cooper validate_byte(returns_t *expected, returns_t *value, int check)
126057718be8SEnji Cooper {
126157718be8SEnji Cooper 	char *ch;
126257718be8SEnji Cooper 	size_t i;
126357718be8SEnji Cooper 
126457718be8SEnji Cooper 	if (verbose) {
126557718be8SEnji Cooper 		ch = value->return_value;
126657718be8SEnji Cooper 		fprintf(stderr, "checking returned byte stream: ");
126757718be8SEnji Cooper 		for (i = 0; i < value->return_len; i++)
126857718be8SEnji Cooper 			fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
126957718be8SEnji Cooper 		fprintf(stderr, "\n");
127057718be8SEnji Cooper 
127157718be8SEnji Cooper 		fprintf(stderr, "%s byte stream: ",
127257718be8SEnji Cooper 			(check == 0)? "matches" : "does not match");
127357718be8SEnji Cooper 		ch = (char *) expected->return_value;
127457718be8SEnji Cooper 		for (i = 0; i < expected->return_len; i++)
127557718be8SEnji Cooper 			fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
127657718be8SEnji Cooper 		fprintf(stderr, "\n");
127757718be8SEnji Cooper 	}
127857718be8SEnji Cooper 
127957718be8SEnji Cooper 	/*
128057718be8SEnji Cooper 	 * No chance of a match if lengths differ...
128157718be8SEnji Cooper 	 */
128257718be8SEnji Cooper 	if ((check == 0) && (expected->return_len != value->return_len))
128357718be8SEnji Cooper 	    errx(1, "Byte validation failed, length mismatch, expected %zu,"
128457718be8SEnji Cooper 		"received %zu", expected->return_len, value->return_len);
128557718be8SEnji Cooper 
128657718be8SEnji Cooper 	/*
128757718be8SEnji Cooper 	 * If check is 0 then we want to throw an error IFF the byte streams
128857718be8SEnji Cooper 	 * do not match, if check is 1 then throw an error if the byte
128957718be8SEnji Cooper 	 * streams match.
129057718be8SEnji Cooper 	 */
129157718be8SEnji Cooper 	if (((check == 0) && memcmp(expected->return_value, value->return_value,
129257718be8SEnji Cooper 				    value->return_len) != 0) ||
129357718be8SEnji Cooper 	    ((check == 1) && (expected->return_len == value->return_len) &&
129457718be8SEnji Cooper 	     memcmp(expected->return_value, value->return_value,
129557718be8SEnji Cooper 		    value->return_len) == 0))
129657718be8SEnji Cooper 		errx(1, "Validate expected %s byte stream at line %zu"
129757718be8SEnji Cooper 		    "of file %s",
129857718be8SEnji Cooper 		    (check == 0)? "matching" : "not matching", line, cur_file);
129957718be8SEnji Cooper 	if (verbose) {
130057718be8SEnji Cooper 		fprintf(stderr, "Validated expected %s byte stream "
130157718be8SEnji Cooper 		    "at line %zu of file %s\n",
130257718be8SEnji Cooper 		    (check == 0)? "matching" : "not matching",
130357718be8SEnji Cooper 		    line, cur_file);
130457718be8SEnji Cooper 	}
130557718be8SEnji Cooper }
130657718be8SEnji Cooper 
130757718be8SEnji Cooper /*
130857718be8SEnji Cooper  * Validate the variable at i against the expected value, throw an
130957718be8SEnji Cooper  * error if they don't match, if check is non-zero then the match is
131057718be8SEnji Cooper  * negated.
131157718be8SEnji Cooper  */
131257718be8SEnji Cooper static void
validate_variable(int ret,returns_enum_t type,const void * value,int i,int check)131357718be8SEnji Cooper validate_variable(int ret, returns_enum_t type, const void *value, int i,
131457718be8SEnji Cooper     int check)
131557718be8SEnji Cooper {
131657718be8SEnji Cooper 	returns_t *retval;
131757718be8SEnji Cooper 	var_t *varptr;
131857718be8SEnji Cooper 
131957718be8SEnji Cooper 	retval = &command.returns[ret];
132057718be8SEnji Cooper 	varptr = &vars[command.returns[ret].return_index];
132157718be8SEnji Cooper 
132257718be8SEnji Cooper 	if (varptr->value == NULL)
132357718be8SEnji Cooper 		err(1, "Variable %s has no value assigned to it", varptr->name);
132457718be8SEnji Cooper 
132557718be8SEnji Cooper 
132657718be8SEnji Cooper 	if (varptr->type != type)
132757718be8SEnji Cooper 		err(1, "Variable %s is not the expected type", varptr->name);
132857718be8SEnji Cooper 
132957718be8SEnji Cooper 	if (type != ret_byte) {
133057718be8SEnji Cooper 		if ((((check == 0) && strcmp(value, varptr->value) != 0))
133157718be8SEnji Cooper 		    || ((check == 1) && strcmp(value, varptr->value) == 0))
133257718be8SEnji Cooper 			err(1, "Variable %s contains %s instead of %s"
133357718be8SEnji Cooper 			    " value %s at line %zu of file %s",
133457718be8SEnji Cooper 			    varptr->name, (const char *)varptr->value,
133557718be8SEnji Cooper 			    (check == 0)? "expected" : "not matching",
133657718be8SEnji Cooper 			    (const char *)value,
133757718be8SEnji Cooper 			    line, cur_file);
133857718be8SEnji Cooper 		if (verbose) {
133957718be8SEnji Cooper 			fprintf(stderr, "Variable %s contains %s value "
134057718be8SEnji Cooper 			    "%s at line %zu of file %s\n",
134157718be8SEnji Cooper 			    varptr->name,
134257718be8SEnji Cooper 			    (check == 0)? "expected" : "not matching",
134357718be8SEnji Cooper 			    (const char *)varptr->value, line, cur_file);
134457718be8SEnji Cooper 		}
134557718be8SEnji Cooper 	} else {
134657718be8SEnji Cooper 		if ((check == 0) && (retval->return_len != varptr->len))
134757718be8SEnji Cooper 			err(1, "Byte validation failed, length mismatch");
134857718be8SEnji Cooper 
134957718be8SEnji Cooper 		/*
135057718be8SEnji Cooper 		 * If check is 0 then we want to throw an error IFF
135157718be8SEnji Cooper 		 * the byte streams do not match, if check is 1 then
135257718be8SEnji Cooper 		 * throw an error if the byte streams match.
135357718be8SEnji Cooper 		 */
135457718be8SEnji Cooper 		if (((check == 0) && memcmp(retval->return_value, varptr->value,
135557718be8SEnji Cooper 					    varptr->len) != 0) ||
135657718be8SEnji Cooper 		    ((check == 1) && (retval->return_len == varptr->len) &&
135757718be8SEnji Cooper 		     memcmp(retval->return_value, varptr->value,
135857718be8SEnji Cooper 			    varptr->len) == 0))
135957718be8SEnji Cooper 			err(1, "Validate expected %s byte stream at line %zu"
136057718be8SEnji Cooper 			    " of file %s",
136157718be8SEnji Cooper 			    (check == 0)? "matching" : "not matching",
136257718be8SEnji Cooper 			    line, cur_file);
136357718be8SEnji Cooper 		if (verbose) {
136457718be8SEnji Cooper 			fprintf(stderr, "Validated expected %s byte stream "
136557718be8SEnji Cooper 			    "at line %zu of file %s\n",
136657718be8SEnji Cooper 			    (check == 0)? "matching" : "not matching",
136757718be8SEnji Cooper 			    line, cur_file);
136857718be8SEnji Cooper 		}
136957718be8SEnji Cooper 	}
137057718be8SEnji Cooper }
137157718be8SEnji Cooper 
137257718be8SEnji Cooper /*
137357718be8SEnji Cooper  * Write a string to the command pipe - we feed the number of bytes coming
137457718be8SEnji Cooper  * down first to allow storage allocation and then follow up with the data.
137557718be8SEnji Cooper  * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
137657718be8SEnji Cooper  */
137757718be8SEnji Cooper static void
write_cmd_pipe(char * cmd)137857718be8SEnji Cooper write_cmd_pipe(char *cmd)
137957718be8SEnji Cooper {
138057718be8SEnji Cooper 	args_t arg;
138157718be8SEnji Cooper 	size_t len;
138257718be8SEnji Cooper 
138357718be8SEnji Cooper 	if (cmd == NULL)
138457718be8SEnji Cooper 		len = 0;
138557718be8SEnji Cooper 	else
138657718be8SEnji Cooper 		len = strlen(cmd);
138757718be8SEnji Cooper 
138857718be8SEnji Cooper 	arg.arg_type = arg_static;
138957718be8SEnji Cooper 	arg.arg_len = len;
139057718be8SEnji Cooper 	arg.arg_string = cmd;
139157718be8SEnji Cooper 	write_cmd_pipe_args(arg.arg_type, &arg);
139257718be8SEnji Cooper 
139357718be8SEnji Cooper }
139457718be8SEnji Cooper 
139557718be8SEnji Cooper static void
write_cmd_pipe_args(args_state_t type,void * data)139657718be8SEnji Cooper write_cmd_pipe_args(args_state_t type, void *data)
139757718be8SEnji Cooper {
139857718be8SEnji Cooper 	var_t *var_data;
139957718be8SEnji Cooper 	args_t *arg_data;
140057718be8SEnji Cooper 	int len, send_type;
140157718be8SEnji Cooper 	void *cmd;
140257718be8SEnji Cooper 
140357718be8SEnji Cooper 	arg_data = data;
140457718be8SEnji Cooper 	switch (type) {
140557718be8SEnji Cooper 	case arg_var:
140657718be8SEnji Cooper 		var_data = data;
140757718be8SEnji Cooper 		len = var_data->len;
140857718be8SEnji Cooper 		cmd = var_data->value;
140957718be8SEnji Cooper 		if (type == arg_byte)
141057718be8SEnji Cooper 			send_type = ret_byte;
141157718be8SEnji Cooper 		else
141257718be8SEnji Cooper 			send_type = ret_string;
141357718be8SEnji Cooper 		break;
141457718be8SEnji Cooper 
141557718be8SEnji Cooper 	case arg_null:
141657718be8SEnji Cooper 		send_type = ret_null;
141757718be8SEnji Cooper 		len = 0;
141857718be8SEnji Cooper 		break;
141957718be8SEnji Cooper 
142057718be8SEnji Cooper 	default:
142157718be8SEnji Cooper 		if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
142257718be8SEnji Cooper 			len = -1;
142357718be8SEnji Cooper 		else
142457718be8SEnji Cooper 			len = arg_data->arg_len;
142557718be8SEnji Cooper 		cmd = arg_data->arg_string;
142657718be8SEnji Cooper 		if (type == arg_byte)
142757718be8SEnji Cooper 			send_type = ret_byte;
142857718be8SEnji Cooper 		else
142957718be8SEnji Cooper 			send_type = ret_string;
143057718be8SEnji Cooper 	}
143157718be8SEnji Cooper 
143257718be8SEnji Cooper 	if (verbose) {
143357718be8SEnji Cooper 		fprintf(stderr, "Writing type %s to command pipe\n",
143457718be8SEnji Cooper 		    returns_enum_names[send_type]);
143557718be8SEnji Cooper 	}
143657718be8SEnji Cooper 
143757718be8SEnji Cooper 	if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0)
143857718be8SEnji Cooper 		err(1, "command pipe write for type failed");
143957718be8SEnji Cooper 
144057718be8SEnji Cooper 	if (verbose) {
144157718be8SEnji Cooper 		fprintf(stderr, "Writing length %d to command pipe\n", len);
144257718be8SEnji Cooper 	}
144357718be8SEnji Cooper 
144457718be8SEnji Cooper 	if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0)
144557718be8SEnji Cooper 		err(1, "command pipe write for length failed");
144657718be8SEnji Cooper 
144757718be8SEnji Cooper 	if (len > 0) {
144857718be8SEnji Cooper 		if (verbose) {
144957718be8SEnji Cooper 			fprintf(stderr, "Writing data >%s< to command pipe\n",
145057718be8SEnji Cooper 			    (const char *)cmd);
145157718be8SEnji Cooper 		}
145257718be8SEnji Cooper 		if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0)
145357718be8SEnji Cooper 			err(1, "command pipe write of data failed");
145457718be8SEnji Cooper 	}
145557718be8SEnji Cooper }
145657718be8SEnji Cooper 
145757718be8SEnji Cooper /*
145857718be8SEnji Cooper  * Read a response from the command pipe, first we will receive the
145957718be8SEnji Cooper  * length of the response then the actual data.
146057718be8SEnji Cooper  */
146157718be8SEnji Cooper static void
read_cmd_pipe(returns_t * response)146257718be8SEnji Cooper read_cmd_pipe(returns_t *response)
146357718be8SEnji Cooper {
146457718be8SEnji Cooper 	int len, type;
146557718be8SEnji Cooper 	struct pollfd rfd[2];
146657718be8SEnji Cooper 	char *str;
146757718be8SEnji Cooper 
146857718be8SEnji Cooper 	/*
146957718be8SEnji Cooper 	 * Check if there is data to read - just in case slave has died, we
147057718be8SEnji Cooper 	 * don't want to block on the read and just hang.  We also check
147157718be8SEnji Cooper 	 * output from the slave because the slave may be blocked waiting
147257718be8SEnji Cooper 	 * for a flush on its stdout.
147357718be8SEnji Cooper 	 */
147457718be8SEnji Cooper 	rfd[0].fd = slvpipe[READ_PIPE];
147557718be8SEnji Cooper 	rfd[0].events = POLLIN;
147657718be8SEnji Cooper 	rfd[1].fd = master;
147757718be8SEnji Cooper 	rfd[1].events = POLLIN;
147857718be8SEnji Cooper 
147957718be8SEnji Cooper 	do {
148057718be8SEnji Cooper 		if (poll(rfd, 2, 4000) == 0)
148157718be8SEnji Cooper 			errx(2, "%s, %zu: Command pipe read timeout",
148257718be8SEnji Cooper 			    cur_file, line);
148357718be8SEnji Cooper 
148457718be8SEnji Cooper 		if ((rfd[1].revents & POLLIN) == POLLIN) {
148557718be8SEnji Cooper 			if (verbose) {
148657718be8SEnji Cooper 				fprintf(stderr,
148757718be8SEnji Cooper 				    "draining output from slave\n");
148857718be8SEnji Cooper 			}
148957718be8SEnji Cooper 			save_slave_output(false);
149057718be8SEnji Cooper 		}
149157718be8SEnji Cooper 	}
149257718be8SEnji Cooper 	while((rfd[1].revents & POLLIN) == POLLIN);
149357718be8SEnji Cooper 
149457718be8SEnji Cooper 	if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0)
149557718be8SEnji Cooper 		err(1, "command pipe read for type failed");
149657718be8SEnji Cooper 	response->return_type = type;
149757718be8SEnji Cooper 
149857718be8SEnji Cooper 	if ((type != ret_ok) && (type != ret_err) && (type != ret_count)) {
149957718be8SEnji Cooper 		if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
150057718be8SEnji Cooper 			err(1, "command pipe read for length failed");
150157718be8SEnji Cooper 		response->return_len = len;
150257718be8SEnji Cooper 
150357718be8SEnji Cooper 		if (verbose) {
150457718be8SEnji Cooper 			fprintf(stderr,
150557718be8SEnji Cooper 			    "Reading %d bytes from command pipe\n", len);
150657718be8SEnji Cooper 		}
150757718be8SEnji Cooper 
150857718be8SEnji Cooper 		if ((response->return_value = malloc(len + 1)) == NULL)
150957718be8SEnji Cooper 			err(1, "Failed to alloc memory for cmd pipe read");
151057718be8SEnji Cooper 
151157718be8SEnji Cooper 		if (read(slvpipe[READ_PIPE], response->return_value, len) < 0)
151257718be8SEnji Cooper 			err(1, "command pipe read of data failed");
151357718be8SEnji Cooper 
151457718be8SEnji Cooper 		if (response->return_type != ret_byte) {
151557718be8SEnji Cooper 			str = response->return_value;
151657718be8SEnji Cooper 			str[len] = '\0';
151757718be8SEnji Cooper 
151857718be8SEnji Cooper 			if (verbose) {
151957718be8SEnji Cooper 				fprintf(stderr, "Read data >%s< from pipe\n",
152057718be8SEnji Cooper 				    (const char *)response->return_value);
152157718be8SEnji Cooper 			}
152257718be8SEnji Cooper 		}
152357718be8SEnji Cooper 	} else {
152457718be8SEnji Cooper 		response->return_value = NULL;
152557718be8SEnji Cooper 		if (type == ret_count) {
152657718be8SEnji Cooper 			if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
152757718be8SEnji Cooper 				err(1, "command pipe read for number of "
152857718be8SEnji Cooper 				       "returns failed");
152957718be8SEnji Cooper 			response->return_len = len;
153057718be8SEnji Cooper 		}
153157718be8SEnji Cooper 
153257718be8SEnji Cooper 		if (verbose) {
153357718be8SEnji Cooper 			fprintf(stderr, "Read type %s from pipe\n",
153457718be8SEnji Cooper 			    returns_enum_names[type]);
153557718be8SEnji Cooper 		}
153657718be8SEnji Cooper 	}
153757718be8SEnji Cooper }
153857718be8SEnji Cooper 
153957718be8SEnji Cooper /*
154057718be8SEnji Cooper  * Check for writes from the slave on the pty, save the output into a
154157718be8SEnji Cooper  * buffer for later checking if discard is false.
154257718be8SEnji Cooper  */
154357718be8SEnji Cooper #define MAX_DRAIN 256
154457718be8SEnji Cooper 
154557718be8SEnji Cooper static void
save_slave_output(bool discard)154657718be8SEnji Cooper save_slave_output(bool discard)
154757718be8SEnji Cooper {
154857718be8SEnji Cooper 	char *new_data, drain[MAX_DRAIN];
154957718be8SEnji Cooper 	size_t to_allocate;
155057718be8SEnji Cooper 	ssize_t result;
155157718be8SEnji Cooper 	size_t i;
155257718be8SEnji Cooper 
155357718be8SEnji Cooper 	result = 0;
155457718be8SEnji Cooper 	for (;;) {
155557718be8SEnji Cooper 		if (result == -1)
155657718be8SEnji Cooper 			err(2, "poll of slave pty failed");
155757718be8SEnji Cooper 		result = MAX_DRAIN;
155857718be8SEnji Cooper 		if ((result = read(master, drain, result)) < 0) {
155957718be8SEnji Cooper 			if (errno == EAGAIN)
156057718be8SEnji Cooper 				break;
156157718be8SEnji Cooper 			else
156257718be8SEnji Cooper 				err(2, "draining slave pty failed");
156357718be8SEnji Cooper 		}
156457718be8SEnji Cooper 		if (result == 0)
156557718be8SEnji Cooper 			abort();
156657718be8SEnji Cooper 
156757718be8SEnji Cooper 		if (!discard) {
156857718be8SEnji Cooper 			if ((size_t)result >
156957718be8SEnji Cooper 			    (saved_output.allocated - saved_output.count)) {
157057718be8SEnji Cooper 				to_allocate = 1024 * ((result / 1024) + 1);
157157718be8SEnji Cooper 
157257718be8SEnji Cooper 				if ((new_data = realloc(saved_output.data,
157357718be8SEnji Cooper 					saved_output.allocated + to_allocate))
157457718be8SEnji Cooper 				    == NULL)
157557718be8SEnji Cooper 					err(2, "Realloc of saved_output failed");
157657718be8SEnji Cooper 				saved_output.data = new_data;
157757718be8SEnji Cooper 				saved_output.allocated += to_allocate;
157857718be8SEnji Cooper 			}
157957718be8SEnji Cooper 
158057718be8SEnji Cooper 			if (verbose) {
158157718be8SEnji Cooper 				fprintf(stderr, "count = %zu, "
158257718be8SEnji Cooper 				    "allocated = %zu\n", saved_output.count,
158357718be8SEnji Cooper 				    saved_output.allocated);
158457718be8SEnji Cooper 				for (i = 0; i < (size_t)result; i++) {
158557718be8SEnji Cooper 					fprintf(stderr, "Saving slave output "
158657718be8SEnji Cooper 					    "at %zu: 0x%x (%c)\n",
158757718be8SEnji Cooper 					    saved_output.count + i, drain[i],
158857718be8SEnji Cooper 					    (drain[i] >= ' ')? drain[i] : '-');
158957718be8SEnji Cooper 				}
159057718be8SEnji Cooper 			}
159157718be8SEnji Cooper 
159257718be8SEnji Cooper 			memcpy(&saved_output.data[saved_output.count], drain,
159357718be8SEnji Cooper 			       result);
159457718be8SEnji Cooper 			saved_output.count += result;
159557718be8SEnji Cooper 
159657718be8SEnji Cooper 			if (verbose) {
159757718be8SEnji Cooper 				fprintf(stderr, "count = %zu, "
159857718be8SEnji Cooper 				    "allocated = %zu\n", saved_output.count,
159957718be8SEnji Cooper 				    saved_output.allocated);
160057718be8SEnji Cooper 			}
160157718be8SEnji Cooper 		} else {
160257718be8SEnji Cooper 			if (verbose) {
160357718be8SEnji Cooper 				for (i = 0; i < (size_t)result; i++) {
160457718be8SEnji Cooper 					fprintf(stderr, "Discarding slave "
160557718be8SEnji Cooper 					    "output 0x%x (%c)\n",
160657718be8SEnji Cooper 					    drain[i],
160757718be8SEnji Cooper 					    (drain[i] >= ' ')? drain[i] : '-');
160857718be8SEnji Cooper 				}
160957718be8SEnji Cooper 			}
161057718be8SEnji Cooper 		}
161157718be8SEnji Cooper 	}
161257718be8SEnji Cooper }
161357718be8SEnji Cooper 
161457718be8SEnji Cooper static void
yyerror(const char * msg)161557718be8SEnji Cooper yyerror(const char *msg)
161657718be8SEnji Cooper {
161757718be8SEnji Cooper 	warnx("%s in line %zu of file %s", msg, line, cur_file);
161857718be8SEnji Cooper }
1619