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