1 /* expect.c - expect commands
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 <sys/types.h>
15 #include <ctype.h> /* for isspace */
16 #include <time.h> /* for time(3) */
21 #include "expect_cf.h"
23 #ifdef HAVE_SYS_WAIT_H
35 #include "tcl_regexp.h"
36 #include "exp_rename.h"
38 #include "exp_command.h"
40 #include "exp_event.h"
42 #include "exp_tstamp.h" /* this should disappear when interact */
43 /* loses ref's to it */
48 /* initial length of strings that we can guarantee patterns can match */
49 int exp_default_match_max = 2000;
50 #define INIT_EXPECT_TIMEOUT_LIT "10" /* seconds */
51 #define INIT_EXPECT_TIMEOUT 10 /* seconds */
52 int exp_default_parity = TRUE;
53 int exp_default_rm_nulls = TRUE;
55 /* user variable names */
56 #define EXPECT_TIMEOUT "timeout"
57 #define EXPECT_OUT "expect_out"
59 /* 1 ecase struct is reserved for each case in the expect command. Note that
60 eof/timeout don't use any of theirs, but the algorithm is simpler this way. */
62 struct ecase { /* case for expect command */
64 char *pat; /* original pattern spec */
65 char *body; /* ptr to body to be executed upon match */
69 #define PAT_FULLBUFFER 4
70 #define PAT_GLOB 5 /* glob-style pattern list */
71 #define PAT_RE 6 /* regular expression */
72 #define PAT_EXACT 7 /* exact string */
73 #define PAT_NULL 8 /* ASCII 0 */
74 #define PAT_TYPES 9 /* used to size array of pattern type descriptions */
75 int use; /* PAT_XXX */
76 int simple_start;/* offset from start of buffer denoting where a */
77 /* glob or exact match begins */
78 int transfer; /* if false, leave matched chars in input stream */
79 int indices; /* if true, write indices */
80 /* int iwrite;*/ /* if true write spawn_id */
81 int iread; /* if true, reread indirects */
82 int timestamp; /* if true, write timestamps */
83 #define CASE_UNKNOWN 0
86 int Case; /* convert case before doing match? */
87 Expect_regexp *re; /* if this is 0, then pattern match via glob */
90 /* descriptions of the pattern types, used for debugging */
91 char *pattern_style[PAT_TYPES];
93 struct exp_cases_descriptor {
98 /* This describes an Expect command */
100 struct exp_cmd_descriptor {
101 int cmdtype; /* bg, before, after */
102 int duration; /* permanent or temporary */
103 int timeout_specified_by_flag; /* if -timeout flag used */
104 int timeout; /* timeout period if flag used */
105 struct exp_cases_descriptor ecd;
106 struct exp_i *i_list;
108 /* note that exp_cmds[FG] is just a fake, the real contents is stored
109 in some dynamically-allocated variable. We use exp_cmds[FG] mostly
110 as a well-known address and also as a convenience and so we allocate
111 just a few of its fields that we need. */
114 exp_cmd_init(cmd,cmdtype,duration)
115 struct exp_cmd_descriptor *cmd;
119 cmd->duration = duration;
120 cmd->cmdtype = cmdtype;
126 static int i_read_errno;/* place to save errno, if i_read() == -1, so it
127 doesn't get overwritten before we get to read it */
129 static jmp_buf env; /* for interruptable read() */
130 /* longjmp(env,1) times out the read */
131 /* longjmp(env,2) restarts the read */
132 static int env_valid = FALSE; /* whether we can longjmp or not */
136 static int alarm_fired; /* if alarm occurs */
139 void exp_background_filehandlers_run_all();
141 /* exp_indirect_updateX is called by Tcl when an indirect variable is set */
142 static char *exp_indirect_update1(); /* 1-part Tcl variable names */
143 static char *exp_indirect_update2(); /* 2-part Tcl variable names */
145 static int exp_i_read _ANSI_ARGS_((Tcl_Interp *,int,int,int));
151 int n; /* unused, for compatibility with STDC */
155 /* check env_valid first to protect us from the alarm occurring */
156 /* in the window between i_read and alarm(0) */
157 if (env_valid) longjmp(env,1);
160 #endif /*SIMPLE_EVENT*/
166 int n; /* unused, for compatibility with STDC */
169 signal(SIGALRM,sigalarm_handler);
172 /* check env_valid first to protect us from the alarm occurring */
173 /* in the window between i_read and alarm(0) */
174 if (env_valid) longjmp(env,1);
180 /* upon interrupt, act like timeout */
184 int n; /* unused, for compatibility with STDC */
187 signal(SIGINT,sigint_handler);/* not nec. for BSD, but doesn't hurt */
191 if (exp_tcl_debugger_available) {
192 /* if the debugger is active and we're reading something, */
193 /* force the debugger to go interactive now and when done, */
194 /* restart the read. */
196 Dbg_On(exp_interp,env_valid);
198 /* restart the read */
199 if (env_valid) longjmp(env,2);
201 /* if no read is in progess, just let debugger start at */
202 /* the next command. */
208 /* the ability to timeout a read via ^C is hereby removed 8-Mar-1993 - DEL */
210 /* longjmp if we are executing a read inside of expect command */
211 if (env_valid) longjmp(env,1);
214 /* if anywhere else in code, prepare to exit */
215 exp_exit(exp_interp,0);
219 /* remove nulls from s. Initially, the number of chars in s is c, */
220 /* not strlen(s). This count does not include the trailing null. */
221 /* returns number of nulls removed. */
227 char *s2 = s; /* points to place in original string to put */
228 /* next non-null character */
232 for (i=0;i<c;i++,s++) {
243 /* free up everything in ecase */
245 free_ecase(interp,ec,free_ilist)
248 int free_ilist; /* if we should free ilist */
250 if (ec->re) ckfree((char *)ec->re);
252 if (ec->i_list->duration == EXP_PERMANENT) {
253 if (ec->pat) ckfree(ec->pat);
254 if (ec->body) ckfree(ec->body);
258 ec->i_list->ecount--;
259 if (ec->i_list->ecount == 0)
260 exp_free_i(interp,ec->i_list,exp_indirect_update2);
263 ckfree((char *)ec); /* NEW */
266 /* free up any argv structures in the ecases */
268 free_ecases(interp,eg,free_ilist)
270 struct exp_cmd_descriptor *eg;
271 int free_ilist; /* if true, free ilists */
275 if (!eg->ecd.cases) return;
277 for (i=0;i<eg->ecd.count;i++) {
278 free_ecase(interp,eg->ecd.cases[i],free_ilist);
280 ckfree((char *)eg->ecd.cases);
288 /* no standard defn for this, and some systems don't even have it, so avoid */
289 /* the whole quagmire by calling it something else */
290 static char *exp_strdup(s)
293 char *news = ckalloc(strlen(s) + 1);
299 /* In many places, there is no need to malloc a copy of a string, since it */
300 /* will be freed before we return to Tcl */
302 save_str(lhs,rhs,nosave)
303 char **lhs; /* left hand side */
304 char *rhs; /* right hand side */
307 if (nosave || (rhs == 0)) {
310 *lhs = ckalloc(strlen(rhs) + 1);
315 /* return TRUE if string appears to be a set of arguments
316 The intent of this test is to support the ability of commands to have
317 all their args braced as one. This conflicts with the possibility of
318 actually intending to have a single argument.
319 The bad case is in expect which can have a single argument with embedded
320 \n's although it's rare. Examples that this code should handle:
326 \nfoo\n TRUE (set of args)
329 Current test is very cheap and almost always right :-)
332 exp_one_arg_braced(p)
350 /* called to execute a command of only one argument - a hack to commands */
351 /* to be called with all args surrounded by an outer set of braces */
352 /* returns TCL_whatever */
355 exp_eval_with_one_arg(clientData,interp,argv)
356 ClientData clientData;
364 /* + 11 is for " -nobrace " and null at end */
365 buf = ckalloc(strlen(argv[0]) + strlen(argv[1]) + 11);
366 /* recreate statement (with -nobrace to prevent recursion) */
367 sprintf(buf,"%s -nobrace %s",argv[0],argv[1]);
370 * replace top-level newlines with blanks
373 /* Should only be necessary to run over argv[1] and then sprintf */
374 /* that into the buffer, but the ICEM guys insist that writing */
375 /* back over the original arguments makes their Tcl compiler very */
378 extern char *TclWordEnd();
380 for (;isspace(*a);a++) {
381 if (*a == '\n') *a = ' ';
383 #if TCL_MAJOR_VERSION < 8
384 a = TclWordEnd(a,0,(int *)0)+1;
386 a = TclWordEnd(a,&a[strlen(a)],0,(int *)0)+1;
390 rc = Tcl_Eval(interp,buf);
405 /* ec->iwrite = FALSE;*/
407 ec->timestamp = FALSE;
409 ec->Case = CASE_NORM;
413 static struct ecase *
416 struct ecase *ec = (struct ecase *)ckalloc(sizeof(struct ecase));
424 parse_expect_args parses the arguments to expect or its variants.
425 It normally returns TCL_OK, and returns TCL_ERROR for failure.
426 (It can't return i_list directly because there is no way to differentiate
427 between clearing, say, expect_before and signalling an error.)
429 eg (expect_global) is initialized to reflect the arguments parsed
430 eg->ecd.cases is an array of ecases
431 eg->ecd.count is the # of ecases
432 eg->i_list is a linked list of exp_i's which represent the -i info
434 Each exp_i is chained to the next so that they can be easily free'd if
435 necessary. Each exp_i has a reference count. If the -i is not used
436 (e.g., has no following patterns), the ref count will be 0.
438 Each ecase points to an exp_i. Several ecases may point to the same exp_i.
439 Variables named by indirect exp_i's are read for the direct values.
441 If called from a foreground expect and no patterns or -i are given, a
442 default exp_i is forced so that the command "expect" works right.
444 The exp_i chain can be broken by the caller if desired.
449 parse_expect_args(interp,eg,default_spawn_id,argc,argv)
451 struct exp_cmd_descriptor *eg;
452 int default_spawn_id; /* suggested master if called as expect_user or _tty */
458 struct ecase ec; /* temporary to collect args */
463 eg->timeout_specified_by_flag = FALSE;
467 /* Allocate an array to store the ecases. Force array even if 0 */
468 /* cases. This will often be too large (i.e., if there are flags) */
469 /* but won't affect anything. */
471 eg->ecd.cases = (struct ecase **)ckalloc(
472 sizeof(struct ecase *) * (1+(argc/2)));
476 for (i = 0;i<argc;i++) {
479 if (exp_flageq("timeout",arg,7)) {
480 ec.use = PAT_TIMEOUT;
481 } else if (exp_flageq("eof",arg,3)) {
483 } else if (exp_flageq("full_buffer",arg,11)) {
484 ec.use = PAT_FULLBUFFER;
485 } else if (exp_flageq("default",arg,7)) {
486 ec.use = PAT_DEFAULT;
487 } else if (exp_flageq("null",arg,4)) {
489 } else if (arg[0] == '-') {
491 if (exp_flageq1('-',arg) /* "--" is deprecated */
492 || exp_flageq("glob",arg,2)) {
494 /* assignment here is not actually necessary */
495 /* since cases are initialized this way above */
496 /* ec.use = PAT_GLOB; */
497 } else if (exp_flageq("regexp",arg,2)) {
500 Expect_TclRegError((char *)0);
501 if (!(ec.re = Expect_TclRegComp(argv[i]))) {
502 exp_error(interp,"bad regular expression: %s",
506 } else if (exp_flageq("exact",arg,2)) {
509 } else if (exp_flageq("notransfer",arg,1)) {
512 } else if (exp_flageq("nocase",arg,3)) {
513 ec.Case = CASE_LOWER;
515 } else if (exp_flageq1('i',arg)) {
518 exp_error(interp,"-i requires following spawn_id");
522 ec.i_list = exp_new_i_complex(interp,argv[i],
523 eg->duration,exp_indirect_update2);
525 ec.i_list->cmdtype = eg->cmdtype;
527 /* link new i_list to head of list */
528 ec.i_list->next = eg->i_list;
529 eg->i_list = ec.i_list;
532 } else if (exp_flageq("indices",arg,2)) {
535 } else if (exp_flageq("iwrite",arg,2)) {
536 /* ec.iwrite = TRUE;*/
538 } else if (exp_flageq("iread",arg,2)) {
541 } else if (exp_flageq("timestamp",arg,2)) {
544 } else if (exp_flageq("timeout",arg,2)) {
547 exp_error(interp,"-timeout requires following # of seconds");
551 eg->timeout = atoi(argv[i]);
552 eg->timeout_specified_by_flag = TRUE;
554 } else if (exp_flageq("nobrace",arg,7)) {
555 /* nobrace does nothing but take up space */
556 /* on the command line which prevents */
557 /* us from re-expanding any command lines */
558 /* of one argument that looks like it should */
559 /* be expanded to multiple arguments. */
562 exp_error(interp,"usage: unrecognized flag <%s>",arg);
567 /* if no -i, use previous one */
569 /* if no -i flag has occurred yet, use default */
571 if (default_spawn_id != EXP_SPAWN_ID_BAD) {
572 eg->i_list = exp_new_i_simple(default_spawn_id,eg->duration);
574 /* it'll be checked later, if used */
575 (void) exp_update_master(interp,&default_spawn_id,0,0);
576 eg->i_list = exp_new_i_simple(default_spawn_id,eg->duration);
579 ec.i_list = eg->i_list;
583 /* save original pattern spec */
584 /* keywords such as "-timeout" are saved as patterns here */
585 /* useful for debugging but not otherwise used */
586 save_str(&ec.pat,argv[i],eg->duration == EXP_TEMPORARY);
587 save_str(&ec.body,argv[i+1],eg->duration == EXP_TEMPORARY);
591 *(eg->ecd.cases[eg->ecd.count] = ecase_new()) = ec;
593 /* clear out for next set */
599 /* if no patterns at all have appeared force the current */
600 /* spawn id to be added to list anyway */
602 if (eg->i_list == 0) {
603 if (default_spawn_id != EXP_SPAWN_ID_BAD) {
604 eg->i_list = exp_new_i_simple(default_spawn_id,eg->duration);
606 /* it'll be checked later, if used */
607 (void) exp_update_master(interp,&default_spawn_id,0,0);
608 eg->i_list = exp_new_i_simple(default_spawn_id,eg->duration);
615 /* very hard to free case_master_list here if it hasn't already */
616 /* been attached to a case, ugh */
618 /* note that i_list must be avail to free ecases! */
619 free_ecases(interp,eg,0);
621 /* undo temporary ecase */
622 /* free_ecase doesn't quite handle this right, so do it by hand */
623 if (ec.re) ckfree((char *)ec.re);
624 if (eg->duration == EXP_PERMANENT) {
625 if (ec.pat) ckfree(ec.pat);
626 if (ec.body) ckfree(ec.body);
630 exp_free_i(interp,eg->i_list,exp_indirect_update2);
634 #define EXP_IS_DEFAULT(x) ((x) == EXP_TIMEOUT || (x) == EXP_EOF)
636 static char yes[] = "yes\r\n";
637 static char no[] = "no\r\n";
639 /* this describes status of a successful match */
641 struct ecase *e; /* ecase that matched */
642 struct exp_f *f; /* struct exp_f that matched */
643 char *buffer; /* buffer that matched */
644 int match; /* # of chars in buffer that matched */
645 /* or # of chars in buffer at EOF */
649 /* like eval_cases, but handles only a single cases that needs a real */
651 /* returns EXP_X where X is MATCH, NOMATCH, FULLBUFFER, TCLERRROR */
653 eval_case_string(interp,e,m,o,last_f,last_case,suffix)
657 struct eval_out *o; /* 'output' - i.e., final case of interest */
658 /* next two args are for debugging, when they change, reprint buffer */
659 struct exp_f **last_f;
663 struct exp_f *f = exp_fs + m;
666 /* if -nocase, use the lowerized buffer */
667 buffer = ((e->Case == CASE_NORM)?f->buffer:f->lower);
669 /* if master or case changed, redisplay debug-buffer */
670 if ((f != *last_f) || e->Case != *last_case) {
671 debuglog("\r\nexpect%s: does \"%s\" (spawn_id %d) match %s ",
673 dprintify(buffer),f-exp_fs,
674 pattern_style[e->use]);
676 *last_case = e->Case;
679 if (e->use == PAT_RE) {
680 debuglog("\"%s\"? ",dprintify(e->pat));
681 Expect_TclRegError((char *)0);
682 if (buffer && Expect_TclRegExec(e->re,buffer,buffer)) {
684 o->match = e->re->endp[0]-buffer;
691 if (TclGetRegError()) {
692 exp_error(interp,"-re failed: %s",TclGetRegError());
693 return(EXP_TCLERROR);
696 } else if (e->use == PAT_GLOB) {
697 int match; /* # of chars that matched */
699 debuglog("\"%s\"? ",dprintify(e->pat));
700 if (buffer && (-1 != (match = Exp_StringMatch(
701 buffer,e->pat,&e->simple_start)))) {
709 } else if (e->use == PAT_EXACT) {
710 char *p = strstr(buffer,e->pat);
711 debuglog("\"%s\"? ",dprintify(e->pat));
713 e->simple_start = p - buffer;
715 o->match = strlen(e->pat);
721 } else if (e->use == PAT_NULL) {
724 for (;i<f->size;i++) {
725 if (buffer[i] == 0) {
727 o->match = i+1; /* in this case, match is */
728 /* just the # of chars + 1 */
729 /* before the null */
737 } else if ((f->size == f->msize) && (f->size > 0)) {
738 debuglog("%s? ",e->pat);
740 o->match = f->umsize;
741 o->buffer = f->buffer;
744 return(EXP_FULLBUFFER);
749 /* sets o.e if successfully finds a matching pattern, eof, timeout or deflt */
750 /* returns original status arg or EXP_TCLERROR */
752 eval_cases(interp,eg,m,o,last_f,last_case,status,masters,mcount,suffix)
754 struct exp_cmd_descriptor *eg;
756 struct eval_out *o; /* 'output' - i.e., final case of interest */
757 /* next two args are for debugging, when they change, reprint buffer */
758 struct exp_f **last_f;
766 int em; /* master of ecase */
769 if (o->e || status == EXP_TCLERROR || eg->ecd.count == 0) return(status);
771 if (status == EXP_TIMEOUT) {
772 for (i=0;i<eg->ecd.count;i++) {
773 e = eg->ecd.cases[i];
774 if (e->use == PAT_TIMEOUT || e->use == PAT_DEFAULT) {
780 } else if (status == EXP_EOF) {
781 for (i=0;i<eg->ecd.count;i++) {
782 e = eg->ecd.cases[i];
783 if (e->use == PAT_EOF || e->use == PAT_DEFAULT) {
784 struct exp_fd_list *fdl;
786 for (fdl=e->i_list->fd_list; fdl ;fdl=fdl->next) {
788 if (em == EXP_SPAWN_ID_ANY || em == m) {
798 /* the top loops are split from the bottom loop only because I can't */
799 /* split'em further. */
801 /* The bufferful condition does not prevent a pattern match from */
802 /* occurring and vice versa, so it is scanned with patterns */
803 for (i=0;i<eg->ecd.count;i++) {
804 struct exp_fd_list *fdl;
807 e = eg->ecd.cases[i];
808 if (e->use == PAT_TIMEOUT ||
809 e->use == PAT_DEFAULT ||
810 e->use == PAT_EOF) continue;
812 for (fdl = e->i_list->fd_list; fdl; fdl = fdl->next) {
814 /* if em == EXP_SPAWN_ID_ANY, then user is explicitly asking */
815 /* every case to be checked against every master */
816 if (em == EXP_SPAWN_ID_ANY) {
817 /* test against each spawn_id */
818 for (j=0;j<mcount;j++) {
819 status = eval_case_string(interp,e,masters[j],o,last_f,last_case,suffix);
820 if (status != EXP_NOMATCH) return(status);
823 /* reject things immediately from wrong spawn_id */
824 if (em != m) continue;
826 status = eval_case_string(interp,e,m,o,last_f,last_case,suffix);
827 if (status != EXP_NOMATCH) return(status);
835 ecases_remove_by_expi(interp,ecmd,exp_i)
837 struct exp_cmd_descriptor *ecmd;
842 /* delete every ecase dependent on it */
843 for (i=0;i<ecmd->ecd.count;) {
844 struct ecase *e = ecmd->ecd.cases[i];
845 if (e->i_list == exp_i) {
846 free_ecase(interp,e,0);
848 /* shift remaining elements down */
849 /* but only if there are any left */
850 if (i+1 != ecmd->ecd.count) {
851 memcpy(&ecmd->ecd.cases[i],
852 &ecmd->ecd.cases[i+1],
853 ((ecmd->ecd.count - i) - 1) *
854 sizeof(struct exp_cmd_descriptor *));
857 if (0 == ecmd->ecd.count) {
858 ckfree((char *)ecmd->ecd.cases);
867 /* remove exp_i from list */
869 exp_i_remove(interp,ei,exp_i)
871 struct exp_i **ei; /* list to remove from */
872 struct exp_i *exp_i; /* element to remove */
874 /* since it's in middle of list, free exp_i by hand */
875 for (;*ei; ei = &(*ei)->next) {
879 exp_free_i(interp,exp_i,exp_indirect_update2);
885 /* remove exp_i from list and remove any dependent ecases */
887 exp_i_remove_with_ecases(interp,ecmd,exp_i)
889 struct exp_cmd_descriptor *ecmd;
892 ecases_remove_by_expi(interp,ecmd,exp_i);
893 exp_i_remove(interp,&ecmd->i_list,exp_i);
896 /* remove ecases tied to a single direct spawn id */
898 ecmd_remove_fd(interp,ecmd,m,direct)
900 struct exp_cmd_descriptor *ecmd;
904 struct exp_i *exp_i, *next;
905 struct exp_fd_list **fdl;
907 for (exp_i=ecmd->i_list;exp_i;exp_i=next) {
910 if (!(direct & exp_i->direct)) continue;
912 for (fdl = &exp_i->fd_list;*fdl;) {
913 if (m == ((*fdl)->fd)) {
914 struct exp_fd_list *tmp = *fdl;
916 exp_free_fd_single(tmp);
918 /* if last bg ecase, disarm spawn id */
919 if ((ecmd->cmdtype == EXP_CMD_BG) && (m != EXP_SPAWN_ID_ANY)) {
920 exp_fs[m].bg_ecount--;
921 if (exp_fs[m].bg_ecount == 0) {
922 exp_disarm_background_filehandler(m);
923 exp_fs[m].bg_interp = 0;
932 /* if left with no fds (and is direct), get rid of it */
933 /* and any dependent ecases */
934 if (exp_i->direct == EXP_DIRECT && !exp_i->fd_list) {
935 exp_i_remove_with_ecases(interp,ecmd,exp_i);
940 /* this is called from exp_close to clean up the fd */
942 exp_ecmd_remove_fd_direct_and_indirect(interp,m)
946 ecmd_remove_fd(interp,&exp_cmds[EXP_CMD_BEFORE],m,EXP_DIRECT|EXP_INDIRECT);
947 ecmd_remove_fd(interp,&exp_cmds[EXP_CMD_AFTER],m,EXP_DIRECT|EXP_INDIRECT);
948 ecmd_remove_fd(interp,&exp_cmds[EXP_CMD_BG],m,EXP_DIRECT|EXP_INDIRECT);
950 /* force it - explanation in exp_tk.c where this func is defined */
951 exp_disarm_background_filehandler_force(m);
954 /* arm a list of background fd's */
956 fd_list_arm(interp,fdl)
958 struct exp_fd_list *fdl;
960 /* for each spawn id in list, arm if necessary */
961 for (;fdl;fdl=fdl->next) {
963 if (m == EXP_SPAWN_ID_ANY) continue;
965 if (exp_fs[m].bg_ecount == 0) {
966 exp_arm_background_filehandler(m);
967 exp_fs[m].bg_interp = interp;
969 exp_fs[m].bg_ecount++;
973 /* return TRUE if this ecase is used by this fd */
975 exp_i_uses_fd(exp_i,fd)
979 struct exp_fd_list *fdp;
981 for (fdp = exp_i->fd_list;fdp;fdp=fdp->next) {
982 if (fdp->fd == fd) return 1;
988 ecase_append(interp,ec)
992 if (!ec->transfer) Tcl_AppendElement(interp,"-notransfer");
993 if (ec->indices) Tcl_AppendElement(interp,"-indices");
994 /* if (ec->iwrite) Tcl_AppendElement(interp,"-iwrite");*/
995 if (!ec->Case) Tcl_AppendElement(interp,"-nocase");
997 if (ec->re) Tcl_AppendElement(interp,"-re");
998 else if (ec->use == PAT_GLOB) Tcl_AppendElement(interp,"-gl");
999 else if (ec->use == PAT_EXACT) Tcl_AppendElement(interp,"-ex");
1000 Tcl_AppendElement(interp,ec->pat);
1001 Tcl_AppendElement(interp,ec->body?ec->body:"");
1004 /* append all ecases that match this exp_i */
1006 ecase_by_exp_i_append(interp,ecmd,exp_i)
1008 struct exp_cmd_descriptor *ecmd;
1009 struct exp_i *exp_i;
1012 for (i=0;i<ecmd->ecd.count;i++) {
1013 if (ecmd->ecd.cases[i]->i_list == exp_i) {
1014 ecase_append(interp,ecmd->ecd.cases[i]);
1020 exp_i_append(interp,exp_i)
1022 struct exp_i *exp_i;
1024 Tcl_AppendElement(interp,"-i");
1025 if (exp_i->direct == EXP_INDIRECT) {
1026 Tcl_AppendElement(interp,exp_i->variable);
1028 struct exp_fd_list *fdp;
1030 /* if more than one element, add braces */
1031 if (exp_i->fd_list->next)
1032 Tcl_AppendResult(interp," {",(char *)0);
1034 for (fdp = exp_i->fd_list;fdp;fdp=fdp->next) {
1035 char buf[10]; /* big enough for a small int */
1036 sprintf(buf,"%d",fdp->fd);
1037 Tcl_AppendElement(interp,buf);
1040 if (exp_i->fd_list->next)
1041 Tcl_AppendResult(interp,"} ",(char *)0);
1046 /* delete ecases based on named -i descriptors */
1048 expect_delete(interp,ecmd,argc,argv)
1050 struct exp_cmd_descriptor *ecmd;
1055 if (streq(argv[0],"-i") && argv[1]) {
1058 } else if (streq(argv[0],"-all")) {
1061 } else if (streq(argv[0],"-noindirect")) {
1062 direct &= ~EXP_INDIRECT;
1065 exp_error(interp,"usage: -delete [-all | -i spawn_id]\n");
1071 /* same logic as at end of regular expect cmd */
1072 free_ecases(interp,ecmd,0);
1073 exp_free_i(interp,ecmd->i_list,exp_indirect_update2);
1078 if (0 == exp_update_master(interp,&m,0,0)) {
1081 } else if (Tcl_GetInt(interp,iflag,&m) != TCL_OK) {
1082 /* handle as in indirect */
1084 struct exp_i **old_i;
1086 for (old_i=&ecmd->i_list;*old_i;) {
1089 if ((*old_i)->direct == EXP_DIRECT) continue;
1090 if (!streq((*old_i)->variable,iflag)) continue;
1092 ecases_remove_by_expi(interp,ecmd,*old_i);
1094 /* unlink from middle of list */
1098 exp_free_i(interp,tmp_i,exp_indirect_update2);
1100 old_i = &(*old_i)->next;
1105 /* delete ecases of this direct_fd */
1106 /* unfinish after this ... */
1107 for (exp_i=ecmd->i_list;exp_i;exp_i=exp_i->next) {
1108 if (!(direct & exp_i->direct)) continue;
1109 if (!exp_i_uses_fd(exp_i,m)) continue;
1111 /* delete each ecase that uses this exp_i */
1114 ecase_by_exp_i_append(interp,ecmd,exp_i);
1121 /* return current setting of the permanent expect_before/after/bg */
1123 expect_info(interp,ecmd,argc,argv)
1125 struct exp_cmd_descriptor *ecmd;
1129 struct exp_i *exp_i;
1131 int direct = EXP_DIRECT|EXP_INDIRECT;
1133 int all = FALSE; /* report on all fds */
1137 if (streq(argv[0],"-i") && argv[1]) {
1140 } else if (streq(argv[0],"-all")) {
1143 } else if (streq(argv[0],"-noindirect")) {
1144 direct &= ~EXP_INDIRECT;
1147 exp_error(interp,"usage: -info [-all | -i spawn_id]\n");
1153 /* avoid printing out -i when redundant */
1154 struct exp_i *previous = 0;
1156 for (i=0;i<ecmd->ecd.count;i++) {
1157 if (previous != ecmd->ecd.cases[i]->i_list) {
1158 exp_i_append(interp,ecmd->ecd.cases[i]->i_list);
1159 previous = ecmd->ecd.cases[i]->i_list;
1161 ecase_append(interp,ecmd->ecd.cases[i]);
1167 if (0 == exp_update_master(interp,&m,0,0)) {
1170 } else if (Tcl_GetInt(interp,iflag,&m) != TCL_OK) {
1171 /* handle as in indirect */
1172 Tcl_ResetResult(interp);
1173 for (i=0;i<ecmd->ecd.count;i++) {
1174 if (ecmd->ecd.cases[i]->i_list->direct == EXP_INDIRECT &&
1175 streq(ecmd->ecd.cases[i]->i_list->variable,iflag)) {
1176 ecase_append(interp,ecmd->ecd.cases[i]);
1182 /* print ecases of this direct_fd */
1183 for (exp_i=ecmd->i_list;exp_i;exp_i=exp_i->next) {
1184 if (!(direct & exp_i->direct)) continue;
1185 if (!exp_i_uses_fd(exp_i,m)) continue;
1186 ecase_by_exp_i_append(interp,ecmd,exp_i);
1192 /* Exp_ExpectGlobalCmd is invoked to process expect_before/after */
1195 Exp_ExpectGlobalCmd(clientData, interp, argc, argv)
1196 ClientData clientData;
1201 int result = TCL_OK;
1202 struct exp_i *exp_i, **eip;
1203 struct exp_fd_list *fdl; /* temp for interating over fd_list */
1204 struct exp_cmd_descriptor eg;
1207 struct exp_cmd_descriptor *ecmd = (struct exp_cmd_descriptor *) clientData;
1209 if ((argc == 2) && exp_one_arg_braced(argv[1])) {
1210 return(exp_eval_with_one_arg(clientData,interp,argv));
1211 } else if ((argc == 3) && streq(argv[1],"-brace")) {
1213 new_argv[0] = argv[0];
1214 new_argv[1] = argv[2];
1215 return(exp_eval_with_one_arg(clientData,interp,new_argv));
1218 if (argc > 1 && (argv[1][0] == '-')) {
1219 if (exp_flageq("info",&argv[1][1],4)) {
1220 return(expect_info(interp,ecmd,argc-2,argv+2));
1224 exp_cmd_init(&eg,ecmd->cmdtype,EXP_PERMANENT);
1226 if (TCL_ERROR == parse_expect_args(interp,&eg,EXP_SPAWN_ID_BAD,
1232 * visit each NEW direct exp_i looking for spawn ids.
1233 * When found, remove them from any OLD exp_i's.
1236 /* visit each exp_i */
1237 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1238 if (exp_i->direct == EXP_INDIRECT) continue;
1240 /* for each spawn id, remove it from ecases */
1241 for (fdl=exp_i->fd_list;fdl;fdl=fdl->next) {
1244 /* validate all input descriptors */
1245 if (m != EXP_SPAWN_ID_ANY) {
1246 if (!exp_fd2f(interp,m,1,1,"expect")) {
1252 /* remove spawn id from exp_i */
1253 ecmd_remove_fd(interp,ecmd,m,EXP_DIRECT);
1258 * For each indirect variable, release its old ecases and
1259 * clean up the matching spawn ids.
1260 * Same logic as in "expect_X delete" command.
1263 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1264 struct exp_i **old_i;
1266 if (exp_i->direct == EXP_DIRECT) continue;
1268 for (old_i = &ecmd->i_list;*old_i;) {
1271 if (((*old_i)->direct == EXP_DIRECT) ||
1272 (!streq((*old_i)->variable,exp_i->variable))) {
1273 old_i = &(*old_i)->next;
1277 ecases_remove_by_expi(interp,ecmd,*old_i);
1279 /* unlink from middle of list */
1283 exp_free_i(interp,tmp,exp_indirect_update2);
1286 /* if new one has ecases, update it */
1287 if (exp_i->ecount) {
1288 char *msg = exp_indirect_update1(interp,ecmd,exp_i);
1290 /* unusual way of handling error return */
1291 /* because of Tcl's variable tracing */
1292 strcpy(interp->result,msg);
1294 goto indirect_update_abort;
1298 /* empty i_lists have to be removed from global eg.i_list */
1299 /* before returning, even if during error */
1300 indirect_update_abort:
1303 * New exp_i's that have 0 ecases indicate fd/vars to be deleted.
1304 * Now that the deletions have been done, discard the new exp_i's.
1307 for (exp_i=eg.i_list;exp_i;) {
1308 struct exp_i *next = exp_i->next;
1310 if (exp_i->ecount == 0) {
1311 exp_i_remove(interp,&eg.i_list,exp_i);
1315 if (result == TCL_ERROR) goto cleanup;
1318 * arm all new bg direct fds
1321 if (ecmd->cmdtype == EXP_CMD_BG) {
1322 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1323 if (exp_i->direct == EXP_DIRECT) {
1324 fd_list_arm(interp,exp_i->fd_list);
1330 * now that old ecases are gone, add new ecases and exp_i's (both
1331 * direct and indirect).
1336 count = ecmd->ecd.count + eg.ecd.count;
1338 int start_index; /* where to add new ecases in old list */
1340 if (ecmd->ecd.count) {
1342 ecmd->ecd.cases = (struct ecase **)ckrealloc((char *)ecmd->ecd.cases, count * sizeof(struct ecase *));
1343 start_index = ecmd->ecd.count;
1345 /* append to beginning */
1346 ecmd->ecd.cases = (struct ecase **)ckalloc(eg.ecd.count * sizeof(struct ecase *));
1349 memcpy(&ecmd->ecd.cases[start_index],eg.ecd.cases,
1350 eg.ecd.count*sizeof(struct ecase *));
1351 ecmd->ecd.count = count;
1354 /* append exp_i's */
1355 for (eip = &ecmd->i_list;*eip;eip = &(*eip)->next) {
1356 /* empty loop to get to end of list */
1358 /* *exp_i now points to end of list */
1360 *eip = eg.i_list; /* connect new list to end of current list */
1363 if (result == TCL_ERROR) {
1364 /* in event of error, free any unreferenced ecases */
1365 /* but first, split up i_list so that exp_i's aren't */
1368 for (exp_i=eg.i_list;exp_i;) {
1369 struct exp_i *next = exp_i->next;
1373 free_ecases(interp,&eg,1);
1375 if (eg.ecd.cases) ckfree((char *)eg.ecd.cases);
1378 if (ecmd->cmdtype == EXP_CMD_BG) {
1379 exp_background_filehandlers_run_all();
1385 /* adjusts file according to user's size request */
1392 /* get the latest buffer size. Double the user input for */
1393 /* two reasons. 1) Need twice the space in case the match */
1394 /* straddles two bufferfuls, 2) easier to hack the division */
1395 /* by two when shifting the buffers later on. The extra */
1396 /* byte in the malloc's is just space for a null we can slam on the */
1397 /* end. It makes the logic easier later. The -1 here is so that */
1398 /* requests actually come out to even/word boundaries (if user */
1399 /* gives "reasonable" requests) */
1400 new_msize = f->umsize*2 - 1;
1401 if (new_msize != f->msize) {
1403 /* allocate buffer space for 1st time */
1404 f->buffer = ckalloc((unsigned)new_msize+1);
1405 f->lower = ckalloc((unsigned)new_msize+1);
1408 /* buffer already exists - resize */
1410 /* if truncated, forget about some data */
1411 if (f->size > new_msize) {
1412 /* copy end of buffer down */
1413 memmove(f->buffer,f->buffer+(f->size - new_msize),new_msize);
1414 memmove(f->lower, f->lower +(f->size - new_msize),new_msize);
1415 f->size = new_msize;
1417 f->key = expect_key++;
1420 f->buffer = ckrealloc(f->buffer,new_msize+1);
1421 f->lower = ckrealloc(f->lower,new_msize+1);
1423 f->msize = new_msize;
1424 f->buffer[f->size] = '\0';
1425 f->lower[f->size] = '\0';
1432 expect_read() does the logical equivalent of a read() for the
1433 expect command. This includes figuring out which descriptor should
1436 The result of the read() is left in a spawn_id's buffer rather than
1437 explicitly passing it back. Note that if someone else has modified a
1438 buffer either before or while this expect is running (i.e., if we or
1439 some event has called Tcl_Eval which did another expect/interact),
1440 expect_read will also call this a successful read (for the purposes if
1441 needing to pattern match against it).
1444 /* if it returns a negative number, it corresponds to a EXP_XXX result */
1445 /* if it returns a non-negative number, it means there is data */
1446 /* (0 means nothing new was actually read, but it should be looked at again) */
1448 expect_read(interp,masters,masters_max,m,timeout,key)
1450 int *masters; /* If 0, then m is already known and set. */
1451 int masters_max; /* If *masters is not-zero, then masters_max */
1452 /* is the number of masters. */
1453 /* If *masters is zero, then masters_max */
1454 /* is used as the mask (ready vs except). */
1455 /* Crude but simplifies the interface. */
1456 int *m; /* Out variable to leave new master. */
1463 int tcl_set_flags; /* if we have to discard chars, this tells */
1464 /* whether to show user locally or globally */
1467 /* we already know the master, just find out what happened */
1468 cc = exp_get_next_event_info(interp,*m,masters_max);
1469 tcl_set_flags = TCL_GLOBAL_ONLY;
1471 cc = exp_get_next_event(interp,masters,masters_max,m,timeout,key);
1475 if (cc == EXP_DATA_NEW) {
1476 /* try to read it */
1478 cc = exp_i_read(interp,*m,timeout,tcl_set_flags);
1480 /* the meaning of 0 from i_read means eof. Muck with it a */
1481 /* little, so that from now on it means "no new data arrived */
1482 /* but it should be looked at again anyway". */
1485 } else if (cc > 0) {
1487 f->buffer[f->size += cc] = '\0';
1489 /* strip parity if requested */
1490 if (f->parity == 0) {
1491 /* do it from end backwards */
1492 char *p = f->buffer + f->size - 1;
1499 assert(cc < 0) in which case some sort of error was
1500 encountered such as an interrupt with that forced an
1503 } else if (cc == EXP_DATA_OLD) {
1506 } else if (cc == EXP_RECONFIGURE) {
1507 return EXP_RECONFIGURE;
1510 if (cc == EXP_ABEOF) { /* abnormal EOF */
1511 /* On many systems, ptys produce EIO upon EOF - sigh */
1512 if (i_read_errno == EIO) {
1513 /* Sun, Cray, BSD, and others */
1515 } else if (i_read_errno == EINVAL) {
1516 /* Solaris 2.4 occasionally returns this */
1519 if (i_read_errno == EBADF) {
1520 exp_error(interp,"bad spawn_id (process died earlier?)");
1522 exp_error(interp,"i_read(spawn_id=%d): %s",*m,
1523 Tcl_PosixError(interp));
1524 exp_close(interp,*m);
1526 return(EXP_TCLERROR);
1527 /* was goto error; */
1531 /* EOF, TIMEOUT, and ERROR return here */
1532 /* In such cases, there is no need to update screen since, if there */
1533 /* was prior data read, it would have been sent to the screen when */
1535 if (cc < 0) return (cc);
1537 /* update display */
1539 if (f->size) write_count = f->size - f->printed;
1540 else write_count = 0;
1543 if (logfile_all || (loguser && logfile)) {
1544 fwrite(f->buffer + f->printed,1,write_count,logfile);
1546 /* don't write to user if they're seeing it already, */
1547 /* that is, typing it! */
1548 if (loguser && !exp_is_stdinfd(*m) && !exp_is_devttyfd(*m))
1549 fwrite(f->buffer + f->printed,
1550 1,write_count,stdout);
1551 if (debugfile) fwrite(f->buffer + f->printed,
1552 1,write_count,debugfile);
1554 /* remove nulls from input, since there is no way */
1555 /* for Tcl to deal with such strings. Doing it here */
1556 /* lets them be sent to the screen, just in case */
1557 /* they are involved in formatting operations */
1559 f->size -= rm_nulls(f->buffer + f->printed,write_count);
1561 f->buffer[f->size] = '\0';
1563 /* copy to lowercase buffer */
1564 exp_lowmemcpy(f->lower+f->printed,
1565 f->buffer+f->printed,
1566 1 + f->size - f->printed);
1568 f->printed = f->size; /* count'm even if not logging */
1573 /* when buffer fills, copy second half over first and */
1574 /* continue, so we can do matches over multiple buffers */
1576 exp_buffer_shuffle(interp,f,save_flags,array_name,caller_name)
1583 char spawn_id[10]; /* enough for a %d */
1584 char match_char; /* place to hold char temporarily */
1585 /* uprooted by a NULL */
1587 int first_half = f->size/2;
1588 int second_half = f->size - first_half;
1591 * allow user to see data we are discarding
1594 sprintf(spawn_id,"%d",f-exp_fs);
1595 debuglog("%s: set %s(spawn_id) \"%s\"\r\n",
1596 caller_name,array_name,dprintify(spawn_id));
1597 Tcl_SetVar2(interp,array_name,"spawn_id",spawn_id,save_flags);
1599 /* temporarily null-terminate buffer in middle */
1600 match_char = f->buffer[first_half];
1601 f->buffer[first_half] = 0;
1603 debuglog("%s: set %s(buffer) \"%s\"\r\n",
1604 caller_name,array_name,dprintify(f->buffer));
1605 Tcl_SetVar2(interp,array_name,"buffer",f->buffer,save_flags);
1607 /* remove middle-null-terminator */
1608 f->buffer[first_half] = match_char;
1610 memcpy(f->buffer,f->buffer+first_half,second_half);
1611 memcpy(f->lower, f->lower +first_half,second_half);
1612 f->size = second_half;
1613 f->printed -= first_half;
1614 if (f->printed < 0) f->printed = 0;
1617 /* map EXP_ style return value to TCL_ style return value */
1618 /* not defined to work on TCL_OK */
1620 exp_tcl2_returnvalue(x)
1624 case TCL_ERROR: return EXP_TCLERROR;
1625 case TCL_RETURN: return EXP_TCLRET;
1626 case TCL_BREAK: return EXP_TCLBRK;
1627 case TCL_CONTINUE: return EXP_TCLCNT;
1628 case EXP_CONTINUE: return EXP_TCLCNTEXP;
1629 case EXP_CONTINUE_TIMER: return EXP_TCLCNTTIMER;
1630 case EXP_TCL_RETURN: return EXP_TCLRETTCL;
1634 /* map from EXP_ style return value to TCL_ style return values */
1636 exp_2tcl_returnvalue(x)
1640 case EXP_TCLERROR: return TCL_ERROR;
1641 case EXP_TCLRET: return TCL_RETURN;
1642 case EXP_TCLBRK: return TCL_BREAK;
1643 case EXP_TCLCNT: return TCL_CONTINUE;
1644 case EXP_TCLCNTEXP: return EXP_CONTINUE;
1645 case EXP_TCLCNTTIMER: return EXP_CONTINUE_TIMER;
1646 case EXP_TCLRETTCL: return EXP_TCL_RETURN;
1650 /* returns # of chars read or (non-positive) error of form EXP_XXX */
1651 /* returns 0 for end of file */
1652 /* If timeout is non-zero, set an alarm before doing the read, else assume */
1653 /* the read will complete immediately. */
1656 exp_i_read(interp,m,timeout,save_flags)
1663 int cc = EXP_TIMEOUT;
1666 if (f->size == f->msize)
1667 exp_buffer_shuffle(interp,f,save_flags,EXPECT_OUT,"expect");
1672 alarm_fired = FALSE;
1675 signal(SIGALRM,sigalarm_handler);
1676 alarm((timeout > 0)?timeout:1);
1680 cc = read(m,f->buffer+f->size, f->msize-f->size);
1681 i_read_errno = errno;
1687 /* check if alarm went off */
1688 if (i_read_errno == EINTR) {
1692 if (Tcl_AsyncReady()) {
1693 int rc = Tcl_AsyncInvoke(interp,TCL_OK);
1694 if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
1697 exp_error(interp,"spawn_id %d no longer valid",f-exp_fs);
1698 return EXP_TCLERROR;
1708 /* variables predefined by expect are retrieved using this routine
1709 which looks in the global space if they are not in the local space.
1710 This allows the user to localize them if desired, and also to
1711 avoid having to put "global" in procedure definitions.
1714 exp_get_var(interp,var)
1720 if (NULL != (val = Tcl_GetVar(interp,var,0 /* local */)))
1722 return(Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY));
1729 static int timeout = INIT_EXPECT_TIMEOUT;
1732 if (NULL != (t = exp_get_var(interp,EXPECT_TIMEOUT))) {
1738 /* make a copy of a linked list (1st arg) and attach to end of another (2nd
1741 update_expect_fds(i_list,fd_union)
1742 struct exp_i *i_list;
1743 struct exp_fd_list **fd_union;
1747 /* for each i_list in an expect statement ... */
1748 for (p=i_list;p;p=p->next) {
1749 struct exp_fd_list *fdl;
1751 /* for each fd in the i_list */
1752 for (fdl=p->fd_list;fdl;fdl=fdl->next) {
1753 struct exp_fd_list *tmpfdl;
1754 struct exp_fd_list *u;
1756 if (fdl->fd == EXP_SPAWN_ID_ANY) continue;
1758 /* check this one against all so far */
1759 for (u = *fd_union;u;u=u->next) {
1760 if (fdl->fd == u->fd) goto found;
1762 /* if not found, link in as head of list */
1763 tmpfdl = exp_new_fd(fdl->fd);
1764 tmpfdl->next = *fd_union;
1773 exp_cmdtype_printable(cmdtype)
1777 case EXP_CMD_FG: return("expect");
1778 case EXP_CMD_BG: return("expect_background");
1779 case EXP_CMD_BEFORE: return("expect_before");
1780 case EXP_CMD_AFTER: return("expect_after");
1783 return("unknown expect command");
1787 /* exp_indirect_update2 is called back via Tcl's trace handler whenever */
1788 /* an indirect spawn id list is changed */
1791 exp_indirect_update2(clientData, interp, name1, name2, flags)
1792 ClientData clientData;
1793 Tcl_Interp *interp; /* Interpreter containing variable. */
1794 char *name1; /* Name of variable. */
1795 char *name2; /* Second part of variable name. */
1796 int flags; /* Information about what happened. */
1800 struct exp_i *exp_i = (struct exp_i *)clientData;
1801 exp_configure_count++;
1802 msg = exp_indirect_update1(interp,&exp_cmds[exp_i->cmdtype],exp_i);
1804 exp_background_filehandlers_run_all();
1810 exp_indirect_update1(interp,ecmd,exp_i)
1812 struct exp_cmd_descriptor *ecmd;
1813 struct exp_i *exp_i;
1815 struct exp_fd_list *fdl; /* temp for interating over fd_list */
1818 * disarm any fd's that lose all their ecases
1821 if (ecmd->cmdtype == EXP_CMD_BG) {
1822 /* clean up each spawn id used by this exp_i */
1823 for (fdl=exp_i->fd_list;fdl;fdl=fdl->next) {
1826 if (m == EXP_SPAWN_ID_ANY) continue;
1828 /* silently skip closed or preposterous fds */
1829 /* since we're just disabling them anyway */
1830 /* preposterous fds will have been reported */
1831 /* by code in next section already */
1832 if (!exp_fd2f(interp,fdl->fd,1,0,"")) continue;
1834 exp_fs[m].bg_ecount--;
1835 if (exp_fs[m].bg_ecount == 0) {
1836 exp_disarm_background_filehandler(m);
1837 exp_fs[m].bg_interp = 0;
1843 * reread indirect variable
1846 exp_i_update(interp,exp_i);
1849 * check validity of all fd's in variable
1852 for (fdl=exp_i->fd_list;fdl;fdl=fdl->next) {
1853 /* validate all input descriptors */
1854 if (fdl->fd == EXP_SPAWN_ID_ANY) continue;
1856 if (!exp_fd2f(interp,fdl->fd,1,1,
1857 exp_cmdtype_printable(ecmd->cmdtype))) {
1858 static char msg[200];
1859 sprintf(msg,"%s from indirect variable (%s)",
1860 interp->result,exp_i->variable);
1865 /* for each spawn id in list, arm if necessary */
1866 if (ecmd->cmdtype == EXP_CMD_BG) {
1867 fd_list_arm(interp,exp_i->fd_list);
1874 exp_background_filehandlers_run_all()
1879 /* kick off any that already have input waiting */
1880 for (m=0;m<=exp_fd_max;m++) {
1882 if (!f->valid) continue;
1884 /* is bg_interp the best way to check if armed? */
1885 if (f->bg_interp && (f->size > 0)) {
1886 exp_background_filehandler((ClientData)f->fd_ptr,0/*ignored*/);
1891 /* this function is called from the background when input arrives */
1894 exp_background_filehandler(clientData,mask)
1895 ClientData clientData;
1901 int cc; /* number of chars returned in a single read */
1902 /* or negative EXP_whatever */
1903 struct exp_f *f; /* file associated with master */
1905 int i; /* trusty temporary */
1907 struct eval_out eo; /* final case of interest */
1908 struct exp_f *last_f; /* for differentiating when multiple f's */
1909 /* to print out better debugging messages */
1910 int last_case; /* as above but for case */
1912 /* restore our environment */
1913 m = *(int *)clientData;
1915 interp = f->bg_interp;
1917 /* temporarily prevent this handler from being invoked again */
1918 exp_block_background_filehandler(m);
1920 /* if mask == 0, then we've been called because the patterns changed */
1921 /* not because the waiting data has changed, so don't actually do */
1927 cc = expect_read(interp,(int *)0,mask,&m,EXP_TIME_INFINITY,0);
1931 eo.e = 0; /* no final case yet */
1932 eo.f = 0; /* no final file selected yet */
1933 eo.match = 0; /* nothing matched yet */
1935 /* force redisplay of buffer when debugging */
1938 if (cc == EXP_EOF) {
1940 } else if (cc < 0) { /* EXP_TCLERROR or any other weird value*/
1942 /* if we were going to do this right, we should */
1943 /* differentiate between things like HP ioctl-open-traps */
1944 /* that fall out here and should rightfully be ignored */
1945 /* and real errors that should be reported. Come to */
1946 /* think of it, the only errors will come from HP */
1947 /* ioctl handshake botches anyway. */
1949 /* normal case, got data */
1950 /* new data if cc > 0, same old data if cc == 0 */
1952 /* below here, cc as general status */
1956 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BEFORE],
1957 m,&eo,&last_f,&last_case,cc,&m,1,"_background");
1958 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BG],
1959 m,&eo,&last_f,&last_case,cc,&m,1,"_background");
1960 cc = eval_cases(interp,&exp_cmds[EXP_CMD_AFTER],
1961 m,&eo,&last_f,&last_case,cc,&m,1,"_background");
1962 if (cc == EXP_TCLERROR) {
1963 /* only likely problem here is some internal regexp botch */
1964 Tcl_BackgroundError(interp);
1967 /* special eof code that cannot be done in eval_cases */
1968 /* or above, because it would then be executed several times */
1969 if (cc == EXP_EOF) {
1971 eo.match = eo.f->size;
1972 eo.buffer = eo.f->buffer;
1973 debuglog("expect_background: read eof\r\n");
1977 /* if we get here, there must not have been a match */
1982 #define out(i,val) debuglog("expect_background: set %s(%s) \"%s\"\r\n",EXPECT_OUT,i, \
1984 Tcl_SetVar2(interp,EXPECT_OUT,i,val,TCL_GLOBAL_ONLY);
1986 /* int iwrite = FALSE;*/ /* write spawn_id? */
1988 char *buffer; /* pointer to normal or lowercased data */
1989 struct ecase *e = 0; /* points to current ecase */
1990 int match = -1; /* characters matched */
1991 char match_char; /* place to hold char temporarily */
1992 /* uprooted by a NULL */
1998 /* iwrite = e->iwrite;*/
1999 if (cc != EXP_TIMEOUT) {
2008 time(¤t_time);
2009 elapsed_time = current_time - start_time;
2010 elapsed_time_total = current_time - start_time_total;
2011 sprintf(value,"%d",elapsed_time);
2012 out("seconds",value);
2013 sprintf(value,"%d",elapsed_time_total);
2014 out("seconds_total",value);
2016 exp_timestamp(interp,¤t_time,EXPECT_OUT);
2019 } else if (cc == EXP_EOF) {
2020 /* read an eof but no user-supplied case */
2027 char name[20], value[20];
2029 if (e && e->use == PAT_RE) {
2030 Expect_regexp *re = e->re;
2032 for (i=0;i<NSUBEXP;i++) {
2035 if (re->startp[i] == 0) continue;
2039 sprintf(name,"%d,start",i);
2040 offset = re->startp[i]-buffer;
2041 sprintf(value,"%d",offset);
2045 sprintf(name,"%d,end",i);
2047 re->endp[i]-buffer-1);
2052 sprintf(name,"%d,string",i);
2054 /* temporarily null-terminate in */
2056 match_char = *re->endp[i];
2058 out(name,re->startp[i]);
2059 *re->endp[i] = match_char;
2061 /* redefine length of string that */
2062 /* matched for later extraction */
2063 match = re->endp[0]-buffer;
2064 } else if (e && (e->use == PAT_GLOB || e->use == PAT_EXACT)) {
2069 sprintf(value,"%d",e->simple_start);
2070 out("0,start",value);
2073 sprintf(value,"%d",e->simple_start + match - 1);
2078 str = f->buffer + e->simple_start;
2079 /* temporarily null-terminate in middle */
2080 match_char = str[match];
2082 out("0,string",str);
2083 str[match] = match_char;
2085 /* redefine length of string that */
2086 /* matched for later extraction */
2087 match += e->simple_start;
2088 } else if (e && e->use == PAT_NULL && e->indices) {
2090 sprintf(value,"%d",match-1);
2091 out("0,start",value);
2093 sprintf(value,"%d",match-1);
2095 } else if (e && e->use == PAT_FULLBUFFER) {
2096 debuglog("expect_background: full buffer\r\n");
2100 /* this is broken out of (match > 0) (above) since it can */
2101 /* that an EOF occurred with match == 0 */
2103 char spawn_id[10]; /* enough for a %d */
2106 sprintf(spawn_id,"%d",f-exp_fs);
2107 out("spawn_id",spawn_id);
2110 /* save buf[0..match] */
2111 /* temporarily null-terminate string in middle */
2112 match_char = f->buffer[match];
2113 f->buffer[match] = 0;
2114 out("buffer",f->buffer);
2115 /* remove middle-null-terminator */
2116 f->buffer[match] = match_char;
2118 /* "!e" means no case matched - transfer by default */
2119 if (!e || e->transfer) {
2120 /* delete matched chars from input buffer */
2122 f->printed -= match;
2124 memmove(f->buffer,f->buffer+match,f->size);
2125 memmove(f->lower,f->lower+match,f->size);
2127 f->buffer[f->size] = '\0';
2128 f->lower[f->size] = '\0';
2131 if (cc == EXP_EOF) {
2132 /* exp_close() deletes all background bodies */
2133 /* so save eof body temporarily */
2135 eof_body = ckalloc(strlen(body)+1);
2136 strcpy(eof_body,body);
2140 exp_close(interp,f - exp_fs);
2146 int result = Tcl_GlobalEval(interp,body);
2147 if (result != TCL_OK) Tcl_BackgroundError(interp);
2149 if (eof_body) ckfree(eof_body);
2154 * Event handler will not call us back if there is more input
2155 * pending but it has already arrived. bg_status will be
2156 * "blocked" only if armed.
2158 if (exp_fs[m].valid && (exp_fs[m].bg_status == blocked)
2165 /* fd could have gone away, so check before using */
2166 if (exp_fs[m].valid)
2167 exp_unblock_background_filehandler(m);
2173 Exp_ExpectCmd(clientData, interp, argc, argv)
2174 ClientData clientData;
2179 int cc; /* number of chars returned in a single read */
2180 /* or negative EXP_whatever */
2181 int m; /* before doing an actual read, attempt */
2182 /* to match upon any spawn_id */
2183 struct exp_f *f; /* file associated with master */
2185 int i; /* trusty temporary */
2186 struct exp_cmd_descriptor eg;
2187 struct exp_fd_list *fd_list; /* list of masters to watch */
2188 struct exp_fd_list *fdl; /* temp for interating over fd_list */
2189 int *masters; /* array of masters to watch */
2190 int mcount; /* number of masters to watch */
2192 struct eval_out eo; /* final case of interest */
2194 int result; /* Tcl result */
2196 time_t start_time_total;/* time at beginning of this procedure */
2197 time_t start_time = 0; /* time when restart label hit */
2198 time_t current_time = 0;/* current time (when we last looked)*/
2199 time_t end_time; /* future time at which to give up */
2200 time_t elapsed_time_total;/* time from now to match/fail/timeout */
2201 time_t elapsed_time; /* time from restart to (ditto) */
2203 struct exp_f *last_f; /* for differentiating when multiple f's */
2204 /* to print out better debugging messages */
2205 int last_case; /* as above but for case */
2206 int first_time = 1; /* if not "restarted" */
2208 int key; /* identify this expect command instance */
2209 int configure_count; /* monitor exp_configure_count */
2211 int timeout; /* seconds */
2212 int remtime; /* remaining time in timeout */
2213 int reset_timer; /* should timer be reset after continue? */
2215 if ((argc == 2) && exp_one_arg_braced(argv[1])) {
2216 return(exp_eval_with_one_arg(clientData,interp,argv));
2217 } else if ((argc == 3) && streq(argv[1],"-brace")) {
2219 new_argv[0] = argv[0];
2220 new_argv[1] = argv[2];
2221 return(exp_eval_with_one_arg(clientData,interp,new_argv));
2224 time(&start_time_total);
2225 start_time = start_time_total;
2228 /* make arg list for processing cases */
2229 /* do it dynamically, since expect can be called recursively */
2231 exp_cmd_init(&eg,EXP_CMD_FG,EXP_TEMPORARY);
2234 if (TCL_ERROR == parse_expect_args(interp,&eg,
2235 *(int *)clientData,argc,argv))
2238 restart_with_update:
2239 /* validate all descriptors */
2240 /* and flatten fds into array */
2242 if ((TCL_ERROR == update_expect_fds(exp_cmds[EXP_CMD_BEFORE].i_list,&fd_list))
2243 || (TCL_ERROR == update_expect_fds(exp_cmds[EXP_CMD_AFTER].i_list, &fd_list))
2244 || (TCL_ERROR == update_expect_fds(eg.i_list,&fd_list))) {
2249 /* declare ourselves "in sync" with external view of close/indirect */
2250 configure_count = exp_configure_count;
2252 /* count and validate fd_list */
2254 for (fdl=fd_list;fdl;fdl=fdl->next) {
2256 /* validate all input descriptors */
2257 if (!exp_fd2f(interp,fdl->fd,1,1,"expect")) {
2263 /* make into an array */
2264 masters = (int *)ckalloc(mcount * sizeof(int));
2265 for (fdl=fd_list,i=0;fdl;fdl=fdl->next,i++) {
2266 masters[i] = fdl->fd;
2270 if (first_time) first_time = 0;
2271 else time(&start_time);
2273 if (eg.timeout_specified_by_flag) {
2274 timeout = eg.timeout;
2276 /* get the latest timeout */
2277 timeout = get_timeout(interp);
2285 /* end of restart code */
2287 eo.e = 0; /* no final case yet */
2288 eo.f = 0; /* no final file selected yet */
2289 eo.match = 0; /* nothing matched yet */
2291 /* timeout code is a little tricky, be very careful changing it */
2292 if (timeout != EXP_TIME_INFINITY) {
2293 /* if exp_continue -continue_timer, do not update end_time */
2295 time(¤t_time);
2296 end_time = current_time + timeout;
2302 /* remtime and current_time updated at bottom of loop */
2306 if ((timeout != EXP_TIME_INFINITY) && (remtime < 0)) {
2309 cc = expect_read(interp,masters,mcount,&m,remtime,key);
2313 if (cc == EXP_EOF) {
2315 } else if (cc == EXP_TIMEOUT) {
2316 debuglog("expect: timed out\r\n");
2317 } else if (cc == EXP_RECONFIGURE) {
2318 reset_timer = FALSE;
2319 goto restart_with_update;
2320 } else if (cc < 0) { /* EXP_TCLERROR or any other weird value*/
2323 /* new data if cc > 0, same old data if cc == 0 */
2327 /* below here, cc as general status */
2330 /* force redisplay of buffer when debugging */
2334 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BEFORE],
2335 m,&eo,&last_f,&last_case,cc,masters,mcount,"");
2336 cc = eval_cases(interp,&eg,
2337 m,&eo,&last_f,&last_case,cc,masters,mcount,"");
2338 cc = eval_cases(interp,&exp_cmds[EXP_CMD_AFTER],
2339 m,&eo,&last_f,&last_case,cc,masters,mcount,"");
2340 if (cc == EXP_TCLERROR) goto error;
2341 /* special eof code that cannot be done in eval_cases */
2342 /* or above, because it would then be executed several times */
2343 if (cc == EXP_EOF) {
2345 eo.match = eo.f->size;
2346 eo.buffer = eo.f->buffer;
2347 debuglog("expect: read eof\r\n");
2349 } else if (cc == EXP_TIMEOUT) break;
2350 /* break if timeout or eof and failed to find a case for it */
2354 /* no match was made with current data, force a read */
2355 f->force_read = TRUE;
2357 if (timeout != EXP_TIME_INFINITY) {
2358 time(¤t_time);
2359 remtime = end_time - current_time;
2366 result = exp_2tcl_returnvalue(cc);
2368 #define out(i,val) debuglog("expect: set %s(%s) \"%s\"\r\n",EXPECT_OUT,i, \
2370 Tcl_SetVar2(interp,EXPECT_OUT,i,val,0);
2372 if (result != TCL_ERROR) {
2373 /* int iwrite = FALSE;*/ /* write spawn_id? */
2375 char *buffer; /* pointer to normal or lowercased data */
2376 struct ecase *e = 0; /* points to current ecase */
2377 int match = -1; /* characters matched */
2378 char match_char; /* place to hold char temporarily */
2379 /* uprooted by a NULL */
2385 /* iwrite = e->iwrite;*/
2386 if (cc != EXP_TIMEOUT) {
2394 time(¤t_time);
2395 elapsed_time = current_time - start_time;
2396 elapsed_time_total = current_time - start_time_total;
2397 sprintf(value,"%d",elapsed_time);
2398 out("seconds",value);
2399 sprintf(value,"%d",elapsed_time_total);
2400 out("seconds_total",value);
2403 exp_timestamp(interp,¤t_time,EXPECT_OUT);
2405 } else if (cc == EXP_EOF) {
2406 /* read an eof but no user-supplied case */
2413 char name[20], value[20];
2415 if (e && e->use == PAT_RE) {
2416 Expect_regexp *re = e->re;
2418 for (i=0;i<NSUBEXP;i++) {
2421 if (re->startp[i] == 0) continue;
2425 sprintf(name,"%d,start",i);
2426 offset = re->startp[i]-buffer;
2427 sprintf(value,"%d",offset);
2431 sprintf(name,"%d,end",i);
2433 re->endp[i]-buffer-1);
2438 sprintf(name,"%d,string",i);
2440 /* temporarily null-terminate in */
2442 match_char = *re->endp[i];
2444 out(name,re->startp[i]);
2445 *re->endp[i] = match_char;
2447 /* redefine length of string that */
2448 /* matched for later extraction */
2449 match = re->endp[0]-buffer;
2450 } else if (e && (e->use == PAT_GLOB || e->use == PAT_EXACT)) {
2455 sprintf(value,"%d",e->simple_start);
2456 out("0,start",value);
2459 sprintf(value,"%d",e->simple_start + match - 1);
2464 str = f->buffer + e->simple_start;
2465 /* temporarily null-terminate in middle */
2466 match_char = str[match];
2468 out("0,string",str);
2469 str[match] = match_char;
2471 /* redefine length of string that */
2472 /* matched for later extraction */
2473 match += e->simple_start;
2474 } else if (e && e->use == PAT_NULL && e->indices) {
2476 sprintf(value,"%d",match-1);
2477 out("0,start",value);
2479 sprintf(value,"%d",match-1);
2481 } else if (e && e->use == PAT_FULLBUFFER) {
2482 debuglog("expect: full buffer\r\n");
2486 /* this is broken out of (match > 0) (above) since it can */
2487 /* that an EOF occurred with match == 0 */
2489 char spawn_id[10]; /* enough for a %d */
2492 sprintf(spawn_id,"%d",f-exp_fs);
2493 out("spawn_id",spawn_id);
2496 /* save buf[0..match] */
2497 /* temporarily null-terminate string in middle */
2498 match_char = f->buffer[match];
2499 f->buffer[match] = 0;
2500 out("buffer",f->buffer);
2501 /* remove middle-null-terminator */
2502 f->buffer[match] = match_char;
2504 /* "!e" means no case matched - transfer by default */
2505 if (!e || e->transfer) {
2506 /* delete matched chars from input buffer */
2508 f->printed -= match;
2510 memmove(f->buffer,f->buffer+match,f->size);
2511 memmove(f->lower,f->lower+match,f->size);
2513 f->buffer[f->size] = '\0';
2514 f->lower[f->size] = '\0';
2517 if (cc == EXP_EOF) {
2518 /* exp_close() deletes all background bodies */
2519 /* so save eof body temporarily */
2521 eof_body = ckalloc(strlen(body)+1);
2522 strcpy(eof_body,body);
2526 exp_close(interp,f - exp_fs);
2532 result = Tcl_Eval(interp,body);
2534 if (eof_body) ckfree(eof_body);
2539 if (result == EXP_CONTINUE_TIMER) {
2540 reset_timer = FALSE;
2541 result = EXP_CONTINUE;
2544 if ((result == EXP_CONTINUE)
2545 && (configure_count == exp_configure_count)) {
2546 debuglog("expect: continuing expect\r\n");
2551 exp_free_fd(fd_list);
2555 ckfree((char *)masters);
2559 if (result == EXP_CONTINUE) {
2560 debuglog("expect: continuing expect after update\r\n");
2561 goto restart_with_update;
2564 free_ecases(interp,&eg,0); /* requires i_lists to be avail */
2565 exp_free_i(interp,eg.i_list,exp_indirect_update2);
2571 /* beginning of deprecated code */
2573 #define out(elt) Tcl_SetVar2(interp,array,elt,ascii,0);
2575 exp_timestamp(interp,timeval,array)
2583 tm = localtime(timeval); /* split */
2584 ascii = asctime(tm); /* print */
2585 ascii[24] = '\0'; /* zap trailing \n */
2589 sprintf(ascii,"%ld",*timeval);
2592 sprintf(ascii,"%d",tm->tm_sec);
2594 sprintf(ascii,"%d",tm->tm_min);
2596 sprintf(ascii,"%d",tm->tm_hour);
2598 sprintf(ascii,"%d",tm->tm_mday);
2600 sprintf(ascii,"%d",tm->tm_mon);
2602 sprintf(ascii,"%d",tm->tm_year);
2604 sprintf(ascii,"%d",tm->tm_wday);
2606 sprintf(ascii,"%d",tm->tm_yday);
2608 sprintf(ascii,"%d",tm->tm_isdst);
2611 /* end of deprecated code */
2615 Exp_TimestampCmd(clientData, interp, argc, argv)
2616 ClientData clientData;
2622 time_t seconds = -1;
2623 int gmt = FALSE; /* local time by default */
2625 Tcl_DString dstring;
2630 if (streq(*argv,"-format")) {
2632 if (!*argv) goto usage_error;
2635 } else if (streq(*argv,"-seconds")) {
2637 if (!*argv) goto usage_error;
2638 seconds = atoi(*argv);
2640 } else if (streq(*argv,"-gmt")) {
2646 if (argc) goto usage_error;
2648 if (seconds == -1) {
2652 Tcl_DStringInit(&dstring);
2656 tm = gmtime(&seconds);
2658 tm = localtime(&seconds);
2660 /* exp_strftime(interp->result,TCL_RESULT_SIZE,format,tm);*/
2661 exp_strftime(format,tm,&dstring);
2662 Tcl_DStringResult(interp,&dstring);
2664 sprintf(interp->result,"%ld",seconds);
2669 exp_error(interp,"args: [-seconds #] [-format format]");
2674 /* lowmemcpy - like memcpy but it lowercases result */
2676 exp_lowmemcpy(dest,src,n)
2682 *dest = ((isascii(*src) && isupper(*src))?tolower(*src):*src);
2689 Exp_MatchMaxCmd(clientData,interp,argc,argv)
2690 ClientData clientData;
2698 int Default = FALSE;
2702 for (;argc>0;argc--,argv++) {
2703 if (streq(*argv,"-d")) {
2705 } else if (streq(*argv,"-i")) {
2708 exp_error(interp,"-i needs argument");
2717 if (!(f = exp_update_master(interp,&m,0,0)))
2720 if (!(f = exp_fd2f(interp,m,0,0,"match_max")))
2723 } else if (m != -1) {
2724 exp_error(interp,"cannot do -d and -i at the same time");
2730 size = exp_default_match_max;
2734 sprintf(interp->result,"%d",size);
2739 exp_error(interp,"too many arguments");
2743 /* all that's left is to set the size */
2744 size = atoi(argv[0]);
2746 exp_error(interp,"must be positive");
2750 if (Default) exp_default_match_max = size;
2751 else f->umsize = size;
2758 Exp_RemoveNullsCmd(clientData,interp,argc,argv)
2759 ClientData clientData;
2767 int Default = FALSE;
2771 for (;argc>0;argc--,argv++) {
2772 if (streq(*argv,"-d")) {
2774 } else if (streq(*argv,"-i")) {
2777 exp_error(interp,"-i needs argument");
2786 if (!(f = exp_update_master(interp,&m,0,0)))
2789 if (!(f = exp_fd2f(interp,m,0,0,"remove_nulls")))
2792 } else if (m != -1) {
2793 exp_error(interp,"cannot do -d and -i at the same time");
2799 value = exp_default_match_max;
2801 value = f->rm_nulls;
2803 sprintf(interp->result,"%d",value);
2808 exp_error(interp,"too many arguments");
2812 /* all that's left is to set the value */
2813 value = atoi(argv[0]);
2814 if (value != 0 && value != 1) {
2815 exp_error(interp,"must be 0 or 1");
2819 if (Default) exp_default_rm_nulls = value;
2820 else f->rm_nulls = value;
2827 Exp_ParityCmd(clientData,interp,argc,argv)
2828 ClientData clientData;
2836 int Default = FALSE;
2840 for (;argc>0;argc--,argv++) {
2841 if (streq(*argv,"-d")) {
2843 } else if (streq(*argv,"-i")) {
2846 exp_error(interp,"-i needs argument");
2855 if (!(f = exp_update_master(interp,&m,0,0)))
2858 if (!(f = exp_fd2f(interp,m,0,0,"parity")))
2861 } else if (m != -1) {
2862 exp_error(interp,"cannot do -d and -i at the same time");
2868 parity = exp_default_parity;
2872 sprintf(interp->result,"%d",parity);
2877 exp_error(interp,"too many arguments");
2881 /* all that's left is to set the parity */
2882 parity = atoi(argv[0]);
2884 if (Default) exp_default_parity = parity;
2885 else f->parity = parity;
2890 #if DEBUG_PERM_ECASES
2891 /* This big chunk of code is just for debugging the permanent */
2895 struct exp_fd_list *fdl;
2898 printf("%d ",fdl->fd);
2899 exp_fd_print(fdl->next);
2904 struct exp_i *exp_i;
2907 printf("exp_i %x",exp_i);
2908 printf((exp_i->direct == EXP_DIRECT)?" direct":" indirect");
2909 printf((exp_i->duration == EXP_PERMANENT)?" perm":" tmp");
2910 printf(" ecount = %d\n",exp_i->ecount);
2911 printf("variable %s, value %s\n",
2912 ((exp_i->variable)?exp_i->variable:"--"),
2913 ((exp_i->value)?exp_i->value:"--"));
2915 exp_fd_print(exp_i->fd_list); printf("\n");
2916 exp_i_print(exp_i->next);
2920 exp_ecase_print(ecase)
2921 struct ecase *ecase;
2923 printf("pat <%s>\n",ecase->pat);
2924 printf("exp_i = %x\n",ecase->i_list);
2928 exp_ecases_print(ecd)
2929 struct exp_cases_descriptor *ecd;
2933 printf("%d cases\n",ecd->count);
2934 for (i=0;i<ecd->count;i++) exp_ecase_print(ecd->cases[i]);
2939 struct exp_cmd_descriptor *ecmd;
2941 printf("expect cmd type: %17s",exp_cmdtype_printable(ecmd->cmdtype));
2942 printf((ecmd->duration==EXP_PERMANENT)?" perm ": "tmp ");
2944 exp_ecases_print(&ecmd->ecd);
2945 exp_i_print(ecmd->i_list);
2951 exp_cmd_print(&exp_cmds[EXP_CMD_BEFORE]);
2952 exp_cmd_print(&exp_cmds[EXP_CMD_AFTER]);
2953 exp_cmd_print(&exp_cmds[EXP_CMD_BG]);
2958 cmdX(clientData, interp, argc, argv)
2959 ClientData clientData;
2967 #endif /*DEBUG_PERM_ECASES*/
2969 /* need address for passing into cmdExpect */
2970 static int spawn_id_bad = EXP_SPAWN_ID_BAD;
2971 static int spawn_id_user = EXP_SPAWN_ID_USER;
2973 static struct exp_cmd_data
2975 {"expect", exp_proc(Exp_ExpectCmd), (ClientData)&spawn_id_bad, 0},
2976 {"expect_after",exp_proc(Exp_ExpectGlobalCmd),(ClientData)&exp_cmds[EXP_CMD_AFTER],0},
2977 {"expect_before",exp_proc(Exp_ExpectGlobalCmd),(ClientData)&exp_cmds[EXP_CMD_BEFORE],0},
2978 {"expect_user", exp_proc(Exp_ExpectCmd), (ClientData)&spawn_id_user, 0},
2979 {"expect_tty", exp_proc(Exp_ExpectCmd), (ClientData)&exp_dev_tty, 0},
2980 {"expect_background",exp_proc(Exp_ExpectGlobalCmd),(ClientData)&exp_cmds[EXP_CMD_BG],0},
2981 {"match_max", exp_proc(Exp_MatchMaxCmd), 0, 0},
2982 {"remove_nulls",exp_proc(Exp_RemoveNullsCmd), 0, 0},
2983 {"parity", exp_proc(Exp_ParityCmd), 0, 0},
2984 {"timestamp", exp_proc(Exp_TimestampCmd), 0, 0},
2988 exp_init_expect_cmds(interp)
2991 exp_create_commands(interp,cmd_data);
2993 Tcl_SetVar(interp,EXPECT_TIMEOUT,INIT_EXPECT_TIMEOUT_LIT,0);
2994 Tcl_SetVar(interp,EXP_SPAWN_ID_ANY_VARNAME,EXP_SPAWN_ID_ANY_LIT,0);
2996 exp_cmd_init(&exp_cmds[EXP_CMD_BEFORE],EXP_CMD_BEFORE,EXP_PERMANENT);
2997 exp_cmd_init(&exp_cmds[EXP_CMD_AFTER ],EXP_CMD_AFTER, EXP_PERMANENT);
2998 exp_cmd_init(&exp_cmds[EXP_CMD_BG ],EXP_CMD_BG, EXP_PERMANENT);
2999 exp_cmd_init(&exp_cmds[EXP_CMD_FG ],EXP_CMD_FG, EXP_TEMPORARY);
3001 /* preallocate to one element, so future realloc's work */
3002 exp_cmds[EXP_CMD_BEFORE].ecd.cases = 0;
3003 exp_cmds[EXP_CMD_AFTER ].ecd.cases = 0;
3004 exp_cmds[EXP_CMD_BG ].ecd.cases = 0;
3006 pattern_style[PAT_EOF] = "eof";
3007 pattern_style[PAT_TIMEOUT] = "timeout";
3008 pattern_style[PAT_DEFAULT] = "default";
3009 pattern_style[PAT_FULLBUFFER] = "full buffer";
3010 pattern_style[PAT_GLOB] = "glob pattern";
3011 pattern_style[PAT_RE] = "regular expression";
3012 pattern_style[PAT_EXACT] = "exact string";
3013 pattern_style[PAT_NULL] = "null";
3016 Tcl_CreateCommand(interp,"x",
3017 cmdX,(ClientData)0,exp_deleteProc);
3024 signal(SIGALRM,sigalarm_handler);
3025 signal(SIGINT,sigint_handler);