xref: /netbsd-src/tests/lib/libcurses/director/testlang_parse.y (revision 345cf9fb81bd0411c53e25d62cd93bdcaa865312)
1 %{
2 /*	$NetBSD: testlang_parse.y,v 1.54 2023/12/10 15:51:13 rillig Exp $	*/
3 
4 /*-
5  * Copyright 2009 Brett Lymn <blymn@NetBSD.org>
6  * Copyright 2021 Roland Illig <rillig@NetBSD.org>
7  *
8  * All rights reserved.
9  *
10  * This code has been donated to The NetBSD Foundation by the Author.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <assert.h>
33 #include <curses.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <err.h>
37 #include <unistd.h>
38 #include <poll.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <limits.h>
44 #include <time.h>
45 #include <vis.h>
46 #include <stdint.h>
47 #include "returns.h"
48 #include "director.h"
49 
50 #define YYDEBUG 1
51 
52 extern int verbose;
53 extern int check_file_flag;
54 extern int master;
55 extern struct pollfd readfd;
56 extern char *check_path;
57 extern char *cur_file;		/* from director.c */
58 
59 int yylex(void);
60 
61 size_t line = 1;
62 
63 static int input_delay;
64 
65 /* time delay between inputs chars - default to 0.1ms minimum to prevent
66  * problems with input tests
67  */
68 #define DELAY_MIN 0.1
69 
70 /* time delay after a function call - allows the slave time to
71  * run the function and output data before we do other actions.
72  * Set this to 50ms.
73  */
74 #define POST_CALL_DELAY 50
75 
76 static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
77 static struct timespec delay_post_call = {0, 1000 * POST_CALL_DELAY};
78 
79 static char *input_str;	/* string to feed in as input */
80 static bool no_input;	/* don't need more input */
81 
82 static wchar_t *vals = NULL;	/* wchars to attach to a cchar type */
83 static unsigned nvals;		/* number of wchars */
84 
85 const char *const enum_names[] = {	/* for data_enum_t */
86 	"unused", "numeric", "static", "string", "byte", "cchar", "wchar", "ERR",
87 	"OK", "NULL", "not NULL", "variable", "reference", "return count",
88 	"slave error"
89 };
90 
91 typedef struct {
92 	data_enum_t	arg_type;
93 	size_t		arg_len;
94 	char		*arg_string;
95 	int		var_index;
96 } args_t;
97 
98 typedef struct {
99 	char		*function;
100 	int		nrets;		/* number of returns */
101 	ct_data_t	*returns;	/* array of expected returns */
102 	int		nargs;		/* number of arguments */
103 	args_t		*args;		/* arguments for the call */
104 } cmd_line_t;
105 
106 static cmd_line_t	command;
107 
108 typedef struct {
109 	char *name;
110 	size_t len;
111 	data_enum_t type;
112 	void *value;
113 	cchar_t cchar;
114 } var_t;
115 
116 static size_t nvars; 		/* Number of declared variables */
117 static var_t *vars; 		/* Variables defined during the test. */
118 
119 static int	check_function_table(char *, const char *const[], int);
120 static int	find_var_index(const char *);
121 static void 	assign_arg(data_enum_t, void *);
122 static int	assign_var(const char *);
123 void		init_parse_variables(int);
124 static void	validate(int, void *);
125 static void	validate_return(const char *, const char *, int);
126 static void	validate_variable(int, data_enum_t, const void *, int, int);
127 static void	validate_byte(ct_data_t *, ct_data_t *, int);
128 static void	validate_cchar(cchar_t *, cchar_t *, int);
129 static void	validate_wchar(wchar_t *, wchar_t *, int);
130 static void	write_cmd_pipe(char *);
131 static void	write_cmd_pipe_args(data_enum_t, void *);
132 static void	read_cmd_pipe(ct_data_t *);
133 static void	write_func_and_args(void);
134 static void	compare_streams(const char *, bool);
135 static void	do_function_call(size_t);
136 static void	check(void);
137 static void	delay_millis(const char *);
138 static void	do_input(const char *);
139 static void	do_noinput(void);
140 static void	save_slave_output(bool);
141 static void	validate_type(data_enum_t, ct_data_t *, int);
142 static void	set_var(data_enum_t, const char *, void *);
143 static void	validate_reference(int, void *);
144 static char *	numeric_or(const char *, const char *);
145 static char *	get_numeric_var(const char *);
146 static void	perform_delay(struct timespec *);
147 static void	set_cchar(char *, void *);
148 static void	set_wchar(char *);
149 static wchar_t *add_to_vals(data_enum_t, void *);
150 
151 #define variants(fn) "" fn, "mv" fn, "w" fn, "mvw" fn
152 static const char *const input_functions[] = {
153 	variants("getch"),
154 	variants("getnstr"),
155 	variants("getstr"),
156 	variants("getn_wstr"),
157 	variants("get_wch"),
158 	variants("get_wstr"),
159 	variants("scanw"),
160 };
161 #undef variants
162 
163 static const unsigned ninput_functions =
164 	sizeof(input_functions) / sizeof(input_functions[0]);
165 
166 extern saved_data_t saved_output;
167 
168 %}
169 
170 %union {
171 	char *string;
172 	ct_data_t *retval;
173 	wchar_t	*vals;
174 }
175 
176 %token <string> PATH
177 %token <string> STRING
178 %token <retval> BYTE
179 %token <string> VARNAME
180 %token <string> FILENAME
181 %token <string> VARIABLE
182 %token <string> REFERENCE
183 %token <string> NULL_RET
184 %token <string> NON_NULL
185 %token <string> ERR_RET
186 %token <string> OK_RET
187 %token <string> numeric
188 %token <string> DELAY
189 %token <string> INPUT
190 %token <string> COMPARE
191 %token <string> COMPAREND
192 %token <string> ASSIGN
193 %token <string> CCHAR
194 %token <string> WCHAR
195 %token EOL CALL CHECK NOINPUT OR MULTIPLIER LPAREN RPAREN LBRACK RBRACK
196 %token COMMA
197 %token CALL2 CALL3 CALL4
198 
199 %type <string> attributes expr
200 %type <vals> array_elements array_element
201 
202 %nonassoc OR
203 
204 %%
205 
206 statements	: /* empty */
207 		| statement EOL statements
208 		;
209 
210 statement	: assign
211 		| call
212 		| call2
213 		| call3
214 		| call4
215 		| check
216 		| delay
217 		| input
218 		| noinput
219 		| compare
220 		| comparend
221 		| cchar
222 		| wchar
223 		| /* empty */
224 		;
225 
226 assign		: ASSIGN VARNAME numeric {
227 			set_var(data_number, $2, $3);
228 		}
229 		| ASSIGN VARNAME LPAREN expr RPAREN {
230 			set_var(data_number, $2, $4);
231 		}
232 		| ASSIGN VARNAME STRING {
233 			set_var(data_string, $2, $3);
234 		}
235 		| ASSIGN VARNAME BYTE {
236 			set_var(data_byte, $2, $3);
237 		}
238 		;
239 
240 cchar		: CCHAR VARNAME attributes char_vals {
241 			set_cchar($2, $3);
242 		}
243 		;
244 
245 wchar		: WCHAR VARNAME char_vals {
246 			set_wchar($2);
247 		}
248 		;
249 
250 attributes	: numeric
251 		| LPAREN expr RPAREN {
252 			$$ = $2;
253 		}
254 		| VARIABLE {
255 			$$ = get_numeric_var($1);
256 		}
257 		;
258 
259 char_vals	: numeric {
260 			add_to_vals(data_number, $1);
261 		}
262 		| LBRACK array_elements RBRACK
263 		| VARIABLE {
264 			add_to_vals(data_var, $1);
265 		}
266 		| STRING {
267 			add_to_vals(data_string, $1);
268 		}
269 		| BYTE {
270 			add_to_vals(data_byte, $1);
271 		}
272 		;
273 
274 call		: CALL result fn_name args {
275 			do_function_call(1);
276 		}
277 		;
278 
279 call2		: CALL2 result result fn_name args {
280 			do_function_call(2);
281 		}
282 		;
283 
284 call3		: CALL3 result result result fn_name args {
285 			do_function_call(3);
286 		}
287 		;
288 
289 call4		: CALL4 result result result result fn_name args {
290 			do_function_call(4);
291 		}
292 		;
293 
294 check		: CHECK var returns {
295 			check();
296 		}
297 		;
298 
299 delay		: DELAY numeric {
300 			delay_millis($2);
301 		}
302 		;
303 
304 input		: INPUT STRING {
305 			do_input($2);
306 		}
307 		;
308 
309 noinput		: NOINPUT {
310 			do_noinput();
311 		}
312 		;
313 
314 compare		: COMPARE PATH {
315 			compare_streams($2, true);
316 		}
317 		| COMPARE FILENAME {
318 			compare_streams($2, true);
319 		}
320 		;
321 
322 comparend	: COMPAREND PATH {
323 			compare_streams($2, false);
324 		}
325 		| COMPAREND FILENAME {
326 			compare_streams($2, false);
327 		}
328 		;
329 
330 
331 result		: returns
332 		| reference
333 		;
334 
335 returns		: numeric {
336 			assign_rets(data_number, $1);
337 		}
338 		| LPAREN expr RPAREN {
339 			assign_rets(data_number, $2);
340 		}
341 		| STRING {
342 			assign_rets(data_string, $1);
343 		}
344 		| BYTE {
345 			assign_rets(data_byte, (void *) $1);
346 		}
347 		| ERR_RET {
348 			assign_rets(data_err, NULL);
349 		}
350 		| OK_RET {
351 			assign_rets(data_ok, NULL);
352 		}
353 		| NULL_RET {
354 			assign_rets(data_null, NULL);
355 		}
356 		| NON_NULL {
357 			assign_rets(data_nonnull, NULL);
358 		}
359 		| var
360 		;
361 
362 var		: VARNAME {
363 			assign_rets(data_var, $1);
364 		}
365 		;
366 
367 reference	: VARIABLE {
368 			assign_rets(data_ref, $1);
369 		}
370 		;
371 
372 fn_name		: VARNAME {
373 			if (command.function != NULL)
374 				free(command.function);
375 
376 			command.function = malloc(strlen($1) + 1);
377 			if (command.function == NULL)
378 				err(1, "Could not allocate memory for function name");
379 			strcpy(command.function, $1);
380 		}
381 		;
382 
383 array_elements	: array_element
384 		| array_element COMMA array_elements
385 		;
386 
387 array_element	: numeric {
388 			$$ = add_to_vals(data_number, $1);
389 		}
390 		| VARIABLE {
391 			$$ = add_to_vals(data_number, get_numeric_var($1));
392 		}
393 		| BYTE {
394 			$$ = add_to_vals(data_byte, (void *) $1);
395 		}
396 		| STRING {
397 			$$ = add_to_vals(data_string, (void *) $1);
398 		}
399 		| numeric MULTIPLIER numeric {
400 			unsigned long i;
401 			unsigned long acount;
402 
403 			acount = strtoul($3, NULL, 10);
404 			for (i = 0; i < acount; i++) {
405 				$$ = add_to_vals(data_number, $1);
406 			}
407 		}
408 		| VARIABLE MULTIPLIER numeric {
409 			unsigned long i, acount;
410 			char *val;
411 
412 			acount = strtoul($3, NULL, 10);
413 			val = get_numeric_var($1);
414 			for (i = 0; i < acount; i++) {
415 				$$ = add_to_vals(data_number, val);
416 			}
417 		}
418 		| BYTE MULTIPLIER numeric {
419 			unsigned long i, acount;
420 
421 			acount = strtoul($3, NULL, 10);
422 			for (i = 0; i < acount; i++) {
423 				$$ = add_to_vals(data_byte, (void *) $1);
424 			}
425 		}
426 		| STRING MULTIPLIER numeric {
427 			unsigned long i, acount;
428 
429 			acount = strtoul($3, NULL, 10);
430 			for (i = 0; i < acount; i++) {
431 				$$ = add_to_vals(data_string, (void *) $1);
432 			}
433 		}
434 		;
435 
436 expr		: numeric
437 		| VARIABLE {
438 			$$ = get_numeric_var($1);
439 		}
440 		| expr OR expr {
441 			$$ = numeric_or($1, $3);
442 		}
443 		;
444 
445 args		: /* empty */
446 		| arg args
447 		;
448 
449 arg		: LPAREN expr RPAREN {
450 			assign_arg(data_static, $2);
451 		}
452 		| numeric {
453 			assign_arg(data_static, $1);
454 		}
455 		| STRING {
456 			assign_arg(data_static, $1);
457 		}
458 		| BYTE {
459 			assign_arg(data_byte, $1);
460 		}
461 		| PATH {
462 			assign_arg(data_static, $1);
463 		}
464 		| FILENAME {
465 			assign_arg(data_static, $1);
466 		}
467 		| VARNAME {
468 			assign_arg(data_static, $1);
469 		}
470 		| VARIABLE {
471 			assign_arg(data_var, $1);
472 		}
473 		| NULL_RET {
474 			assign_arg(data_null, $1);
475 		}
476 		;
477 
478 %%
479 
480 static void
481 excess(const char *fname, size_t lineno, const char *func, const char *comment,
482     const void *data, size_t datalen)
483 {
484 	size_t dstlen = datalen * 4 + 1;
485 	char *dst = malloc(dstlen);
486 
487 	if (dst == NULL)
488 		err(1, "malloc");
489 
490 	if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
491 		err(1, "strnvisx");
492 
493 	warnx("%s:%zu: [%s] Excess %zu bytes%s [%s]",
494 	    fname, lineno, func, datalen, comment, dst);
495 	free(dst);
496 }
497 
498 /*
499  * Get the value of a variable, error if the variable has not been set or
500  * is not a numeric type.
501  */
502 static char *
503 get_numeric_var(const char *var)
504 {
505 	int i;
506 
507 	if ((i = find_var_index(var)) < 0)
508 		errx(1, "Variable %s is undefined", var);
509 
510 	if (vars[i].type != data_number)
511 		errx(1, "Variable %s is not a numeric type", var);
512 
513 	return vars[i].value;
514 }
515 
516 /*
517  * Perform a bitwise OR on two numbers and return the result.
518  */
519 static char *
520 numeric_or(const char *n1, const char *n2)
521 {
522 	unsigned long i1, i2, result;
523 	char *ret;
524 
525 	i1 = strtoul(n1, NULL, 10);
526 	i2 = strtoul(n2, NULL, 10);
527 
528 	result = i1 | i2;
529 	asprintf(&ret, "%lu", result);
530 
531 	if (verbose) {
532 		fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
533 		    " results in 0x%lx (%s)\n",
534 		    i1, n1, i2, n2, result, ret);
535 	}
536 
537 	return ret;
538 }
539 
540 /*
541  * Sleep for the specified time, handle the sleep getting interrupted
542  * by a signal.
543  */
544 static void
545 perform_delay(struct timespec *ts)
546 {
547 	struct timespec delay_copy, delay_remainder;
548 
549 	delay_copy = *ts;
550 	while (nanosleep(&delay_copy, &delay_remainder) < 0) {
551 		if (errno != EINTR)
552 			err(2, "nanosleep returned error");
553 		delay_copy = delay_remainder;
554 	}
555 }
556 
557 /*
558  * Add to temporary vals array
559  */
560 static wchar_t *
561 add_to_vals(data_enum_t argtype, void *arg)
562 {
563 	wchar_t *retval = NULL;
564 	int have_malloced;
565 	int i;
566 	ct_data_t *ret;
567 
568 	have_malloced = 0;
569 
570 	if (nvals == 0) {
571 		have_malloced = 1;
572 		retval = malloc(sizeof(wchar_t));
573 	} else {
574 		retval = realloc(vals, (nvals + 1) * sizeof(wchar_t));
575 	}
576 
577 	if (retval == NULL)
578 		return retval;
579 
580 	vals = retval;
581 
582 	switch (argtype) {
583 	case data_number:
584 		vals[nvals++] = (wchar_t) strtoul((char *) arg, NULL, 10);
585 		break;
586 
587 	case data_string:
588 		vals[nvals++] = (wchar_t) ((char *)arg)[0];
589 		break;
590 
591 	case data_byte:
592 		ret = (ct_data_t *) arg;
593 		vals[nvals++] = *((wchar_t *) ret->data_value);
594 		break;
595 
596 	case data_var:
597 		if ((i = find_var_index((char *) arg)) < 0)
598 			errx(1, "%s:%zu: Variable %s is undefined",
599 			    cur_file, line, (const char *) arg);
600 
601 		switch (vars[i].type) {
602 
603 		case data_number:
604 		case data_string:
605 		case data_byte:
606 			retval = add_to_vals(vars[i].type, vars[i].value);
607 			break;
608 
609 		default:
610 			errx(1,
611 			    "%s:%zu: Variable %s has invalid type for cchar",
612 			    cur_file, line, (const char *) arg);
613 			break;
614 
615 		}
616 		break;
617 
618 	default:
619 		errx(1, "%s:%zu: Internal error: Unhandled type for vals array",
620 		    cur_file, line);
621 
622 		/* if we get here without a value then tidy up */
623 		if ((nvals == 0) && (have_malloced == 1)) {
624 			free(retval);
625 			retval = vals;
626 		}
627 		break;
628 
629 	}
630 
631 	return retval;
632 }
633 
634 /*
635  * Assign the value given to the named variable.
636  */
637 static void
638 set_var(data_enum_t type, const char *name, void *value)
639 {
640 	int i;
641 	char *number;
642 	ct_data_t *ret;
643 
644 	i = find_var_index(name);
645 	if (i < 0)
646 		i = assign_var(name);
647 
648 	vars[i].type = type;
649 	if ((type == data_number) || (type == data_string)) {
650 		number = value;
651 		vars[i].len = strlen(number) + 1;
652 		vars[i].value = malloc(vars[i].len + 1);
653 		if (vars[i].value == NULL)
654 			err(1, "Could not malloc memory for assign string");
655 		strcpy(vars[i].value, number);
656 	} else {
657 		/* can only be a byte value */
658 		ret = value;
659 		vars[i].len = ret->data_len;
660 		vars[i].value = malloc(vars[i].len);
661 		if (vars[i].value == NULL)
662 			err(1, "Could not malloc memory to assign byte string");
663 		memcpy(vars[i].value, ret->data_value, vars[i].len);
664 	}
665 }
666 
667 /*
668  * Form up a complex character type from the given components.
669  */
670 static void
671 set_cchar(char *name, void *attributes)
672 {
673 	int i;
674 	unsigned j;
675 	attr_t attribs;
676 
677 	if (nvals >= CURSES_CCHAR_MAX)
678 		errx(1, "%s:%zu: %s: too many characters in complex char type",
679 		    cur_file, line, __func__);
680 
681 	i = find_var_index(name);
682 	if (i < 0)
683 		i = assign_var(name);
684 
685 	if (sscanf((char *) attributes, "%d", &attribs) != 1)
686 		errx(1,
687 		    "%s:%zu: %s: conversion of attributes to integer failed",
688 		    cur_file, line, __func__);
689 
690 	vars[i].type = data_cchar;
691 	vars[i].cchar.attributes = attribs;
692 	vars[i].cchar.elements = nvals;
693 	for (j = 0; j < nvals; j++)
694 		vars[i].cchar.vals[j] = vals[j];
695 
696 	nvals = 0;
697 	vals = NULL;
698 
699 }
700 
701 /*
702  * Form up a wide character string type from the given components.
703  */
704 static void
705 set_wchar(char *name)
706 {
707 	int i;
708 	unsigned j;
709 	wchar_t *wcval;
710 
711 	i = find_var_index(name);
712 	if (i < 0)
713 		i = assign_var(name);
714 
715 	vars[i].type = data_wchar;
716 	vars[i].len = (nvals+1) * sizeof(wchar_t);
717 	vars[i].value = malloc(vars[i].len);
718 	if (vars[i].value == NULL)
719 		err(1, "Could not malloc memory to assign wchar string");
720 	wcval = vars[i].value;
721 	for(j = 0; j < nvals; j++)
722 		wcval[j] = vals[j];
723 	wcval[nvals] = L'\0';
724 	nvals = 0;
725 	vals = NULL;
726 
727 }
728 
729 /*
730  * Add a new variable to the vars array, the value will be assigned later,
731  * when a test function call returns.
732  */
733 static int
734 assign_var(const char *varname)
735 {
736 	var_t *temp;
737 	char *name;
738 
739 	if ((name = malloc(strlen(varname) + 1)) == NULL)
740 		err(1, "Alloc of varname failed");
741 
742 	if ((temp = realloc(vars, sizeof(*temp) * (nvars + 1))) == NULL) {
743 		free(name);
744 		err(1, "Realloc of vars array failed");
745 	}
746 
747 	strcpy(name, varname);
748 	vars = temp;
749 	vars[nvars].name = name;
750 	vars[nvars].len = 0;
751 	vars[nvars].value = NULL;
752 	nvars++;
753 
754 	return (nvars - 1);
755 }
756 
757 /*
758  * Allocate and assign a new argument of the given type.
759  */
760 static void
761 assign_arg(data_enum_t arg_type, void *arg)
762 {
763 	args_t *temp, cur;
764 	char *str = arg;
765 	ct_data_t *ret;
766 
767 	if (verbose) {
768 		fprintf(stderr, "function is >%s<, adding arg >%s< type %s (%d)\n",
769 		       command.function, str, enum_names[arg_type], arg_type);
770 	}
771 
772 	cur.arg_type = arg_type;
773 	if (cur.arg_type == data_var) {
774 		cur.var_index = find_var_index(arg);
775 		if (cur.var_index < 0)
776 			errx(1, "%s:%zu: Invalid variable %s",
777 			    cur_file, line, str);
778 	} else if (cur.arg_type == data_byte) {
779 		ret = arg;
780 		cur.arg_len = ret->data_len;
781 		cur.arg_string = malloc(cur.arg_len);
782 		if (cur.arg_string == NULL)
783 			err(1, "Could not malloc memory for arg bytes");
784 		memcpy(cur.arg_string, ret->data_value, cur.arg_len);
785 	} else if (cur.arg_type == data_null) {
786 		cur.arg_len = 0;
787 		cur.arg_string = NULL;
788 	} else {
789 		cur.arg_len = strlen(str);
790 		cur.arg_string = malloc(cur.arg_len + 1);
791 		if (cur.arg_string == NULL)
792 			err(1, "Could not malloc memory for arg string");
793 		strcpy(cur.arg_string, arg);
794 	}
795 
796 	temp = realloc(command.args, sizeof(*temp) * (command.nargs + 1));
797 	if (temp == NULL)
798 		err(1, "Failed to reallocate args");
799 	command.args = temp;
800 	memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
801 	command.nargs++;
802 }
803 
804 /*
805  * Allocate and assign a new return.
806  */
807 static void
808 assign_rets(data_enum_t ret_type, void *ret)
809 {
810 	ct_data_t *temp, cur;
811 	char *ret_str;
812 	ct_data_t *ret_ret;
813 
814 	cur.data_type = ret_type;
815 	if (ret_type != data_var) {
816 		if ((ret_type == data_number) || (ret_type == data_string)) {
817 			ret_str = ret;
818 			cur.data_len = strlen(ret_str) + 1;
819 			cur.data_value = malloc(cur.data_len + 1);
820 			if (cur.data_value == NULL)
821 				err(1,
822 				    "Could not malloc memory for arg string");
823 			strcpy(cur.data_value, ret_str);
824 		} else if (ret_type == data_byte) {
825 			ret_ret = ret;
826 			cur.data_len = ret_ret->data_len;
827 			cur.data_value = malloc(cur.data_len);
828 			if (cur.data_value == NULL)
829 				err(1,
830 				    "Could not malloc memory for byte string");
831 			memcpy(cur.data_value, ret_ret->data_value,
832 			       cur.data_len);
833 		} else if (ret_type == data_ref) {
834 			if ((cur.data_index = find_var_index(ret)) < 0)
835 				errx(1, "Undefined variable reference");
836 		}
837 	} else {
838 		cur.data_index = find_var_index(ret);
839 		if (cur.data_index < 0)
840 			cur.data_index = assign_var(ret);
841 	}
842 
843 	temp = realloc(command.returns, sizeof(*temp) * (command.nrets + 1));
844 	if (temp == NULL)
845 		err(1, "Failed to reallocate returns");
846 	command.returns = temp;
847 	memcpy(&command.returns[command.nrets], &cur, sizeof(ct_data_t));
848 	command.nrets++;
849 }
850 
851 /*
852  * Find the given variable name in the var array and return the i
853  * return -1 if var is not found.
854  */
855 static int
856 find_var_index(const char *var_name)
857 {
858 	int result;
859 	size_t i;
860 
861 	result = -1;
862 
863 	for (i = 0; i < nvars; i++) {
864 		if (strcmp(var_name, vars[i].name) == 0) {
865 			result = i;
866 			break;
867 		}
868 	}
869 
870 	return result;
871 }
872 
873 /*
874  * Check the given function name in the given table of names, return 1 if
875  * there is a match.
876  */
877 static int
878 check_function_table(char *function, const char *const table[], int nfunctions)
879 {
880 	int i;
881 
882 	for (i = 0; i < nfunctions; i++) {
883 		if (strcmp(function, table[i]) == 0)
884 			return 1;
885 	}
886 
887 	return 0;
888 }
889 
890 /*
891  * Compare the output from the slave against the given file and report
892  * any differences.
893  */
894 static void
895 compare_streams(const char *filename, bool discard)
896 {
897 	char check_file[PATH_MAX], drain[100], ref, data;
898 	struct pollfd fds[2];
899 	int nfd, check_fd;
900 	ssize_t result;
901 	size_t offs;
902 
903 	/*
904 	 * Don't prepend check path iff check file has an absolute
905 	 * path.
906 	 */
907 	if (filename[0] != '/') {
908 		if (strlcpy(check_file, check_path, sizeof(check_file))
909 		    >= sizeof(check_file))
910 			errx(2, "CHECK_PATH too long");
911 
912 		if (strlcat(check_file, "/", sizeof(check_file))
913 		    >= sizeof(check_file))
914 			errx(2, "Could not append / to check file path");
915 	} else {
916 		check_file[0] = '\0';
917 	}
918 
919 	if (strlcat(check_file, filename, sizeof(check_file))
920 	    >= sizeof(check_file))
921 		errx(2, "Path to check file path overflowed");
922 
923 	int create_check_file = 0;
924 
925 	if (check_file_flag == (GEN_CHECK_FILE | FORCE_GEN))
926 		create_check_file = 1;
927 	else if ((check_fd = open(check_file, O_RDONLY, 0)) < 0) {
928 		if (check_file_flag & GEN_CHECK_FILE)
929 			create_check_file = 1;
930 		else
931 			err(2, "%s:%zu: failed to open file %s",
932 			    cur_file, line, check_file);
933 	}
934 
935 	if (create_check_file) {
936 		check_fd = open(check_file, O_WRONLY | O_CREAT, 0644);
937 		if (check_fd < 0) {
938 			err(2, "%s:%zu: failed to create file %s",
939 			    cur_file, line, check_file);
940 		}
941 	}
942 
943 	fds[0].fd = check_fd;
944 	fds[0].events = create_check_file ? POLLOUT:POLLIN;
945 	fds[1].fd = master;
946 	fds[1].events = POLLIN;
947 
948 	nfd = 2;
949 	/*
950 	 * if we have saved output then only check for data in the
951 	 * reference file since the slave data may already be drained.
952 	 */
953 	if (saved_output.count > 0)
954 		nfd = 1;
955 
956 	offs = 0;
957 	while (poll(fds, nfd, 500) == nfd) {
958 		/* Read from check file if doing comparison */
959 		if (!create_check_file) {
960 			if (fds[0].revents & POLLIN) {
961 				if ((result = read(check_fd, &ref, 1)) < 1) {
962 					if (result != 0) {
963 						err(2, "Bad read on file %s",
964 						    check_file);
965 					} else {
966 						break;
967 					}
968 				}
969 			}
970 		}
971 
972 		if (saved_output.count > 0) {
973 			data = saved_output.data[saved_output.readp];
974 			saved_output.count--;
975 			saved_output.readp++;
976 			/* run out of saved data, switch to file */
977 			if (saved_output.count == 0)
978 				nfd = 2;
979 		} else {
980 			int revent = (create_check_file == 1) ? POLLOUT:POLLIN;
981 			if (fds[0].revents & revent) {
982 				if (read(master, &data, 1) < 1)
983 					err(2, "Bad read on slave pty");
984 			} else
985 				continue;
986 		}
987 
988 		if (create_check_file) {
989 			if ((result = write(check_fd, &data, 1)) < 1)
990 				err(2, "Bad write on file %s", check_file);
991 			ref = data;
992 		}
993 
994 		if (verbose) {
995 			if (create_check_file)
996 				fprintf(stderr, "Saving reference byte 0x%x (%c)"
997 					" against slave byte 0x%x (%c)\n",
998 					ref, (ref >= ' ') ? ref : '-',
999 					data, (data >= ' ' )? data : '-');
1000 			else
1001 				fprintf(stderr, "Comparing reference byte 0x%x (%c)"
1002 					" against slave byte 0x%x (%c)\n",
1003 					ref, (ref >= ' ') ? ref : '-',
1004 					data, (data >= ' ' )? data : '-');
1005 		}
1006 
1007 		if (!create_check_file && ref != data) {
1008 			errx(2, "%s:%zu: refresh data from slave does "
1009 			    "not match expected from file %s offset %zu "
1010 			    "[reference 0x%02x (%c) != slave 0x%02x (%c)]",
1011 			    cur_file, line, check_file, offs,
1012 			    ref, (ref >= ' ') ? ref : '-',
1013 			    data, (data >= ' ') ? data : '-');
1014 		}
1015 
1016 		offs++;
1017 	}
1018 
1019 	/*
1020 	 * if creating a check file, there shouldn't be
1021 	 * anymore saved output
1022 	 */
1023 	if (saved_output.count > 0) {
1024 		if (create_check_file)
1025 			errx(2, "Slave output not flushed correctly");
1026 		else
1027 			excess(cur_file, line, __func__, " from slave",
1028 				&saved_output.data[saved_output.readp], saved_output.count);
1029 	}
1030 
1031 	/* discard any excess saved output if required */
1032 	if (discard) {
1033 		saved_output.count = 0;
1034 		saved_output.readp = 0;
1035 	}
1036 
1037 	if (!create_check_file && (result = poll(fds, 2, 0)) != 0) {
1038 		if (result == -1)
1039 			err(2, "poll of file descriptors failed");
1040 
1041 		if ((fds[1].revents & POLLIN) == POLLIN) {
1042 			save_slave_output(true);
1043 		} else if ((fds[0].revents & POLLIN) == POLLIN) {
1044 			/*
1045 			 * handle excess in file if it exists.  Poll
1046 			 * says there is data until EOF is read.
1047 			 * Check next read is EOF, if it is not then
1048 			 * the file really has more data than the
1049 			 * slave produced so flag this as a warning.
1050 			 */
1051 			result = read(check_fd, drain, sizeof(drain));
1052 			if (result == -1)
1053 				err(1, "read of data file failed");
1054 
1055 			if (result > 0) {
1056 				excess(check_file, 0, __func__, "", drain,
1057 				    result);
1058 			}
1059 		}
1060 	}
1061 
1062 	close(check_fd);
1063 }
1064 
1065 /*
1066  * Pass a function call and arguments to the slave and wait for the
1067  * results.  The variable nresults determines how many returns we expect
1068  * back from the slave.  These results will be validated against the
1069  * expected returns or assigned to variables.
1070  */
1071 static void
1072 do_function_call(size_t nresults)
1073 {
1074 #define MAX_RESULTS 4
1075 	char *p;
1076 	int do_input;
1077 	size_t i;
1078 	struct pollfd fds[3];
1079 	ct_data_t response[MAX_RESULTS], returns_count;
1080 	assert(nresults <= MAX_RESULTS);
1081 
1082 	do_input = check_function_table(command.function, input_functions,
1083 	    ninput_functions);
1084 
1085 	write_func_and_args();
1086 
1087 	/*
1088 	 * We should get the number of returns back here, grab it before
1089 	 * doing input otherwise it will confuse the input poll
1090 	 */
1091 	read_cmd_pipe(&returns_count);
1092 	if (returns_count.data_type != data_count)
1093 		errx(2, "expected return type of data_count but received %s",
1094 		    enum_names[returns_count.data_type]);
1095 
1096 	perform_delay(&delay_post_call); /* let slave catch up */
1097 
1098 	if (verbose) {
1099 		fprintf(stderr, "Expect %zu results from slave, slave "
1100 		    "reported %zu\n", nresults, returns_count.data_len);
1101 	}
1102 
1103 	if ((no_input == false) && (do_input == 1)) {
1104 		if (verbose) {
1105 			fprintf(stderr, "doing input with inputstr >%s<\n",
1106 			    input_str);
1107 		}
1108 
1109 		if (input_str == NULL)
1110 			errx(2, "%s:%zu: Call to input function "
1111 			    "but no input defined", cur_file, line);
1112 
1113 		fds[0].fd = from_slave;
1114 		fds[0].events = POLLIN;
1115 		fds[1].fd = master;
1116 		fds[1].events = POLLOUT;
1117  		p = input_str;
1118 		save_slave_output(false);
1119 		while (*p != '\0') {
1120 			perform_delay(&delay_spec);
1121 
1122 			if (poll(fds, 2, 0) < 0)
1123 				err(2, "poll failed");
1124 			if (fds[0].revents & POLLIN) {
1125 				warnx("%s:%zu: Slave function "
1126 				    "returned before end of input string",
1127 				    cur_file, line);
1128 				break;
1129 			}
1130 			if ((fds[1].revents & POLLOUT) == 0)
1131 				continue;
1132 			if (verbose) {
1133 				fprintf(stderr, "Writing char >%c< to slave\n",
1134 				    *p);
1135 			}
1136 			if (write(master, p, 1) != 1) {
1137 				warn("%s:%zu: Slave function write error",
1138 				    cur_file, line);
1139 				break;
1140 			}
1141 			p++;
1142 
1143 		}
1144 		save_slave_output(false);
1145 
1146 		if (verbose) {
1147 			fprintf(stderr, "Input done.\n");
1148 		}
1149 
1150 		/* done with the input string, free the resources */
1151 		free(input_str);
1152 		input_str = NULL;
1153 	}
1154 
1155 	if (verbose) {
1156 		fds[0].fd = to_slave;
1157 		fds[0].events = POLLIN;
1158 
1159 		fds[1].fd = from_slave;
1160 		fds[1].events = POLLOUT;
1161 
1162 		fds[2].fd = master;
1163 		fds[2].events = POLLIN | POLLOUT;
1164 
1165 		i = poll(&fds[0], 3, 1000);
1166 		fprintf(stderr, "Poll returned %zu\n", i);
1167 		for (i = 0; i < 3; i++) {
1168 			fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
1169 				i, fds[i].revents);
1170 		}
1171 	}
1172 
1173 	/* drain any trailing output */
1174 	save_slave_output(false);
1175 
1176 	for (i = 0; i < returns_count.data_len; i++) {
1177 		read_cmd_pipe(&response[i]);
1178 	}
1179 
1180 	/*
1181 	 * Check for a slave error in the first return slot, if the
1182 	 * slave errored then we may not have the number of returns we
1183 	 * expect but in this case we should report the slave error
1184 	 * instead of a return count mismatch.
1185 	 */
1186 	if ((returns_count.data_len > 0) &&
1187 	    (response[0].data_type == data_slave_error))
1188 		errx(2, "Slave returned error: %s",
1189 		    (const char *)response[0].data_value);
1190 
1191 	if (returns_count.data_len != nresults)
1192 		errx(2, "Incorrect number of returns from slave, expected %zu "
1193 		    "but received %zu", nresults, returns_count.data_len);
1194 
1195 	if (verbose) {
1196 		for (i = 0; i < nresults; i++) {
1197 			if ((response[i].data_type != data_byte) &&
1198 			    (response[i].data_type != data_err) &&
1199 			    (response[i].data_type != data_ok))
1200 				fprintf(stderr,
1201 					"received response >%s< "
1202 					"expected",
1203 					(const char *)response[i].data_value);
1204 			else
1205 				fprintf(stderr, "received");
1206 
1207 			fprintf(stderr, " data_type %s\n",
1208 			    enum_names[command.returns[i].data_type]);
1209 		}
1210 	}
1211 
1212 	for (i = 0; i < nresults; i++) {
1213 		if (command.returns[i].data_type != data_var) {
1214 			validate(i, &response[i]);
1215 		} else {
1216 			vars[command.returns[i].data_index].len =
1217 				response[i].data_len;
1218 
1219 			if (response[i].data_type == data_cchar) {
1220 				vars[command.returns[i].data_index].cchar =
1221 					*((cchar_t *)response[i].data_value);
1222 		} else {
1223 				vars[command.returns[i].data_index].value =
1224 					response[i].data_value;
1225 			}
1226 
1227 			vars[command.returns[i].data_index].type =
1228 				response[i].data_type;
1229 		}
1230 	}
1231 
1232 	if (verbose && (saved_output.count > 0))
1233 		excess(cur_file, line, __func__, " from slave",
1234 		    &saved_output.data[saved_output.readp], saved_output.count);
1235 
1236 	init_parse_variables(0);
1237 }
1238 
1239 /*
1240  * Write the function and command arguments to the command pipe.
1241  */
1242 static void
1243 write_func_and_args(void)
1244 {
1245 	int i;
1246 
1247 	if (verbose) {
1248 		fprintf(stderr, "calling function >%s<\n", command.function);
1249 	}
1250 
1251 	write_cmd_pipe(command.function);
1252 	for (i = 0; i < command.nargs; i++) {
1253 		if (command.args[i].arg_type == data_var)
1254 			write_cmd_pipe_args(command.args[i].arg_type,
1255 					    &vars[command.args[i].var_index]);
1256 		else
1257 			write_cmd_pipe_args(command.args[i].arg_type,
1258 					    &command.args[i]);
1259 	}
1260 
1261 	write_cmd_pipe(NULL); /* signal end of arguments */
1262 }
1263 
1264 static void
1265 check(void)
1266 {
1267 	ct_data_t retvar;
1268 	var_t *vptr;
1269 
1270 	if (command.returns[0].data_index == -1)
1271 		errx(1, "%s:%zu: Undefined variable in check statement",
1272 		    cur_file, line);
1273 
1274 	if (command.returns[1].data_type == data_var) {
1275 		vptr = &vars[command.returns[1].data_index];
1276 		command.returns[1].data_type = vptr->type;
1277 		command.returns[1].data_len = vptr->len;
1278 		if (vptr->type != data_cchar)
1279 			command.returns[1].data_value = vptr->value;
1280 		else
1281 			command.returns[1].data_value = &vptr->cchar;
1282 	}
1283 
1284 	if (verbose) {
1285 		fprintf(stderr, "Checking contents of variable %s for %s\n",
1286 		    vars[command.returns[0].data_index].name,
1287 		    enum_names[command.returns[1].data_type]);
1288 	}
1289 
1290 	/*
1291 	 * Check if var and return have same data types
1292 	 */
1293 	if (((command.returns[1].data_type == data_byte) &&
1294 	     (vars[command.returns[0].data_index].type != data_byte)))
1295 		errx(1, "Var type %s (%d) does not match return type %s (%d)",
1296 		    enum_names[vars[command.returns[0].data_index].type],
1297 		    vars[command.returns[0].data_index].type,
1298 		    enum_names[command.returns[1].data_type],
1299 		    command.returns[1].data_type);
1300 
1301 	switch (command.returns[1].data_type) {
1302 	case data_err:
1303 	case data_ok:
1304 		validate_type(vars[command.returns[0].data_index].type,
1305 			&command.returns[1], 0);
1306 		break;
1307 
1308 	case data_null:
1309 		validate_variable(0, data_string, "NULL",
1310 				  command.returns[0].data_index, 0);
1311 		break;
1312 
1313 	case data_nonnull:
1314 		validate_variable(0, data_string, "NULL",
1315 				  command.returns[0].data_index, 1);
1316 		break;
1317 
1318 	case data_string:
1319 	case data_number:
1320 		if (verbose) {
1321 			fprintf(stderr, " %s == returned %s\n",
1322 			    (const char *)command.returns[1].data_value,
1323 			    (const char *)
1324 			    vars[command.returns[0].data_index].value);
1325 		}
1326 		validate_variable(0, data_string,
1327 		    command.returns[1].data_value,
1328 		    command.returns[0].data_index, 0);
1329 		break;
1330 
1331 	case data_byte:
1332 		vptr = &vars[command.returns[0].data_index];
1333 		retvar.data_len = vptr->len;
1334 		retvar.data_type = vptr->type;
1335 		retvar.data_value = vptr->value;
1336 		validate_byte(&retvar, &command.returns[1], 0);
1337 		break;
1338 
1339 	case data_cchar:
1340 		validate_cchar(&vars[command.returns[0].data_index].cchar,
1341 			(cchar_t *) command.returns[1].data_value, 0);
1342 		break;
1343 
1344 	case data_wchar:
1345 		validate_wchar((wchar_t *) vars[command.returns[0].data_index].value,
1346 			(wchar_t *) command.returns[1].data_value, 0);
1347 		break;
1348 
1349 	default:
1350 		errx(1, "%s:%zu: Malformed check statement", cur_file, line);
1351 		break;
1352 	}
1353 
1354 	init_parse_variables(0);
1355 }
1356 
1357 static void
1358 delay_millis(const char *millis)
1359 {
1360 	/* set the inter-character delay */
1361 	if (sscanf(millis, "%d", &input_delay) == 0)
1362 		errx(1, "%s:%zu: Delay specification %s must be an int",
1363 		    cur_file, line, millis);
1364 	if (verbose) {
1365 		fprintf(stderr, "Set input delay to %d ms\n", input_delay);
1366 	}
1367 
1368 	if (input_delay < DELAY_MIN)
1369 		input_delay = DELAY_MIN;
1370 	/*
1371 	 * Fill in the timespec structure now ready for use later.
1372 	 * The delay is specified in milliseconds so convert to timespec
1373 	 * values
1374 	 */
1375 	delay_spec.tv_sec = input_delay / 1000;
1376 	delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
1377 	if (verbose) {
1378 		fprintf(stderr, "set delay to %jd.%jd\n",
1379 		    (intmax_t)delay_spec.tv_sec,
1380 		    (intmax_t)delay_spec.tv_nsec);
1381 	}
1382 
1383 	init_parse_variables(0);
1384 }
1385 
1386 static void
1387 do_input(const char *s)
1388 {
1389 	if (input_str != NULL) {
1390 		warnx("%s:%zu: Discarding unused input string", cur_file, line);
1391 		free(input_str);
1392 	}
1393 
1394 	if ((input_str = strdup(s)) == NULL)
1395 		err(2, "Cannot allocate memory for input string");
1396 }
1397 
1398 static void
1399 do_noinput(void)
1400 {
1401 	if (input_str != NULL) {
1402 		warnx("%s:%zu: Discarding unused input string", cur_file, line);
1403 		free(input_str);
1404 	}
1405 
1406 	no_input = true;
1407 }
1408 
1409 /*
1410  * Initialise the command structure - if initial is non-zero then just set
1411  * everything to sane values otherwise free any memory that was allocated
1412  * when building the structure.
1413  */
1414 void
1415 init_parse_variables(int initial)
1416 {
1417 	int i, result;
1418 	struct pollfd slave_pty;
1419 
1420 	if (initial == 0) {
1421 		free(command.function);
1422 		for (i = 0; i < command.nrets; i++) {
1423 			if (command.returns[i].data_type == data_number)
1424 				free(command.returns[i].data_value);
1425 		}
1426 		free(command.returns);
1427 
1428 		for (i = 0; i < command.nargs; i++) {
1429 			if (command.args[i].arg_type != data_var)
1430 				free(command.args[i].arg_string);
1431 		}
1432 		free(command.args);
1433 	} else {
1434 		line = 1;
1435 		input_delay = 0;
1436 		vars = NULL;
1437 		nvars = 0;
1438 		input_str = NULL;
1439 		saved_output.allocated = 0;
1440 		saved_output.count = 0;
1441 		saved_output.readp = 0;
1442 		saved_output.data = NULL;
1443 	}
1444 
1445 	no_input = false;
1446 	command.function = NULL;
1447 	command.nargs = 0;
1448 	command.args = NULL;
1449 	command.nrets = 0;
1450 	command.returns = NULL;
1451 
1452 	/*
1453 	 * Check the slave pty for stray output from the slave, at this
1454 	 * point we should not see any data as it should have been
1455 	 * consumed by the test functions.  If we see data then we have
1456 	 * either a bug or are not handling an output generating function
1457 	 * correctly.
1458 	 */
1459 	slave_pty.fd = master;
1460 	slave_pty.events = POLLIN;
1461 	result = poll(&slave_pty, 1, 0);
1462 
1463 	if (result < 0)
1464 		err(2, "Poll of slave pty failed");
1465 	else if (result > 0)
1466 		warnx("%s:%zu: Unexpected data from slave", cur_file, line);
1467 }
1468 
1469 /*
1470  * Validate the response against the expected return.  The variable
1471  * i is the i into the rets array in command.
1472  */
1473 static void
1474 validate(int i, void *data)
1475 {
1476 	char *response;
1477 	ct_data_t *byte_response;
1478 
1479 	byte_response = data;
1480 	if ((command.returns[i].data_type != data_byte) &&
1481 	    (command.returns[i].data_type != data_err) &&
1482 	    (command.returns[i].data_type != data_ok)) {
1483 		if ((byte_response->data_type == data_byte) ||
1484 		    (byte_response->data_type == data_err) ||
1485 		    (byte_response->data_type == data_ok))
1486 			errx(1,
1487 			    "%s:%zu: %s: expecting type %s, received type %s",
1488 			    cur_file, line, __func__,
1489 			    enum_names[command.returns[i].data_type],
1490 			    enum_names[byte_response->data_type]);
1491 
1492 		response = byte_response->data_value;
1493 	}
1494 
1495 	switch (command.returns[i].data_type) {
1496 	case data_err:
1497 		validate_type(data_err, byte_response, 0);
1498 		break;
1499 
1500 	case data_ok:
1501 		validate_type(data_ok, byte_response, 0);
1502 		break;
1503 
1504 	case data_null:
1505 		validate_return("NULL", response, 0);
1506 		break;
1507 
1508 	case data_nonnull:
1509 		validate_return("NULL", response, 1);
1510 		break;
1511 
1512 	case data_string:
1513 	case data_number:
1514 		validate_return(command.returns[i].data_value,
1515 				response, 0);
1516 		break;
1517 
1518 	case data_ref:
1519 		validate_reference(i, response);
1520 		break;
1521 
1522 	case data_byte:
1523 		validate_byte(&command.returns[i], byte_response, 0);
1524 		break;
1525 
1526 	default:
1527 		errx(1, "%s:%zu: Malformed statement", cur_file, line);
1528 		break;
1529 	}
1530 }
1531 
1532 /*
1533  * Validate the return against the contents of a variable.
1534  */
1535 static void
1536 validate_reference(int i, void *data)
1537 {
1538 	char *response;
1539 	ct_data_t *byte_response;
1540 	var_t *varp;
1541 
1542 	varp = &vars[command.returns[i].data_index];
1543 
1544 	byte_response = data;
1545 	if (command.returns[i].data_type != data_byte)
1546 		response = data;
1547 
1548 	if (verbose) {
1549 		fprintf(stderr,
1550 		    "%s: return type of %s, value %s \n", __func__,
1551 		    enum_names[varp->type],
1552 		    (varp->type != data_cchar && varp->type != data_wchar)
1553 			? (const char *)varp->value : "-");
1554 	}
1555 
1556 	switch (varp->type) {
1557 	case data_string:
1558 	case data_number:
1559 		validate_return(varp->value, response, 0);
1560 		break;
1561 
1562 	case data_byte:
1563 		validate_byte(varp->value, byte_response, 0);
1564 		break;
1565 
1566 	case data_cchar:
1567 		validate_cchar(&(varp->cchar), (cchar_t *) response, 0);
1568 		break;
1569 
1570 	case data_wchar:
1571 		validate_wchar((wchar_t *) varp->value, (wchar_t *) response, 0);
1572 		break;
1573 
1574 	default:
1575 		errx(1, "%s:%zu: Invalid return type for reference",
1576 		    cur_file, line);
1577 		break;
1578 	}
1579 }
1580 
1581 /*
1582  * Validate the return type against the expected type, throw an error
1583  * if they don't match.
1584  */
1585 static void
1586 validate_type(data_enum_t expected, ct_data_t *value, int check)
1587 {
1588 	if (((check == 0) && (expected != value->data_type)) ||
1589 	    ((check == 1) && (expected == value->data_type)))
1590 		errx(1, "%s:%zu: Validate expected type %s %s %s",
1591 		    cur_file, line,
1592 		    enum_names[expected],
1593 		    (check == 0)? "matching" : "not matching",
1594 		    enum_names[value->data_type]);
1595 
1596 	if (verbose) {
1597 		fprintf(stderr, "%s:%zu: Validated expected type %s %s %s\n",
1598 		    cur_file, line,
1599 		    enum_names[expected],
1600 		    (check == 0)? "matching" : "not matching",
1601 		    enum_names[value->data_type]);
1602 	}
1603 }
1604 
1605 /*
1606  * Validate the return value against the expected value, throw an error
1607  * if they don't match.
1608  */
1609 static void
1610 validate_return(const char *expected, const char *value, int check)
1611 {
1612 	if (((check == 0) && strcmp(expected, value) != 0) ||
1613 	    ((check == 1) && strcmp(expected, value) == 0))
1614 		errx(1, "%s:%zu: Validate expected >%s< %s >%s<",
1615 		    cur_file, line,
1616 		    expected,
1617 		    (check == 0)? "matching" : "not matching",
1618 		    value);
1619 	if (verbose) {
1620 		fprintf(stderr,
1621 		    "%s:%zu: Validated expected value >%s< %s >%s<\n",
1622 		    cur_file, line,
1623 		    expected,
1624 		    (check == 0)? "matches" : "does not match",
1625 		    value);
1626 	}
1627 }
1628 
1629 /*
1630  * Validate the return value against the expected value, throw an error
1631  * if they don't match expectations.
1632  */
1633 static void
1634 validate_byte(ct_data_t *expected, ct_data_t *value, int check)
1635 {
1636 	char *ch;
1637 	size_t i;
1638 
1639 	if (verbose) {
1640 		ch = value->data_value;
1641 		fprintf(stderr, "checking returned byte stream: ");
1642 		for (i = 0; i < value->data_len; i++)
1643 			fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
1644 		fprintf(stderr, "\n");
1645 
1646 		fprintf(stderr, "%s byte stream: ",
1647 			(check == 0)? "matches" : "does not match");
1648 		ch = (char *) expected->data_value;
1649 		for (i = 0; i < expected->data_len; i++)
1650 			fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
1651 		fprintf(stderr, "\n");
1652 	}
1653 
1654 	/*
1655 	 * No chance of a match if lengths differ...
1656 	 */
1657 	if ((check == 0) && (expected->data_len != value->data_len))
1658 		errx(1,
1659 		    "Byte validation failed, length mismatch, "
1660 		    "expected %zu, received %zu",
1661 		    expected->data_len, value->data_len);
1662 
1663 	/*
1664 	 * If check is 0 then we want to throw an error IFF the byte streams
1665 	 * do not match, if check is 1 then throw an error if the byte
1666 	 * streams match.
1667 	 */
1668 	if (((check == 0) && memcmp(expected->data_value, value->data_value,
1669 				    value->data_len) != 0) ||
1670 	    ((check == 1) && (expected->data_len == value->data_len) &&
1671 	     memcmp(expected->data_value, value->data_value,
1672 		    value->data_len) == 0))
1673 		errx(1, "%s:%zu: Validate expected %s byte stream",
1674 		    cur_file, line,
1675 		    (check == 0)? "matching" : "not matching");
1676 	if (verbose) {
1677 		fprintf(stderr, "%s:%zu: Validated expected %s byte stream\n",
1678 		    cur_file, line,
1679 		    (check == 0)? "matching" : "not matching");
1680 	}
1681 }
1682 
1683 /*
1684  * Validate the return cchar against the expected cchar, throw an error
1685  * if they don't match expectations.
1686  */
1687 static void
1688 validate_cchar(cchar_t *expected, cchar_t *value, int check)
1689 {
1690 	unsigned j;
1691 
1692 	/*
1693 	 * No chance of a match if elements count differ...
1694 	 */
1695 	if ((expected->elements != value->elements)) {
1696 		if (check == 0)
1697 			errx(1,
1698 			    "cchar validation failed, elements count mismatch, "
1699 			    "expected %d, received %d",
1700 			    expected->elements, value->elements);
1701 		else {
1702 			if (verbose)
1703 				fprintf(stderr,
1704 				    "%s:%zu: Validated expected %s cchar",
1705 				    cur_file, line, "not matching");
1706 			return;
1707 		}
1708 	}
1709 
1710 	/*
1711 	 * No chance of a match if attributes differ...
1712 	 */
1713 
1714 	if ((expected->attributes & WA_ATTRIBUTES) !=
1715 			(value->attributes & WA_ATTRIBUTES )) {
1716 		if (check == 0)
1717 			errx(1,
1718 			    "cchar validation failed, attributes mismatch, "
1719 			    "expected 0x%x, received 0x%x",
1720 			    expected->attributes & WA_ATTRIBUTES,
1721 			    value->attributes & WA_ATTRIBUTES);
1722 		else {
1723 			if (verbose)
1724 				fprintf(stderr,
1725 				    "%s:%zu: Validated expected %s cchar\n",
1726 				    cur_file, line, "not matching");
1727 			return;
1728 		}
1729 	}
1730 
1731 	/*
1732 	 * If check is 0 then we want to throw an error IFF the vals
1733 	 * do not match, if check is 1 then throw an error if the vals
1734 	 * streams match.
1735 	 */
1736 	for(j = 0; j < expected->elements; j++) {
1737 		if (expected->vals[j] != value->vals[j]) {
1738 			if (check == 0)
1739 				errx(1,
1740 				    "cchar validation failed, vals mismatch, "
1741 				    "expected 0x%x, received 0x%x",
1742 				    expected->vals[j], value->vals[j]);
1743 			else {
1744 				if (verbose)
1745 					fprintf(stderr,
1746 					    "%s:%zu: Validated expected %s "
1747 					    "cchar\n",
1748 					    cur_file, line, "not matching");
1749 				return;
1750 			}
1751 		}
1752 	}
1753 
1754 	if (verbose) {
1755 		fprintf(stderr,
1756 		    "%s:%zu: Validated expected %s cchar\n",
1757 		    cur_file, line, (check == 0)? "matching" : "not matching");
1758 	}
1759 }
1760 
1761 /*
1762  * Validate the return wchar string against the expected wchar, throw an
1763  * error if they don't match expectations.
1764  */
1765 static void
1766 validate_wchar(wchar_t *expected, wchar_t *value, int check)
1767 {
1768 	unsigned j;
1769 
1770 	unsigned len1 = 0;
1771 	unsigned len2 = 0;
1772 	wchar_t *p;
1773 
1774 	p = expected;
1775 	while (*p++ != L'\0')
1776 		len1++;
1777 
1778 	p = value;
1779 	while (*p++ != L'\0')
1780 		len2++;
1781 
1782 	/*
1783 	 * No chance of a match if length differ...
1784 	 */
1785 	if (len1 != len2) {
1786 		if (check == 0)
1787 			errx(1,
1788 			    "wchar string validation failed, length mismatch, "
1789 			    "expected %d, received %d",
1790 			    len1, len2);
1791 		else {
1792 			if (verbose)
1793 				fprintf(stderr,
1794 				    "%s:%zu: Validated expected %s wchar\n",
1795 				    cur_file, line, "not matching");
1796 			return;
1797 		}
1798 	}
1799 
1800 	/*
1801 	 * If check is 0 then we want to throw an error IFF the vals
1802 	 * do not match, if check is 1 then throw an error if the vals
1803 	 * streams match.
1804 	 */
1805 	for(j = 0; j < len1; j++) {
1806 		if (expected[j] != value[j]) {
1807 			if (check == 0)
1808 				errx(1, "wchar validation failed at index %d, expected %d,"
1809 				"received %d", j, expected[j], value[j]);
1810 			else {
1811 				if (verbose)
1812 					fprintf(stderr,
1813 					    "%s:%zu: Validated expected %s wchar\n",
1814 					    cur_file, line, "not matching");
1815 				return;
1816 			}
1817 		}
1818 	}
1819 
1820 	if (verbose) {
1821 		fprintf(stderr,
1822 		    "%s:%zu: Validated expected %s wchar\n",
1823 		    cur_file, line,
1824 		    (check == 0)? "matching" : "not matching");
1825 	}
1826 }
1827 
1828 /*
1829  * Validate the variable at i against the expected value, throw an
1830  * error if they don't match, if check is non-zero then the match is
1831  * negated.
1832  */
1833 static void
1834 validate_variable(int ret, data_enum_t type, const void *value, int i,
1835     int check)
1836 {
1837 	ct_data_t *retval;
1838 	var_t *varptr;
1839 
1840 	retval = &command.returns[ret];
1841 	varptr = &vars[command.returns[ret].data_index];
1842 
1843 	if (varptr->value == NULL)
1844 		errx(1, "Variable %s has no value assigned to it", varptr->name);
1845 
1846 
1847 	if (varptr->type != type)
1848 		errx(1, "Variable %s is not the expected type", varptr->name);
1849 
1850 	if (type != data_byte) {
1851 		if ((((check == 0) && strcmp(value, varptr->value) != 0))
1852 		    || ((check == 1) && strcmp(value, varptr->value) == 0))
1853 			errx(1, "%s:%zu: Variable %s contains %s instead of %s"
1854 			    " value %s",
1855 			    cur_file, line,
1856 			    varptr->name, (const char *)varptr->value,
1857 			    (check == 0)? "expected" : "not matching",
1858 			    (const char *)value);
1859 		if (verbose) {
1860 			fprintf(stderr,
1861 			    "%s:%zu: Variable %s contains %s value %s\n",
1862 			    cur_file, line,
1863 			    varptr->name,
1864 			    (check == 0)? "expected" : "not matching",
1865 			    (const char *)varptr->value);
1866 		}
1867 	} else {
1868 		if ((check == 0) && (retval->data_len != varptr->len))
1869 			errx(1, "Byte validation failed, length mismatch");
1870 
1871 		/*
1872 		 * If check is 0 then we want to throw an error IFF
1873 		 * the byte streams do not match, if check is 1 then
1874 		 * throw an error if the byte streams match.
1875 		 */
1876 		if (((check == 0) && memcmp(retval->data_value, varptr->value,
1877 					    varptr->len) != 0) ||
1878 		    ((check == 1) && (retval->data_len == varptr->len) &&
1879 		     memcmp(retval->data_value, varptr->value,
1880 			    varptr->len) == 0))
1881 			errx(1, "%s:%zu: Validate expected %s byte stream",
1882 			    cur_file, line,
1883 			    (check == 0)? "matching" : "not matching");
1884 		if (verbose) {
1885 			fprintf(stderr,
1886 			    "%s:%zu: Validated expected %s byte stream\n",
1887 			    cur_file, line,
1888 			    (check == 0)? "matching" : "not matching");
1889 		}
1890 	}
1891 }
1892 
1893 /*
1894  * Write a string to the command pipe - we feed the number of bytes coming
1895  * down first to allow storage allocation and then follow up with the data.
1896  * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
1897  */
1898 static void
1899 write_cmd_pipe(char *cmd)
1900 {
1901 	args_t arg;
1902 	size_t len;
1903 
1904 	if (cmd == NULL)
1905 		len = 0;
1906 	else
1907 		len = strlen(cmd);
1908 
1909 	arg.arg_type = data_static;
1910 	arg.arg_len = len;
1911 	arg.arg_string = cmd;
1912 	write_cmd_pipe_args(arg.arg_type, &arg);
1913 
1914 }
1915 
1916 static void
1917 write_cmd_pipe_args(data_enum_t type, void *data)
1918 {
1919 	var_t *var_data;
1920 	args_t *arg_data;
1921 	int len, send_type;
1922 	void *cmd;
1923 
1924 	arg_data = data;
1925 	switch (type) {
1926 	case data_var:
1927 		var_data = data;
1928 		len = var_data->len;
1929 		cmd = var_data->value;
1930 
1931 		switch (var_data->type) {
1932 		case data_byte:
1933 			send_type = data_byte;
1934 			break;
1935 
1936 		case data_cchar:
1937 			send_type = data_cchar;
1938 			cmd = (void *) &var_data->cchar;
1939 			len = sizeof(cchar_t);
1940 			break;
1941 
1942 		case data_wchar:
1943 			send_type = data_wchar;
1944 			break;
1945 
1946 		default:
1947 			send_type = data_string;
1948 			break;
1949 		}
1950 		break;
1951 
1952 	case data_null:
1953 		send_type = data_null;
1954 		len = 0;
1955 		break;
1956 
1957 	default:
1958 		if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
1959 			len = -1;
1960 		else
1961 			len = arg_data->arg_len;
1962 		cmd = arg_data->arg_string;
1963 		if (type == data_byte)
1964 			send_type = data_byte;
1965 		else
1966 			send_type = data_string;
1967 	}
1968 
1969 	if (verbose) {
1970 		fprintf(stderr, "Writing type %s to command pipe\n",
1971 		    enum_names[send_type]);
1972 	}
1973 
1974 	if (write(to_slave, &send_type, sizeof(int)) < 0)
1975 		err(1, "command pipe write for type failed");
1976 
1977 	if (verbose) {
1978 		if (send_type == data_cchar)
1979 			fprintf(stderr,
1980 			    "Writing cchar to command pipe\n");
1981 		else if (send_type == data_wchar)
1982 			fprintf(stderr,
1983 			    "Writing wchar(%d sized) to command pipe\n", len);
1984 		else
1985 			fprintf(stderr,
1986 			    "Writing length %d to command pipe\n", len);
1987 	}
1988 
1989 	if (write(to_slave, &len, sizeof(int)) < 0)
1990 		err(1, "command pipe write for length failed");
1991 
1992 	if (len > 0) {
1993 		if (verbose) {
1994 			fprintf(stderr, "Writing data >%s< to command pipe\n",
1995 			    (const char *)cmd);
1996 		}
1997 		if (write(to_slave, cmd, len) < 0)
1998 			err(1, "command pipe write of data failed");
1999 	}
2000 }
2001 
2002 /*
2003  * Read a response from the command pipe, first we will receive the
2004  * length of the response then the actual data.
2005  */
2006 static void
2007 read_cmd_pipe(ct_data_t *response)
2008 {
2009 	int len, type;
2010 	struct pollfd rfd[2];
2011 	char *str;
2012 
2013 	/*
2014 	 * Check if there is data to read - just in case slave has died, we
2015 	 * don't want to block on the read and just hang.  We also check
2016 	 * output from the slave because the slave may be blocked waiting
2017 	 * for a flush on its stdout.
2018 	 */
2019 	rfd[0].fd = from_slave;
2020 	rfd[0].events = POLLIN;
2021 	rfd[1].fd = master;
2022 	rfd[1].events = POLLIN;
2023 
2024 	do {
2025 		if (poll(rfd, 2, 4000) == 0)
2026 			errx(2, "%s:%zu: Command pipe read timeout",
2027 			    cur_file, line);
2028 
2029 		if ((rfd[1].revents & POLLIN) == POLLIN) {
2030 			if (verbose) {
2031 				fprintf(stderr,
2032 				    "draining output from slave\n");
2033 			}
2034 			save_slave_output(false);
2035 		}
2036 	}
2037 	while ((rfd[1].revents & POLLIN) == POLLIN);
2038 
2039 	if (read(from_slave, &type, sizeof(int)) < 0)
2040 		err(1, "command pipe read for type failed");
2041 	response->data_type = type;
2042 
2043 	if ((type != data_ok) && (type != data_err) && (type != data_count)) {
2044 		if (read(from_slave, &len, sizeof(int)) < 0)
2045 			err(1, "command pipe read for length failed");
2046 		response->data_len = len;
2047 
2048 		if (verbose) {
2049 			fprintf(stderr,
2050 			    "Reading %d bytes from command pipe\n", len);
2051 		}
2052 
2053 		if ((response->data_value = malloc(len + 1)) == NULL)
2054 			err(1, "Failed to alloc memory for cmd pipe read");
2055 
2056 		if (read(from_slave, response->data_value, len) < 0)
2057 			err(1, "command pipe read of data failed");
2058 
2059 		if (response->data_type != data_byte) {
2060 			str = response->data_value;
2061 			str[len] = '\0';
2062 
2063 			if (verbose) {
2064 				fprintf(stderr, "Read data >%s< from pipe\n",
2065 				    (const char *)response->data_value);
2066 			}
2067 		}
2068 	} else {
2069 		response->data_value = NULL;
2070 		if (type == data_count) {
2071 			if (read(from_slave, &len, sizeof(int)) < 0)
2072 				err(1, "command pipe read for number of "
2073 				       "returns failed");
2074 			response->data_len = len;
2075 		}
2076 
2077 		if (verbose) {
2078 			fprintf(stderr, "Read type %s from pipe\n",
2079 			    enum_names[type]);
2080 		}
2081 	}
2082 }
2083 
2084 /*
2085  * Check for writes from the slave on the pty, save the output into a
2086  * buffer for later checking if discard is false.
2087  */
2088 #define MAX_DRAIN 256
2089 
2090 static void
2091 save_slave_output(bool discard)
2092 {
2093 	char *new_data, drain[MAX_DRAIN];
2094 	size_t to_allocate;
2095 	ssize_t result;
2096 	size_t i;
2097 
2098 	result = 0;
2099 	for (;;) {
2100 		if (result == -1)
2101 			err(2, "poll of slave pty failed");
2102 		result = MAX_DRAIN;
2103 		if ((result = read(master, drain, result)) < 0) {
2104 			if (errno == EAGAIN)
2105 				break;
2106 			else
2107 				err(2, "draining slave pty failed");
2108 		}
2109 		if (result == 0)
2110 			abort();
2111 
2112 		if (!discard) {
2113 			if ((size_t)result >
2114 			    (saved_output.allocated - saved_output.count)) {
2115 				to_allocate = 1024 * ((result / 1024) + 1);
2116 
2117 				if ((new_data = realloc(saved_output.data,
2118 					saved_output.allocated + to_allocate))
2119 				    == NULL)
2120 					err(2, "Realloc of saved_output failed");
2121 				saved_output.data = new_data;
2122 				saved_output.allocated += to_allocate;
2123 			}
2124 
2125 			if (verbose) {
2126 				fprintf(stderr,
2127 				    "count = %zu, allocated = %zu\n",
2128 				    saved_output.count, saved_output.allocated);
2129 				for (i = 0; i < (size_t)result; i++) {
2130 					fprintf(stderr, "Saving slave output "
2131 					    "at %zu: 0x%x (%c)\n",
2132 					    saved_output.count + i, drain[i],
2133 					    (drain[i] >= ' ')? drain[i] : '-');
2134 				}
2135 			}
2136 
2137 			memcpy(&saved_output.data[saved_output.count], drain,
2138 			       result);
2139 			saved_output.count += result;
2140 
2141 			if (verbose) {
2142 				fprintf(stderr,
2143 				    "count = %zu, allocated = %zu\n",
2144 				    saved_output.count, saved_output.allocated);
2145 			}
2146 		} else {
2147 			if (verbose) {
2148 				for (i = 0; i < (size_t)result; i++) {
2149 					fprintf(stderr, "Discarding slave "
2150 					    "output 0x%x (%c)\n",
2151 					    drain[i],
2152 					    (drain[i] >= ' ')? drain[i] : '-');
2153 				}
2154 			}
2155 		}
2156 	}
2157 }
2158 
2159 static void
2160 yyerror(const char *msg)
2161 {
2162 	errx(1, "%s:%zu: %s", cur_file, line, msg);
2163 }
2164