1 /*
2 * Copyright (c) 1995-2009, 2013-2020 Paul Mattes.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the names of Paul Mattes nor the names of his contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * Script interface utility for x3270, c3270, wc3270, s3270 and ws3270.
30 *
31 * Accesses an emulator command stream in one of several different ways:
32 *
33 * - (Unix only) Using the file descriptors defined by the environment
34 * variables X3270OUTPUT (output from the emulator, input to script) and
35 * X3270INPUT (input to the emulator, output from script). These are
36 * automatically passed to child scripts by the Unix emulators' Script()
37 * action.
38 *
39 * - Using a loopback IPv4 socket whose TCP port is defined by the
40 * environment variable X3270PORT. This is automatically passed to child
41 * scripts by the Windows emulators' Script() action.
42 *
43 * - (Unix only) Using the Unix-domain socket /tmp/x3sck.<x3270-pid>. This
44 * socket is created by the Unix emulators' -socket option.
45 *
46 * - Using a loopback IPv4 socket whose TCP port is passed in explicitly.
47 * This port is bound by the emulators by the -scriptport option.
48 */
49
50 #include "globals.h"
51
52 #include <errno.h>
53 #if !defined(_WIN32) /*[*/
54 # include <signal.h>
55 # include <sys/types.h>
56 # include <sys/socket.h>
57 # include <sys/un.h>
58 # include <netinet/in.h>
59 # include <arpa/inet.h>
60 #endif /*]*/
61
62 #if !defined(_WIN32) /*[*/
63 # if defined(HAVE_NCURSESW_NCURSES_H) /*[*/
64 # include <ncursesw/ncurses.h>
65 # elif defined(HAVE_NCURSES_NCURSES_H) /*][*/
66 # include <ncurses/ncurses.h>
67 # elif defined(HAVE_NCURSES_H) /*][*/
68 # include <ncurses.h>
69 # else /*][*/
70 # include <curses.h>
71 # endif /*]*/
72 # if defined(HAVE_NCURSESW_TERM_H) /*[*/
73 # include <ncursesw/term.h>
74 # elif defined(HAVE_NCURSES_TERM_H) /*][*/
75 # include <ncurses/term.h>
76 # elif defined(HAVE_TERM_H) /*][*/
77 # include <term.h>
78 # endif /*]*/
79 # if defined(HAVE_LIBREADLINE) /*[*/
80 # include <readline/readline.h>
81 # if defined(HAVE_READLINE_HISTORY_H) /*[*/
82 # include <readline/history.h>
83 # endif /*]*/
84 # endif /*]*/
85 #endif
86
87 #include "base64.h"
88 #include "s3270_proto.h"
89 #include "w3misc.h"
90
91 #define IBS 4096
92
93 #define NO_STATUS (-1)
94 #define ALL_FIELDS (-2)
95
96 #if defined(_WIN32) /*[*/
97 #define DIRSEP '\\'
98 #define OPTS "H:iI:L:s:St:v"
99 #define FD_ENV_REQUIRED true
100 #else /*][*/
101 #define DIRSEP '/'
102 #define OPTS "H:iI:L:p:Ps:St:v"
103 #define FD_ENV_REQUIRED false
104 #endif /*]*/
105
106 #if !defined(HAVE_TIPARM) /*[*/
107 #define tiparm tparm
108 #endif /*]*/
109
110 typedef enum {
111 ITYPE_DATA, /* data: */
112 ITYPE_INPUT, /* input: */
113 ITYPE_PWINPUT /* pwinput: */
114 } itype_t;
115
116 static char *me;
117 static int verbose = 0;
118 static char *buf;
119 static size_t buf_size = 0;
120
121 static void iterative_io(int pid, unsigned short port);
122 static int single_io(int pid, unsigned short port, socket_t socket, int infd,
123 int outfd, int fn, char *cmd, char **data_ret, char **prompt_ret,
124 itype_t *itype);
125 static void interactive_io(int port, const char *emulator_name,
126 const char *help_name, const char *localization);
127
128 #if defined(HAVE_LIBREADLINE) /*[*/
129 static char **attempted_completion();
130 static char *completion_entry(const char *, int);
131 #endif /*]*/
132
133 /* Localization data. */
134 typedef struct i18n {
135 struct i18n *next;
136 char *key;
137 char *translation;
138 } i18n_t;
139 i18n_t *i18n = NULL;
140 #define BANNER "x3270if.banner"
141 #define QUIT "x3270if.quit"
142
143 static void
x3270if_usage(void)144 x3270if_usage(void)
145 {
146 fprintf(stderr, "\
147 usage:\n\
148 %s [options] \"action[(param[,...])]\"\n\
149 execute the named action\n\
150 %s [options] -s field\n\
151 display status field 0..12\n\
152 %s [options] -S\n\
153 display all status fields\n\
154 %s [options] -i\n\
155 shuttle commands and responses between stdin/stdout and emulator\n\
156 %s [options] -I <emulator-name> [-H <help-action-name>]\n\
157 interactive command window\n\
158 %s --version\n\
159 options:\n\
160 -v verbose operation\n"
161 #if !defined(_WIN32) /*[*/
162 " -p pid connect to process <pid>\n"
163 #endif /*]*/
164 " -t port connect to TCP port <port>\n",
165 me, me, me, me, me, me);
166 exit(__LINE__);
167 }
168
169 /* Get a file descriptor from the environment. */
170 static int
fd_env(const char * name,bool required)171 fd_env(const char *name, bool required)
172 {
173 char *fdname;
174 int fd;
175
176 fdname = getenv(name);
177 if (fdname == NULL) {
178 if (required) {
179 fprintf(stderr, "%s: %s not set in the environment\n", me,
180 name);
181 exit(__LINE__);
182 } else {
183 return -1;
184 }
185 }
186 fd = atoi(fdname);
187 if (fd <= 0) {
188 fprintf(stderr, "%s: invalid value '%s' for %s\n", me, fdname,
189 name);
190 exit(__LINE__);
191 }
192 if (verbose) {
193 fprintf(stderr, "%s is %d\n", name, fd);
194 }
195 return fd;
196 }
197
198 int
main(int argc,char * argv[])199 main(int argc, char *argv[])
200 {
201 int c;
202 int fn = NO_STATUS;
203 char *ptr;
204 int iterative = 0;
205 int pid = 0;
206 unsigned short port = 0;
207 const char *emulator_name = NULL;
208 const char *help_name = NULL;
209 const char *localization = NULL;
210 #if !defined(_WIN32) /*[*/
211 bool force_pipes = false;
212 #endif /*]*/
213
214 #if defined(_WIN32) /*[*/
215 if (sockstart() < 0) {
216 exit(__LINE__);
217 }
218 #endif /*]*/
219
220 /* Identify yourself. */
221 if ((me = strrchr(argv[0], DIRSEP)) != NULL) {
222 me++;
223 } else {
224 me = argv[0];
225 }
226
227 if (argc > 1 && !strcmp(argv[1], "--version")) {
228 printf("%s\n", build);
229 return 0;
230 }
231
232 /* Parse options. */
233 opterr = 0;
234 while ((c = getopt(argc, argv, OPTS)) != -1) {
235 switch (c) {
236 case 'H':
237 help_name = optarg;
238 break;
239 case 'i':
240 if (fn >= 0) {
241 x3270if_usage();
242 }
243 iterative++;
244 break;
245 case 'I':
246 if (fn > 0) {
247 x3270if_usage();
248 }
249 iterative++;
250 emulator_name = optarg;
251 break;
252 case 'L':
253 localization = optarg;
254 break;
255 #if !defined(_WIN32) /*[*/
256 case 'p':
257 pid = (int)strtoul(optarg, &ptr, 0);
258 if (ptr == optarg || *ptr != '\0' || pid <= 0) {
259 fprintf(stderr, "%s: Invalid process ID: '%s'\n", me, optarg);
260 x3270if_usage();
261 }
262 break;
263 case 'P':
264 force_pipes = true;
265 break;
266 #endif /*]*/
267 case 's':
268 if (fn >= 0 || iterative) {
269 x3270if_usage();
270 }
271 fn = (int)strtol(optarg, &ptr, 0);
272 if (ptr == optarg || *ptr != '\0' || fn < 0) {
273 fprintf(stderr, "%s: Invalid field number: '%s'\n", me, optarg);
274 x3270if_usage();
275 }
276 break;
277 case 'S':
278 if (fn >= 0 || iterative) {
279 x3270if_usage();
280 }
281 fn = ALL_FIELDS;
282 break;
283 case 't':
284 port = (unsigned short)strtoul(optarg, &ptr, 0);
285 if (ptr == optarg || *ptr != '\0' || port <= 0) {
286 fprintf(stderr, "%s: Invalid port: '%s'\n", me, optarg);
287 x3270if_usage();
288 }
289 break;
290 case 'v':
291 verbose++;
292 break;
293 default:
294 x3270if_usage();
295 break;
296 }
297 }
298
299 /* Validate positional arguments. */
300 if (optind == argc) {
301 /* No positional arguments. */
302 if (fn == NO_STATUS && !iterative) {
303 x3270if_usage();
304 }
305 } else {
306 /* Got positional arguments. */
307 if (iterative) {
308 x3270if_usage();
309 }
310 if (argc - optind > 1) {
311 x3270if_usage();
312 }
313 }
314 if (pid && port) {
315 x3270if_usage();
316 }
317 if (help_name != NULL && emulator_name == NULL) {
318 x3270if_usage();
319 }
320
321 #if !defined(_WIN32) /*[*/
322 /* Ignore broken pipes. */
323 signal(SIGPIPE, SIG_IGN);
324 #endif /*]*/
325
326 /* Do the I/O. */
327 if (iterative && emulator_name != NULL) {
328 interactive_io(port, emulator_name, help_name, localization);
329 } else if (iterative) {
330 iterative_io(pid, port);
331 } else {
332 int infd = -1;
333 int outfd = -1;
334
335 #if !defined(_WIN32) /*[*/
336 if (force_pipes) {
337 infd = fd_env(OUTPUT_ENV, true);
338 outfd = fd_env(INPUT_ENV, true);
339 }
340 #endif /*]*/
341 return single_io(pid, port, INVALID_SOCKET, infd, outfd, fn,
342 argv[optind], NULL, NULL, NULL);
343 }
344 return 0;
345 }
346
347 #if !defined(_WIN32) /*[*/
348 /* Connect to a Unix-domain socket. */
349 static socket_t
usock(int pid)350 usock(int pid)
351 {
352 struct sockaddr_un ssun;
353 socket_t fd;
354
355 fd = socket(AF_UNIX, SOCK_STREAM, 0);
356 if (fd == INVALID_SOCKET) {
357 perror("socket");
358 exit(__LINE__);
359 }
360 memset(&ssun, '\0', sizeof(struct sockaddr_un));
361 ssun.sun_family = AF_UNIX;
362 snprintf(ssun.sun_path, sizeof(ssun.sun_path), "/tmp/x3sck.%d", pid);
363 if (connect(fd, (struct sockaddr *)&ssun, sizeof(ssun)) < 0) {
364 perror("connect");
365 exit(__LINE__);
366 }
367 return fd;
368 }
369 #endif /*]*/
370
371 /* Connect to a TCP socket. */
372 static socket_t
tsock(unsigned short port)373 tsock(unsigned short port)
374 {
375 struct sockaddr_in sin;
376 socket_t fd;
377
378 fd = socket(AF_INET, SOCK_STREAM, 0);
379 if (fd == INVALID_SOCKET) {
380 #if defined(_WIN32) /*[*/
381 win32_perror("socket");
382 #else /*][*/
383 perror("socket");
384 #endif /*]*/
385 exit(__LINE__);
386 }
387 memset(&sin, '\0', sizeof(struct sockaddr_in));
388 sin.sin_family = AF_INET;
389 sin.sin_port = htons(port);
390 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
391 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
392 #if defined(_WIN32) /*[*/
393 win32_perror("connect(%u)", port);
394 #else /*][*/
395 perror("connect");
396 #endif /*]*/
397 exit(__LINE__);
398 }
399 return fd;
400 }
401
402 /* Get the input type from a buffer. */
403 static itype_t
get_itype(const char * buf)404 get_itype(const char *buf)
405 {
406 if (!strncmp(buf, DATA_PREFIX, PREFIX_LEN)) {
407 return ITYPE_DATA;
408 }
409 if (!strncmp(buf, INPUT_PREFIX, PREFIX_LEN)) {
410 return ITYPE_INPUT;
411 }
412 if (!strncmp(buf, PWINPUT_PREFIX, PREFIX_LEN)) {
413 return ITYPE_PWINPUT;
414 }
415 return ITYPE_DATA; /* wrong */
416 }
417
418 /* Do a single command, and interpret the results. */
419 static int
single_io(int pid,unsigned short port,socket_t socket,int xinfd,int xoutfd,int fn,char * cmd,char ** data_ret,char ** prompt_ret,itype_t * itype)420 single_io(int pid, unsigned short port, socket_t socket, int xinfd, int xoutfd,
421 int fn, char *cmd, char **data_ret, char **prompt_ret, itype_t *itype)
422 {
423 int port_env;
424 int infd = -1, outfd = -1;
425 socket_t insocket = INVALID_SOCKET, outsocket = INVALID_SOCKET;
426 bool is_socket = false;
427 char *status = NULL;
428 int nr;
429 int xs = -1;
430 int nw = 0;
431 char rbuf[IBS];
432 size_t sl = 0;
433 int done = 0;
434 char *cmd_nl;
435 char *wstr;
436 size_t ret_sl = 0;
437 itype_t input_itype = ITYPE_DATA;
438
439 /* Verify the environment and open files. */
440 if (socket != INVALID_SOCKET) {
441 insocket = socket;
442 outsocket = socket;
443 is_socket = true;
444 } else if (xinfd != -1 && xoutfd != -1) {
445 infd = xinfd;
446 outfd = xoutfd;
447 } else {
448 #if !defined(_WIN32) /*[*/
449 if (pid) {
450 insocket = outsocket = usock(pid);
451 is_socket = true;
452 } else
453 #endif /*]*/
454 if (port) {
455 insocket = outsocket = tsock(port);
456 is_socket = true;
457 } else if ((port_env = fd_env(PORT_ENV, FD_ENV_REQUIRED)) >= 0) {
458 insocket = outsocket = tsock(port_env);
459 is_socket = true;
460 } else {
461 #if defined(_WIN32) /*[*/
462 return -1;
463 #else /*][*/
464 infd = fd_env(OUTPUT_ENV, true);
465 outfd = fd_env(INPUT_ENV, true);
466 #endif /*]*/
467 }
468 if ((!is_socket && infd < 0) || (is_socket && insocket == INVALID_SOCKET)) {
469 perror("x3270if: input");
470 exit(__LINE__);
471 }
472 if ((!is_socket && outfd < 0) ||
473 (is_socket && outsocket == INVALID_SOCKET)) {
474 perror("x3270if: output");
475 exit(__LINE__);
476 }
477 }
478
479 if (prompt_ret != NULL) {
480 *prompt_ret = NULL;
481 }
482 if (itype != NULL) {
483 *itype = ITYPE_DATA;
484 }
485
486 /* Speak to x3270. */
487 if (verbose) {
488 fprintf(stderr, "i+ out %s\n", (cmd != NULL) ? cmd : "");
489 }
490
491 if (cmd != NULL) {
492 cmd_nl = Malloc(strlen(cmd) + 2);
493 sprintf(cmd_nl, "%s\n", cmd);
494 wstr = cmd_nl;
495 } else {
496 cmd_nl = NULL;
497 wstr = "\n";
498 }
499
500 if (is_socket) {
501 nw = send(outsocket, wstr, (int)strlen(wstr), 0);
502 } else {
503 nw = write(outfd, wstr, (int)strlen(wstr));
504 }
505 if (nw < 0) {
506 if (is_socket) {
507 #if defined(_WIN32) /*[*/
508 win32_perror("x3270if: send");
509 #else /*][*/
510 perror("x3270if: send");
511 #endif /*]*/
512 } else {
513 perror("x3270if: write");
514 }
515 exit(__LINE__);
516 }
517 if (cmd_nl != NULL) {
518 Free(cmd_nl);
519 }
520
521 if (data_ret != NULL) {
522 *data_ret = NULL;
523 }
524
525 #if defined(_WIN32) /*[*/
526 retry:
527 #endif /*]*/
528 /* Get the answer. */
529 while (!done &&
530 (nr = (is_socket? recv(insocket, rbuf, IBS, 0):
531 read(infd, rbuf, IBS))) > 0) {
532 int i;
533 bool get_more = false;
534
535 i = 0;
536 do {
537 /* Copy from rbuf into buf until '\n'. */
538 while (i < nr && rbuf[i] != '\n') {
539 if (sl + 2 > buf_size) {
540 buf = Realloc(buf, buf_size + IBS);
541 buf_size += IBS;
542 }
543 buf[sl++] = rbuf[i++];
544 }
545 if (rbuf[i] == '\n') {
546 i++;
547 } else {
548 /* Go get more input. */
549 get_more = true;
550 break;
551 }
552
553 /* Process one line of output. */
554 buf[sl] = '\0';
555
556 if (verbose) {
557 fprintf(stderr, "i+ in %s\n", buf);
558 }
559 if (!strcmp(buf, PROMPT_OK)) {
560 fflush(stdout);
561 xs = 0;
562 done = 1;
563 break;
564 } else if (!strcmp(buf, PROMPT_ERROR)) {
565 fflush(stdout);
566 xs = 1;
567 done = 1;
568 break;
569 } else if (!strncmp(buf, DATA_PREFIX, PREFIX_LEN)
570 || !strncmp(buf, INPUT_PREFIX, PREFIX_LEN)
571 || !strncmp(buf, PWINPUT_PREFIX, PREFIX_LEN)) {
572 /*
573 * The protocol is somewhat ambiguous: You could get multiple
574 * inpt: and inpw: in the same response.
575 * We only keep the last.
576 */
577 if (data_ret != NULL) {
578 itype_t this_itype;
579
580 this_itype = get_itype(buf);
581 if (this_itype == ITYPE_INPUT
582 || this_itype == ITYPE_PWINPUT) {
583 input_itype = this_itype;
584 if (*prompt_ret != NULL) {
585 Free(*prompt_ret);
586 }
587 *prompt_ret = NewString(buf + PREFIX_LEN);
588 } else {
589 *data_ret = Realloc(*data_ret,
590 ret_sl + strlen(buf + PREFIX_LEN) + 2);
591 *(*data_ret + ret_sl) = '\0';
592 strcat(strcat(*data_ret, buf + PREFIX_LEN), "\n");
593 ret_sl += strlen(buf + PREFIX_LEN) + 1;
594 }
595 } else {
596 if (printf("%s\n", buf + PREFIX_LEN) < 0) {
597 perror("x3270if: printf");
598 exit(__LINE__);
599 }
600 }
601 } else {
602 Replace(status, NewString(buf));
603 }
604
605 /* Get ready for the next. */
606 sl = 0;
607 } while (i < nr);
608
609 if (get_more) {
610 get_more = false;
611 continue;
612 }
613 }
614 if (nr < 0) {
615 if (is_socket) {
616 #if defined(_WIN32) /*[*/
617 if (WSAGetLastError() == WSAEWOULDBLOCK) {
618 goto retry;
619 }
620 win32_perror("x3270if: recv");
621 #else /*][*/
622 perror("recv");
623 #endif /*]*/
624 } else {
625 perror("read");
626 }
627 exit(__LINE__);
628 } else if (nr == 0) {
629 fprintf(stderr, "x3270if: unexpected EOF\n");
630 exit(__LINE__);
631 }
632
633 if (fflush(stdout) < 0) {
634 perror("x3270if: fflush");
635 exit(__LINE__);
636 }
637
638 /* Print status, if that's what they want. */
639 if (fn != NO_STATUS) {
640 char *sf = NULL;
641 char *sb = status;
642 int rc;
643
644 if (fn == ALL_FIELDS) {
645 rc = printf("%s\n", status);
646 } else {
647 do {
648 if (!fn--) {
649 break;
650 }
651 sf = strtok(sb, " \t");
652 sb = NULL;
653 } while (sf != NULL);
654 rc = printf("%s\n", (sf != NULL) ? sf : "");
655 }
656 if (rc < 0) {
657 perror("x3270if: printf");
658 exit(__LINE__);
659 }
660 }
661
662 if (fflush(stdout) < 0) {
663 perror("x3270if: fflush");
664 exit(__LINE__);
665 }
666
667 if (is_socket && socket == INVALID_SOCKET) {
668 shutdown(insocket, 2);
669 #if defined(_WIN32) /*[*/
670 closesocket(insocket);
671 #else /*][*/
672 close(insocket);
673 if (verbose) {
674 fprintf(stderr, "closed %d\n", insocket);
675 }
676 #endif /*]*/
677 }
678
679 if (itype != NULL) {
680 *itype = input_itype;
681 }
682
683 Free(status);
684 return xs;
685 }
686
687 /* Fetch the ports from the environment. */
688 static void
get_ports(socket_t * socket,int * infd,int * outfd)689 get_ports(socket_t *socket, int *infd, int *outfd)
690 {
691 #if !defined(_WIN32) /*[*/
692 int socketport = -1;
693
694 if (socket != NULL) {
695 socketport = fd_env(PORT_ENV, false);
696 }
697 if (socketport == -1) {
698 *infd = fd_env(OUTPUT_ENV, true);
699 *outfd = fd_env(INPUT_ENV, true);
700 } else {
701 *socket = tsock(socketport);
702 }
703 if (verbose) {
704 fprintf(stderr, "socket: %d, input: %d, output: %d\n",
705 (socket != NULL)? *socket: -1,
706 *infd, *outfd);
707 }
708 #else /*][*/
709 int socketport = fd_env(PORT_ENV, true);
710
711 *socket = tsock(socketport);
712 if (verbose) {
713 fprintf(stderr, "port: %d\n", socketport);
714 }
715 #endif /*]*/
716 }
717
718 #if !defined(_WIN32) /*[*/
719
720 /* Act as a passive pipe to the emulator. */
721 static void
iterative_io(int pid,unsigned short port)722 iterative_io(int pid, unsigned short port)
723 {
724 # define N_IO 2
725 struct {
726 const char *name;
727 int rfd, wfd;
728 char buf[IBS];
729 int offset, count;
730 } io[N_IO]; /* [0] is script->emulator, [1] is emulator->script */
731 fd_set rfds, wfds;
732 int fd_max = 0;
733 int i;
734 int port_env = -1;
735
736 /* Get the x3270 file descriptors. */
737 io[0].name = "script->emulator";
738 io[0].rfd = fileno(stdin);
739 if (pid) {
740 io[0].wfd = usock(pid);
741 } else if (port) {
742 io[0].wfd = tsock(port);
743 } else if ((port_env = fd_env(PORT_ENV, FD_ENV_REQUIRED)) >= 0) {
744 io[0].wfd = tsock(port_env);
745 } else {
746 io[0].wfd = fd_env(INPUT_ENV, true);
747 }
748 io[1].name = "emulator->script";
749 if (pid || port || (port_env >= 0)) {
750 io[1].rfd = dup(io[0].wfd);
751 } else {
752 io[1].rfd = fd_env(OUTPUT_ENV, true);
753 }
754 io[1].wfd = fileno(stdout);
755 for (i = 0; i < N_IO; i++) {
756 if (io[i].rfd > fd_max) {
757 fd_max = io[i].rfd;
758 }
759 if (io[i].wfd > fd_max) {
760 fd_max = io[i].wfd;
761 }
762 io[i].offset = 0;
763 io[i].count = 0;
764 }
765 fd_max++;
766
767 for (;;) {
768 int rv;
769
770 FD_ZERO(&rfds);
771 FD_ZERO(&wfds);
772
773 for (i = 0; i < N_IO; i++) {
774 if (io[i].count) {
775 FD_SET(io[i].wfd, &wfds);
776 if (verbose) {
777 fprintf(stderr, "enabling output %s %d\n",
778 io[i].name, io[i].wfd);
779 }
780 } else {
781 FD_SET(io[i].rfd, &rfds);
782 if (verbose) {
783 fprintf(stderr, "enabling input %s %d\n",
784 io[i].name, io[i].rfd);
785 }
786 }
787 }
788
789 if ((rv = select(fd_max, &rfds, &wfds, NULL, NULL)) < 0) {
790 perror("x3270if: select");
791 exit(__LINE__);
792 }
793 if (verbose) {
794 fprintf(stderr, "select->%d\n", rv);
795 }
796
797 for (i = 0; i < N_IO; i++) {
798 if (io[i].count) {
799 if (FD_ISSET(io[i].wfd, &wfds)) {
800 rv = write(io[i].wfd, io[i].buf + io[i].offset,
801 io[i].count);
802 if (rv < 0) {
803 fprintf(stderr, "x3270if: write(%s): %s",
804 io[i].name, strerror(errno));
805 exit(__LINE__);
806 }
807 io[i].offset += rv;
808 io[i].count -= rv;
809 if (verbose) {
810 fprintf(stderr, "write(%s)->%d\n", io[i].name,
811 rv);
812 }
813 }
814 } else if (FD_ISSET(io[i].rfd, &rfds)) {
815 rv = read(io[i].rfd, io[i].buf, IBS);
816 if (rv < 0) {
817 fprintf(stderr, "x3270if: read(%s): %s", io[i].name,
818 strerror(errno));
819 exit(__LINE__);
820 }
821 if (rv == 0) {
822 exit(0);
823 }
824 io[i].offset = 0;
825 io[i].count = rv;
826 if (verbose) {
827 fprintf(stderr, "read(%s)->%d\n", io[i].name, rv);
828 }
829 }
830 }
831 }
832 }
833
834 #else /*][*/
835
836 static HANDLE stdin_thread;
837 static HANDLE stdin_enable_event, stdin_done_event;
838 static char stdin_buf[1024];
839 static int stdin_nr;
840 static int stdin_error;
841
842 /*
843 * stdin input thread
844 *
845 * Endlessly:
846 * - waits for stdin_enable_event
847 * - reads from stdin
848 * - leaves the input in stdin_buf and the length in stdin_nr
849 * - sets stdin_done_event
850 *
851 * If there is a read error, leaves -1 in stdin_nr and a Windows error code in
852 * stdin_error.
853 */
854 static DWORD WINAPI
stdin_read(LPVOID lpParameter)855 stdin_read(LPVOID lpParameter)
856 {
857 for (;;) {
858 DWORD rv;
859
860 rv = WaitForSingleObject(stdin_enable_event, INFINITE);
861 switch (rv) {
862 case WAIT_ABANDONED:
863 case WAIT_TIMEOUT:
864 case WAIT_FAILED:
865 stdin_nr = -1;
866 stdin_error = GetLastError();
867 SetEvent(stdin_done_event);
868 break;
869 case WAIT_OBJECT_0:
870 stdin_nr = read(0, stdin_buf, sizeof(stdin_buf));
871 if (stdin_nr < 0) {
872 stdin_error = GetLastError();
873 }
874 SetEvent(stdin_done_event);
875 break;
876 }
877 }
878 return 0;
879 }
880
881 /* Act as a passive pipe to the emulator. */
882 static void
iterative_io(int pid,unsigned short port)883 iterative_io(int pid, unsigned short port)
884 {
885 char *port_env;
886 socket_t s;
887 struct sockaddr_in sin;
888 HANDLE socket_event;
889 HANDLE ha[2];
890 DWORD ret;
891 char buf[1024];
892 int nr;
893
894 if (!port) {
895 port_env = getenv(PORT_ENV);
896 if (port_env == NULL) {
897 fprintf(stderr, "Must specify port or put port in " PORT_ENV ".\n");
898 exit(__LINE__);
899 }
900 port = atoi(port_env);
901 if (port <= 0 || (port & ~0xffff)) {
902 fprintf(stderr, "Invalid " PORT_ENV ".\n");
903 exit(__LINE__);
904 }
905 }
906
907 /* Open the socket. */
908 s = socket(PF_INET, SOCK_STREAM, 0);
909 if (s < 0) {
910 win32_perror("socket");
911 exit(__LINE__);
912 }
913 memset(&sin, '\0', sizeof(sin));
914 sin.sin_family = AF_INET;
915 sin.sin_port = htons(port);
916 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
917 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
918 win32_perror("connect(%u) failed", port);
919 exit(__LINE__);
920 }
921 if (verbose) {
922 fprintf(stderr, "<connected to port %d>\n", port);
923 }
924 socket_event = CreateEvent(NULL, FALSE, FALSE, NULL);
925 if (socket_event == NULL) {
926 win32_perror("CreateEvent failed");
927 exit(__LINE__);
928 }
929 if (WSAEventSelect(s, socket_event, FD_READ | FD_CLOSE) != 0) {
930 win32_perror("WSAEventSelect failed");
931 exit(__LINE__);
932 }
933
934 /* Create a thread to read data from the socket. */
935 stdin_enable_event = CreateEvent(NULL, FALSE, FALSE, NULL);
936 stdin_done_event = CreateEvent(NULL, FALSE, FALSE, NULL);
937 stdin_thread = CreateThread(NULL, 0, stdin_read, NULL, 0, NULL);
938 if (stdin_thread == NULL) {
939 win32_perror("CreateThread failed");
940 exit(__LINE__);
941 }
942 SetEvent(stdin_enable_event);
943
944 ha[0] = socket_event;
945 ha[1] = stdin_done_event;
946 for (;;) {
947 ret = WaitForMultipleObjects(2, ha, FALSE, INFINITE);
948 switch (ret) {
949 case WAIT_OBJECT_0: /* socket input */
950 nr = recv(s, buf, sizeof(buf), 0);
951 if (verbose) {
952 fprintf(stderr, "<%d byte%s from socket>\n", nr,
953 (nr == 1)? "": "s");
954 }
955 if (nr < 0) {
956 win32_perror("recv failed");
957 exit(__LINE__);
958 }
959 if (nr == 0) {
960 exit(__LINE__);
961 }
962 fwrite(buf, 1, nr, stdout);
963 fflush(stdout);
964 break;
965 case WAIT_OBJECT_0 + 1: /* stdin input */
966 if (verbose) {
967 fprintf(stderr, "<%d byte%s from stdin>\n", stdin_nr,
968 (stdin_nr == 1)? "": "s");
969 }
970 if (stdin_nr < 0) {
971 fprintf(stderr, "stdin read failed: %s\n",
972 win32_strerror(stdin_error));
973 exit(__LINE__);
974 }
975 if (stdin_nr == 0) {
976 exit(0);
977 }
978 send(s, stdin_buf, stdin_nr, 0);
979 SetEvent(stdin_enable_event);
980 break;
981 case WAIT_FAILED:
982 win32_perror("WaitForMultipleObjects failed");
983 exit(__LINE__);
984 default:
985 fprintf(stderr, "Unexpected return %d from "
986 "WaitForMultipleObjects\n", (int)ret);
987 exit(__LINE__);
988 }
989 }
990 }
991
992 #endif /*]*/
993
994 #if defined(HAVE_LIBREADLINE) /*[*/
995 static char **
attempted_completion(const char * text,int start,int end)996 attempted_completion(const char *text, int start, int end)
997 {
998 /*
999 * At some point, we may get the action list from the emulator, but for
1000 * now, just fail.
1001 */
1002 return NULL;
1003 }
1004
1005 static char *
completion_entry(const char * text,int state)1006 completion_entry(const char *text, int state)
1007 {
1008 /*
1009 * At some point, we may get the action list from the emulator, but for
1010 * now, just fail.
1011 */
1012 return NULL;
1013 }
1014
1015 /* The command line read by readline. */
1016 static char *readline_command;
1017
1018 /* True if readline is finished reading a command. */
1019 static bool readline_done = false;
1020
1021 /* Handle a command line. */
1022 static void
rl_handler(char * command)1023 rl_handler(char *command)
1024 {
1025 /*
1026 * readline's callback handler API doesn't allow context to be passed in or
1027 * out of the handler. So the only way for it to communicate with the
1028 * function that calls rl_callback_read_char() is through global variables.
1029 */
1030 readline_done = true;
1031 readline_command = command;
1032
1033 /*
1034 * Remove the callback handler. If we don't remove it, readline() will
1035 * display the prompt as soon as this function returns.
1036 */
1037 rl_callback_handler_remove();
1038 }
1039 #endif /*]*/
1040
1041 #if defined(_WIN32) /*[*/
1042 static void
set_text_attribute(HANDLE out,WORD attributes)1043 set_text_attribute(HANDLE out, WORD attributes)
1044 {
1045 if (!SetConsoleTextAttribute(out, attributes)) {
1046 win32_perror("Can't set console text attribute");
1047 exit(__LINE__);
1048 }
1049 }
1050 #endif /*[*/
1051
1052 /* Copy and translate a translation. */
1053 static void
xlcpy(char * dest,const char * src)1054 xlcpy(char *dest, const char *src)
1055 {
1056 bool backslash = false;
1057 char c;
1058
1059 /* Skip spaces. */
1060 while ((c = *src) == ' ')
1061 {
1062 src++;
1063 }
1064
1065 /* Copy, translating certain escape sequences. */
1066 while ((c = *src++) != '\0') {
1067 if (backslash) {
1068 if (c == 'n') {
1069 *dest++ = '\n';
1070 } else if (c != 'r') {
1071 *dest++ = c;
1072 }
1073 backslash = false;
1074 } else if (c == '\\') {
1075 backslash = true;
1076 } else {
1077 *dest++ = c;
1078 }
1079 }
1080 *dest = '\0';
1081 }
1082
1083 /* Read the localization file. */
1084 static void
read_localization(const char * filename)1085 read_localization(const char *filename)
1086 {
1087 FILE *f = fopen(filename, "r");
1088 char buf[1024];
1089 char *s;
1090 int line = 1;
1091
1092 if (f == NULL) {
1093 perror(filename);
1094 exit(__LINE__);
1095 }
1096
1097 while ((s = fgets(buf, sizeof(buf), f)) != NULL) {
1098 size_t sl;
1099 char *colon;
1100 i18n_t *ie;
1101
1102 sl = strlen(s);
1103 if (sl > 0 && s[sl - 1] == '\n') {
1104 s[sl - 1] = '\0';
1105 }
1106 colon = strchr(s, ':');
1107 if (colon == NULL || colon == s) {
1108 fprintf(stderr, "%s, line %d: bad format\n", filename, line);
1109 exit(__LINE__);
1110 }
1111
1112 ie = (i18n_t *)Malloc(sizeof(i18n_t) + sl + 2);
1113 ie->key = (char *)(ie + 1);
1114 strncpy(ie->key, s, colon - s);
1115 ie->key[colon - s] = '\0';
1116 ie->translation = ie->key + strlen(ie->key) + 1;
1117 xlcpy(ie->translation, colon + 1);
1118 ie->next = i18n;
1119 i18n = ie;
1120 }
1121
1122 fclose(f);
1123 }
1124
1125 /* Get a localized string. */
1126 static const char *
i18n_get(const char * key)1127 i18n_get(const char *key)
1128 {
1129 i18n_t *ie;
1130
1131 for (ie = i18n; ie != NULL; ie = ie->next) {
1132 if (!strcmp(key, ie->key))
1133 {
1134 return ie->translation;
1135 }
1136 }
1137 return NULL;
1138 }
1139
1140 #if !defined(_WIN32) /*[*/
1141 static char *
tigetstr_def(const char * name,char * def)1142 tigetstr_def(const char *name, char *def)
1143 {
1144 char *s = tigetstr((char *)name);
1145
1146 if (s != NULL && s != (char *)-1) {
1147 return s;
1148 }
1149 return def;
1150 }
1151
1152 /* Get an ANSI color setting attribute. */
1153 static const char *
xsetaf(const char * setaf,int color,const char * sgr)1154 xsetaf(const char *setaf, int color, const char *sgr)
1155 {
1156 static char *x_ret = NULL;
1157
1158 /* Clean up the previous value. */
1159 if (x_ret != NULL) {
1160 Free(x_ret);
1161 x_ret = NULL;
1162 }
1163
1164 if (setaf != NULL) {
1165 char *a, *s;
1166
1167 /* Encode AF. */
1168 a = tiparm((char *)setaf, color);
1169 if (sgr == NULL) {
1170 return a;
1171 }
1172
1173 /* Save encoded AF and encode SGR. */
1174 a = NewString(a);
1175 s = tiparm((char *)sgr, 0, 0, 0, 0, 0, 1, 0, 0, 0);
1176 x_ret = Malloc(strlen(a) + strlen(s) + 1);
1177 sprintf(x_ret, "%s%s", s, a);
1178 Free(a);
1179
1180 /* Return combined SGR and AF. */
1181 return x_ret;
1182 } else {
1183 return "";
1184 }
1185 }
1186 #endif /*]*/
1187
1188 static void
interactive_io(int port,const char * emulator_name,const char * help_name,const char * localization)1189 interactive_io(int port, const char *emulator_name, const char *help_name,
1190 const char *localization)
1191 {
1192 char *prompt, *real_prompt;
1193 socket_t s = INVALID_SOCKET;
1194 int infd = -1, outfd = -1;
1195 size_t prompt_len;
1196 char *data_ret;
1197 char *prompt_ret;
1198 bool aux_input = false;
1199 itype_t itype;
1200 const char *l;
1201 #if defined(_WIN32) /*[*/
1202 HANDLE conout;
1203 CONSOLE_SCREEN_BUFFER_INFO info;
1204 HANDLE socket_event;
1205 #else /*][*/
1206 int colors;
1207 char *setaf;
1208 char *op;
1209 char *sgr;
1210 char *sgr0;
1211 char *prompt_setaf;
1212 int color_offset = 0;
1213 #endif /*]*/
1214
1215 #if !defined(_WIN32) /*[*/
1216 /* Set up terminfo and check for ANSI color. */
1217 setupterm(NULL, fileno(stdout), NULL);
1218 colors = tigetnum("colors");
1219 setaf = tigetstr_def("setaf", NULL);
1220 op = tigetstr_def("op", "");
1221 if (!op[0]) {
1222 setaf = NULL;
1223 }
1224 sgr = tigetstr_def("sgr", NULL);
1225 sgr0 = tigetstr_def("sgr0", "");
1226 if (!sgr0[0]) {
1227 sgr = NULL;
1228 }
1229 if (colors < 8 || setaf == NULL) {
1230 /* No usable color. */
1231 setaf = NULL;
1232 op = "";
1233 sgr = NULL;
1234 sgr0 = "";
1235 } else if (colors >= 16 && sgr != NULL) {
1236 /* Use brighter colors. */
1237 color_offset = 8;
1238 sgr = NULL;
1239 sgr0 = "";
1240 }
1241 if (op[0] && sgr0[0]) {
1242 /* Combine OP and SGR0. */
1243 char *s = Malloc(strlen(op) + strlen(sgr0) + 1);
1244
1245 sprintf(s, "%s%s", op, sgr0);
1246 op = s;
1247 }
1248 #endif
1249
1250 if (port) {
1251 s = tsock(port);
1252 } else {
1253 #if !defined(_WIN32) /*[*/
1254 get_ports(&s, &infd, &outfd);
1255 #else /*][*/
1256 get_ports(&s, NULL, NULL);
1257 #endif /*]*/
1258 }
1259
1260 #if defined(HAVE_LIBREADLINE) /*[*/
1261 # define MLEN 1
1262 # define LEFT "\001"
1263 # define RIGHT "\002"
1264 #else /*]*/
1265 # define MLEN 0
1266 # define LEFT ""
1267 # define RIGHT ""
1268 #endif /*]*/
1269
1270 /* Localize. */
1271 if (localization != NULL) {
1272 read_localization(localization);
1273 }
1274
1275 /* Announce our capabilities. */
1276 data_ret = NULL;
1277 single_io(0, 0, s, infd, outfd, NO_STATUS, "Capabilities(interactive)",
1278 &data_ret, NULL, &itype);
1279
1280 /* Set up the prompt. */
1281 #if !defined(_WIN32) /*[*/
1282 prompt_setaf = (char *)xsetaf(setaf, color_offset + COLOR_BLUE, sgr);
1283 prompt_setaf = Malloc(strlen(prompt_setaf) + 1);
1284 strcpy(prompt_setaf, xsetaf(setaf, color_offset + COLOR_BLUE, sgr));
1285 prompt_len = MLEN + strlen(prompt_setaf) + MLEN + strlen(emulator_name)
1286 + strlen("> ") + MLEN + strlen(op) + MLEN + 1;
1287 prompt = Malloc(prompt_len);
1288 snprintf(prompt, prompt_len, LEFT "%s" RIGHT "%s> " LEFT "%s" RIGHT,
1289 prompt_setaf, emulator_name, op);
1290 #else /*][*/
1291 prompt_len = strlen(emulator_name) + strlen("> ") + 1;
1292 prompt = Malloc(prompt_len);
1293 snprintf(prompt, prompt_len, "%s> ", emulator_name);
1294 #endif /*]*/
1295 real_prompt = prompt;
1296
1297 # if defined(HAVE_LIBREADLINE) /*[*/
1298 /* Set up readline. */
1299 rl_readline_name = (char *)emulator_name;
1300 rl_initialize();
1301 rl_attempted_completion_function = attempted_completion;
1302 # if defined(RL_READLINE_VERSION) && (RL_READLINE_VERSION > 0x0402) /*[*/
1303 rl_completion_entry_function = completion_entry;
1304 # else /*][*/
1305 rl_completion_entry_function = (Function *)completion_entry;
1306 # endif /*]*/
1307 # endif /*]*/
1308
1309 #if defined(_WIN32) /*[*/
1310 /* Open the console handle. */
1311 conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
1312 FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1313 if (conout == NULL) {
1314 win32_perror("Can't open console output handle");
1315 exit(__LINE__);
1316 }
1317 if (!GetConsoleScreenBufferInfo(conout, &info)) {
1318 win32_perror("Can't get console info");
1319 exit(__LINE__);
1320 }
1321
1322 /* wx3270 speaks Unicode. */
1323 SetConsoleOutputCP(65001);
1324
1325 /* Set the title. */
1326 SetConsoleTitle(prompt);
1327
1328 /* Set up the stdin thread. */
1329 stdin_enable_event = CreateEvent(NULL, FALSE, FALSE, NULL);
1330 stdin_done_event = CreateEvent(NULL, FALSE, FALSE, NULL);
1331 stdin_thread = CreateThread(NULL, 0, stdin_read, NULL, 0, NULL);
1332 if (stdin_thread == NULL) {
1333 win32_perror("Cannot create stdin thread");
1334 exit(__LINE__);
1335 }
1336
1337 /* Set up the socket event. */
1338 socket_event = CreateEvent(NULL, FALSE, FALSE, NULL);
1339 if (socket_event == NULL) {
1340 win32_perror("Cannot create socket event");
1341 exit(__LINE__);
1342 }
1343 if (WSAEventSelect(s, socket_event, FD_CLOSE) != 0) {
1344 win32_perror("Cannot set socket events");
1345 exit(__LINE__);
1346 }
1347 #endif /*]*/
1348
1349 /* Introduce yourself. */
1350 l = i18n_get(BANNER);
1351 if (l != NULL) {
1352 printf("%s\n", l);
1353 } else {
1354 printf("%s Prompt\n\n", emulator_name);
1355 printf("To execute one action and close this window, end the command line with '/'.\n");
1356 printf("To close this window, enter just '/' as the command line.\n");
1357 if (help_name != NULL) {
1358 printf("To get help, use the '%s()' action.\n", help_name);
1359 }
1360 }
1361 #if !defined(_WIN32) /*[*/
1362 printf("%s", xsetaf(setaf, color_offset + COLOR_YELLOW, sgr));
1363 # else /*][*/
1364 fflush(stdout);
1365 set_text_attribute(conout, FOREGROUND_GREEN | FOREGROUND_RED);
1366 #endif /*]*/
1367 l = i18n_get(QUIT);
1368 if (l != NULL) {
1369 printf("%s", l);
1370 } else {
1371 printf("Note: The 'Quit()' action will cause %s to exit.",
1372 emulator_name);
1373 }
1374 #if !defined(_WIN32) /*[*/
1375 printf("%s", op);
1376 # else /*][*/
1377 fflush(stdout);
1378 set_text_attribute(conout, info.wAttributes);
1379 #endif /*]*/
1380 printf("\n\n");
1381
1382 for (;;) {
1383 char *command;
1384 int rc;
1385 char *nl;
1386 size_t sl;
1387 bool done = false;
1388 #if !defined(_WIN32) /*[*/
1389 # if !defined(HAVE_LIBREADLINE) /*[*/
1390 char inbuf[1024];
1391 # endif /*]*/
1392 # else /*][*/
1393 HANDLE ha[2];
1394 DWORD rv;
1395 #endif /*]*/
1396
1397 /* Display the prompt. */
1398 #if !defined(_WIN32) /*[*/
1399 # if defined(HAVE_LIBREADLINE) /*[*/
1400 rl_callback_handler_install(prompt, &rl_handler);
1401 # else /*][*/
1402 fputs(prompt, stdout);
1403 fflush(stdout);
1404 # endif /*]*/
1405 #else /*][*/
1406 if (!aux_input) {
1407 set_text_attribute(conout, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
1408 }
1409 fputs(prompt, stdout);
1410 fflush(stdout);
1411 if (!aux_input) {
1412 set_text_attribute(conout, info.wAttributes);
1413 }
1414
1415 /* Enable console input. */
1416 SetEvent(stdin_enable_event);
1417 #endif /*]*/
1418
1419 /* Wait for socket or console input. */
1420 #if !defined(_WIN32) /*[*/
1421 do {
1422 fd_set rfds;
1423 int mfd = (s == INVALID_SOCKET)? infd: s;
1424
1425 FD_ZERO(&rfds);
1426 FD_SET(0, &rfds);
1427 FD_SET(mfd, &rfds);
1428 select(mfd + 1, &rfds, NULL, NULL, NULL);
1429 if (FD_ISSET(mfd, &rfds)) {
1430 /* Pipe input (EOF). */
1431 done = true;
1432 break;
1433 }
1434 if (FD_ISSET(0, &rfds)) {
1435 /* Keyboard input. */
1436 # if defined(HAVE_LIBREADLINE) /*[*/
1437 rl_callback_read_char();
1438 if (!readline_done) {
1439 /* No input yet. */
1440 continue;
1441 }
1442 command = readline_command;
1443 # else /*][*/
1444 command = fgets(inbuf, sizeof(inbuf), stdin);
1445 # endif /*]*/
1446 if (command == NULL) {
1447 done = true;
1448 }
1449 break;
1450 }
1451 } while (true);
1452
1453 if (done) {
1454 # if defined(HAVE_LIBREADLINE) /*[*/
1455 rl_callback_handler_remove();
1456 # endif /*]*/
1457 exit(0);
1458 }
1459
1460 # if defined(HAVE_LIBREADLINE) /*[*/
1461 readline_command = NULL;
1462 readline_done = false;
1463 # endif /*]*/
1464
1465 # else /*][*/
1466 ha[0] = socket_event;
1467 ha[1] = stdin_done_event;
1468 rv = WaitForMultipleObjects(2, ha, FALSE, INFINITE);
1469 switch (rv) {
1470 case WAIT_OBJECT_0: /* socket close */
1471 exit(0);
1472 break;
1473 case WAIT_OBJECT_0 + 1: /* console input */
1474 if (stdin_nr <= 0) {
1475 exit(0);
1476 }
1477 command = stdin_buf;
1478 break;
1479 case WAIT_FAILED:
1480 win32_perror("WaitForMultipleObjects failed");
1481 exit(__LINE__);
1482 break;
1483 default:
1484 fprintf(stderr, "Unexpected return %d from "
1485 "WaitForMultipleObjects\n", (int)rv);
1486 fflush(stderr);
1487 exit(__LINE__);
1488 break;
1489 }
1490 #endif /*]*/
1491
1492 /* We have a line of input. */
1493 if ((nl = strchr(command, '\n')) != NULL) {
1494 *nl = '\0';
1495 }
1496 sl = strlen(command);
1497 if (sl > 0 && command[sl - 1] == '/') {
1498 command[--sl] = '\0';
1499 done = true;
1500 }
1501 # if defined(HAVE_LIBREADLINE) /*[*/
1502 if (!aux_input && command[0]) {
1503 add_history(command);
1504 }
1505 # endif /*]*/
1506
1507 data_ret = NULL;
1508 prompt_ret = NULL;
1509 if (!aux_input) {
1510 rc = single_io(0, 0, s, infd, outfd, NO_STATUS, command,
1511 &data_ret, &prompt_ret, &itype);
1512 } else {
1513 char *command_base64 = base64_encode(command);
1514 char *response = Malloc(strlen(command_base64) + 128);
1515
1516 if (response == NULL) {
1517 fprintf(stderr, "Out of memory\n");
1518 exit(__LINE__);
1519 }
1520 sprintf(response, RESUME_INPUT "(%s)",
1521 command_base64[0]? command_base64: "\"\"");
1522 Free(command_base64);
1523 rc = single_io(0, 0, s, infd, outfd, NO_STATUS, response,
1524 &data_ret, &prompt_ret, &itype);
1525 Free(response);
1526 Free(prompt);
1527 prompt = real_prompt;
1528 aux_input = false;
1529 }
1530 # if defined(HAVE_LIBREADLINE) /*[*/
1531 Free(command);
1532 # endif /*]*/
1533
1534 if (prompt_ret != NULL) {
1535 prompt = base64_decode(prompt_ret);
1536 Free(prompt_ret);
1537 aux_input = true;
1538 }
1539
1540 if (data_ret != NULL) {
1541 if ((sl = strlen(data_ret)) > 0 && data_ret[sl - 1] == '\n') {
1542 data_ret[sl - 1] = '\0';
1543 }
1544 if (*data_ret) {
1545 #if !defined(_WIN32) /*[*/
1546 if (aux_input) {
1547 printf("%s\n", data_ret);
1548 } else {
1549 if (rc) {
1550 printf("%s%s%s\n", xsetaf(setaf,
1551 color_offset + COLOR_RED, sgr), data_ret,
1552 op);
1553 } else {
1554 printf("%s\n", data_ret);
1555 }
1556 }
1557 # else /*][*/
1558 if (!aux_input) {
1559 set_text_attribute(conout,
1560 rc? (FOREGROUND_INTENSITY | FOREGROUND_RED):
1561 info.wAttributes);
1562 }
1563 fputs(data_ret, stdout);
1564 fflush(stdout);
1565 if (!aux_input) {
1566 set_text_attribute(conout, info.wAttributes);
1567 }
1568 fputc('\n', stdout);
1569 #endif /*]*/
1570 }
1571 Free(data_ret);
1572 fflush(stdout);
1573 }
1574
1575 if (done) {
1576 exit(0);
1577 }
1578 }
1579 }
1580
1581 void
Error(const char * msg)1582 Error(const char *msg)
1583 {
1584 fprintf(stderr, "%s\n", msg);
1585 exit(1);
1586 }
1587