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