OSDN Git Service

daily update
[pf3gnuchains/pf3gnuchains3x.git] / expect / exp_tty.c
1 /* exp_tty.c - tty support routines */
2
3 #include "expect_cf.h"
4 #include <stdio.h>
5 #include <signal.h>
6 #include "string.h"
7
8 #ifdef HAVE_SYS_FCNTL_H
9 #  include <sys/fcntl.h>
10 #else
11 #  include <fcntl.h>
12 #endif
13
14 #include <sys/stat.h>
15
16 #ifdef HAVE_INTTYPES_H
17 #  include <inttypes.h>
18 #endif
19 #include <sys/types.h>
20
21 #ifdef HAVE_UNISTD_H
22 # include <unistd.h>
23 #endif
24
25 #ifdef HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #endif
28
29 #if defined(SIGCLD) && !defined(SIGCHLD)
30 #define SIGCHLD SIGCLD
31 #endif
32
33 #include "tcl.h"
34 #include "exp_prog.h"
35 #include "exp_rename.h"
36 #include "exp_tty_in.h"
37 #include "exp_log.h"
38 #include "exp_command.h"
39
40 static int is_raw = FALSE;
41 static int is_noecho = FALSE;
42
43 int exp_ioctled_devtty = FALSE;
44 int exp_stdin_is_tty;
45 int exp_stdout_is_tty;
46
47 /*static*/ extern exp_tty exp_tty_current, exp_tty_cooked;
48 #define tty_current exp_tty_current
49 #define tty_cooked exp_tty_cooked
50
51 int
52 exp_israw()
53 {
54         return is_raw;
55 }
56
57 int
58 exp_isecho()
59 {
60         return !is_noecho;
61 }
62
63 /* if set == 1, set it to raw, else unset it */
64 void
65 exp_tty_raw(set)
66 int set;
67 {
68         if (set == 1) {
69                 is_raw = TRUE;
70 #if defined(HAVE_TERMIOS) || defined(HAVE_TERMIO) /* had POSIX too */
71                 tty_current.c_iflag = 0;
72                 tty_current.c_oflag = 0;
73                 tty_current.c_lflag &= ECHO;  /* disable everything but echo */
74                 tty_current.c_cc[VMIN] = 1;
75                 tty_current.c_cc[VTIME] = 0;
76         } else {
77                 tty_current.c_iflag = tty_cooked.c_iflag;
78                 tty_current.c_oflag = tty_cooked.c_oflag;
79 /*              tty_current.c_lflag = tty_cooked.c_lflag;*/
80 /* attempt 2    tty_current.c_lflag = tty_cooked.c_lflag & ~ECHO;*/
81                 /* retain current echo setting */
82                 tty_current.c_lflag = (tty_cooked.c_lflag & ~ECHO) | (tty_current.c_lflag & ECHO);
83                 tty_current.c_cc[VMIN] = tty_cooked.c_cc[VMIN];
84                 tty_current.c_cc[VTIME] = tty_cooked.c_cc[VTIME];
85 #else
86 #  if defined(HAVE_SGTTYB)
87                 tty_current.sg_flags |= RAW;
88         } else {
89                 tty_current.sg_flags = tty_cooked.sg_flags;
90 #  endif
91 #endif
92                 is_raw = FALSE;
93         }
94 }
95         
96 void
97 exp_tty_echo(set)
98 int set;
99 {
100         if (set == 1) {
101                 is_noecho = FALSE;
102 #if defined(HAVE_TERMIOS) || defined(HAVE_TERMIO) /* had POSIX too */
103                 tty_current.c_lflag |= ECHO;
104         } else {
105                 tty_current.c_lflag &= ~ECHO;
106 #else
107                 tty_current.sg_flags |= ECHO;
108         } else {
109                 tty_current.sg_flags &= ~ECHO;
110 #endif
111                 is_noecho = TRUE;
112         }
113 }
114
115 int
116 exp_tty_set_simple(tty)
117 exp_tty *tty;
118 {
119 #ifdef HAVE_TCSETATTR
120         return(tcsetattr(exp_dev_tty, TCSADRAIN,tty));
121 #else
122         return(ioctl    (exp_dev_tty, TCSETSW  ,tty));
123 #endif
124 }
125
126 int
127 exp_tty_get_simple(tty)
128 exp_tty *tty;
129 {
130 #ifdef HAVE_TCSETATTR
131         return(tcgetattr(exp_dev_tty,         tty));
132 #else
133         return(ioctl    (exp_dev_tty, TCGETS, tty));
134 #endif
135 }
136
137 /* returns 0 if nothing changed */
138 /* if something changed, the out parameters are changed as well */
139 int
140 exp_tty_raw_noecho(interp,tty_old,was_raw,was_echo)
141 Tcl_Interp *interp;
142 exp_tty *tty_old;
143 int *was_raw, *was_echo;
144 {
145         if (exp_disconnected) return(0);
146         if (is_raw && is_noecho) return(0);
147         if (exp_dev_tty == -1) return(0);
148
149         *tty_old = tty_current;         /* save old parameters */
150         *was_raw = is_raw;
151         *was_echo = !is_noecho;
152         debuglog("tty_raw_noecho: was raw = %d  echo = %d\r\n",is_raw,!is_noecho);
153
154         exp_tty_raw(1);
155         exp_tty_echo(-1);
156
157         if (exp_tty_set_simple(&tty_current) == -1) {
158                 errorlog("ioctl(raw): %s\r\n",Tcl_PosixError(interp));
159                 exp_exit(interp,1);
160         }
161
162         exp_ioctled_devtty = TRUE;
163         return(1);
164 }
165
166 /* returns 0 if nothing changed */
167 /* if something changed, the out parameters are changed as well */
168 int
169 exp_tty_cooked_echo(interp,tty_old,was_raw,was_echo)
170 Tcl_Interp *interp;
171 exp_tty *tty_old;
172 int *was_raw, *was_echo;
173 {
174         if (exp_disconnected) return(0);
175         if (!is_raw && !is_noecho) return(0);
176         if (exp_dev_tty == -1) return(0);
177
178         *tty_old = tty_current;         /* save old parameters */
179         *was_raw = is_raw;
180         *was_echo = !is_noecho;
181         debuglog("tty_cooked_echo: was raw = %d  echo = %d\r\n",is_raw,!is_noecho);
182
183         exp_tty_raw(-1);
184         exp_tty_echo(1);
185
186         if (exp_tty_set_simple(&tty_current) == -1) {
187                 errorlog("ioctl(noraw): %s\r\n",Tcl_PosixError(interp));
188                 exp_exit(interp,1);
189         }
190         exp_ioctled_devtty = TRUE;
191
192         return(1);
193 }
194
195 void
196 exp_tty_set(interp,tty,raw,echo)
197 Tcl_Interp *interp;
198 exp_tty *tty;
199 int raw;
200 int echo;
201 {
202         if (exp_tty_set_simple(tty) == -1) {
203                 errorlog("ioctl(set): %s\r\n",Tcl_PosixError(interp));
204                 exp_exit(interp,1);
205         }
206         is_raw = raw;
207         is_noecho = !echo;
208         tty_current = *tty;
209         debuglog("tty_set: raw = %d, echo = %d\r\n",is_raw,!is_noecho);
210         exp_ioctled_devtty = TRUE;
211 }       
212
213 #if 0
214 /* avoids scoping problems */
215 void
216 exp_update_cooked_from_current() {
217         tty_cooked = tty_current;
218 }
219
220 int
221 exp_update_real_tty_from_current() {
222         return(exp_tty_set_simple(&tty_current));
223 }
224
225 int
226 exp_update_current_from_real_tty() {
227         return(exp_tty_get_simple(&tty_current));
228 }
229 #endif
230
231 void
232 exp_init_stdio()
233 {
234         exp_stdin_is_tty = isatty(0);
235         exp_stdout_is_tty = isatty(1);
236
237         setbuf(stdout,(char *)0);       /* unbuffer stdout */
238 }
239
240 /*ARGSUSED*/
241 void
242 exp_tty_break(interp,fd)
243 Tcl_Interp *interp;
244 int fd;
245 {
246 #ifdef POSIX
247         tcsendbreak(fd,0);
248 #else
249 # ifdef TIOCSBRK
250         ioctl(fd,TIOCSBRK,0);
251         exp_dsleep(interp,0.25); /* sleep for at least a quarter of a second */
252         ioctl(fd,TIOCCBRK,0);
253 # else
254         /* dunno how to do this - ignore */
255 # endif
256 #endif
257 }
258
259 /* take strings with newlines and insert carriage-returns.  This allows user */
260 /* to write send_user strings without always putting in \r. */
261 /* If len == 0, use strlen to compute it */
262 /* NB: if terminal is not in raw mode, nothing is done. */
263 char *
264 exp_cook(s,len)
265 char *s;
266 int *len;       /* current and new length of s */
267 {
268         static int destlen = 0;
269         static char *dest = 0;
270         char *d;                /* ptr into dest */
271         unsigned int need;
272
273         if (s == 0) return("<null>");
274
275         if (!is_raw) return(s);
276
277         /* worst case is every character takes 2 to represent */
278         need = 1 + 2*(len?*len:strlen(s));
279         if (need > destlen) {
280                 if (dest) ckfree(dest);
281                 dest = ckalloc(need);
282                 destlen = need;
283         }
284
285         for (d = dest;*s;s++) {
286                 if (*s == '\n') {
287                         *d++ = '\r';
288                         *d++ = '\n';
289                 } else {
290                         *d++ = *s;
291                 }
292         }
293         *d = '\0';
294         if (len) *len = d-dest;
295         return(dest);
296 }
297
298 /* this stupidity because Tcl needs commands in writable space */
299 static char exec_cmd[] = "exec";
300 static char stty_cmd[] = "/bin/stty";
301
302 static int              /* returns TCL_whatever */
303 exec_stty(interp,argc,argv,devtty)
304 Tcl_Interp *interp;
305 int argc;
306 char **argv;
307 int devtty;             /* if true, redirect to /dev/tty */
308 {
309         char **new_argv;
310         int i;
311         int rc;
312
313         /* insert "system" at front, null at end, */
314         /* and optional redirect in middle, hence "+3" */
315         new_argv = (char **)ckalloc((3+argc)*sizeof(char *));
316         new_argv[0] = exec_cmd;
317         new_argv[1] = stty_cmd;
318         for (i=1;i<argc;i++) {
319                 new_argv[i+1] = argv[i];
320         }
321         if (devtty) new_argv[++i] =
322 #ifdef STTY_READS_STDOUT
323                 ">/dev/tty";
324 #else
325                 "</dev/tty";
326 #endif
327
328         new_argv[i+1] = (char *)0;
329
330         Tcl_ResetResult(interp);
331
332         /* normally, I wouldn't set one of Tcl's own variables, but in this */
333         /* case, I only only want to see if Tcl resets it to non-NONE, */
334         /* and I don't know any other way of doing it */
335         Tcl_SetVar(interp,"errorCode","NONE",0);
336
337 #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 3)
338         rc = Tcl_ExecCmd((ClientData)0,interp,argc+1+devtty,new_argv);
339 #else
340         rc = Tcl_ExecObjCmd((ClientData)0,interp,argc+1+devtty,Tcl_NewStringObj(new_argv,-1));
341 #endif
342         ckfree((char *)new_argv);
343
344         /* if stty-reads-stdout, stty will fail since Exec */
345         /* will detect the stderr.  Only by examining errorCode */
346         /* can we tell if a real error occurred. */     
347
348 #ifdef STTY_READS_STDOUT
349         if (rc == TCL_ERROR) {
350                 char *ec = Tcl_GetVar(interp,"errorCode",TCL_GLOBAL_ONLY);
351                 if (ec && !streq(ec,"NONE")) return TCL_ERROR;
352         }
353 #endif
354         return TCL_OK;
355 }
356
357 /*ARGSUSED*/
358 static int
359 Exp_SttyCmd(clientData, interp, argc, argv)
360 ClientData clientData;
361 Tcl_Interp *interp;
362 int argc;
363 char **argv;
364 {
365         /* redirection symbol is not counted as a stty arg in terms */
366         /* of recognition. */
367         int saw_unknown_stty_arg = FALSE;
368         int saw_known_stty_arg = FALSE;
369         int no_args = TRUE;
370
371         int rc = TCL_OK;
372         int cooked = FALSE;
373         int was_raw, was_echo;
374
375
376         char **redirect;        /* location of "<" */
377         char *infile = 0;
378         int fd;                 /* (slave) fd of infile */
379         int master = -1;        /* master fd of infile */
380         char **argv0 = argv;
381
382         for (argv=argv0+1;*argv;argv++) {
383                 if (argv[0][0] == '<') {
384                         redirect = argv;
385                         infile = *(argv+1);
386                         if (!infile) {
387                                 errorlog("usage: < ttyname");
388                                 return TCL_ERROR;
389                         }
390                         if (streq(infile,"/dev/tty")) {
391                                 infile = 0;
392                                 *argv = 0;
393                                 *(argv+1) = 0;
394                                 argc -= 2;
395                         } else {
396                                 master = exp_trap_off(infile);
397                                 if (-1 == (fd = open(infile,2))) {
398                                         errorlog("couldn't open %s: %s",
399                                          infile,Tcl_PosixError(interp));
400                                         return TCL_ERROR;
401                                 }
402                         }
403                         break;
404                 }
405         }
406
407         if (!infile) {          /* work on /dev/tty */
408                 was_raw = exp_israw();
409                 was_echo = exp_isecho();
410
411                 exp_ioctled_devtty = TRUE;
412
413                 for (argv=argv0+1;*argv;argv++) {
414                         if (streq(*argv,"raw") ||
415                             streq(*argv,"-cooked")) {
416                                 exp_tty_raw(1);
417                                 saw_known_stty_arg = TRUE;
418                                 no_args = FALSE;
419                         } else if (streq(*argv,"-raw") ||
420                                    streq(*argv,"cooked")) {
421                                 cooked = TRUE;
422                                 exp_tty_raw(-1);
423                                 saw_known_stty_arg = TRUE;
424                                 no_args = FALSE;
425                         } else if (streq(*argv,"echo")) {
426                                 exp_tty_echo(1);
427                                 saw_known_stty_arg = TRUE;
428                                 no_args = FALSE;
429                         } else if (streq(*argv,"-echo")) {
430                                 exp_tty_echo(-1);
431                                 saw_known_stty_arg = TRUE;
432                                 no_args = FALSE;
433                         } else if (streq(*argv,"rows")) {
434                                 if (*(argv+1)) {
435                                         exp_win_rows_set(*(argv+1));
436                                         argv++;
437                                         no_args = FALSE;
438                                 } else {
439                                         exp_win_rows_get(interp->result);
440                                         return TCL_OK;
441                                 }
442                         } else if (streq(*argv,"columns")) {
443                                 if (*(argv+1)) {
444                                         exp_win_columns_set(*(argv+1));
445                                         argv++;
446                                         no_args = FALSE;
447                                 } else {
448                                         exp_win_columns_get(interp->result);
449                                         return TCL_OK;
450                                 }
451                         } else {
452                                 saw_unknown_stty_arg = TRUE;
453                         }
454                 }
455                 /* if any unknown args, let real stty try */
456                 if (saw_unknown_stty_arg || no_args) {
457                         /* let real stty try */
458                         rc = exec_stty(interp,argc,argv0,1);
459
460                         /* find out what weird options user asked for */
461                         if (exp_tty_get_simple(&tty_current) == -1) {
462                                 exp_error(interp,"stty: ioctl(get): %s\r\n",Tcl_PosixError(interp));
463                                 rc = TCL_ERROR;
464                         }
465                         if (cooked) {
466                                 /* find out user's new defn of 'cooked' */
467                                 tty_cooked = tty_current;
468                         }
469                 } else if (saw_known_stty_arg) {
470                         if (exp_tty_set_simple(&tty_current) == -1) {
471                             if (exp_disconnected || (exp_dev_tty == -1) || !isatty(exp_dev_tty)) {
472                                 errorlog("stty: impossible in this context\n");
473                                 errorlog("are you disconnected or in a batch, at, or cron script?");
474                                 /* user could've conceivably closed /dev/tty as well */
475                             }
476                             exp_error(interp,"stty: ioctl(user): %s\r\n",Tcl_PosixError(interp));
477                             rc = TCL_ERROR;
478                         }
479                 }
480
481                 /* if no result, make a crude one */
482                 if (interp->result[0] == '\0') {
483                         sprintf(interp->result,"%sraw %secho",
484                                 (was_raw?"":"-"),
485                                 (was_echo?"":"-"));
486                 }
487         } else {
488                 /* a different tty */
489
490                 /* temporarily zap redirect */
491                 char *redirect_save = *redirect;
492                 *redirect = 0;
493
494                 for (argv=argv0+1;*argv;argv++) {
495                         if (streq(*argv,"rows")) {
496                                 if (*(argv+1)) {
497                                         exp_win2_rows_set(fd,*(argv+1));
498                                         argv++;
499                                         no_args = FALSE;
500                                 } else {
501                                         exp_win2_rows_get(fd,interp->result);
502                                         goto done;
503                                 }
504                         } else if (streq(*argv,"columns")) {
505                                 if (*(argv+1)) {
506                                         exp_win2_columns_set(fd,*(argv+1));
507                                         argv++;
508                                         no_args = FALSE;
509                                 } else {
510                                         exp_win2_columns_get(fd,interp->result);
511                                         goto done;
512                                 }
513                         } else if (streq(*argv,"<")) {
514                                 break;
515                         } else {
516                                 saw_unknown_stty_arg = TRUE;
517                                 break;
518                         }
519                 }
520
521                 /* restore redirect */
522                 *redirect = redirect_save;
523
524                 close(fd);      /* no more use for this, from now on */
525                                 /* pass by name */
526
527                 if (saw_unknown_stty_arg || no_args) {
528 #ifdef STTY_READS_STDOUT
529                         /* switch "<" to ">" */
530                         char original_redirect_char = (*redirect)[0];
531                         (*redirect)[0] = '>';
532                         /* stderr unredirected so we can get it directly! */
533 #endif
534                         rc = exec_stty(interp,argc,argv0,0);
535 #ifdef STTY_READS_STDOUT
536                         /* restore redirect - don't know if necessary */
537                         (*redirect)[0] = original_redirect_char;
538 #endif
539                 }
540         }
541  done:
542         exp_trap_on(master);
543
544         return rc;
545 }
546
547 /*ARGSUSED*/
548 static int
549 Exp_SystemCmd(clientData, interp, argc, argv)
550 ClientData clientData;
551 Tcl_Interp *interp;
552 int argc;
553 char **argv;
554 {
555         int result = TCL_OK;
556         RETSIGTYPE (*old)();    /* save old sigalarm handler */
557 #define MAX_ARGLIST 10240
558         int i;
559
560         WAIT_STATUS_TYPE waitStatus;
561         int systemStatus
562 ;
563         int abnormalExit = FALSE;
564         char buf[MAX_ARGLIST];
565         char *bufp = buf;
566         int total_len = 0, arg_len;
567
568         int stty_args_recognized = TRUE;
569         int cmd_is_stty = FALSE;
570         int cooked = FALSE;
571         int was_raw, was_echo;
572
573         if (argc == 1) return TCL_OK;
574
575         if (streq(argv[1],"stty")) {
576                 debuglog("system stty is deprecated, use stty\r\n");
577
578                 cmd_is_stty = TRUE;
579                 was_raw = exp_israw();
580                 was_echo = exp_isecho();
581         }
582
583         if (argc > 2 && cmd_is_stty) {
584                 exp_ioctled_devtty = TRUE;
585
586                 for (i=2;i<argc;i++) {
587                         if (streq(argv[i],"raw") ||
588                             streq(argv[i],"-cooked")) {
589                                 exp_tty_raw(1);
590                         } else if (streq(argv[i],"-raw") ||
591                                    streq(argv[i],"cooked")) {
592                                 cooked = TRUE;
593                                 exp_tty_raw(-1);
594                         } else if (streq(argv[i],"echo")) {
595                                 exp_tty_echo(1);
596                         } else if (streq(argv[i],"-echo")) {
597                                 exp_tty_echo(-1);
598                         } else stty_args_recognized = FALSE;
599                 }
600
601                 /* if unknown args, fall thru and let real stty have a go */
602                 if (stty_args_recognized) {
603 #ifdef HAVE_TCSETATTR
604                         if (tcsetattr(exp_dev_tty,TCSADRAIN, &tty_current) == -1) {
605 #else
606                         if (ioctl(exp_dev_tty, TCSETSW, &tty_current) == -1) {
607 #endif
608                             if (exp_disconnected || (exp_dev_tty == -1) || !isatty(exp_dev_tty)) {
609                                 errorlog("system stty: impossible in this context\n");
610                                 errorlog("are you disconnected or in a batch, at, or cron script?");
611                                 /* user could've conceivably closed /dev/tty as well */
612                             }
613                             exp_error(interp,"system stty: ioctl(user): %s\r\n",Tcl_PosixError(interp));
614                             return(TCL_ERROR);
615                         }
616                         if (cmd_is_stty) {
617                                 sprintf(interp->result,"%sraw %secho",
618                                         (was_raw?"":"-"),
619                                         (was_echo?"":"-"));
620                         }
621                         return(TCL_OK);
622                 }
623         }
624
625         for (i = 1;i<argc;i++) {
626                 total_len += (1 + (arg_len = strlen(argv[i])));
627                 if (total_len > MAX_ARGLIST) {
628                         exp_error(interp,"args too long (>=%d chars)",
629                                 total_len);
630                         return(TCL_ERROR);
631                 }
632                 memcpy(bufp,argv[i],arg_len);
633                 bufp += arg_len;
634                 /* no need to check bounds, we accted for it earlier */
635                 memcpy(bufp," ",1);
636                 bufp += 1;
637         }
638
639         *(bufp-1) = '\0';
640         old = signal(SIGCHLD, SIG_DFL);
641         systemStatus = system(buf);
642         signal(SIGCHLD, old);   /* restore signal handler */
643         debuglog("system(%s) = %d\r\n",buf,i);
644
645         if (systemStatus == -1) {
646                 exp_error(interp,Tcl_PosixError(interp));
647                 return TCL_ERROR;
648         }
649         *(int *)&waitStatus = systemStatus;
650
651         if (!stty_args_recognized) {
652                 /* find out what weird options user asked for */
653 #ifdef HAVE_TCSETATTR
654                 if (tcgetattr(exp_dev_tty, &tty_current) == -1) {
655 #else
656                 if (ioctl(exp_dev_tty, TCGETS, &tty_current) == -1) {
657 #endif
658                         errorlog("ioctl(get): %s\r\n",Tcl_PosixError(interp));
659                         exp_exit(interp,1);
660                 }
661                 if (cooked) {
662                         /* find out user's new defn of 'cooked' */
663                         tty_cooked = tty_current;
664                 }
665         }
666
667         if (cmd_is_stty) {
668                 sprintf(interp->result,"%sraw %secho",
669                         (was_raw?"":"-"),
670                         (was_echo?"":"-"));
671         }
672
673 /* following macros stolen from Tcl's tclUnix.h file */
674 /* we can't include the whole thing because it depends on other macros */
675 /* that come out of Tcl's Makefile, sigh */
676
677 #if 0
678
679 #undef WIFEXITED
680 #ifndef WIFEXITED
681 #   define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0)
682 #endif
683
684 #undef WEXITSTATUS
685 #ifndef WEXITSTATUS
686 #   define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
687 #endif
688
689 #undef WIFSIGNALED
690 #ifndef WIFSIGNALED
691 #   define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff)))
692 #endif
693
694 #undef WTERMSIG
695 #ifndef WTERMSIG
696 #   define WTERMSIG(stat)    ((*((int *) &(stat))) & 0x7f)
697 #endif
698
699 #undef WIFSTOPPED
700 #ifndef WIFSTOPPED
701 #   define WIFSTOPPED(stat)  (((*((int *) &(stat))) & 0xff) == 0177)
702 #endif
703
704 #undef WSTOPSIG
705 #ifndef WSTOPSIG
706 #   define WSTOPSIG(stat)    (((*((int *) &(stat))) >> 8) & 0xff)
707 #endif
708
709 #endif /* 0 */
710
711 /* stolen from Tcl.    Again, this is embedded in another routine */
712 /* (CleanupChildren in tclUnixAZ.c) that we can't use directly. */
713
714         if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) {
715             char msg1[20], msg2[20];
716             int pid = 0;        /* fake a pid, since system() won't tell us */ 
717
718             result = TCL_ERROR;
719             sprintf(msg1, "%d", pid);
720             if (WIFEXITED(waitStatus)) {
721                 sprintf(msg2, "%d", WEXITSTATUS(waitStatus));
722                 Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2,
723                         (char *) NULL);
724                 abnormalExit = TRUE;
725             } else if (WIFSIGNALED(waitStatus)) {
726                 char *p;
727         
728                 p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus)));
729                 Tcl_SetErrorCode(interp, "CHILDKILLED", msg1,
730                         Tcl_SignalId((int) (WTERMSIG(waitStatus))), p,
731                         (char *) NULL);
732                 Tcl_AppendResult(interp, "child killed: ", p, "\n",
733                         (char *) NULL);
734             } else if (WIFSTOPPED(waitStatus)) {
735                 char *p;
736
737                 p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus)));
738                 Tcl_SetErrorCode(interp, "CHILDSUSP", msg1,
739                         Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, (char *) NULL);
740                 Tcl_AppendResult(interp, "child suspended: ", p, "\n",
741                         (char *) NULL);
742             } else {
743                 Tcl_AppendResult(interp,
744                         "child wait status didn't make sense\n",
745                         (char *) NULL);
746             }
747         }
748
749     if (abnormalExit && (*interp->result == 0)) {
750         Tcl_AppendResult(interp, "child process exited abnormally",
751                 (char *) NULL);
752     }
753
754     return result;
755 }
756
757 static struct exp_cmd_data
758 cmd_data[]  = {
759 {"stty",        exp_proc(Exp_SttyCmd),  0,      0},
760 {"system",      exp_proc(Exp_SystemCmd),        0,      0},
761 {0}};
762
763 void
764 exp_init_tty_cmds(interp)
765 struct Tcl_Interp *interp;
766 {
767         exp_create_commands(interp,cmd_data);
768 }