1 /* interact (using select) - give user keyboard control
3 Written by: Don Libes, NIST, 2/6/90
5 Design and implementation of this program was paid for by U.S. tax
6 dollars. Therefore it is public domain. However, the author and NIST
7 would appreciate credit if this program or parts of it are used.
11 #include "expect_cf.h"
13 #ifdef HAVE_INTTYPES_H
14 # include <inttypes.h>
16 #include <sys/types.h>
21 #ifdef TIME_WITH_SYS_TIME
22 # include <sys/time.h>
26 # include <sys/time.h>
32 #ifdef HAVE_SYS_WAIT_H
41 #include "exp_tty_in.h"
42 #include "exp_rename.h"
44 #include "exp_command.h"
46 #include "exp_tstamp.h" /* remove when timestamp stuff is gone */
48 #include "tcl_regexp.h"
49 #include "exp_regexp.h"
51 extern char *TclGetRegError();
52 extern void Expect_TclRegError();
54 #define INTER_OUT "interact_out"
57 * tests if we are running this using a real tty
59 * these tests are currently only used to control what gets written to the
60 * logfile. Note that removal of the test of "..._is_tty" means that stdin
61 * or stdout could be redirected and yet stdout would still be logged.
62 * However, it's not clear why anyone would use log_file when these are
63 * redirected in the first place. On the other hand, it is reasonable to
64 * run expect as a daemon in which case, stdin/out do not appear to be
65 * ttys, yet it makes sense for them to be logged with log_file as if they
69 #define real_tty_output(x) (exp_stdout_is_tty && (((x)==1) || ((x)==exp_dev_tty)))
70 #define real_tty_input(x) (exp_stdin_is_tty && (((x)==0) || ((x)==exp_dev_tty)))
73 #define real_tty_output(x) (((x)==1) || ((x)==exp_dev_tty))
74 #define real_tty_input(x) (exp_stdin_is_tty && (((x)==0) || ((x)==exp_dev_tty)))
76 #define new(x) (x *)ckalloc(sizeof(x))
80 int tty_reset; /* if true, reset tty mode upon action */
81 int iread; /* if true, reread indirects */
82 int iwrite; /* if true, write spawn_id element */
83 int timestamp; /* if true, generate timestamp */
84 struct action *next; /* chain only for later for freeing */
88 char *keys; /* original pattern provided by user */
90 int null; /* true if looking to match 0 byte */
92 int echo; /* if keystrokes should be echoed */
93 int writethru; /* if keystrokes should go through to process */
94 int indices; /* true if should write indices */
100 struct exp_i *i_list;
101 struct action *action_eof;
106 struct exp_i *i_list;
107 struct output *output;
108 struct action *action_eof;
109 struct action *action_timeout;
110 struct keymap *keymap;
111 int timeout_nominal; /* timeout nominal */
112 int timeout_remaining; /* timeout remaining */
116 static void free_input();
117 static void free_keymap();
118 static void free_output();
119 static void free_action();
120 static struct action *new_action();
121 static int inter_eval();
123 /* in_keymap() accepts user keystrokes and returns one of MATCH,
124 CANMATCH, or CANTMATCH. These describe whether the keystrokes match a
125 key sequence, and could or can't if more characters arrive. The
126 function assigns a matching keymap if there is a match or can-match.
127 A matching keymap is assigned on can-match so we know whether to echo
130 in_keymap is optimized (if you can call it that) towards a small
131 number of key mappings, but still works well for large maps, since no
132 function calls are made, and we stop as soon as there is a single-char
133 mismatch, and go on to the next one. A hash table or compiled DFA
134 probably would not buy very much here for most maps.
136 The basic idea of how this works is it does a smart sequential search.
137 At each position of the input string, we attempt to match each of the
138 keymaps. If at least one matches, the first match is returned.
140 If there is a CANMATCH and there are more keymaps to try, we continue
141 trying. If there are no more keymaps to try, we stop trying and
142 return with an indication of the first keymap that can match.
144 Note that I've hacked up the regexp pattern matcher in two ways. One
145 is to force the pattern to always be anchored at the front. That way,
146 it doesn't waste time attempting to match later in the string (before
147 we're ready). The other is to return can-match.
152 in_keymap(string,stringlen,keymap,km_match,match_length,skip,rm_nulls)
155 struct keymap *keymap; /* linked list of keymaps */
156 struct keymap **km_match; /* keymap that matches or can match */
157 int *match_length; /* # of chars that matched */
158 int *skip; /* # of chars to skip */
159 int rm_nulls; /* skip nulls if true */
162 char *ks; /* string from a keymap */
163 char *start_search; /* where in the string to start searching */
166 /* assert (*km == 0) */
168 /* a shortcut that should help master output which typically */
169 /* is lengthy and has no key maps. Otherwise it would mindlessly */
170 /* iterate on each character anyway. */
173 return(EXP_CANTMATCH);
176 string_end = string + stringlen;
178 /* Mark beginning of line for ^ . */
181 /* skip over nulls - Pascal Meheut, pascal@cnam.cnam.fr 18-May-1993 */
182 /* for (start_search = string;*start_search;start_search++) {*/
183 for (start_search = string;start_search<string_end;start_search++) {
184 if (*km_match) break; /* if we've already found a CANMATCH */
185 /* don't bother starting search from positions */
186 /* further along the string */
188 for (km=keymap;km;km=km->next) {
189 char *s; /* current character being examined */
192 if (*start_search == 0) {
193 *skip = start_search-string;
194 *match_length = 1; /* s - start_search == 1 */
198 } else if (!km->re) {
200 for (s = start_search,ks = km->keys ;;s++,ks++) {
201 /* if we hit the end of this map, must've matched! */
203 *skip = start_search-string;
204 *match_length = s-start_search;
209 /* if we ran out of user-supplied characters, and */
210 /* still haven't matched, it might match if the user */
211 /* supplies more characters next time */
213 if (s == string_end) {
214 /* skip to next key entry, but remember */
215 /* possibility that this entry might match */
216 if (!*km_match) *km_match = km;
220 /* if this is a problem for you, use exp_parity command */
221 /* if ((*s & 0x7f) == *ks) continue;*/
222 if (*s == *ks) continue;
223 if ((*s == '\0') && rm_nulls) {
231 int r; /* regtry status */
232 Expect_regexp *prog = km->re;
234 /* if anchored, but we're not at beginning, skip pattern */
236 if (string != start_search) continue;
239 /* known starting char - quick test 'fore lotta work */
240 if (prog->regstart) {
241 /* if this is a problem for you, use exp_parity command */
242 /* /* if ((*start_search & 0x7f) != prog->regstart) continue; */
243 if (*start_search != prog->regstart) continue;
245 r = exp_regtry(prog,start_search,match_length);
246 if (r == EXP_MATCH) {
248 *skip = start_search-string;
251 if (r == EXP_CANMATCH) {
252 if (!*km_match) *km_match = km;
259 /* report a can-match */
263 *skip = (start_search-string)-1;
265 *match_length = stringlen - *skip;
268 * there may be nulls in the string in which case
269 * the pattern matchers can report CANMATCH when
270 * the null is hit. So find the null and compute
271 * the length of the possible match.
273 * Later, after we squeeze out the nulls, we will
274 * retry the match, but for now, go along with
275 * calling it a CANMATCH
281 *match_length = (p - start_search) + 1;
282 /*printf(" match_length = %d\n",*match_length);*/
284 return(EXP_CANMATCH);
287 *skip = start_search-string;
288 return(EXP_CANTMATCH);
295 The way that the "simple" interact works is that the original Expect
296 process reads from the tty and writes to the spawned process. A child
297 process is forked to read from the spawned process and write to the
298 tty. It looks like this:
317 #define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
322 static jmp_buf env; /* for interruptable read() */
323 static int reading; /* while we are reading */
324 /* really, while "env" is valid */
325 static int deferred_interrupt = FALSE; /* if signal is received, but not */
326 /* in i_read record this here, so it will */
327 /* be handled next time through i_read */
329 void sigchld_handler()
331 if (reading) longjmp(env,1);
333 deferred_interrupt = TRUE;
336 #define EXP_CHILD_EOF -100
338 /* interruptable read */
340 i_read(fd,buffer,length)
345 int cc = EXP_CHILD_EOF;
347 if (deferred_interrupt) return(cc);
349 if (0 == setjmp(env)) {
351 cc = read(fd,buffer,length);
357 /* exit status for the child process created by cmdInteract */
358 #define CHILD_DIED -2
359 #define SPAWNED_PROCESS_DIED -3
362 clean_up_after_child(interp,master)
366 /* should really be recoded using the common wait code in command.c */
371 pid = wait(&status); /* for slave */
372 for (i=0;i<=exp_fd_max;i++) {
373 if (exp_fs[i].pid == pid) {
374 exp_fs[i].sys_waited = TRUE;
375 exp_fs[i].wait = status;
378 pid = wait(&status); /* for child */
379 for (i=0;i<=exp_fd_max;i++) {
380 if (exp_fs[i].pid == pid) {
381 exp_fs[i].sys_waited = TRUE;
382 exp_fs[i].wait = status;
386 deferred_interrupt = FALSE;
387 exp_close(interp,master);
390 #endif /*SIMPLE_EVENT*/
393 update_interact_fds(interp,fd_count,fd_to_input,fd_list,input_base,
394 do_indirect,config_count,real_tty_caller)
397 struct input ***fd_to_input; /* map from fd's to "struct input"s */
399 struct input *input_base;
400 int do_indirect; /* if true do indirects */
402 int *real_tty_caller;
406 struct exp_fd_list *fdp;
409 int real_tty = FALSE;
411 *config_count = exp_configure_count;
414 for (inp = input_base;inp;inp=inp->next) {
417 /* do not update "direct" entries (again) */
418 /* they were updated upon creation */
419 if (inp->i_list->direct == EXP_INDIRECT) {
420 exp_i_update(interp,inp->i_list);
422 for (outp = inp->output;outp;outp=outp->next) {
423 if (outp->i_list->direct == EXP_INDIRECT) {
424 exp_i_update(interp,outp->i_list);
429 /* revalidate all input descriptors */
430 for (fdp = inp->i_list->fd_list;fdp;fdp=fdp->next) {
432 /* have to "adjust" just in case spawn id hasn't had */
433 /* a buffer sized yet */
434 if (!exp_fd2f(interp,fdp->fd,1,1,"interact"))
438 /* revalidate all output descriptors */
439 for (outp = inp->output;outp;outp=outp->next) {
440 for (fdp = outp->i_list->fd_list;fdp;fdp=fdp->next) {
441 /* make user_spawn_id point to stdout */
444 } else if (fdp->fd == 1) {
446 } else if (!exp_fd2f(interp,fdp->fd,1,0,"interact"))
451 if (!do_indirect) return TCL_OK;
453 if (*fd_to_input == 0) {
454 *fd_to_input = (struct input **)ckalloc(
455 (exp_fd_max+1) * sizeof(struct input *));
456 *fd_list = (int *)ckalloc(count * sizeof(int));
458 *fd_to_input = (struct input **)ckrealloc((char *)*fd_to_input,
459 (exp_fd_max+1) * sizeof(struct input *));
460 *fd_list = (int *)ckrealloc((char *)*fd_list,count * sizeof(int));
464 for (inp = input_base;inp;inp=inp->next) {
465 for (fdp = inp->i_list->fd_list;fdp;fdp=fdp->next) {
466 /* build map to translate from spawn_id to struct input */
467 (*fd_to_input)[fdp->fd] = inp;
469 /* build input to ready() */
470 (*fd_list)[count] = fdp->fd;
472 if (real_tty_input(fdp->fd)) real_tty = TRUE;
479 *real_tty_caller = real_tty; /* tell caller if we have found that */
480 /* we are using real tty */
487 inter_updateproc(clientData, interp, name1, name2, flags)
488 ClientData clientData;
489 Tcl_Interp *interp; /* Interpreter containing variable. */
490 char *name1; /* Name of variable. */
491 char *name2; /* Second part of variable name. */
492 int flags; /* Information about what happened. */
494 exp_configure_count++;
498 #define finish(x) { status = x; goto done; }
500 static char return_cmd[] = "return";
501 static char interpreter_cmd[] = "interpreter";
505 Exp_InteractCmd(clientData, interp, argc, argv)
506 ClientData clientData;
511 char *arg; /* shorthand for current argv */
514 #endif /*SIMPLE_EVENT*/
517 int input_count; /* count of struct input descriptors */
518 struct input **fd_to_input; /* map from fd's to "struct input"s */
520 struct keymap *km; /* ptr for above while parsing */
521 /* extern char *tclRegexpError; /* declared in tclInt.h */
522 int master = EXP_SPAWN_ID_BAD;
523 char *master_string = 0;/* string representation of master */
524 int need_to_close_master = FALSE; /* if an eof is received */
525 /* we use this to defer close until later */
527 int next_tty_reset = FALSE; /* if we've seen a single -reset */
528 int next_iread = FALSE;/* if we've seen a single -iread */
529 int next_iwrite = FALSE;/* if we've seen a single -iread */
530 int next_re = FALSE; /* if we've seen a single -re */
531 int next_null = FALSE; /* if we've seen the null keyword */
532 int next_writethru = FALSE;/*if macros should also go to proc output */
533 int next_indices = FALSE;/* if we should write indices */
534 int next_echo = FALSE; /* if macros should be echoed */
535 int next_timestamp = FALSE; /* if we should generate a timestamp */
536 /* int next_case_sensitive = TRUE;*/
537 char **oldargv = 0; /* save original argv here if we split it */
538 int status = TCL_OK; /* final return value */
539 int i; /* trusty temp */
541 int timeout_simple = TRUE; /* if no or global timeout */
543 int real_tty; /* TRUE if we are interacting with real tty */
544 int tty_changed = FALSE;/* true if we had to change tty modes for */
545 /* interact to work (i.e., to raw, noecho) */
550 char *replace_user_by_process = 0; /* for -u flag */
552 struct input *input_base;
553 #define input_user input_base
554 struct input *input_default;
555 struct input *inp; /* overused ptr to struct input */
556 struct output *outp; /* overused ptr to struct output */
558 int dash_input_count = 0; /* # of "-input"s seen */
559 int arbitrary_timeout;
561 struct action action_timeout; /* common to all */
562 struct action action_eof; /* common to all */
563 struct action **action_eof_ptr; /* allow -input/ouput to */
564 /* leave their eof-action assignable by a later */
566 struct action *action_base = 0;
567 struct keymap **end_km;
570 int configure_count; /* monitor reconfigure events */
572 if ((argc == 2) && exp_one_arg_braced(argv[1])) {
573 return(exp_eval_with_one_arg(clientData,interp,argv));
574 } else if ((argc == 3) && streq(argv[1],"-brace")) {
576 new_argv[0] = argv[0];
577 new_argv[1] = argv[2];
578 return(exp_eval_with_one_arg(clientData,interp,new_argv));
584 default_timeout = EXP_TIME_INFINITY;
585 arbitrary_timeout = EXP_TIME_INFINITY; /* if user specifies */
586 /* a bunch of timeouts with EXP_TIME_INFINITY, this will be */
587 /* left around for us to find. */
589 input_user = new(struct input);
590 input_user->i_list = exp_new_i_simple(0,EXP_TEMPORARY); /* stdin by default */
591 input_user->output = 0;
592 input_user->action_eof = &action_eof;
593 input_user->timeout_nominal = EXP_TIME_INFINITY;
594 input_user->action_timeout = 0;
595 input_user->keymap = 0;
597 end_km = &input_user->keymap;
599 action_eof_ptr = &input_user->action_eof;
601 input_default = new(struct input);
602 input_default->i_list = exp_new_i_simple(EXP_SPAWN_ID_BAD,EXP_TEMPORARY); /* fix up later */
603 input_default->output = 0;
604 input_default->action_eof = &action_eof;
605 input_default->timeout_nominal = EXP_TIME_INFINITY;
606 input_default->action_timeout = 0;
607 input_default->keymap = 0;
608 input_default->next = 0; /* no one else */
609 input_user->next = input_default;
611 /* default and common -eof action */
612 action_eof.statement = return_cmd;
613 action_eof.tty_reset = FALSE;
614 action_eof.iread = FALSE;
615 action_eof.iwrite = FALSE;
616 action_eof.timestamp = FALSE;
618 for (;argc>0;argc--,argv++) {
620 if (exp_flageq("eof",arg,3)) {
621 struct action *action;
624 *action_eof_ptr = action = new_action(&action_base);
626 action->statement = *argv;
628 action->tty_reset = next_tty_reset;
629 next_tty_reset = FALSE;
630 action->iwrite = next_iwrite;
632 action->iread = next_iread;
634 action->timestamp = next_timestamp;
635 next_timestamp = FALSE;
637 } else if (exp_flageq("timeout",arg,7)) {
639 struct action *action;
643 exp_error(interp,"timeout needs time");
649 /* we need an arbitrary timeout to start */
650 /* search for lowest one later */
651 if (t != -1) arbitrary_timeout = t;
653 timeout_simple = FALSE;
654 action = inp->action_timeout = new_action(&action_base);
655 inp->timeout_nominal = t;
657 action->statement = *argv;
659 action->tty_reset = next_tty_reset;
660 next_tty_reset = FALSE;
661 action->iwrite = next_iwrite;
663 action->iread = next_iread;
665 action->timestamp = next_timestamp;
666 next_timestamp = FALSE;
668 } else if (exp_flageq("null",arg,4)) {
670 } else if (arg[0] == '-') {
672 if (exp_flageq1('-',arg) /* "--" */
673 || (exp_flageq("exact",arg,3))) {
675 } else if (exp_flageq("regexp",arg,2)) {
677 exp_error(interp,"-re needs pattern");
683 } else if (exp_flageq("input",arg,2)) {
685 if (dash_input_count == 2) {
687 input_user->next = input_default;
688 } else if (dash_input_count > 2) {
689 struct input *previous_input = inp;
690 inp = new(struct input);
691 previous_input->next = inp;
694 inp->action_eof = &action_eof;
695 action_eof_ptr = &inp->action_eof;
696 inp->timeout_nominal = default_timeout;
697 inp->action_timeout = &action_timeout;
699 end_km = &inp->keymap;
703 exp_error(interp,"-input needs argument");
706 /* inp->spawn_id = atoi(*argv);*/
707 inp->i_list = exp_new_i_complex(interp,*argv,
708 EXP_TEMPORARY,inter_updateproc);
710 } else if (exp_flageq("output",arg,3)) {
713 /* imply a "-input" */
714 if (dash_input_count == 0) dash_input_count = 1;
716 outp = new(struct output);
718 /* link new output in front of others */
725 exp_error(interp,"-output needs argument");
728 outp->i_list = exp_new_i_complex(interp,*argv,
729 EXP_TEMPORARY,inter_updateproc);
731 outp->action_eof = &action_eof;
732 action_eof_ptr = &outp->action_eof;
734 } else if (exp_flageq1('u',arg)) { /* treat process as user */
737 exp_error(interp,"-u needs argument");
740 replace_user_by_process = *argv;
742 /* imply a "-input" */
743 if (dash_input_count == 0) dash_input_count = 1;
746 } else if (exp_flageq1('o',arg)) {
747 /* apply following patterns to opposite side */
750 end_km = &input_default->keymap;
752 /* imply two "-input" */
753 if (dash_input_count < 2) {
754 dash_input_count = 2;
756 action_eof_ptr = &inp->action_eof;
759 } else if (exp_flageq1('i',arg)) {
760 /* substitute master */
763 /* master = atoi(*argv);*/
764 master_string = *argv;
765 /* will be used later on */
767 end_km = &input_default->keymap;
769 /* imply two "-input" */
770 if (dash_input_count < 2) {
771 dash_input_count = 2;
773 action_eof_ptr = &inp->action_eof;
776 /* } else if (exp_flageq("nocase",arg,3)) {*/
777 /* next_case_sensitive = FALSE;*/
779 } else if (exp_flageq("echo",arg,4)) {
782 } else if (exp_flageq("nobuffer",arg,3)) {
783 next_writethru = TRUE;
785 } else if (exp_flageq("indices",arg,3)) {
788 } else if (exp_flageq1('f',arg)) {
789 /* leftover from "fast" days */
791 } else if (exp_flageq("reset",arg,5)) {
792 next_tty_reset = TRUE;
794 } else if (exp_flageq1('F',arg)) {
795 /* leftover from "fast" days */
797 } else if (exp_flageq("iread",arg,2)) {
800 } else if (exp_flageq("iwrite",arg,2)) {
803 } else if (exp_flageq("eof",arg,3)) {
804 struct action *action;
807 debuglog("-eof is deprecated, use eof\r\n");
808 *action_eof_ptr = action = new_action(&action_base);
809 action->statement = *argv;
810 action->tty_reset = next_tty_reset;
811 next_tty_reset = FALSE;
812 action->iwrite = next_iwrite;
814 action->iread = next_iread;
816 action->timestamp = next_timestamp;
817 next_timestamp = FALSE;
820 } else if (exp_flageq("timeout",arg,7)) {
822 struct action *action;
823 debuglog("-timeout is deprecated, use timeout\r\n");
827 exp_error(interp,"-timeout needs time");
834 arbitrary_timeout = t;
835 /* we need an arbitrary timeout to start */
836 /* search for lowest one later */
839 /* if -timeout comes before "-input", then applies */
840 /* to all descriptors, else just the current one */
841 if (dash_input_count > 0) {
842 timeout_simple = FALSE;
843 action = inp->action_timeout =
844 new_action(&action_base);
845 inp->timeout_nominal = t;
847 action = &action_timeout;
851 timeout_simple = FALSE;
852 action = inp->action_timeout = new_action(&action_base);
853 inp->timeout_nominal = t;
855 action->statement = *argv;
856 action->tty_reset = next_tty_reset;
857 next_tty_reset = FALSE;
858 action->iwrite = next_iwrite;
860 action->iread = next_iread;
862 action->timestamp = next_timestamp;
863 next_timestamp = FALSE;
865 } else if (exp_flageq("timestamp",arg,2)) {
866 debuglog("-timestamp is deprecated, use exp_timestamp command\r\n");
867 next_timestamp = TRUE;
869 } else if (exp_flageq("nobrace",arg,7)) {
870 /* nobrace does nothing but take up space */
871 /* on the command line which prevents */
872 /* us from re-expanding any command lines */
873 /* of one argument that looks like it should */
874 /* be expanded to multiple arguments. */
880 * pick up the pattern
883 km = new(struct keymap);
885 /* so that we can match in order user specified */
886 /* link to end of keymap list */
891 km->echo = next_echo;
892 km->writethru = next_writethru;
893 km->indices = next_indices;
894 km->action.tty_reset = next_tty_reset;
895 km->action.iwrite = next_iwrite;
896 km->action.iread = next_iread;
897 km->action.timestamp = next_timestamp;
898 /* km->case_sensitive = next_case_sensitive;*/
900 next_indices = next_echo = next_writethru = FALSE;
901 next_tty_reset = FALSE;
902 next_iwrite = next_iread = FALSE;
903 /* next_case_sensitive = TRUE;*/
910 Expect_TclRegError((char *)0);
911 if (0 == (km->re = Expect_TclRegComp(*argv))) {
912 exp_error(interp,"bad regular expression: %s",
924 km->action.statement = *argv;
925 debuglog("defining key %s, action %s\r\n",
927 km->action.statement?(dprintify(km->action.statement))
930 /* imply a "-input" */
931 if (dash_input_count == 0) dash_input_count = 1;
934 /* if the user has not supplied either "-output" for the */
935 /* default two "-input"s, fix them up here */
937 if (!input_user->output) {
938 struct output *o = new(struct output);
939 if (master_string == 0) {
940 if (0 == exp_update_master(interp,&master,1,1)) {
943 o->i_list = exp_new_i_simple(master,EXP_TEMPORARY);
945 o->i_list = exp_new_i_complex(interp,master_string,
946 EXP_TEMPORARY,inter_updateproc);
949 if (master == EXP_SPAWN_ID_BAD) {
950 if (0 == exp_update_master(interp,&master,1,1)) {
954 o->i_list = exp_new_i_simple(master,EXP_TEMPORARY);
956 o->next = 0; /* no one else */
957 o->action_eof = &action_eof;
958 input_user->output = o;
961 if (!input_default->output) {
962 struct output *o = new(struct output);
963 o->i_list = exp_new_i_simple(1,EXP_TEMPORARY);/* stdout by default */
964 o->next = 0; /* no one else */
965 o->action_eof = &action_eof;
966 input_default->output = o;
969 /* if user has given "-u" flag, substitute process for user */
970 /* in first two -inputs */
971 if (replace_user_by_process) {
972 /* through away old ones */
973 exp_free_i(interp,input_user->i_list, inter_updateproc);
974 exp_free_i(interp,input_default->output->i_list,inter_updateproc);
976 /* replace with arg to -u */
977 input_user->i_list = exp_new_i_complex(interp,
978 replace_user_by_process,
979 EXP_TEMPORARY,inter_updateproc);
980 input_default->output->i_list = exp_new_i_complex(interp,
981 replace_user_by_process,
982 EXP_TEMPORARY,inter_updateproc);
986 * now fix up for default spawn id
989 /* user could have replaced it with an indirect, so force update */
990 if (input_default->i_list->direct == EXP_INDIRECT) {
991 exp_i_update(interp,input_default->i_list);
994 if (input_default->i_list->fd_list
995 && (input_default->i_list->fd_list->fd == EXP_SPAWN_ID_BAD)) {
996 if (master_string == 0) {
997 if (0 == exp_update_master(interp,&master,1,1)) {
1000 input_default->i_list->fd_list->fd = master;
1002 /* discard old one and install new one */
1003 exp_free_i(interp,input_default->i_list,inter_updateproc);
1004 input_default->i_list = exp_new_i_complex(interp,master_string,
1005 EXP_TEMPORARY,inter_updateproc);
1008 if (master == EXP_SPAWN_ID_BAD) {
1009 if (0 == exp_update_master(interp,&master,1,1)) {
1013 input_default->i_list->fd_list->fd = master;
1018 * check for user attempting to interact with self
1019 * they're almost certainly just fooling around
1022 /* user could have replaced it with an indirect, so force update */
1023 if (input_user->i_list->direct == EXP_INDIRECT) {
1024 exp_i_update(interp,input_user->i_list);
1027 if (input_user->i_list->fd_list && input_default->i_list->fd_list
1028 && (input_user->i_list->fd_list->fd == input_default->i_list->fd_list->fd)) {
1029 exp_error(interp,"cannot interact with self - set spawn_id to a spawned process");
1036 /***************************************************************/
1037 /* all data structures are sufficiently set up that we can now */
1038 /* "finish()" to terminate this procedure */
1039 /***************************************************************/
1041 status = update_interact_fds(interp,&input_count,&fd_to_input,&fd_list,input_base,1,&configure_count,&real_tty);
1042 if (status == TCL_ERROR) finish(TCL_ERROR);
1045 tty_changed = exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);
1048 for (inp = input_base,i=0;inp;inp=inp->next,i++) {
1050 inp->timeout_remaining = inp->timeout_nominal;
1055 /* declare ourselves "in sync" with external view of close/indirect */
1056 configure_count = exp_configure_count;
1058 #ifndef SIMPLE_EVENT
1059 /* loop waiting (in event handler) for input */
1061 int te; /* result of Tcl_Eval */
1063 int rc; /* return code from ready. This is further */
1064 /* refined by matcher. */
1065 int cc; /* chars count from read() */
1067 int m_out; /* where master echoes to */
1068 struct action *action = 0;
1069 time_t previous_time;
1070 time_t current_time;
1071 int match_length, skip;
1072 int change; /* if action requires cooked mode */
1073 int attempt_match = TRUE;
1074 struct input *soonest_input;
1075 int print; /* # of chars to print */
1076 int oldprinted; /* old version of u->printed */
1078 int timeout; /* current as opposed to default_timeout */
1080 /* calculate how long to wait */
1081 /* by finding shortest remaining timeout */
1082 if (timeout_simple) {
1083 timeout = default_timeout;
1085 timeout = arbitrary_timeout;
1087 for (inp=input_base;inp;inp=inp->next) {
1088 if ((inp->timeout_remaining != EXP_TIME_INFINITY) &&
1089 (inp->timeout_remaining <= timeout)) {
1090 soonest_input = inp;
1091 timeout = inp->timeout_remaining;
1095 time(&previous_time);
1096 /* timestamp here rather than simply saving old */
1097 /* current time (after ready()) to account for */
1098 /* possibility of slow actions */
1100 /* timeout can actually be EXP_TIME_INFINITY here if user */
1101 /* explicitly supplied it in a few cases (or */
1102 /* the count-down code is broken) */
1105 /* update the world, if necessary */
1106 if (configure_count != exp_configure_count) {
1107 status = update_interact_fds(interp,&input_count,
1108 &fd_to_input,&fd_list,input_base,1,
1109 &configure_count,&real_tty);
1110 if (status) finish(status);
1113 rc = exp_get_next_event(interp,fd_list,input_count,&m,timeout,key);
1114 if (rc == EXP_TCLERROR) return(TCL_ERROR);
1116 if (rc == EXP_RECONFIGURE) continue;
1118 if (rc == EXP_TIMEOUT) {
1119 if (timeout_simple) {
1120 action = &action_timeout;
1123 action = soonest_input->action_timeout;
1124 /* arbitrarily pick first fd out of list */
1125 m = soonest_input->i_list->fd_list->fd;
1128 if (!timeout_simple) {
1131 time(¤t_time);
1132 time_diff = current_time - previous_time;
1134 /* update all timers */
1135 for (inp=input_base;inp;inp=inp->next) {
1136 if (inp->timeout_remaining != EXP_TIME_INFINITY) {
1137 inp->timeout_remaining -= time_diff;
1138 if (inp->timeout_remaining < 0)
1139 inp->timeout_remaining = 0;
1144 /* at this point, we have some kind of event which can be */
1145 /* immediately processed - i.e. something that doesn't block */
1147 /* figure out who we are */
1148 inp = fd_to_input[m];
1153 inp->timeout_remaining = inp->timeout_nominal;
1157 if (u->size == u->msize) {
1158 /* In theory, interact could be invoked when this situation */
1159 /* already exists, hence the "probably" in the warning below */
1161 debuglog("WARNING: interact buffer is full, probably because your\r\n");
1162 debuglog("patterns have matched all of it but require more chars\r\n");
1163 debuglog("in order to complete the match.\r\n");
1164 debuglog("Dumping first half of buffer in order to continue\r\n");
1165 debuglog("Recommend you enlarge the buffer or fix your patterns.\r\n");
1166 exp_buffer_shuffle(interp,u,0,INTER_OUT,"interact");
1168 cc = read(m, u->buffer + u->size,
1169 u->msize - u->size);
1173 u->buffer[u->size] = '\0';
1175 /* strip parity if requested */
1176 if (u->parity == 0) {
1177 /* do it from end backwards */
1178 char *p = u->buffer + u->size - 1;
1185 /* avoid another function call if possible */
1186 if (debugfile || is_debugging) {
1187 debuglog("spawn id %d sent <%s>\r\n",m,
1188 exp_printify(u->buffer + u->size - cc));
1194 /* Most systems have read() return 0, allowing */
1195 /* control to fall thru and into this code. On some */
1196 /* systems (currently HP and new SGI), read() does */
1197 /* see eof, and it must be detected earlier. Then */
1198 /* control jumps directly to this EXP_EOF label. */
1202 action = inp->action_eof;
1203 attempt_match = FALSE;
1205 debuglog("interact: received eof from spawn_id %d\r\n",m);
1206 /* actual close is done later so that we have a */
1207 /* chance to flush out any remaining characters */
1208 need_to_close_master = TRUE;
1211 /* should really check for remaining chars and */
1212 /* flush them but this will only happen in the */
1213 /* unlikely scenario that there are partially */
1214 /* matched buffered chars. */
1215 /* So for now, indicate no chars to skip. */
1217 exp_close(interp,m);
1224 action = inp->action_timeout;
1225 attempt_match = FALSE;
1232 if (attempt_match) {
1233 rc = in_keymap(u->buffer,u->size,inp->keymap,
1234 &km,&match_length,&skip,u->rm_nulls);
1236 attempt_match = TRUE;
1239 /* put regexp result in variables */
1241 #define out(var,val) debuglog("expect: set %s(%s) \"%s\"\r\n",INTER_OUT,var, \
1243 Tcl_SetVar2(interp,INTER_OUT,var,val,0);
1245 char name[20], value[20];
1246 Expect_regexp *re = km->re;
1247 char match_char;/* place to hold char temporarily */
1248 /* uprooted by a NULL */
1250 for (i=0;i<NSUBEXP;i++) {
1253 if (re->startp[i] == 0) continue;
1257 sprintf(name,"%d,start",i);
1258 offset = re->startp[i]-u->buffer;
1259 sprintf(value,"%d",offset);
1263 sprintf(name,"%d,end",i);
1264 sprintf(value,"%d",re->endp[i]-u->buffer-1);
1269 sprintf(name,"%d,string",i);
1270 /* temporarily null-terminate in */
1272 match_char = *re->endp[i];
1274 out(name,re->startp[i]);
1275 *re->endp[i] = match_char;
1280 * dispose of chars that should be skipped
1281 * i.e., chars that cannot possibly be part of a match.
1284 /* "skip" is count of chars not involved in match */
1285 /* "print" is count with chars involved in match */
1287 if (km && km->writethru) {
1288 print = skip + match_length;
1289 } else print = skip;
1292 * echo chars if appropriate
1294 if (km && km->echo) {
1295 int seen; /* either printed or echoed */
1297 /* echo to stdout rather than stdin */
1298 m_out = (m == 0)?1:m;
1300 /* write is unlikely to fail, since we just read */
1301 /* from same descriptor */
1302 seen = u->printed + u->echoed;
1304 write(m_out,u->buffer+skip,match_length);
1305 } else if ((match_length + skip - seen) > 0) {
1306 write(m_out,u->buffer+seen,match_length+skip-seen);
1308 u->echoed = match_length + skip - u->printed;
1311 oldprinted = u->printed;
1313 /* If expect has left characters in buffer, it has */
1314 /* already echoed them to the screen, thus we must */
1315 /* prevent them being rewritten. Unfortunately this */
1316 /* gives the possibility of matching chars that have */
1317 /* already been output, but we do so since the user */
1318 /* could have avoided it by flushing the output */
1319 /* buffers directly. */
1320 if (print > u->printed) { /* usual case */
1321 int wc; /* return code from write() */
1322 for (outp = inp->output;outp;outp=outp->next) {
1323 struct exp_fd_list *fdp;
1324 for (fdp = outp->i_list->fd_list;fdp;fdp=fdp->next) {
1325 int od; /* output descriptor */
1327 /* send to logfile if open */
1328 /* and user is seeing it */
1329 if (logfile && real_tty_output(fdp->fd)) {
1330 fwrite(u->buffer+u->printed,1,
1331 print - u->printed,logfile);
1334 /* send to each output descriptor */
1336 /* if opened by Tcl, it may use a different */
1337 /* output descriptor */
1338 od = (exp_fs[od].tcl_handle?exp_fs[od].tcl_output:od);
1340 wc = write(od,u->buffer+u->printed,
1341 print - u->printed);
1343 debuglog("interact: write on spawn id %d failed (%s)\r\n",fdp->fd,Tcl_PosixError(interp));
1344 action = outp->action_eof;
1345 change = (action && action->tty_reset);
1347 if (change && tty_changed)
1348 exp_tty_set(interp,&tty_old,was_raw,was_echo);
1349 te = inter_eval(interp,action,m);
1351 if (change && real_tty) tty_changed =
1352 exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);
1357 case EXP_TCL_RETURN:
1362 /* god knows what the user might */
1363 /* have done to us in the way of */
1364 /* closed fds, so .... */
1365 action = 0; /* reset action */
1376 /* u->printed is now accurate with respect to the buffer */
1377 /* However, we're about to shift the old data out of the */
1378 /* buffer. Thus, u->size, printed, and echoed must be */
1381 /* first update size based on skip information */
1382 /* then set skip to the total amount skipped */
1384 if (rc == EXP_MATCH) {
1385 action = &km->action;
1387 skip += match_length;
1391 memcpy(u->buffer, u->buffer + skip, u->size);
1392 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
1397 memcpy(u->buffer, u->buffer + skip, u->size);
1398 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
1403 /* as long as buffer is still around, null terminate it */
1404 if (rc != EXP_EOF) {
1405 u->buffer[u->size] = '\0';
1406 u->lower [u->size] = '\0';
1409 u->buffer[u->size] = '\0';
1410 u->lower [u->size] = '\0';
1413 /* now update printed based on total amount skipped */
1416 /* if more skipped than printed (i.e., keymap encountered) */
1417 /* for printed positive */
1418 if (u->printed < 0) u->printed = 0;
1420 /* if we are in the middle of a match, force the next event */
1421 /* to wait for more data to arrive */
1422 u->force_read = (rc == EXP_CANMATCH);
1424 /* finally reset echoed if necessary */
1425 if (rc != EXP_CANMATCH) {
1426 if (skip >= oldprinted + u->echoed) u->echoed = 0;
1429 if (rc == EXP_EOF) {
1430 exp_close(interp,m);
1431 need_to_close_master = FALSE;
1436 change = (action && action->tty_reset);
1437 if (change && tty_changed)
1438 exp_tty_set(interp,&tty_old,was_raw,was_echo);
1440 te = inter_eval(interp,action,m);
1442 if (change && real_tty) tty_changed =
1443 exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);
1448 case EXP_TCL_RETURN:
1453 /* god knows what the user might */
1454 /* have done to us in the way of */
1455 /* closed fds, so .... */
1456 action = 0; /* reset action */
1464 #else /* SIMPLE_EVENT */
1465 /* deferred_interrupt = FALSE;*/
1467 int te; /* result of Tcl_Eval */
1469 int rc; /* return code from ready. This is further */
1470 /* refined by matcher. */
1471 int cc; /* chars count from read() */
1473 struct action *action = 0;
1474 time_t previous_time;
1475 time_t current_time;
1476 int match_length, skip;
1477 int change; /* if action requires cooked mode */
1478 int attempt_match = TRUE;
1479 struct input *soonest_input;
1480 int print; /* # of chars to print */
1481 int oldprinted; /* old version of u->printed */
1483 int timeout; /* current as opposed to default_timeout */
1485 if (-1 == (pid = fork())) {
1486 exp_error(interp,"fork: %s",Tcl_PosixError(interp));
1489 if (pid == 0) { /* child - send process output to user */
1490 exp_close(interp,0);
1492 m = fd_list[1]; /* get 2nd fd */
1497 /* calculate how long to wait */
1498 /* by finding shortest remaining timeout */
1499 if (timeout_simple) {
1500 timeout = default_timeout;
1502 timeout = arbitrary_timeout;
1504 for (inp=input_base;inp;inp=inp->next) {
1505 if ((inp->timeout_remaining != EXP_TIME_INFINITY) &&
1506 (inp->timeout_remaining < timeout))
1507 soonest_input = inp;
1508 timeout = inp->timeout_remaining;
1511 time(&previous_time);
1512 /* timestamp here rather than simply saving old */
1513 /* current time (after ready()) to account for */
1514 /* possibility of slow actions */
1516 /* timeout can actually be EXP_TIME_INFINITY here if user */
1517 /* explicitly supplied it in a few cases (or */
1518 /* the count-down code is broken) */
1521 /* +1 so we can look at the "other" file descriptor */
1522 rc = exp_get_next_event(interp,fd_list+1,input_count,&m,timeout,key);
1523 if (!timeout_simple) {
1526 time(¤t_time);
1527 time_diff = current_time - previous_time;
1529 /* update all timers */
1530 for (inp=input_base;inp;inp=inp->next) {
1531 if (inp->timeout_remaining != EXP_TIME_INFINITY) {
1532 inp->timeout_remaining -= time_diff;
1533 if (inp->timeout_remaining < 0)
1534 inp->timeout_remaining = 0;
1539 /* at this point, we have some kind of event which can be */
1540 /* immediately processed - i.e. something that doesn't block */
1542 /* figure out who we are */
1543 inp = fd_to_input[m];
1549 cc = read(m, u->buffer + u->size,
1550 u->msize - u->size);
1554 u->buffer[u->size] = '\0';
1556 /* strip parity if requested */
1557 if (u->parity == 0) {
1558 /* do it from end backwards */
1559 char *p = u->buffer + u->size - 1;
1566 /* avoid another function call if possible */
1567 if (debugfile || is_debugging) {
1568 debuglog("spawn id %d sent <%s>\r\n",m,
1569 exp_printify(u->buffer + u->size - cc));
1575 /* Most systems have read() return 0, allowing */
1576 /* control to fall thru and into this code. On some */
1577 /* systems (currently HP and new SGI), read() does */
1578 /* see eof, and it must be detected earlier. Then */
1579 /* control jumps directly to this EXP_EOF label. */
1581 action = inp->action_eof;
1582 attempt_match = FALSE;
1585 debuglog("interact: child received eof from spawn_id %d\r\n",m);
1586 exp_close(interp,m);
1595 if (attempt_match) {
1596 rc = in_keymap(u->buffer,u->size,inp->keymap,
1597 &km,&match_length,&skip);
1599 attempt_match = TRUE;
1602 /* put regexp result in variables */
1604 #define INTER_OUT "interact_out"
1605 #define out(i,val) debuglog("expect: set %s(%s) \"%s\"\r\n",INTER_OUT,i, \
1607 Tcl_SetVar2(interp,INTER_OUT,i,val,0);
1609 char name[20], value[20];
1610 regexp *re = km->re;
1611 char match_char;/* place to hold char temporarily */
1612 /* uprooted by a NULL */
1614 for (i=0;i<NSUBEXP;i++) {
1617 if (re->startp[i] == 0) continue;
1621 sprintf(name,"%d,start",i);
1622 offset = re->startp[i]-u->buffer;
1623 sprintf(value,"%d",offset);
1627 sprintf(name,"%d,end",i);
1628 sprintf(value,"%d",re->endp[i]-u->buffer-1);
1633 sprintf(name,"%d,string",i);
1634 /* temporarily null-terminate in */
1636 match_char = *re->endp[i];
1638 out(name,re->startp[i]);
1639 *re->endp[i] = match_char;
1643 /* dispose of chars that should be skipped */
1645 /* skip is chars not involved in match */
1646 /* print is with chars involved in match */
1648 if (km && km->writethru) {
1649 print = skip + match_length;
1650 } else print = skip;
1652 /* figure out if we should echo any chars */
1653 if (km && km->echo) {
1654 int seen; /* either printed or echoed */
1656 /* echo to stdout rather than stdin */
1659 /* write is unlikely to fail, since we just read */
1660 /* from same descriptor */
1661 seen = u->printed + u->echoed;
1663 write(m,u->buffer+skip,match_length);
1664 } else if ((match_length + skip - seen) > 0) {
1665 write(m,u->buffer+seen,match_length+skip-seen);
1667 u->echoed = match_length + skip - u->printed;
1670 oldprinted = u->printed;
1672 /* If expect has left characters in buffer, it has */
1673 /* already echoed them to the screen, thus we must */
1674 /* prevent them being rewritten. Unfortunately this */
1675 /* gives the possibility of matching chars that have */
1676 /* already been output, but we do so since the user */
1677 /* could have avoided it by flushing the output */
1678 /* buffers directly. */
1679 if (print > u->printed) { /* usual case */
1680 int wc; /* return code from write() */
1681 for (outp = inp->output;outp;outp=outp->next) {
1682 struct exp_fd_list *fdp;
1683 for (fdp = outp->i_list->fd_list;fdp;fdp=fdp->next) {
1684 int od; /* output descriptor */
1686 /* send to logfile if open */
1687 /* and user is seeing it */
1688 if (logfile && real_tty_output(fdp->fd)) {
1689 fwrite(u->buffer+u->printed,1,
1690 print - u->printed,logfile);
1693 /* send to each output descriptor */
1695 /* if opened by Tcl, it may use a different */
1696 /* output descriptor */
1697 od = (exp_fs[od].tcl_handle?exp_fs[od].tcl_output:od);
1699 wc = write(od,u->buffer+u->printed,
1700 print - u->printed);
1702 debuglog("interact: write on spawn id %d failed (%s)\r\n",fdp->fd,Tcl_PosixError(interp));
1703 action = outp->action_eof;
1705 te = inter_eval(interp,action,m);
1711 case EXP_TCL_RETURN:
1716 /* god knows what the user might */
1717 /* have done to us in the way of */
1718 /* closed fds, so .... */
1719 action = 0; /* reset action */
1730 /* u->printed is now accurate with respect to the buffer */
1731 /* However, we're about to shift the old data out of the */
1732 /* buffer. Thus, u->size, printed, and echoed must be */
1735 /* first update size based on skip information */
1736 /* then set skip to the total amount skipped */
1738 if (rc == EXP_MATCH) {
1739 action = &km->action;
1741 skip += match_length;
1745 memcpy(u->buffer, u->buffer + skip, u->size);
1746 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
1750 memcpy(u->buffer, u->buffer + skip, u->size);
1751 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
1755 /* as long as buffer is still around, null terminate it */
1756 if (rc != EXP_EOF) {
1757 u->buffer[u->size] = '\0';
1758 u->lower [u->size] = '\0';
1760 /* now update printed based on total amount skipped */
1763 /* if more skipped than printed (i.e., keymap encountered) */
1764 /* for printed positive */
1765 if (u->printed < 0) u->printed = 0;
1767 /* if we are in the middle of a match, force the next event */
1768 /* to wait for more data to arrive */
1769 u->force_read = (rc == EXP_CANMATCH);
1771 /* finally reset echoed if necessary */
1772 if (rc != EXP_CANMATCH) {
1773 if (skip >= oldprinted + u->echoed) u->echoed = 0;
1777 te = inter_eval(interp,action,m);
1782 case EXP_TCL_RETURN:
1787 /* god knows what the user might */
1788 /* have done to us in the way of */
1789 /* closed fds, so .... */
1790 action = 0; /* reset action */
1797 } else { /* parent - send user keystrokes to process */
1800 #if defined(SIGCLD) && !defined(SIGCHLD)
1801 #define SIGCHLD SIGCLD
1803 debuglog("fork = %d\r\n",pid);
1804 signal(SIGCHLD,sigchld_handler);
1806 /* tty_changed = exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);*/
1808 m = fd_list[0]; /* get 1st fd */
1812 /* calculate how long to wait */
1813 /* by finding shortest remaining timeout */
1814 if (timeout_simple) {
1815 timeout = default_timeout;
1817 timeout = arbitrary_timeout;
1819 for (inp=input_base;inp;inp=inp->next) {
1820 if ((inp->timeout_remaining != EXP_TIME_INFINITY) &&
1821 (inp->timeout_remaining < timeout))
1822 soonest_input = inp;
1823 timeout = inp->timeout_remaining;
1826 time(&previous_time);
1827 /* timestamp here rather than simply saving old */
1828 /* current time (after ready()) to account for */
1829 /* possibility of slow actions */
1831 /* timeout can actually be EXP_TIME_INFINITY here if user */
1832 /* explicitly supplied it in a few cases (or */
1833 /* the count-down code is broken) */
1836 rc = exp_get_next_event(interp,fd_list,input_count,&m,timeout,key);
1837 if (!timeout_simple) {
1840 time(¤t_time);
1841 time_diff = current_time - previous_time;
1843 /* update all timers */
1844 for (inp=input_base;inp;inp=inp->next) {
1845 if (inp->timeout_remaining != EXP_TIME_INFINITY) {
1846 inp->timeout_remaining -= time_diff;
1847 if (inp->timeout_remaining < 0)
1848 inp->timeout_remaining = 0;
1853 /* at this point, we have some kind of event which can be */
1854 /* immediately processed - i.e. something that doesn't block */
1856 /* figure out who we are */
1857 inp = fd_to_input[m];
1863 cc = i_read(m, u->buffer + u->size,
1864 u->msize - u->size);
1868 u->buffer[u->size] = '\0';
1870 /* strip parity if requested */
1871 if (u->parity == 0) {
1872 /* do it from end backwards */
1873 char *p = u->buffer + u->size - 1;
1880 /* avoid another function call if possible */
1881 if (debugfile || is_debugging) {
1882 debuglog("spawn id %d sent <%s>\r\n",m,
1883 exp_printify(u->buffer + u->size - cc));
1886 } else if (cc == EXP_CHILD_EOF) {
1887 /* user could potentially have two outputs in which */
1888 /* case we might be looking at the wrong one, but */
1889 /* the likelihood of this is nil */
1890 action = inp->output->action_eof;
1891 attempt_match = FALSE;
1894 debuglog("interact: process died/eof\r\n");
1895 clean_up_after_child(interp,fd_list[1]);
1900 /* Most systems have read() return 0, allowing */
1901 /* control to fall thru and into this code. On some */
1902 /* systems (currently HP and new SGI), read() does */
1903 /* see eof, and it must be detected earlier. Then */
1904 /* control jumps directly to this EXP_EOF label. */
1906 action = inp->action_eof;
1907 attempt_match = FALSE;
1910 debuglog("user sent EOF or disappeared\n\n");
1919 if (attempt_match) {
1920 rc = in_keymap(u->buffer,u->size,inp->keymap,
1921 &km,&match_length,&skip);
1923 attempt_match = TRUE;
1926 /* put regexp result in variables */
1928 char name[20], value[20];
1929 regexp *re = km->re;
1930 char match_char;/* place to hold char temporarily */
1931 /* uprooted by a NULL */
1933 for (i=0;i<NSUBEXP;i++) {
1936 if (re->startp[i] == 0) continue;
1940 sprintf(name,"%d,start",i);
1941 offset = re->startp[i]-u->buffer;
1942 sprintf(value,"%d",offset);
1946 sprintf(name,"%d,end",i);
1947 sprintf(value,"%d",re->endp[i]-u->buffer-1);
1952 sprintf(name,"%d,string",i);
1953 /* temporarily null-terminate in */
1955 match_char = *re->endp[i];
1957 out(name,re->startp[i]);
1958 *re->endp[i] = match_char;
1962 /* dispose of chars that should be skipped */
1964 /* skip is chars not involved in match */
1965 /* print is with chars involved in match */
1967 if (km && km->writethru) {
1968 print = skip + match_length;
1969 } else print = skip;
1971 /* figure out if we should echo any chars */
1972 if (km && km->echo) {
1973 int seen; /* either printed or echoed */
1975 /* echo to stdout rather than stdin */
1978 /* write is unlikely to fail, since we just read */
1979 /* from same descriptor */
1980 seen = u->printed + u->echoed;
1982 write(m,u->buffer+skip,match_length);
1983 } else if ((match_length + skip - seen) > 0) {
1984 write(m,u->buffer+seen,match_length+skip-seen);
1986 u->echoed = match_length + skip - u->printed;
1989 oldprinted = u->printed;
1991 /* If expect has left characters in buffer, it has */
1992 /* already echoed them to the screen, thus we must */
1993 /* prevent them being rewritten. Unfortunately this */
1994 /* gives the possibility of matching chars that have */
1995 /* already been output, but we do so since the user */
1996 /* could have avoided it by flushing the output */
1997 /* buffers directly. */
1998 if (print > u->printed) { /* usual case */
1999 int wc; /* return code from write() */
2000 for (outp = inp->output;outp;outp=outp->next) {
2001 struct exp_fd_list *fdp;
2002 for (fdp = outp->i_list->fd_list;fdp;fdp=fdp->next) {
2003 int od; /* output descriptor */
2005 /* send to logfile if open */
2006 /* and user is seeing it */
2007 if (logfile && real_tty_output(fdp->fd)) {
2008 fwrite(u->buffer+u->printed,1,
2009 print - u->printed,logfile);
2012 /* send to each output descriptor */
2014 /* if opened by Tcl, it may use a different */
2015 /* output descriptor */
2016 od = (exp_fs[od].tcl_handle?exp_fs[od].tcl_output:od);
2018 wc = write(od,u->buffer+u->printed,
2019 print - u->printed);
2021 debuglog("interact: write on spawn id %d failed (%s)\r\n",fdp->fd,Tcl_PosixError(interp));
2022 clean_up_after_child(interp,fdp->fd);
2023 action = outp->action_eof;
2024 change = (action && action->tty_reset);
2025 if (change && tty_changed)
2026 exp_tty_set(interp,&tty_old,was_raw,was_echo);
2027 te = inter_eval(interp,action,m);
2029 if (change && real_tty) tty_changed =
2030 exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);
2035 case EXP_TCL_RETURN:
2040 /* god knows what the user might */
2041 /* have done to us in the way of */
2042 /* closed fds, so .... */
2043 action = 0; /* reset action */
2054 /* u->printed is now accurate with respect to the buffer */
2055 /* However, we're about to shift the old data out of the */
2056 /* buffer. Thus, u->size, printed, and echoed must be */
2059 /* first update size based on skip information */
2060 /* then set skip to the total amount skipped */
2062 if (rc == EXP_MATCH) {
2063 action = &km->action;
2065 skip += match_length;
2069 memcpy(u->buffer, u->buffer + skip, u->size);
2070 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
2074 memcpy(u->buffer, u->buffer + skip, u->size);
2075 exp_lowmemcpy(u->lower,u->buffer+ skip, u->size);
2079 /* as long as buffer is still around, null terminate it */
2080 if (rc != EXP_EOF) {
2081 u->buffer[u->size] = '\0';
2082 u->lower [u->size] = '\0';
2084 /* now update printed based on total amount skipped */
2087 /* if more skipped than printed (i.e., keymap encountered) */
2088 /* for printed positive */
2089 if (u->printed < 0) u->printed = 0;
2091 /* if we are in the middle of a match, force the next event */
2092 /* to wait for more data to arrive */
2093 u->force_read = (rc == EXP_CANMATCH);
2095 /* finally reset echoed if necessary */
2096 if (rc != EXP_CANMATCH) {
2097 if (skip >= oldprinted + u->echoed) u->echoed = 0;
2101 change = (action && action->tty_reset);
2102 if (change && tty_changed)
2103 exp_tty_set(interp,&tty_old,was_raw,was_echo);
2105 te = inter_eval(interp,action,m);
2107 if (change && real_tty) tty_changed =
2108 exp_tty_raw_noecho(interp,&tty_old,&was_raw,&was_echo);
2113 case EXP_TCL_RETURN:
2118 /* god knows what the user might */
2119 /* have done to us in the way of */
2120 /* closed fds, so .... */
2121 action = 0; /* reset action */
2130 #endif /* SIMPLE_EVENT */
2134 /* force child to exit upon eof from master */
2136 exit(SPAWNED_PROCESS_DIED);
2138 #endif /* SIMPLE_EVENT */
2140 if (need_to_close_master) exp_close(interp,master);
2142 if (tty_changed) exp_tty_set(interp,&tty_old,was_raw,was_echo);
2143 if (oldargv) ckfree((char *)argv);
2144 if (fd_list) ckfree((char *)fd_list);
2145 if (fd_to_input) ckfree((char *)fd_to_input);
2146 free_input(interp,input_base);
2147 free_action(action_base);
2152 /* version of Tcl_Eval for interact */
2154 inter_eval(interp,action,spawn_id)
2156 struct action *action;
2163 if (action->timestamp) {
2164 time_t current_time;
2165 time(¤t_time);
2166 exp_timestamp(interp,¤t_time,INTER_OUT);
2170 if (action->iwrite) {
2171 sprintf(value,"%d",spawn_id);
2172 out("spawn_id",value);
2175 if (action->statement) {
2176 status = Tcl_Eval(interp,action->statement);
2178 exp_nflog("\r\n",1);
2179 status = exp_interpreter(interp);
2189 if (km == 0) return;
2190 free_keymap(km->next);
2199 struct action *next;
2209 free_input(interp,i)
2214 free_input(interp,i->next);
2216 exp_free_i(interp,i->i_list,inter_updateproc);
2217 free_output(interp,i->output);
2218 free_keymap(i->keymap);
2222 static struct action *
2224 struct action **base;
2226 struct action *o = new(struct action);
2228 /* stick new action into beginning of list of all actions */
2236 free_output(interp,o)
2241 free_output(interp,o->next);
2242 exp_free_i(interp,o->i_list,inter_updateproc);
2247 static struct exp_cmd_data cmd_data[] = {
2248 {"interact", exp_proc(Exp_InteractCmd), 0, 0},
2252 exp_init_interact_cmds(interp)
2255 exp_create_commands(interp,cmd_data);