testlang_parse.y revision 1.3.2.1 1 1.1 blymn %{
2 1.3.2.1 cherry /* $NetBSD: testlang_parse.y,v 1.3.2.1 2011/06/23 14:20:40 cherry Exp $ */
3 1.1 blymn
4 1.1 blymn /*-
5 1.1 blymn * Copyright 2009 Brett Lymn <blymn (at) NetBSD.org>
6 1.1 blymn *
7 1.1 blymn * All rights reserved.
8 1.1 blymn *
9 1.1 blymn * This code has been donated to The NetBSD Foundation by the Author.
10 1.1 blymn *
11 1.1 blymn * Redistribution and use in source and binary forms, with or without
12 1.1 blymn * modification, are permitted provided that the following conditions
13 1.1 blymn * are met:
14 1.1 blymn * 1. Redistributions of source code must retain the above copyright
15 1.1 blymn * notice, this list of conditions and the following disclaimer.
16 1.1 blymn * 2. The name of the author may not be used to endorse or promote products
17 1.1 blymn * derived from this software withough specific prior written permission
18 1.1 blymn *
19 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 1.1 blymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 1.1 blymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 1.1 blymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 1.1 blymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 1.1 blymn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 1.1 blymn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 1.1 blymn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 1.1 blymn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 1.1 blymn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 1.1 blymn *
30 1.1 blymn *
31 1.1 blymn */
32 1.1 blymn #include <assert.h>
33 1.1 blymn #include <errno.h>
34 1.1 blymn #include <fcntl.h>
35 1.3 christos #include <err.h>
36 1.3 christos #include <unistd.h>
37 1.1 blymn #include <poll.h>
38 1.1 blymn #include <stdbool.h>
39 1.1 blymn #include <stdio.h>
40 1.1 blymn #include <string.h>
41 1.1 blymn #include <sys/syslimits.h>
42 1.1 blymn #include <time.h>
43 1.3.2.1 cherry #include <vis.h>
44 1.1 blymn #include "returns.h"
45 1.1 blymn
46 1.1 blymn #define YYDEBUG 1
47 1.1 blymn
48 1.1 blymn extern int verbose;
49 1.1 blymn extern int cmdpipe[2];
50 1.1 blymn extern int slvpipe[2];
51 1.1 blymn extern int master;
52 1.1 blymn extern struct pollfd readfd;
53 1.1 blymn extern char *check_path;
54 1.1 blymn extern char *cur_file; /* from director.c */
55 1.1 blymn
56 1.3 christos int yylex(void);
57 1.3 christos
58 1.1 blymn size_t line;
59 1.1 blymn
60 1.1 blymn static int input_delay;
61 1.1 blymn
62 1.1 blymn /* time delay between inputs chars - default to 0.1ms minimum to prevent
63 1.1 blymn * problems with input tests
64 1.1 blymn */
65 1.1 blymn #define DELAY_MIN 0.1
66 1.1 blymn static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
67 1.1 blymn static char *input_str; /* string to feed in as input */
68 1.1 blymn static bool no_input; /* don't need more input */
69 1.1 blymn
70 1.1 blymn #define READ_PIPE 0
71 1.1 blymn #define WRITE_PIPE 1
72 1.1 blymn
73 1.3.2.1 cherry const char *returns_enum_names[] = {
74 1.1 blymn "unused", "numeric", "string", "byte", "ERR", "OK", "NULL", "not NULL",
75 1.1 blymn "variable", "reference", "returns count", "slave error"
76 1.1 blymn };
77 1.1 blymn
78 1.1 blymn typedef enum {
79 1.1 blymn arg_static,
80 1.1 blymn arg_byte,
81 1.2 blymn arg_var,
82 1.2 blymn arg_null
83 1.1 blymn } args_state_t;
84 1.1 blymn
85 1.3.2.1 cherry static const char *args_enum_names[] = {
86 1.2 blymn "static", "byte", "var", "NULL"
87 1.1 blymn };
88 1.1 blymn
89 1.1 blymn typedef struct {
90 1.1 blymn args_state_t arg_type;
91 1.1 blymn size_t arg_len;
92 1.1 blymn char *arg_string;
93 1.1 blymn int var_index;
94 1.1 blymn } args_t;
95 1.1 blymn
96 1.1 blymn typedef struct {
97 1.1 blymn char *function;
98 1.1 blymn int nrets; /* number of returns */
99 1.1 blymn returns_t *returns; /* array of expected returns */
100 1.1 blymn int nargs; /* number of arguments */
101 1.1 blymn args_t *args; /* arguments for the call */
102 1.1 blymn } cmd_line_t;
103 1.1 blymn
104 1.1 blymn static cmd_line_t command;
105 1.1 blymn
106 1.1 blymn typedef struct {
107 1.1 blymn char *name;
108 1.1 blymn size_t len;
109 1.1 blymn returns_enum_t type;
110 1.1 blymn void *value;
111 1.1 blymn } var_t;
112 1.1 blymn
113 1.1 blymn static size_t nvars; /* Number of declared variables */
114 1.1 blymn static var_t *vars; /* Variables defined during the test. */
115 1.1 blymn
116 1.1 blymn static int check_function_table(char *, const char *[], int);
117 1.3.2.1 cherry static int find_var_index(const char *);
118 1.1 blymn static void assign_arg(args_state_t, void *);
119 1.1 blymn static int assign_var(char *);
120 1.1 blymn void init_parse_variables(int);
121 1.1 blymn static void validate(int, void *);
122 1.3.2.1 cherry static void validate_return(const char *, const char *, int);
123 1.3.2.1 cherry static void validate_variable(int, returns_enum_t, const void *, int, int);
124 1.1 blymn static void validate_byte(returns_t *, returns_t *, int);
125 1.1 blymn static void write_cmd_pipe(char *);
126 1.1 blymn static void write_cmd_pipe_args(args_state_t, void *);
127 1.1 blymn static void read_cmd_pipe(returns_t *);
128 1.3.2.1 cherry static void write_func_and_args(void);
129 1.1 blymn static void compare_streams(char *, bool);
130 1.3.2.1 cherry static void do_function_call(size_t);
131 1.1 blymn static void save_slave_output(bool);
132 1.1 blymn static void validate_type(returns_enum_t, returns_t *, int);
133 1.1 blymn static void set_var(returns_enum_t, char *, void *);
134 1.1 blymn static void validate_reference(int, void *);
135 1.1 blymn static char *numeric_or(char *, char *);
136 1.3.2.1 cherry static char *get_numeric_var(const char *);
137 1.1 blymn
138 1.1 blymn static const char *input_functions[] = {
139 1.1 blymn "inch", "getch", "getnstr", "getstr", "innstr", "instr", "mvgetnstr",
140 1.1 blymn "mvgetstr", "mvinchstr", "mvinchnstr", "mvgetnstr", "mvgetstr",
141 1.1 blymn "mvinchstr", "mvinchnstr", "winch", "wgetch", "wgetnstr", "wgetstr",
142 1.1 blymn "winchnstr", "winchstr", "winnstr", "winstr"
143 1.1 blymn };
144 1.1 blymn
145 1.1 blymn static const unsigned ninput_functions =
146 1.1 blymn sizeof(input_functions) / sizeof(char *);
147 1.1 blymn
148 1.1 blymn saved_data_t saved_output;
149 1.1 blymn
150 1.1 blymn %}
151 1.1 blymn
152 1.1 blymn %union {
153 1.1 blymn char *string;
154 1.1 blymn returns_t *retval;
155 1.1 blymn }
156 1.1 blymn
157 1.1 blymn %token <string> PATH
158 1.1 blymn %token <string> STRING
159 1.1 blymn %token <retval> BYTE
160 1.1 blymn %token <string> VARNAME
161 1.1 blymn %token <string> FILENAME
162 1.1 blymn %token <string> VARIABLE
163 1.1 blymn %token <string> REFERENCE
164 1.1 blymn %token <string> NULL_RET
165 1.1 blymn %token <string> NON_NULL
166 1.1 blymn %token <string> ERR_RET
167 1.1 blymn %token <string> OK_RET
168 1.1 blymn %token <string> numeric
169 1.1 blymn %token <string> DELAY
170 1.1 blymn %token <string> INPUT
171 1.1 blymn %token <string> COMPARE
172 1.1 blymn %token <string> COMPAREND
173 1.1 blymn %token <string> ASSIGN
174 1.1 blymn %token EOL CALL CHECK NOINPUT OR LHB RHB
175 1.1 blymn %token CALL2 CALL3 CALL4 DRAIN
176 1.1 blymn
177 1.1 blymn %nonassoc OR
178 1.1 blymn
179 1.1 blymn %%
180 1.1 blymn
181 1.1 blymn statement : /* empty */
182 1.1 blymn | assign statement
183 1.1 blymn | call statement
184 1.1 blymn | call2 statement
185 1.1 blymn | call3 statement
186 1.1 blymn | call4 statement
187 1.1 blymn | check statement
188 1.1 blymn | delay statement
189 1.1 blymn | input statement
190 1.1 blymn | noinput statement
191 1.1 blymn | compare statement
192 1.1 blymn | comparend statement
193 1.1 blymn | eol statement
194 1.1 blymn ;
195 1.1 blymn
196 1.1 blymn assign : ASSIGN VARNAME numeric {set_var(ret_number, $2, $3);} eol
197 1.1 blymn | ASSIGN VARNAME LHB expr RHB {set_var(ret_number, $2, $<string>4);} eol
198 1.1 blymn | ASSIGN VARNAME STRING {set_var(ret_string, $2, $3);} eol
199 1.1 blymn | ASSIGN VARNAME BYTE {set_var(ret_byte, $2, $3);} eol
200 1.1 blymn ;
201 1.1 blymn
202 1.1 blymn call : CALL result fn_name args eol {
203 1.1 blymn do_function_call(1);
204 1.1 blymn }
205 1.1 blymn ;
206 1.1 blymn
207 1.1 blymn call2 : CALL2 result result fn_name args eol {
208 1.1 blymn do_function_call(2);
209 1.1 blymn }
210 1.1 blymn ;
211 1.1 blymn
212 1.1 blymn call3 : CALL3 result result result fn_name args eol {
213 1.1 blymn do_function_call(3);
214 1.1 blymn }
215 1.1 blymn ;
216 1.1 blymn
217 1.1 blymn call4 : CALL4 result result result result fn_name args eol {
218 1.1 blymn do_function_call(4);
219 1.1 blymn }
220 1.1 blymn ;
221 1.1 blymn
222 1.1 blymn check : CHECK var returns eol {
223 1.3.2.1 cherry returns_t retvar;
224 1.1 blymn var_t *vptr;
225 1.1 blymn if (command.returns[0].return_index == -1)
226 1.3.2.1 cherry err(1, "Undefined variable in check statement, line %zu"
227 1.1 blymn " of file %s", line, cur_file);
228 1.1 blymn
229 1.1 blymn if (verbose)
230 1.1 blymn fprintf(stderr, "Checking contents of variable %s for %s\n",
231 1.3.2.1 cherry vars[command.returns[0].return_index].name,
232 1.3.2.1 cherry returns_enum_names[command.returns[1].return_type]);
233 1.1 blymn
234 1.1 blymn if (((command.returns[1].return_type == arg_byte) &&
235 1.1 blymn (vars[command.returns[0].return_index].type != ret_byte)) ||
236 1.1 blymn ((command.returns[1].return_type == arg_static) &&
237 1.1 blymn (vars[command.returns[0].return_index].type != ret_string)))
238 1.1 blymn err(1, "Var type %s (%d) does not match return type %s (%d)",
239 1.1 blymn returns_enum_names[vars[command.returns[0].return_index].type],
240 1.1 blymn vars[command.returns[0].return_index].type,
241 1.1 blymn returns_enum_names[command.returns[1].return_type],
242 1.1 blymn command.returns[1].return_type);
243 1.1 blymn
244 1.1 blymn switch (command.returns[1].return_type) {
245 1.1 blymn case ret_err:
246 1.1 blymn validate_variable(0, ret_string, "ERR",
247 1.1 blymn command.returns[0].return_index, 0);
248 1.1 blymn break;
249 1.1 blymn
250 1.1 blymn case ret_ok:
251 1.1 blymn validate_variable(0, ret_string, "OK",
252 1.1 blymn command.returns[0].return_index, 0);
253 1.1 blymn break;
254 1.1 blymn
255 1.1 blymn case ret_null:
256 1.1 blymn validate_variable(0, ret_string, "NULL",
257 1.1 blymn command.returns[0].return_index, 0);
258 1.1 blymn break;
259 1.1 blymn
260 1.1 blymn case ret_nonnull:
261 1.1 blymn validate_variable(0, ret_string, "NULL",
262 1.1 blymn command.returns[0].return_index, 1);
263 1.1 blymn break;
264 1.1 blymn
265 1.1 blymn case ret_string:
266 1.1 blymn case ret_number:
267 1.1 blymn if (verbose)
268 1.1 blymn fprintf(stderr, " %s == returned %s\n",
269 1.3.2.1 cherry (const char *)command.returns[1].return_value,
270 1.3.2.1 cherry (const char *)
271 1.3.2.1 cherry vars[command.returns[0].return_index].value);
272 1.1 blymn validate_variable(0, ret_string,
273 1.3.2.1 cherry command.returns[1].return_value,
274 1.3.2.1 cherry command.returns[0].return_index, 0);
275 1.1 blymn break;
276 1.1 blymn
277 1.1 blymn case ret_byte:
278 1.1 blymn vptr = &vars[command.returns[0].return_index];
279 1.3.2.1 cherry retvar.return_len = vptr->len;
280 1.3.2.1 cherry retvar.return_type = vptr->type;
281 1.3.2.1 cherry retvar.return_value = vptr->value;
282 1.3.2.1 cherry validate_byte(&retvar, &command.returns[1], 0);
283 1.1 blymn break;
284 1.1 blymn
285 1.1 blymn default:
286 1.3.2.1 cherry err(1, "Malformed check statement at line %zu "
287 1.1 blymn "of file %s", line, cur_file);
288 1.1 blymn break;
289 1.1 blymn }
290 1.1 blymn
291 1.1 blymn init_parse_variables(0);
292 1.1 blymn }
293 1.1 blymn ;
294 1.1 blymn
295 1.1 blymn delay : DELAY numeric eol {
296 1.1 blymn /* set the inter-character delay */
297 1.1 blymn if (sscanf($2, "%d", &input_delay) == 0)
298 1.1 blymn err(1, "delay specification %s could not be converted to "
299 1.3.2.1 cherry "numeric at line %zu of file %s", $2, line, cur_file);
300 1.1 blymn if (verbose)
301 1.1 blymn fprintf(stderr, "Set input delay to %d ms\n", input_delay);
302 1.1 blymn
303 1.1 blymn if (input_delay < DELAY_MIN)
304 1.1 blymn input_delay = 1000 * DELAY_MIN; /* ms to ns */
305 1.1 blymn /*
306 1.1 blymn * Fill in the timespec structure now ready for use later.
307 1.1 blymn * The delay is specified in milliseconds so convert to timespec
308 1.1 blymn * values
309 1.1 blymn */
310 1.1 blymn delay_spec.tv_sec = input_delay / 1000;
311 1.1 blymn delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
312 1.1 blymn
313 1.1 blymn init_parse_variables(0);
314 1.1 blymn }
315 1.1 blymn ;
316 1.1 blymn
317 1.1 blymn input : INPUT STRING eol {
318 1.1 blymn if (input_str != NULL) {
319 1.3.2.1 cherry warnx("%s, %zu: Discarding unused input string",
320 1.3.2.1 cherry cur_file, line);
321 1.1 blymn free(input_str);
322 1.1 blymn }
323 1.1 blymn
324 1.1 blymn if ((input_str = malloc(strlen($2) + 1)) == NULL)
325 1.1 blymn err(2, "Cannot allocate memory for input string");
326 1.1 blymn
327 1.1 blymn strlcpy(input_str, $2, strlen($2) + 1);
328 1.1 blymn }
329 1.1 blymn ;
330 1.1 blymn
331 1.1 blymn
332 1.1 blymn noinput : NOINPUT eol {
333 1.1 blymn if (input_str != NULL) {
334 1.3.2.1 cherry warnx("%s, %zu: Discarding unused input string",
335 1.3.2.1 cherry cur_file, line);
336 1.1 blymn free(input_str);
337 1.1 blymn }
338 1.1 blymn
339 1.1 blymn no_input = true;
340 1.1 blymn }
341 1.1 blymn
342 1.1 blymn compare : COMPARE PATH eol
343 1.1 blymn | COMPARE FILENAME eol
344 1.1 blymn {
345 1.1 blymn compare_streams($2, true);
346 1.1 blymn }
347 1.1 blymn ;
348 1.1 blymn
349 1.1 blymn
350 1.1 blymn comparend : COMPAREND PATH eol
351 1.1 blymn | COMPAREND FILENAME eol
352 1.1 blymn {
353 1.1 blymn compare_streams($2, false);
354 1.1 blymn }
355 1.1 blymn ;
356 1.1 blymn
357 1.1 blymn
358 1.1 blymn result : returns
359 1.1 blymn | var
360 1.1 blymn | reference
361 1.1 blymn ;
362 1.1 blymn
363 1.1 blymn returns : numeric { assign_rets(ret_number, $1); }
364 1.1 blymn | LHB expr RHB { assign_rets(ret_number, $<string>2); }
365 1.1 blymn | STRING { assign_rets(ret_string, $1); }
366 1.1 blymn | BYTE { assign_rets(ret_byte, (void *) $1); }
367 1.1 blymn | ERR_RET { assign_rets(ret_err, NULL); }
368 1.1 blymn | OK_RET { assign_rets(ret_ok, NULL); }
369 1.1 blymn | NULL_RET { assign_rets(ret_null, NULL); }
370 1.1 blymn | NON_NULL { assign_rets(ret_nonnull, NULL); }
371 1.1 blymn ;
372 1.1 blymn
373 1.1 blymn var : VARNAME {
374 1.1 blymn assign_rets(ret_var, $1);
375 1.1 blymn }
376 1.1 blymn ;
377 1.1 blymn
378 1.1 blymn reference : VARIABLE {
379 1.1 blymn assign_rets(ret_ref, $1);
380 1.1 blymn }
381 1.1 blymn
382 1.1 blymn fn_name : VARNAME {
383 1.1 blymn if (command.function != NULL)
384 1.1 blymn free(command.function);
385 1.1 blymn
386 1.1 blymn command.function = malloc(strlen($1) + 1);
387 1.1 blymn if (command.function == NULL)
388 1.1 blymn err(1, "Could not allocate memory for function name");
389 1.1 blymn strcpy(command.function, $1);
390 1.1 blymn }
391 1.1 blymn ;
392 1.1 blymn
393 1.1 blymn expr : numeric
394 1.1 blymn | VARIABLE
395 1.1 blymn { $<string>$ = get_numeric_var($1); }
396 1.1 blymn | expr OR expr
397 1.1 blymn { $<string>$ = numeric_or($<string>1, $<string>3); }
398 1.1 blymn ;
399 1.1 blymn
400 1.1 blymn args : /* empty */
401 1.1 blymn | LHB expr RHB { assign_arg(arg_static, $<string>2); } args
402 1.1 blymn | numeric { assign_arg(arg_static, $1); } args
403 1.1 blymn | STRING { assign_arg(arg_static, $1); } args
404 1.1 blymn | BYTE { assign_arg(arg_byte, $1); } args
405 1.1 blymn | PATH { assign_arg(arg_static, $1); } args
406 1.1 blymn | FILENAME { assign_arg(arg_static, $1); } args
407 1.1 blymn | VARNAME { assign_arg(arg_static, $1); } args
408 1.1 blymn | VARIABLE { assign_arg(arg_var, $1); } args
409 1.2 blymn | NULL_RET { assign_arg(arg_null, $1); } args
410 1.1 blymn ;
411 1.1 blymn
412 1.1 blymn eol : EOL
413 1.1 blymn ;
414 1.1 blymn
415 1.1 blymn %%
416 1.1 blymn
417 1.3.2.1 cherry static void
418 1.3.2.1 cherry excess(const char *fname, size_t lineno, const char *func, const char *comment,
419 1.3.2.1 cherry const void *data, size_t datalen)
420 1.3.2.1 cherry {
421 1.3.2.1 cherry size_t dstlen = datalen * 4 + 1;
422 1.3.2.1 cherry char *dst = malloc(dstlen);
423 1.3.2.1 cherry
424 1.3.2.1 cherry if (dst == NULL)
425 1.3.2.1 cherry err(1, "malloc");
426 1.3.2.1 cherry
427 1.3.2.1 cherry if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
428 1.3.2.1 cherry err(1, "strnvisx");
429 1.3.2.1 cherry
430 1.3.2.1 cherry warnx("%s, %zu: [%s] Excess %zu bytes%s [%s]",
431 1.3.2.1 cherry fname, lineno, func, datalen, comment, dst);
432 1.3.2.1 cherry free(dst);
433 1.3.2.1 cherry }
434 1.3.2.1 cherry
435 1.1 blymn /*
436 1.1 blymn * Get the value of a variable, error if the variable has not been set or
437 1.1 blymn * is not a numeric type.
438 1.1 blymn */
439 1.1 blymn static char *
440 1.3.2.1 cherry get_numeric_var(const char *var)
441 1.1 blymn {
442 1.3.2.1 cherry int i;
443 1.1 blymn
444 1.3.2.1 cherry if ((i = find_var_index(var)) < 0)
445 1.1 blymn err(1, "Variable %s is undefined", var);
446 1.1 blymn
447 1.3.2.1 cherry if (vars[i].type != ret_number)
448 1.3.2.1 cherry err(1, "Variable %s is not a numeric type", var);
449 1.1 blymn
450 1.3.2.1 cherry return vars[i].value;
451 1.1 blymn }
452 1.1 blymn
453 1.1 blymn /*
454 1.1 blymn * Perform a bitwise OR on two numbers and return the result.
455 1.1 blymn */
456 1.1 blymn static char *
457 1.1 blymn numeric_or(char *n1, char *n2)
458 1.1 blymn {
459 1.1 blymn unsigned long i1, i2, result;
460 1.1 blymn char *ret;
461 1.1 blymn
462 1.1 blymn i1 = strtoul(n1, NULL, 10);
463 1.1 blymn i2 = strtoul(n2, NULL, 10);
464 1.1 blymn
465 1.1 blymn result = i1 | i2;
466 1.1 blymn asprintf(&ret, "%lu", result);
467 1.1 blymn
468 1.1 blymn if (verbose)
469 1.3.2.1 cherry fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
470 1.3.2.1 cherry " results in 0x%lx (%s)\n",
471 1.3.2.1 cherry i1, n1, i2, n2, result, ret);
472 1.1 blymn
473 1.1 blymn return ret;
474 1.1 blymn }
475 1.1 blymn
476 1.1 blymn /*
477 1.1 blymn * Assign the value given to the named variable.
478 1.1 blymn */
479 1.1 blymn static void
480 1.1 blymn set_var(returns_enum_t type, char *name, void *value)
481 1.1 blymn {
482 1.3.2.1 cherry int i;
483 1.1 blymn char *number;
484 1.1 blymn returns_t *ret;
485 1.1 blymn
486 1.3.2.1 cherry i = find_var_index(name);
487 1.3.2.1 cherry if (i < 0)
488 1.3.2.1 cherry i = assign_var(name);
489 1.1 blymn
490 1.3.2.1 cherry vars[i].type = type;
491 1.1 blymn if ((type == ret_number) || (type == ret_string)) {
492 1.1 blymn number = value;
493 1.3.2.1 cherry vars[i].len = strlen(number) + 1;
494 1.3.2.1 cherry vars[i].value = malloc(vars[i].len + 1);
495 1.3.2.1 cherry if (vars[i].value == NULL)
496 1.1 blymn err(1, "Could not malloc memory for assign string");
497 1.3.2.1 cherry strcpy(vars[i].value, number);
498 1.1 blymn } else {
499 1.1 blymn /* can only be a byte value */
500 1.1 blymn ret = value;
501 1.3.2.1 cherry vars[i].len = ret->return_len;
502 1.3.2.1 cherry vars[i].value = malloc(vars[i].len);
503 1.3.2.1 cherry if (vars[i].value == NULL)
504 1.1 blymn err(1, "Could not malloc memory to assign byte string");
505 1.3.2.1 cherry memcpy(vars[i].value, ret->return_value, vars[i].len);
506 1.1 blymn }
507 1.1 blymn }
508 1.1 blymn
509 1.1 blymn /*
510 1.1 blymn * Add a new variable to the vars array, the value will be assigned later,
511 1.1 blymn * when a test function call returns.
512 1.1 blymn */
513 1.1 blymn static int
514 1.1 blymn assign_var(char *varname)
515 1.1 blymn {
516 1.1 blymn var_t *temp;
517 1.1 blymn char *name;
518 1.1 blymn
519 1.1 blymn if ((name = malloc(strlen(varname) + 1)) == NULL)
520 1.1 blymn err(1, "Alloc of varname failed");
521 1.1 blymn
522 1.1 blymn if ((temp = (var_t *) realloc(vars, sizeof(var_t) * (nvars + 1)))
523 1.1 blymn == NULL) {
524 1.1 blymn free(name);
525 1.1 blymn err(1, "Realloc of vars array failed");
526 1.1 blymn }
527 1.1 blymn
528 1.1 blymn strcpy(name, varname);
529 1.1 blymn vars = temp;
530 1.1 blymn vars[nvars].name = name;
531 1.1 blymn vars[nvars].len = 0;
532 1.1 blymn vars[nvars].value = NULL;
533 1.1 blymn nvars++;
534 1.1 blymn
535 1.1 blymn return (nvars - 1);
536 1.1 blymn }
537 1.1 blymn
538 1.1 blymn /*
539 1.1 blymn * Allocate and assign a new argument of the given type.
540 1.1 blymn */
541 1.1 blymn static void
542 1.1 blymn assign_arg(args_state_t arg_type, void *arg)
543 1.1 blymn {
544 1.1 blymn args_t *temp, cur;
545 1.3.2.1 cherry char *str = arg;
546 1.1 blymn returns_t *ret;
547 1.1 blymn
548 1.1 blymn if (verbose)
549 1.1 blymn printf("function is >%s<, adding arg >%s< type %s\n",
550 1.3.2.1 cherry command.function, str, args_enum_names[arg_type]);
551 1.1 blymn
552 1.1 blymn cur.arg_type = arg_type;
553 1.2 blymn switch (arg_type) {
554 1.2 blymn case arg_var:
555 1.1 blymn cur.var_index = find_var_index(arg);
556 1.1 blymn if (cur.var_index < 0)
557 1.3.2.1 cherry err(1, "Invalid variable %s at line %zu of file %s",
558 1.3.2.1 cherry str, line, cur_file);
559 1.1 blymn cur.arg_type = ret_string;
560 1.2 blymn break;
561 1.2 blymn
562 1.2 blymn case arg_byte:
563 1.2 blymn ret = arg;
564 1.2 blymn cur.arg_len = ret->return_len;
565 1.2 blymn cur.arg_string = malloc(cur.arg_len);
566 1.2 blymn if (cur.arg_string == NULL)
567 1.2 blymn err(1, "Could not malloc memory for arg bytes");
568 1.2 blymn memcpy(cur.arg_string, ret->return_value, cur.arg_len);
569 1.2 blymn break;
570 1.2 blymn
571 1.2 blymn case arg_null:
572 1.2 blymn cur.arg_len = 0;
573 1.2 blymn cur.arg_string = NULL;
574 1.2 blymn break;
575 1.2 blymn
576 1.2 blymn default:
577 1.2 blymn cur.arg_len = strlen(str);
578 1.2 blymn cur.arg_string = malloc(cur.arg_len + 1);
579 1.2 blymn if (cur.arg_string == NULL)
580 1.2 blymn err(1, "Could not malloc memory for arg string");
581 1.2 blymn strcpy(cur.arg_string, arg);
582 1.1 blymn }
583 1.1 blymn
584 1.1 blymn temp = realloc(command.args, sizeof(args_t) * (command.nargs + 1));
585 1.1 blymn if (temp == NULL)
586 1.1 blymn err(1, "Failed to reallocate args");
587 1.1 blymn command.args = temp;
588 1.1 blymn memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
589 1.1 blymn command.nargs++;
590 1.1 blymn }
591 1.1 blymn
592 1.1 blymn /*
593 1.1 blymn * Allocate and assign a new return.
594 1.1 blymn */
595 1.1 blymn static void
596 1.1 blymn assign_rets(returns_enum_t ret_type, void *ret)
597 1.1 blymn {
598 1.1 blymn returns_t *temp, cur;
599 1.1 blymn char *ret_str;
600 1.1 blymn returns_t *ret_ret;
601 1.1 blymn
602 1.1 blymn cur.return_type = ret_type;
603 1.1 blymn if (ret_type != ret_var) {
604 1.1 blymn if ((ret_type == ret_number) || (ret_type == ret_string)) {
605 1.1 blymn ret_str = ret;
606 1.1 blymn cur.return_len = strlen(ret_str) + 1;
607 1.1 blymn cur.return_value = malloc(cur.return_len + 1);
608 1.1 blymn if (cur.return_value == NULL)
609 1.1 blymn err(1,
610 1.1 blymn "Could not malloc memory for arg string");
611 1.1 blymn strcpy(cur.return_value, ret_str);
612 1.1 blymn } else if (ret_type == ret_byte) {
613 1.1 blymn ret_ret = ret;
614 1.1 blymn cur.return_len = ret_ret->return_len;
615 1.1 blymn cur.return_value = malloc(cur.return_len);
616 1.1 blymn if (cur.return_value == NULL)
617 1.1 blymn err(1,
618 1.1 blymn "Could not malloc memory for byte string");
619 1.1 blymn memcpy(cur.return_value, ret_ret->return_value,
620 1.1 blymn cur.return_len);
621 1.1 blymn } else if (ret_type == ret_ref) {
622 1.1 blymn if ((cur.return_index = find_var_index(ret)) < 0)
623 1.1 blymn err(1, "Undefined variable reference");
624 1.1 blymn }
625 1.1 blymn } else {
626 1.1 blymn cur.return_index = find_var_index(ret);
627 1.1 blymn if (cur.return_index < 0)
628 1.1 blymn cur.return_index = assign_var(ret);
629 1.1 blymn }
630 1.1 blymn
631 1.1 blymn temp = realloc(command.returns,
632 1.1 blymn sizeof(returns_t) * (command.nrets + 1));
633 1.1 blymn if (temp == NULL)
634 1.1 blymn err(1, "Failed to reallocate returns");
635 1.1 blymn command.returns = temp;
636 1.1 blymn memcpy(&command.returns[command.nrets], &cur, sizeof(returns_t));
637 1.1 blymn command.nrets++;
638 1.1 blymn }
639 1.1 blymn
640 1.1 blymn /*
641 1.3.2.1 cherry * Find the given variable name in the var array and return the i
642 1.1 blymn * return -1 if var is not found.
643 1.1 blymn */
644 1.1 blymn static int
645 1.3.2.1 cherry find_var_index(const char *var_name)
646 1.1 blymn {
647 1.3.2.1 cherry int result;
648 1.3.2.1 cherry size_t i;
649 1.1 blymn
650 1.1 blymn result = -1;
651 1.1 blymn
652 1.1 blymn for (i = 0; i < nvars; i++) {
653 1.1 blymn if (strcmp(var_name, vars[i].name) == 0) {
654 1.1 blymn result = i;
655 1.1 blymn break;
656 1.1 blymn }
657 1.1 blymn }
658 1.1 blymn
659 1.1 blymn return result;
660 1.1 blymn }
661 1.1 blymn
662 1.1 blymn /*
663 1.1 blymn * Check the given function name in the given table of names, return 1 if
664 1.1 blymn * there is a match.
665 1.1 blymn */
666 1.1 blymn static int check_function_table(char *function, const char *table[],
667 1.1 blymn int nfunctions)
668 1.1 blymn {
669 1.1 blymn int i;
670 1.1 blymn
671 1.1 blymn for (i = 0; i < nfunctions; i++) {
672 1.1 blymn if ((strlen(function) == strlen(table[i])) &&
673 1.1 blymn (strcmp(function, table[i]) == 0))
674 1.1 blymn return 1;
675 1.1 blymn }
676 1.1 blymn
677 1.1 blymn return 0;
678 1.1 blymn }
679 1.1 blymn
680 1.1 blymn /*
681 1.1 blymn * Compare the output from the slave against the given file and report
682 1.1 blymn * any differences.
683 1.1 blymn */
684 1.1 blymn static void
685 1.1 blymn compare_streams(char *filename, bool discard)
686 1.1 blymn {
687 1.3.2.1 cherry char check_file[PATH_MAX], drain[100], ref, data;
688 1.1 blymn struct pollfd fds[2];
689 1.3.2.1 cherry int nfd, check_fd;
690 1.3.2.1 cherry ssize_t result;
691 1.1 blymn
692 1.1 blymn /*
693 1.1 blymn * Don't prepend check path iff check file has an absolute
694 1.1 blymn * path.
695 1.1 blymn */
696 1.1 blymn if (filename[0] != '/') {
697 1.1 blymn if (strlcpy(check_file, check_path, sizeof(check_file))
698 1.1 blymn >= sizeof(check_file))
699 1.1 blymn err(2, "CHECK_PATH too long");
700 1.1 blymn
701 1.1 blymn if (strlcat(check_file, "/", sizeof(check_file))
702 1.1 blymn >= sizeof(check_file))
703 1.1 blymn err(2, "Could not append / to check file path");
704 1.1 blymn } else {
705 1.1 blymn check_file[0] = '\0';
706 1.1 blymn }
707 1.1 blymn
708 1.1 blymn if (strlcat(check_file, filename, sizeof(check_file))
709 1.1 blymn >= sizeof(check_file))
710 1.1 blymn err(2, "Path to check file path overflowed");
711 1.1 blymn
712 1.1 blymn if ((check_fd = open(check_file, O_RDONLY, 0)) < 0)
713 1.3.2.1 cherry err(2, "failed to open file %s line %zu of file %s",
714 1.1 blymn check_file, line, cur_file);
715 1.1 blymn
716 1.1 blymn fds[0].fd = check_fd;
717 1.1 blymn fds[0].events = POLLIN;
718 1.1 blymn fds[0].revents = 0;
719 1.1 blymn fds[1].fd = master;
720 1.1 blymn fds[1].events = POLLIN;
721 1.1 blymn fds[1].revents = 0;
722 1.1 blymn
723 1.1 blymn nfd = 2;
724 1.1 blymn /*
725 1.1 blymn * if we have saved output then only check for data in the
726 1.1 blymn * reference file since the slave data may already be drained.
727 1.1 blymn */
728 1.1 blymn if (saved_output.count > 0)
729 1.1 blymn nfd = 1;
730 1.1 blymn
731 1.1 blymn while (poll(&fds[0], nfd, 500) == nfd) {
732 1.1 blymn if ((result = read(check_fd, &ref, 1)) < 1) {
733 1.1 blymn if (result != 0) {
734 1.3.2.1 cherry err(2, "Bad read on file %s", check_file);
735 1.1 blymn } else {
736 1.1 blymn break;
737 1.1 blymn }
738 1.1 blymn }
739 1.1 blymn
740 1.1 blymn if (saved_output.count > 0) {
741 1.1 blymn data = saved_output.data[saved_output.readp];
742 1.1 blymn saved_output.count--;
743 1.1 blymn saved_output.readp++;
744 1.1 blymn /* run out of saved data, switch to file */
745 1.1 blymn if (saved_output.count == 0)
746 1.1 blymn nfd = 2;
747 1.1 blymn } else {
748 1.1 blymn if (read(master, &data, 1) < 1)
749 1.1 blymn err(2, "Bad read on slave pty");
750 1.1 blymn }
751 1.1 blymn
752 1.1 blymn if (verbose) {
753 1.1 blymn fprintf(stderr, "Comparing reference byte 0x%x (%c)"
754 1.1 blymn " against slave byte 0x%x (%c)\n", ref,
755 1.1 blymn (ref >= ' ')? ref : '-',
756 1.1 blymn data, (data >= ' ')? data : '-');
757 1.1 blymn }
758 1.1 blymn
759 1.1 blymn if (ref != data) {
760 1.3.2.1 cherry warnx("%s, %zu: refresh data from slave does "
761 1.3.2.1 cherry "not match expected from file %s",
762 1.3.2.1 cherry cur_file, line, check_file);
763 1.1 blymn
764 1.1 blymn if (!verbose)
765 1.1 blymn exit(2);
766 1.1 blymn }
767 1.1 blymn
768 1.1 blymn fds[0].revents = 0;
769 1.1 blymn fds[1].revents = 0;
770 1.1 blymn }
771 1.1 blymn
772 1.1 blymn
773 1.1 blymn if (saved_output.count > 0)
774 1.3.2.1 cherry excess(cur_file, line, __func__, " from slave",
775 1.3.2.1 cherry &saved_output.data[saved_output.readp], saved_output.count);
776 1.1 blymn
777 1.1 blymn /* discard any excess saved output if required */
778 1.1 blymn if (discard) {
779 1.1 blymn saved_output.count = 0;
780 1.1 blymn saved_output.readp = 0;
781 1.1 blymn }
782 1.1 blymn
783 1.1 blymn fds[0].revents = 0;
784 1.1 blymn fds[1].revents = 0;
785 1.1 blymn if ((result = poll(&fds[0], 2, 0)) != 0) {
786 1.1 blymn if (result == -1)
787 1.1 blymn err(2, "poll of file descriptors failed");
788 1.1 blymn
789 1.3.2.1 cherry if ((fds[1].revents & POLLIN) == POLLIN) {
790 1.1 blymn save_slave_output(true);
791 1.1 blymn } else {
792 1.1 blymn /*
793 1.1 blymn * handle excess in file if it exists. Poll
794 1.1 blymn * says there is data until EOF is read.
795 1.1 blymn * Check next read is EOF, if it is not then
796 1.1 blymn * the file really has more data than the
797 1.1 blymn * slave produced so flag this as a warning.
798 1.1 blymn */
799 1.3.2.1 cherry result = read(check_fd, drain, sizeof(drain));
800 1.1 blymn if (result == -1)
801 1.3 christos err(1, "read of data file failed");
802 1.1 blymn
803 1.1 blymn if (result > 0) {
804 1.3.2.1 cherry excess(check_file, 0, __func__, "", drain,
805 1.3.2.1 cherry result);
806 1.1 blymn if (!verbose)
807 1.1 blymn exit(2);
808 1.1 blymn }
809 1.1 blymn }
810 1.1 blymn }
811 1.1 blymn
812 1.1 blymn close(check_fd);
813 1.1 blymn }
814 1.1 blymn
815 1.1 blymn /*
816 1.1 blymn * Pass a function call and arguments to the slave and wait for the
817 1.1 blymn * results. The variable nresults determines how many returns we expect
818 1.1 blymn * back from the slave. These results will be validated against the
819 1.1 blymn * expected returns or assigned to variables.
820 1.1 blymn */
821 1.1 blymn static void
822 1.3.2.1 cherry do_function_call(size_t nresults)
823 1.1 blymn {
824 1.1 blymn #define MAX_RESULTS 4
825 1.1 blymn char *p;
826 1.3.2.1 cherry int do_input;
827 1.3.2.1 cherry size_t i;
828 1.1 blymn struct pollfd fds[3];
829 1.1 blymn returns_t response[MAX_RESULTS], returns_count;
830 1.1 blymn
831 1.1 blymn assert(nresults <= MAX_RESULTS);
832 1.1 blymn
833 1.1 blymn do_input = check_function_table(command.function, input_functions,
834 1.3.2.1 cherry ninput_functions);
835 1.1 blymn
836 1.1 blymn write_func_and_args();
837 1.1 blymn
838 1.1 blymn /*
839 1.1 blymn * We should get the number of returns back here, grab it before
840 1.1 blymn * doing input otherwise it will confuse the input poll
841 1.1 blymn */
842 1.1 blymn read_cmd_pipe(&returns_count);
843 1.3.2.1 cherry if (returns_count.return_type != ret_count)
844 1.1 blymn err(2, "expected return type of ret_count but received %s",
845 1.1 blymn returns_enum_names[returns_count.return_type]);
846 1.1 blymn
847 1.1 blymn if (verbose)
848 1.3.2.1 cherry fprintf(stderr, "Expect %zu results from slave, slave "
849 1.3.2.1 cherry "reported %zu\n", nresults, returns_count.return_len);
850 1.1 blymn
851 1.1 blymn if ((no_input == false) && (do_input == 1)) {
852 1.1 blymn if (verbose)
853 1.1 blymn fprintf(stderr, "doing input with inputstr >%s<\n",
854 1.1 blymn input_str);
855 1.1 blymn
856 1.3.2.1 cherry if (input_str == NULL)
857 1.3.2.1 cherry errx(2, "%s, %zu: Call to input function "
858 1.3.2.1 cherry "but no input defined", cur_file, line);
859 1.1 blymn
860 1.1 blymn fds[0].fd = slvpipe[READ_PIPE];
861 1.1 blymn fds[0].events = POLLIN;
862 1.1 blymn p = input_str;
863 1.1 blymn save_slave_output(false);
864 1.1 blymn while(*p != '\0') {
865 1.1 blymn if (verbose) {
866 1.1 blymn fprintf(stderr, "Writing char >%c< to slave\n",
867 1.1 blymn *p);
868 1.1 blymn fflush(stderr);
869 1.1 blymn }
870 1.1 blymn
871 1.1 blymn nanosleep(&delay_spec, NULL);
872 1.1 blymn
873 1.1 blymn write(master, p, 1);
874 1.1 blymn save_slave_output(false);
875 1.1 blymn
876 1.1 blymn p++;
877 1.1 blymn fds[0].revents = 0;
878 1.1 blymn
879 1.1 blymn /* check for slave function returning unexpectedly */
880 1.1 blymn if ((poll(&fds[0], 1, 10) > 0) && (*p != '\0')) {
881 1.3.2.1 cherry warnx("%s, %zu: Slave function "
882 1.3.2.1 cherry "returned before end of input string",
883 1.3.2.1 cherry cur_file, line);
884 1.1 blymn break;
885 1.1 blymn }
886 1.1 blymn }
887 1.1 blymn
888 1.1 blymn if (verbose) {
889 1.1 blymn fprintf(stderr, "Input done.\n");
890 1.1 blymn }
891 1.1 blymn
892 1.1 blymn /* done with the input string, free the resources */
893 1.1 blymn free(input_str);
894 1.1 blymn input_str = NULL;
895 1.1 blymn }
896 1.1 blymn
897 1.1 blymn if (verbose) {
898 1.1 blymn fds[0].fd = slvpipe[READ_PIPE];
899 1.1 blymn fds[0].events = POLLIN;
900 1.1 blymn fds[0].revents = 0;
901 1.1 blymn
902 1.1 blymn fds[1].fd = slvpipe[WRITE_PIPE];
903 1.1 blymn fds[1].events = POLLOUT;
904 1.1 blymn fds[1].revents = 0;
905 1.1 blymn
906 1.1 blymn fds[2].fd = master;
907 1.1 blymn fds[2].events = POLLIN | POLLOUT;
908 1.1 blymn fds[2].revents = 0;
909 1.1 blymn
910 1.1 blymn i = poll(&fds[0], 3, 1000);
911 1.3.2.1 cherry fprintf(stderr, "Poll returned %zu\n", i);
912 1.1 blymn for (i = 0; i < 3; i++) {
913 1.3.2.1 cherry fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
914 1.1 blymn i, fds[i].revents);
915 1.1 blymn }
916 1.1 blymn }
917 1.1 blymn
918 1.1 blymn /* drain any trailing output */
919 1.1 blymn save_slave_output(false);
920 1.1 blymn
921 1.1 blymn for (i = 0; i < returns_count.return_len; i++) {
922 1.1 blymn read_cmd_pipe(&response[i]);
923 1.1 blymn }
924 1.1 blymn
925 1.1 blymn /*
926 1.1 blymn * Check for a slave error in the first return slot, if the
927 1.1 blymn * slave errored then we may not have the number of returns we
928 1.1 blymn * expect but in this case we should report the slave error
929 1.1 blymn * instead of a return count mismatch.
930 1.1 blymn */
931 1.1 blymn if ((returns_count.return_len > 0) &&
932 1.1 blymn (response[0].return_type == ret_slave_error))
933 1.3.2.1 cherry err(2, "Slave returned error: %s",
934 1.3.2.1 cherry (const char *)response[0].return_value);
935 1.1 blymn
936 1.1 blymn if (returns_count.return_len != nresults)
937 1.3.2.1 cherry err(2, "Incorrect number of returns from slave, expected %zu "
938 1.3.2.1 cherry "but received %zu", nresults, returns_count.return_len);
939 1.1 blymn
940 1.1 blymn if (verbose) {
941 1.1 blymn for (i = 0; i < nresults; i++) {
942 1.1 blymn if ((response[i].return_type != ret_byte) &&
943 1.1 blymn (response[i].return_type != ret_err) &&
944 1.1 blymn (response[i].return_type != ret_ok))
945 1.1 blymn fprintf(stderr,
946 1.1 blymn "received response >%s< "
947 1.3.2.1 cherry "expected",
948 1.3.2.1 cherry (const char *)response[i].return_value);
949 1.1 blymn else
950 1.1 blymn fprintf(stderr, "received");
951 1.1 blymn
952 1.1 blymn fprintf(stderr, " return_type %s\n",
953 1.3.2.1 cherry returns_enum_names[command.returns[i].return_type]);
954 1.1 blymn }
955 1.1 blymn }
956 1.1 blymn
957 1.1 blymn for (i = 0; i < nresults; i++) {
958 1.1 blymn if (command.returns[i].return_type != ret_var) {
959 1.1 blymn validate(i, &response[i]);
960 1.1 blymn } else {
961 1.1 blymn vars[command.returns[i].return_index].len =
962 1.1 blymn response[i].return_len;
963 1.1 blymn vars[command.returns[i].return_index].value =
964 1.1 blymn response[i].return_value;
965 1.1 blymn vars[command.returns[i].return_index].type =
966 1.1 blymn response[i].return_type;
967 1.1 blymn }
968 1.1 blymn }
969 1.3.2.1 cherry #if 0
970 1.1 blymn if (saved_output.count > 0)
971 1.3.2.1 cherry excess(cur_file, line, __func__, " from slave",
972 1.3.2.1 cherry &saved_output.data[saved_output.readp], saved_output.count);
973 1.3.2.1 cherry #endif
974 1.1 blymn
975 1.1 blymn init_parse_variables(0);
976 1.1 blymn }
977 1.1 blymn
978 1.1 blymn /*
979 1.1 blymn * Write the function and command arguments to the command pipe.
980 1.1 blymn */
981 1.1 blymn static void
982 1.3.2.1 cherry write_func_and_args(void)
983 1.1 blymn {
984 1.1 blymn int i;
985 1.1 blymn
986 1.1 blymn if (verbose)
987 1.1 blymn fprintf(stderr, "calling function >%s<\n", command.function);
988 1.1 blymn
989 1.1 blymn write_cmd_pipe(command.function);
990 1.1 blymn for (i = 0; i < command.nargs; i++) {
991 1.1 blymn if (command.args[i].arg_type == arg_var)
992 1.1 blymn write_cmd_pipe_args(command.args[i].arg_type,
993 1.1 blymn &vars[command.args[i].var_index]);
994 1.1 blymn else
995 1.1 blymn write_cmd_pipe_args(command.args[i].arg_type,
996 1.1 blymn &command.args[i]);
997 1.1 blymn }
998 1.1 blymn
999 1.1 blymn write_cmd_pipe(NULL); /* signal end of arguments */
1000 1.1 blymn }
1001 1.1 blymn
1002 1.1 blymn /*
1003 1.1 blymn * Initialise the command structure - if initial is non-zero then just set
1004 1.1 blymn * everything to sane values otherwise free any memory that was allocated
1005 1.1 blymn * when building the structure.
1006 1.1 blymn */
1007 1.1 blymn void
1008 1.1 blymn init_parse_variables(int initial)
1009 1.1 blymn {
1010 1.1 blymn int i, result;
1011 1.1 blymn struct pollfd slave_pty;
1012 1.1 blymn
1013 1.1 blymn if (initial == 0) {
1014 1.1 blymn free(command.function);
1015 1.1 blymn for (i = 0; i < command.nrets; i++) {
1016 1.1 blymn if (command.returns[i].return_type == ret_number)
1017 1.1 blymn free(command.returns[i].return_value);
1018 1.1 blymn }
1019 1.1 blymn free(command.returns);
1020 1.1 blymn
1021 1.1 blymn for (i = 0; i < command.nargs; i++) {
1022 1.1 blymn if (command.args[i].arg_type != arg_var)
1023 1.1 blymn free(command.args[i].arg_string);
1024 1.1 blymn }
1025 1.1 blymn free(command.args);
1026 1.1 blymn } else {
1027 1.1 blymn line = 0;
1028 1.1 blymn input_delay = 0;
1029 1.1 blymn vars = NULL;
1030 1.1 blymn nvars = 0;
1031 1.1 blymn input_str = NULL;
1032 1.1 blymn saved_output.allocated = 0;
1033 1.1 blymn saved_output.count = 0;
1034 1.1 blymn saved_output.readp = 0;
1035 1.1 blymn saved_output.data = NULL;
1036 1.1 blymn }
1037 1.1 blymn
1038 1.1 blymn no_input = false;
1039 1.1 blymn command.function = NULL;
1040 1.1 blymn command.nargs = 0;
1041 1.1 blymn command.args = NULL;
1042 1.1 blymn command.nrets = 0;
1043 1.1 blymn command.returns = NULL;
1044 1.1 blymn
1045 1.1 blymn /*
1046 1.1 blymn * Check the slave pty for stray output from the slave, at this
1047 1.1 blymn * point we should not see any data as it should have been
1048 1.1 blymn * consumed by the test functions. If we see data then we have
1049 1.1 blymn * either a bug or are not handling an output generating function
1050 1.1 blymn * correctly.
1051 1.1 blymn */
1052 1.1 blymn slave_pty.fd = master;
1053 1.1 blymn slave_pty.events = POLLIN;
1054 1.1 blymn slave_pty.revents = 0;
1055 1.1 blymn result = poll(&slave_pty, 1, 0);
1056 1.1 blymn
1057 1.1 blymn if (result < 0)
1058 1.1 blymn err(2, "Poll of slave pty failed");
1059 1.1 blymn else if (result > 0)
1060 1.3.2.1 cherry warnx("%s, %zu: Unexpected data from slave", cur_file, line);
1061 1.1 blymn }
1062 1.1 blymn
1063 1.1 blymn /*
1064 1.1 blymn * Validate the response against the expected return. The variable
1065 1.3.2.1 cherry * i is the i into the rets array in command.
1066 1.1 blymn */
1067 1.1 blymn static void
1068 1.3.2.1 cherry validate(int i, void *data)
1069 1.1 blymn {
1070 1.1 blymn char *response;
1071 1.1 blymn returns_t *byte_response;
1072 1.1 blymn
1073 1.1 blymn byte_response = data;
1074 1.3.2.1 cherry if ((command.returns[i].return_type != ret_byte) &&
1075 1.3.2.1 cherry (command.returns[i].return_type != ret_err) &&
1076 1.3.2.1 cherry (command.returns[i].return_type != ret_ok))
1077 1.1 blymn response = byte_response->return_value;
1078 1.1 blymn
1079 1.3.2.1 cherry switch (command.returns[i].return_type) {
1080 1.1 blymn case ret_err:
1081 1.1 blymn validate_type(ret_err, byte_response, 0);
1082 1.1 blymn break;
1083 1.1 blymn
1084 1.1 blymn case ret_ok:
1085 1.1 blymn validate_type(ret_ok, byte_response, 0);
1086 1.1 blymn break;
1087 1.1 blymn
1088 1.1 blymn case ret_null:
1089 1.1 blymn validate_return("NULL", response, 0);
1090 1.1 blymn break;
1091 1.1 blymn
1092 1.1 blymn case ret_nonnull:
1093 1.1 blymn validate_return("NULL", response, 1);
1094 1.1 blymn break;
1095 1.1 blymn
1096 1.1 blymn case ret_string:
1097 1.1 blymn case ret_number:
1098 1.3.2.1 cherry validate_return(command.returns[i].return_value,
1099 1.1 blymn response, 0);
1100 1.1 blymn break;
1101 1.1 blymn
1102 1.1 blymn case ret_ref:
1103 1.3.2.1 cherry validate_reference(i, response);
1104 1.1 blymn break;
1105 1.1 blymn
1106 1.1 blymn case ret_byte:
1107 1.3.2.1 cherry validate_byte(&command.returns[i], byte_response, 0);
1108 1.1 blymn break;
1109 1.1 blymn
1110 1.1 blymn default:
1111 1.3.2.1 cherry err(1, "Malformed statement at line %zu of file %s",
1112 1.1 blymn line, cur_file);
1113 1.1 blymn break;
1114 1.1 blymn }
1115 1.1 blymn }
1116 1.1 blymn
1117 1.1 blymn /*
1118 1.1 blymn * Validate the return against the contents of a variable.
1119 1.1 blymn */
1120 1.1 blymn static void
1121 1.3.2.1 cherry validate_reference(int i, void *data)
1122 1.1 blymn {
1123 1.1 blymn char *response;
1124 1.1 blymn returns_t *byte_response;
1125 1.1 blymn var_t *varp;
1126 1.1 blymn
1127 1.3.2.1 cherry varp = &vars[command.returns[i].return_index];
1128 1.1 blymn
1129 1.1 blymn byte_response = data;
1130 1.3.2.1 cherry if (command.returns[i].return_type != ret_byte)
1131 1.1 blymn response = data;
1132 1.1 blymn
1133 1.1 blymn if (verbose)
1134 1.1 blymn fprintf(stderr,
1135 1.1 blymn "validate_reference: return type of %s, value %s \n",
1136 1.3.2.1 cherry returns_enum_names[varp->type],
1137 1.3.2.1 cherry (const char *)varp->value);
1138 1.1 blymn
1139 1.1 blymn switch (varp->type) {
1140 1.1 blymn case ret_string:
1141 1.1 blymn case ret_number:
1142 1.1 blymn validate_return(varp->value, response, 0);
1143 1.1 blymn break;
1144 1.1 blymn
1145 1.1 blymn case ret_byte:
1146 1.1 blymn validate_byte(varp->value, byte_response, 0);
1147 1.1 blymn break;
1148 1.1 blymn
1149 1.1 blymn default:
1150 1.1 blymn err(1,
1151 1.3.2.1 cherry "Invalid return type for reference at line %zu of file %s",
1152 1.1 blymn line, cur_file);
1153 1.1 blymn break;
1154 1.1 blymn }
1155 1.1 blymn }
1156 1.1 blymn
1157 1.1 blymn /*
1158 1.1 blymn * Validate the return type against the expected type, throw an error
1159 1.1 blymn * if they don't match.
1160 1.1 blymn */
1161 1.1 blymn static void
1162 1.1 blymn validate_type(returns_enum_t expected, returns_t *value, int check)
1163 1.1 blymn {
1164 1.1 blymn if (((check == 0) && (expected != value->return_type)) ||
1165 1.1 blymn ((check == 1) && (expected == value->return_type)))
1166 1.3.2.1 cherry err(1, "Validate expected type %s %s %s line %zu of file %s",
1167 1.1 blymn returns_enum_names[expected],
1168 1.1 blymn (check == 0)? "matching" : "not matching",
1169 1.1 blymn returns_enum_names[value->return_type], line, cur_file);
1170 1.1 blymn
1171 1.1 blymn if (verbose)
1172 1.3.2.1 cherry fprintf(stderr, "Validate expected type %s %s %s line %zu"
1173 1.1 blymn " of file %s\n",
1174 1.1 blymn returns_enum_names[expected],
1175 1.1 blymn (check == 0)? "matching" : "not matching",
1176 1.1 blymn returns_enum_names[value->return_type], line, cur_file);
1177 1.1 blymn }
1178 1.1 blymn
1179 1.1 blymn /*
1180 1.1 blymn * Validate the return value against the expected value, throw an error
1181 1.1 blymn * if they don't match.
1182 1.1 blymn */
1183 1.1 blymn static void
1184 1.3.2.1 cherry validate_return(const char *expected, const char *value, int check)
1185 1.1 blymn {
1186 1.1 blymn if (((check == 0) && strcmp(expected, value) != 0) ||
1187 1.1 blymn ((check == 1) && strcmp(expected, value) == 0))
1188 1.3.2.1 cherry err(1, "Validate expected %s %s %s line %zu of file %s",
1189 1.1 blymn expected,
1190 1.1 blymn (check == 0)? "matching" : "not matching", value,
1191 1.1 blymn line, cur_file);
1192 1.1 blymn if (verbose)
1193 1.1 blymn fprintf(stderr, "Validated expected value %s %s %s "
1194 1.3.2.1 cherry "at line %zu of file %s\n", expected,
1195 1.1 blymn (check == 0)? "matches" : "does not match",
1196 1.1 blymn value, line, cur_file);
1197 1.1 blymn }
1198 1.1 blymn
1199 1.1 blymn /*
1200 1.1 blymn * Validate the return value against the expected value, throw an error
1201 1.1 blymn * if they don't match expectations.
1202 1.1 blymn */
1203 1.1 blymn static void
1204 1.1 blymn validate_byte(returns_t *expected, returns_t *value, int check)
1205 1.1 blymn {
1206 1.1 blymn /*
1207 1.1 blymn * No chance of a match if lengths differ...
1208 1.1 blymn */
1209 1.1 blymn if ((check == 0) && (expected->return_len != value->return_len))
1210 1.1 blymn err(1, "Byte validation failed, length mismatch");
1211 1.1 blymn
1212 1.1 blymn /*
1213 1.1 blymn * If check is 0 then we want to throw an error IFF the byte streams
1214 1.1 blymn * do not match, if check is 1 then throw an error if the byte
1215 1.1 blymn * streams match.
1216 1.1 blymn */
1217 1.1 blymn if (((check == 0) && memcmp(expected->return_value, value->return_value,
1218 1.1 blymn value->return_len) != 0) ||
1219 1.1 blymn ((check == 1) && (expected->return_len == value->return_len) &&
1220 1.1 blymn memcmp(expected->return_value, value->return_value,
1221 1.1 blymn value->return_len) == 0))
1222 1.3.2.1 cherry err(1, "Validate expected %s byte stream at line %zu"
1223 1.1 blymn "of file %s",
1224 1.1 blymn (check == 0)? "matching" : "not matching", line, cur_file);
1225 1.1 blymn if (verbose)
1226 1.1 blymn fprintf(stderr, "Validated expected %s byte stream "
1227 1.3.2.1 cherry "at line %zu of file %s\n",
1228 1.1 blymn (check == 0)? "matching" : "not matching",
1229 1.1 blymn line, cur_file);
1230 1.1 blymn }
1231 1.1 blymn
1232 1.1 blymn /*
1233 1.3.2.1 cherry * Validate the variable at i against the expected value, throw an
1234 1.1 blymn * error if they don't match, if check is non-zero then the match is
1235 1.1 blymn * negated.
1236 1.1 blymn */
1237 1.1 blymn static void
1238 1.3.2.1 cherry validate_variable(int ret, returns_enum_t type, const void *value, int i,
1239 1.3.2.1 cherry int check)
1240 1.1 blymn {
1241 1.1 blymn returns_t *retval;
1242 1.1 blymn var_t *varptr;
1243 1.1 blymn
1244 1.3.2.1 cherry retval = &command.returns[ret];
1245 1.1 blymn varptr = &vars[command.returns[ret].return_index];
1246 1.1 blymn
1247 1.1 blymn if (varptr->value == NULL)
1248 1.3.2.1 cherry err(1, "Variable %s has no value assigned to it", varptr->name);
1249 1.1 blymn
1250 1.1 blymn
1251 1.1 blymn if (varptr->type != type)
1252 1.3.2.1 cherry err(1, "Variable %s is not the expected type", varptr->name);
1253 1.1 blymn
1254 1.1 blymn if (type != ret_byte) {
1255 1.1 blymn if ((((check == 0) && strcmp(value, varptr->value) != 0))
1256 1.1 blymn || ((check == 1) && strcmp(value, varptr->value) == 0))
1257 1.1 blymn err(1, "Variable %s contains %s instead of %s"
1258 1.3.2.1 cherry " value %s at line %zu of file %s",
1259 1.3.2.1 cherry varptr->name, (const char *)varptr->value,
1260 1.3.2.1 cherry (check == 0)? "expected" : "not matching",
1261 1.3.2.1 cherry (const char *)value,
1262 1.1 blymn line, cur_file);
1263 1.1 blymn if (verbose)
1264 1.1 blymn fprintf(stderr, "Variable %s contains %s value "
1265 1.3.2.1 cherry "%s at line %zu of file %s\n",
1266 1.1 blymn varptr->name,
1267 1.1 blymn (check == 0)? "expected" : "not matching",
1268 1.3.2.1 cherry (const char *)varptr->value, line, cur_file);
1269 1.1 blymn } else {
1270 1.1 blymn if ((check == 0) && (retval->return_len != varptr->len))
1271 1.1 blymn err(1, "Byte validation failed, length mismatch");
1272 1.1 blymn
1273 1.1 blymn /*
1274 1.1 blymn * If check is 0 then we want to throw an error IFF
1275 1.1 blymn * the byte streams do not match, if check is 1 then
1276 1.1 blymn * throw an error if the byte streams match.
1277 1.1 blymn */
1278 1.1 blymn if (((check == 0) && memcmp(retval->return_value, varptr->value,
1279 1.1 blymn varptr->len) != 0) ||
1280 1.1 blymn ((check == 1) && (retval->return_len == varptr->len) &&
1281 1.1 blymn memcmp(retval->return_value, varptr->value,
1282 1.1 blymn varptr->len) == 0))
1283 1.3.2.1 cherry err(1, "Validate expected %s byte stream at line %zu"
1284 1.1 blymn " of file %s",
1285 1.1 blymn (check == 0)? "matching" : "not matching",
1286 1.1 blymn line, cur_file);
1287 1.1 blymn if (verbose)
1288 1.1 blymn fprintf(stderr, "Validated expected %s byte stream "
1289 1.3.2.1 cherry "at line %zu of file %s\n",
1290 1.1 blymn (check == 0)? "matching" : "not matching",
1291 1.1 blymn line, cur_file);
1292 1.1 blymn }
1293 1.1 blymn }
1294 1.1 blymn
1295 1.1 blymn /*
1296 1.1 blymn * Write a string to the command pipe - we feed the number of bytes coming
1297 1.1 blymn * down first to allow storage allocation and then follow up with the data.
1298 1.1 blymn * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
1299 1.1 blymn */
1300 1.1 blymn static void
1301 1.1 blymn write_cmd_pipe(char *cmd)
1302 1.1 blymn {
1303 1.1 blymn args_t arg;
1304 1.1 blymn size_t len;
1305 1.1 blymn
1306 1.1 blymn if (cmd == NULL)
1307 1.1 blymn len = 0;
1308 1.1 blymn else
1309 1.1 blymn len = strlen(cmd);
1310 1.1 blymn
1311 1.1 blymn arg.arg_type = arg_static;
1312 1.1 blymn arg.arg_len = len;
1313 1.1 blymn arg.arg_string = cmd;
1314 1.1 blymn write_cmd_pipe_args(arg.arg_type, &arg);
1315 1.1 blymn
1316 1.1 blymn }
1317 1.1 blymn
1318 1.1 blymn static void
1319 1.1 blymn write_cmd_pipe_args(args_state_t type, void *data)
1320 1.1 blymn {
1321 1.1 blymn var_t *var_data;
1322 1.1 blymn args_t *arg_data;
1323 1.1 blymn int len, send_type;
1324 1.1 blymn void *cmd;
1325 1.1 blymn
1326 1.1 blymn arg_data = data;
1327 1.2 blymn switch (type) {
1328 1.2 blymn case arg_var:
1329 1.2 blymn var_data = data;
1330 1.2 blymn len = var_data->len;
1331 1.2 blymn cmd = var_data->value;
1332 1.2 blymn if (var_data->type == arg_byte)
1333 1.2 blymn send_type = ret_byte;
1334 1.2 blymn else
1335 1.2 blymn send_type = ret_string;
1336 1.2 blymn break;
1337 1.2 blymn
1338 1.2 blymn case arg_null:
1339 1.2 blymn send_type = ret_null;
1340 1.2 blymn len = 0;
1341 1.2 blymn break;
1342 1.2 blymn
1343 1.2 blymn default:
1344 1.1 blymn if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
1345 1.1 blymn len = -1;
1346 1.1 blymn else
1347 1.1 blymn len = arg_data->arg_len;
1348 1.1 blymn cmd = arg_data->arg_string;
1349 1.1 blymn if (type == arg_byte)
1350 1.1 blymn send_type = ret_byte;
1351 1.1 blymn else
1352 1.1 blymn send_type = ret_string;
1353 1.1 blymn }
1354 1.1 blymn
1355 1.1 blymn if (verbose)
1356 1.1 blymn fprintf(stderr, "Writing type %s to command pipe\n",
1357 1.1 blymn returns_enum_names[send_type]);
1358 1.1 blymn
1359 1.3.2.1 cherry if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0)
1360 1.3.2.1 cherry err(1, "command pipe write for type failed");
1361 1.1 blymn
1362 1.1 blymn if (verbose)
1363 1.1 blymn fprintf(stderr, "Writing length %d to command pipe\n", len);
1364 1.1 blymn
1365 1.3.2.1 cherry if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0)
1366 1.3.2.1 cherry err(1, "command pipe write for length failed");
1367 1.1 blymn
1368 1.1 blymn if (len > 0) {
1369 1.1 blymn if (verbose)
1370 1.1 blymn fprintf(stderr, "Writing data >%s< to command pipe\n",
1371 1.3.2.1 cherry (const char *)cmd);
1372 1.3.2.1 cherry if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0)
1373 1.3.2.1 cherry err(1, "command pipe write of data failed");
1374 1.1 blymn }
1375 1.1 blymn }
1376 1.1 blymn
1377 1.1 blymn /*
1378 1.1 blymn * Read a response from the command pipe, first we will receive the
1379 1.1 blymn * length of the response then the actual data.
1380 1.1 blymn */
1381 1.1 blymn static void
1382 1.1 blymn read_cmd_pipe(returns_t *response)
1383 1.1 blymn {
1384 1.1 blymn int len, type;
1385 1.3.2.1 cherry struct pollfd rfd[2];
1386 1.1 blymn char *str;
1387 1.1 blymn
1388 1.1 blymn /*
1389 1.1 blymn * Check if there is data to read - just in case slave has died, we
1390 1.1 blymn * don't want to block on the read and just hang. We also check
1391 1.1 blymn * output from the slave because the slave may be blocked waiting
1392 1.1 blymn * for a flush on its stdout.
1393 1.1 blymn */
1394 1.3.2.1 cherry rfd[0].fd = slvpipe[READ_PIPE];
1395 1.3.2.1 cherry rfd[0].events = POLLIN;
1396 1.3.2.1 cherry rfd[1].fd = master;
1397 1.3.2.1 cherry rfd[1].events = POLLIN;
1398 1.1 blymn
1399 1.1 blymn do {
1400 1.3.2.1 cherry rfd[0].revents = 0;
1401 1.3.2.1 cherry rfd[1].revents = 0;
1402 1.1 blymn
1403 1.3.2.1 cherry if (poll(rfd, 2, 4000) == 0)
1404 1.3.2.1 cherry errx(2, "%s, %zu: Command pipe read timeout",
1405 1.3.2.1 cherry cur_file, line);
1406 1.1 blymn
1407 1.3.2.1 cherry if ((rfd[1].revents & POLLIN) == POLLIN) {
1408 1.1 blymn if (verbose)
1409 1.1 blymn fprintf(stderr,
1410 1.1 blymn "draining output from slave\n");
1411 1.1 blymn save_slave_output(false);
1412 1.1 blymn }
1413 1.1 blymn }
1414 1.3.2.1 cherry while((rfd[1].revents & POLLIN) == POLLIN);
1415 1.1 blymn
1416 1.3.2.1 cherry if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0)
1417 1.3.2.1 cherry err(1, "command pipe read for type failed");
1418 1.1 blymn response->return_type = type;
1419 1.1 blymn
1420 1.1 blymn if ((type != ret_ok) && (type != ret_err) && (type != ret_count)) {
1421 1.3.2.1 cherry if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
1422 1.3.2.1 cherry err(1, "command pipe read for length failed");
1423 1.1 blymn response->return_len = len;
1424 1.1 blymn
1425 1.1 blymn if (verbose)
1426 1.1 blymn fprintf(stderr,
1427 1.1 blymn "Reading %d bytes from command pipe\n", len);
1428 1.1 blymn
1429 1.1 blymn if ((response->return_value = malloc(len + 1)) == NULL)
1430 1.1 blymn err(1, "Failed to alloc memory for cmd pipe read");
1431 1.1 blymn
1432 1.3.2.1 cherry if (read(slvpipe[READ_PIPE], response->return_value, len) < 0)
1433 1.3.2.1 cherry err(1, "command pipe read of data failed");
1434 1.1 blymn
1435 1.1 blymn if (response->return_type != ret_byte) {
1436 1.1 blymn str = response->return_value;
1437 1.1 blymn str[len] = '\0';
1438 1.1 blymn
1439 1.1 blymn if (verbose)
1440 1.1 blymn fprintf(stderr, "Read data >%s< from pipe\n",
1441 1.3.2.1 cherry (const char *)response->return_value);
1442 1.1 blymn }
1443 1.1 blymn } else {
1444 1.1 blymn response->return_value = NULL;
1445 1.1 blymn if (type == ret_count) {
1446 1.3.2.1 cherry if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
1447 1.3.2.1 cherry err(1, "command pipe read for number of "
1448 1.1 blymn "returns failed");
1449 1.1 blymn response->return_len = len;
1450 1.1 blymn }
1451 1.1 blymn
1452 1.1 blymn if (verbose)
1453 1.1 blymn fprintf(stderr, "Read type %s from pipe\n",
1454 1.1 blymn returns_enum_names[type]);
1455 1.1 blymn }
1456 1.1 blymn }
1457 1.1 blymn
1458 1.1 blymn /*
1459 1.1 blymn * Check for writes from the slave on the pty, save the output into a
1460 1.1 blymn * buffer for later checking if discard is false.
1461 1.1 blymn */
1462 1.1 blymn #define MAX_DRAIN 256
1463 1.1 blymn
1464 1.1 blymn static void
1465 1.1 blymn save_slave_output(bool discard)
1466 1.1 blymn {
1467 1.1 blymn struct pollfd fd;
1468 1.1 blymn char *new_data, drain[MAX_DRAIN];
1469 1.1 blymn size_t to_allocate;
1470 1.3.2.1 cherry ssize_t result;
1471 1.3.2.1 cherry size_t i;
1472 1.1 blymn
1473 1.1 blymn fd.fd = master;
1474 1.1 blymn fd.events = POLLIN;
1475 1.1 blymn fd.revents = 0;
1476 1.1 blymn
1477 1.1 blymn result = 0;
1478 1.1 blymn while (1) {
1479 1.1 blymn if (result == -1)
1480 1.1 blymn err(2, "poll of slave pty failed");
1481 1.1 blymn result = MAX_DRAIN;
1482 1.1 blymn if ((result = read(master, &drain, result)) < 0) {
1483 1.1 blymn if (errno == EAGAIN)
1484 1.1 blymn break;
1485 1.1 blymn else
1486 1.1 blymn err(2, "draining slave pty failed");
1487 1.1 blymn }
1488 1.1 blymn
1489 1.1 blymn fd.revents = 0;
1490 1.3.2.1 cherry if (!discard) {
1491 1.3.2.1 cherry if ((size_t)result >
1492 1.1 blymn (saved_output.allocated - saved_output.count)) {
1493 1.1 blymn to_allocate = 1024 * ((result / 1024) + 1);
1494 1.1 blymn
1495 1.1 blymn if ((new_data = realloc(saved_output.data,
1496 1.1 blymn saved_output.allocated + to_allocate))
1497 1.1 blymn == NULL)
1498 1.1 blymn err(2, "Realloc of saved_output failed");
1499 1.1 blymn saved_output.data = new_data;
1500 1.1 blymn saved_output.allocated += to_allocate;
1501 1.1 blymn }
1502 1.1 blymn
1503 1.1 blymn if (verbose) {
1504 1.3.2.1 cherry fprintf(stderr, "count = %zu, "
1505 1.3.2.1 cherry "allocated = %zu\n", saved_output.count,
1506 1.3.2.1 cherry saved_output.allocated);
1507 1.3.2.1 cherry for (i = 0; i < (size_t)result; i++) {
1508 1.1 blymn fprintf(stderr, "Saving slave output "
1509 1.3.2.1 cherry "0x%x (%c)\n", drain[i],
1510 1.3.2.1 cherry (drain[i] >= ' ')? drain[i] : '-');
1511 1.1 blymn }
1512 1.1 blymn }
1513 1.1 blymn
1514 1.1 blymn memcpy(&saved_output.data[saved_output.count], drain,
1515 1.1 blymn result);
1516 1.1 blymn saved_output.count += result;
1517 1.1 blymn
1518 1.1 blymn if (verbose) {
1519 1.3.2.1 cherry fprintf(stderr, "count = %zu, "
1520 1.3.2.1 cherry "allocated = %zu\n", saved_output.count,
1521 1.3.2.1 cherry saved_output.allocated);
1522 1.1 blymn }
1523 1.1 blymn } else {
1524 1.1 blymn if (verbose) {
1525 1.3.2.1 cherry for (i=0; i < (size_t)result; i++) {
1526 1.1 blymn fprintf(stderr, "Discarding slave "
1527 1.3.2.1 cherry "output 0x%x (%c)\n",
1528 1.3.2.1 cherry drain[i],
1529 1.3.2.1 cherry (drain[i] >= ' ')? drain[i] : '-');
1530 1.1 blymn }
1531 1.1 blymn }
1532 1.1 blymn }
1533 1.1 blymn }
1534 1.1 blymn }
1535 1.1 blymn
1536 1.1 blymn static void
1537 1.1 blymn yyerror(const char *msg)
1538 1.1 blymn {
1539 1.1 blymn warnx("%s in line %zu of file %s", msg, line, cur_file);
1540 1.1 blymn }
1541