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) */
18 #include "expect_cf.h"
20 #ifdef HAVE_SYS_WAIT_H
32 #include "exp_rename.h"
34 #include "exp_command.h"
36 #include "exp_event.h"
38 #include "exp_tstamp.h" /* this should disappear when interact */
39 /* loses ref's to it */
44 /* The initial length is 2000. We increment it by 2000. The maximum
46 #define EXP_MATCH_MAX 2000
47 #define EXP_MATCH_INC 2000
48 #define EXP_MATCH_STEP_LIMIT 0x700000
49 #define EXP_MATCH_LIMIT 0x800000
50 #define EXP_MATCH_LIMIT_QUOTE "0x800000"
52 /* initial length of strings that we can guarantee patterns can match */
53 int exp_default_match_max = EXP_MATCH_MAX;
54 int exp_default_match_max_changed = 0;
55 #define INIT_EXPECT_TIMEOUT_LIT "10" /* seconds */
56 #define INIT_EXPECT_TIMEOUT 10 /* seconds */
57 int exp_default_parity = TRUE;
58 int exp_default_rm_nulls = TRUE;
59 int exp_default_close_on_eof = TRUE;
61 /* user variable names */
62 #define EXPECT_TIMEOUT "timeout"
63 #define EXPECT_OUT "expect_out"
65 typedef struct ThreadSpecificData {
69 static Tcl_ThreadDataKey dataKey;
72 * addr of these placeholders appear as clientData in ExpectCmd * when called
73 * as expect_user and expect_tty. It would be nicer * to invoked
74 * expDevttyGet() but C doesn't allow this in an array initialization, sigh.
76 static ExpState StdinoutPlaceholder;
77 static ExpState DevttyPlaceholder;
79 /* 1 ecase struct is reserved for each case in the expect command. Note that
80 eof/timeout don't use any of theirs, but the algorithm is simpler this way. */
82 struct ecase { /* case for expect command */
84 Tcl_Obj *pat; /* original pattern spec */
85 Tcl_Obj *body; /* ptr to body to be executed upon match */
89 #define PAT_FULLBUFFER 4
90 #define PAT_GLOB 5 /* glob-style pattern list */
91 #define PAT_RE 6 /* regular expression */
92 #define PAT_EXACT 7 /* exact string */
93 #define PAT_NULL 8 /* ASCII 0 */
94 #define PAT_TYPES 9 /* used to size array of pattern type descriptions */
95 int use; /* PAT_XXX */
96 int simple_start;/* offset from start of buffer denoting where a */
97 /* glob or exact match begins */
98 int transfer; /* if false, leave matched chars in input stream */
99 int indices; /* if true, write indices */
100 int iread; /* if true, reread indirects */
101 int timestamp; /* if true, write timestamps */
102 #define CASE_UNKNOWN 0
105 int Case; /* convert case before doing match? */
108 /* descriptions of the pattern types, used for debugging */
109 char *pattern_style[PAT_TYPES];
111 struct exp_cases_descriptor {
113 struct ecase **cases;
116 /* This describes an Expect command */
118 struct exp_cmd_descriptor {
119 int cmdtype; /* bg, before, after */
120 int duration; /* permanent or temporary */
121 int timeout_specified_by_flag; /* if -timeout flag used */
122 int timeout; /* timeout period if flag used */
123 struct exp_cases_descriptor ecd;
124 struct exp_i *i_list;
126 /* note that exp_cmds[FG] is just a fake, the real contents is stored
127 in some dynamically-allocated variable. We use exp_cmds[FG] mostly
128 as a well-known address and also as a convenience and so we allocate
129 just a few of its fields that we need. */
132 exp_cmd_init(cmd,cmdtype,duration)
133 struct exp_cmd_descriptor *cmd;
137 cmd->duration = duration;
138 cmd->cmdtype = cmdtype;
144 static int i_read_errno;/* place to save errno, if i_read() == -1, so it
145 doesn't get overwritten before we get to read it */
148 static int alarm_fired; /* if alarm occurs */
151 void exp_background_channelhandlers_run_all();
153 /* exp_indirect_updateX is called by Tcl when an indirect variable is set */
154 static char *exp_indirect_update1(); /* 1-part Tcl variable names */
155 static char *exp_indirect_update2(); /* 2-part Tcl variable names */
161 int n; /* unused, for compatibility with STDC */
165 #endif /*SIMPLE_EVENT*/
167 /* free up everything in ecase */
169 free_ecase(interp,ec,free_ilist)
172 int free_ilist; /* if we should free ilist */
174 if (ec->i_list->duration == EXP_PERMANENT) {
175 if (ec->pat) Tcl_DecrRefCount(ec->pat);
176 if (ec->body) Tcl_DecrRefCount(ec->body);
180 ec->i_list->ecount--;
181 if (ec->i_list->ecount == 0)
182 exp_free_i(interp,ec->i_list,exp_indirect_update2);
185 ckfree((char *)ec); /* NEW */
188 /* free up any argv structures in the ecases */
190 free_ecases(interp,eg,free_ilist)
192 struct exp_cmd_descriptor *eg;
193 int free_ilist; /* if true, free ilists */
197 if (!eg->ecd.cases) return;
199 for (i=0;i<eg->ecd.count;i++) {
200 free_ecase(interp,eg->ecd.cases[i],free_ilist);
202 ckfree((char *)eg->ecd.cases);
210 /* no standard defn for this, and some systems don't even have it, so avoid */
211 /* the whole quagmire by calling it something else */
212 static char *exp_strdup(s)
215 char *news = ckalloc(strlen(s) + 1);
221 /* In many places, there is no need to malloc a copy of a string, since it */
222 /* will be freed before we return to Tcl */
224 save_str(lhs,rhs,nosave)
225 char **lhs; /* left hand side */
226 char *rhs; /* right hand side */
229 if (nosave || (rhs == 0)) {
232 *lhs = ckalloc(strlen(rhs) + 1);
237 /* return TRUE if string appears to be a set of arguments
238 The intent of this test is to support the ability of commands to have
239 all their args braced as one. This conflicts with the possibility of
240 actually intending to have a single argument.
241 The bad case is in expect which can have a single argument with embedded
242 \n's although it's rare. Examples that this code should handle:
248 \nfoo\n TRUE (set of args)
251 Current test is very cheap and almost always right :-)
254 exp_one_arg_braced(objPtr) /* INTL */
258 char *p = Tcl_GetString(objPtr);
266 if (!isspace(*p)) { /* INTL: ISO space */
273 /* called to execute a command of only one argument - a hack to commands */
274 /* to be called with all args surrounded by an outer set of braces */
275 /* returns TCL_whatever */
278 exp_eval_with_one_arg(clientData,interp,objv) /* INTL */
279 ClientData clientData;
281 Tcl_Obj *CONST objv[]; /* Argument objects. */
283 #define NUM_STATIC_OBJS 20
284 Tcl_Obj *staticObjArray[NUM_STATIC_OBJS];
285 int maxobjs = NUM_STATIC_OBJS;
289 Tcl_Obj **objs = staticObjArray;
290 int objc, bytesLeft, numWords, i;
294 * Prepend the command name and the -nobrace switch so we can
295 * reinvoke without recursing.
299 objs[1] = Tcl_NewStringObj("-nobrace", -1);
300 Tcl_IncrRefCount(objs[0]);
301 Tcl_IncrRefCount(objs[1]);
303 p = Tcl_GetStringFromObj(objv[1], &bytesLeft);
306 * Treat the pattern/action block like a series of Tcl commands.
307 * For each command, parse the command words, perform substititions
308 * on each word, and add the words to an array of values. We don't
309 * actually evaluate the individual commands, just the substitutions.
313 if (Tcl_ParseCommand(interp, p, bytesLeft, 0, &parse)
318 numWords = parse.numWords;
321 * Generate an array of objects for the words of the command.
324 if (objc + numWords > maxobjs) {
326 maxobjs = (objc + numWords) * 2;
327 newobjs = (Tcl_Obj **)ckalloc(maxobjs * sizeof (Tcl_Obj *));
328 memcpy(newobjs, objs, objc*sizeof(Tcl_Obj *));
329 if (objs != staticObjArray) {
336 * For each word, perform substitutions then store the
337 * result in the objs array.
340 for (tokenPtr = parse.tokenPtr; numWords > 0;
341 numWords--, tokenPtr += (tokenPtr->numComponents + 1)) {
342 objs[objc] = Tcl_EvalTokens(interp, tokenPtr+1,
343 tokenPtr->numComponents);
344 if (objs[objc] == NULL) {
353 * Advance to the next command in the script.
355 next = parse.commandStart + parse.commandSize;
356 bytesLeft -= next - p;
358 Tcl_FreeParse(&parse);
359 } while (bytesLeft > 0);
362 * Now evaluate the entire command with no further substitutions.
365 rc = Tcl_EvalObjv(interp, objc, objs, 0);
367 for (i = 0; i < objc; i++) {
368 Tcl_DecrRefCount(objs[i]);
370 if (objs != staticObjArray) {
371 ckfree((char *) objs);
374 #undef NUM_STATIC_OBJS
387 ec->timestamp = FALSE;
388 ec->Case = CASE_NORM;
392 static struct ecase *
395 struct ecase *ec = (struct ecase *)ckalloc(sizeof(struct ecase));
403 parse_expect_args parses the arguments to expect or its variants.
404 It normally returns TCL_OK, and returns TCL_ERROR for failure.
405 (It can't return i_list directly because there is no way to differentiate
406 between clearing, say, expect_before and signalling an error.)
408 eg (expect_global) is initialized to reflect the arguments parsed
409 eg->ecd.cases is an array of ecases
410 eg->ecd.count is the # of ecases
411 eg->i_list is a linked list of exp_i's which represent the -i info
413 Each exp_i is chained to the next so that they can be easily free'd if
414 necessary. Each exp_i has a reference count. If the -i is not used
415 (e.g., has no following patterns), the ref count will be 0.
417 Each ecase points to an exp_i. Several ecases may point to the same exp_i.
418 Variables named by indirect exp_i's are read for the direct values.
420 If called from a foreground expect and no patterns or -i are given, a
421 default exp_i is forced so that the command "expect" works right.
423 The exp_i chain can be broken by the caller if desired.
428 parse_expect_args(interp,eg,default_esPtr,objc,objv)
430 struct exp_cmd_descriptor *eg;
431 ExpState *default_esPtr; /* suggested ExpState if called as expect_user or _tty */
433 Tcl_Obj *CONST objv[]; /* Argument objects. */
437 struct ecase ec; /* temporary to collect args */
439 eg->timeout_specified_by_flag = FALSE;
443 /* Allocate an array to store the ecases. Force array even if 0 */
444 /* cases. This will often be too large (i.e., if there are flags) */
445 /* but won't affect anything. */
447 eg->ecd.cases = (struct ecase **)ckalloc(sizeof(struct ecase *) * (1+(objc/2)));
451 for (i = 1;i<objc;i++) {
453 string = Tcl_GetString(objv[i]);
454 if (string[0] == '-') {
455 static char *flags[] = {
456 "-glob", "-regexp", "-exact", "-notransfer", "-nocase",
457 "-i", "-indices", "-iread", "-timestamp", "-timeout",
458 "-nobrace", "--", (char *)0
461 EXP_ARG_GLOB, EXP_ARG_REGEXP, EXP_ARG_EXACT,
462 EXP_ARG_NOTRANSFER, EXP_ARG_NOCASE, EXP_ARG_SPAWN_ID,
463 EXP_ARG_INDICES, EXP_ARG_IREAD, EXP_ARG_TIMESTAMP,
464 EXP_ARG_DASH_TIMEOUT, EXP_ARG_NOBRACE, EXP_ARG_DASH
468 * Allow abbreviations of switches and report an error if we
469 * get an invalid switch.
472 if (Tcl_GetIndexFromObj(interp, objv[i], flags, "flag", 0,
476 switch ((enum flags) index) {
480 /* assignment here is not actually necessary */
481 /* since cases are initialized this way above */
482 /* ec.use = PAT_GLOB; */
484 Tcl_WrongNumArgs(interp, 1, objv,"-glob pattern");
491 Tcl_WrongNumArgs(interp, 1, objv,"-regexp regexp");
497 * Try compiling the expression so we can report
498 * any errors now rather then when we first try to
502 if (!(Tcl_GetRegExpFromObj(interp, objv[i],
503 TCL_REG_ADVANCED))) {
510 Tcl_WrongNumArgs(interp, 1, objv, "-exact string");
515 case EXP_ARG_NOTRANSFER:
519 ec.Case = CASE_LOWER;
521 case EXP_ARG_SPAWN_ID:
524 Tcl_WrongNumArgs(interp, 1, objv, "-i spawn_id");
527 ec.i_list = exp_new_i_complex(interp,
528 Tcl_GetString(objv[i]),
529 eg->duration, exp_indirect_update2);
530 if (!ec.i_list) goto error;
531 ec.i_list->cmdtype = eg->cmdtype;
533 /* link new i_list to head of list */
534 ec.i_list->next = eg->i_list;
535 eg->i_list = ec.i_list;
537 case EXP_ARG_INDICES:
543 case EXP_ARG_TIMESTAMP:
546 case EXP_ARG_DASH_TIMEOUT:
549 Tcl_WrongNumArgs(interp, 1, objv, "-timeout seconds");
552 if (Tcl_GetIntFromObj(interp, objv[i],
553 &eg->timeout) != TCL_OK) {
556 eg->timeout_specified_by_flag = TRUE;
558 case EXP_ARG_NOBRACE:
559 /* nobrace does nothing but take up space */
560 /* on the command line which prevents */
561 /* us from re-expanding any command lines */
562 /* of one argument that looks like it should */
563 /* be expanded to multiple arguments. */
567 * Keep processing arguments, we aren't ready for the
573 * We have a pattern or keyword.
576 static char *keywords[] = {
577 "timeout", "eof", "full_buffer", "default", "null",
581 EXP_ARG_TIMEOUT, EXP_ARG_EOF, EXP_ARG_FULL_BUFFER,
582 EXP_ARG_DEFAULT, EXP_ARG_NULL
586 * Match keywords exactly, otherwise they are patterns.
589 if (Tcl_GetIndexFromObj(interp, objv[i], keywords, "keyword",
590 1 /* exact */, &index) != TCL_OK) {
591 Tcl_ResetResult(interp);
594 switch ((enum keywords) index) {
595 case EXP_ARG_TIMEOUT:
596 ec.use = PAT_TIMEOUT;
601 case EXP_ARG_FULL_BUFFER:
602 ec.use = PAT_FULLBUFFER;
604 case EXP_ARG_DEFAULT:
605 ec.use = PAT_DEFAULT;
612 /* if no -i, use previous one */
614 /* if no -i flag has occurred yet, use default */
616 if (default_esPtr != EXP_SPAWN_ID_BAD) {
617 eg->i_list = exp_new_i_simple(default_esPtr,eg->duration);
619 default_esPtr = expStateCurrent(interp,0,0,1);
620 if (!default_esPtr) goto error;
621 eg->i_list = exp_new_i_simple(default_esPtr,eg->duration);
624 ec.i_list = eg->i_list;
628 /* save original pattern spec */
629 /* keywords such as "-timeout" are saved as patterns here */
630 /* useful for debugging but not otherwise used */
633 if (eg->duration == EXP_PERMANENT) Tcl_IncrRefCount(ec.pat);
638 if (eg->duration == EXP_PERMANENT) Tcl_IncrRefCount(ec.body);
643 *(eg->ecd.cases[eg->ecd.count] = ecase_new()) = ec;
645 /* clear out for next set */
652 /* if no patterns at all have appeared force the current */
653 /* spawn id to be added to list anyway */
655 if (eg->i_list == 0) {
656 if (default_esPtr != EXP_SPAWN_ID_BAD) {
657 eg->i_list = exp_new_i_simple(default_esPtr,eg->duration);
659 default_esPtr = expStateCurrent(interp,0,0,1);
660 if (!default_esPtr) goto error;
661 eg->i_list = exp_new_i_simple(default_esPtr,eg->duration);
668 /* very hard to free case_master_list here if it hasn't already */
669 /* been attached to a case, ugh */
671 /* note that i_list must be avail to free ecases! */
672 free_ecases(interp,eg,0);
675 exp_free_i(interp,eg->i_list,exp_indirect_update2);
679 #define EXP_IS_DEFAULT(x) ((x) == EXP_TIMEOUT || (x) == EXP_EOF)
681 static char yes[] = "yes\r\n";
682 static char no[] = "no\r\n";
684 /* this describes status of a successful match */
686 struct ecase *e; /* ecase that matched */
687 ExpState *esPtr; /* ExpState that matched */
688 Tcl_Obj *buffer; /* buffer that matched */
689 int match; /* # of bytes in buffer that matched */
690 /* or # of bytes in buffer at EOF */
697 *----------------------------------------------------------------------
699 * string_case_first --
701 * Find the first instance of a pattern in a string.
704 * Returns the pointer to the first instance of the pattern
705 * in the given string, or NULL if no match was found.
710 *----------------------------------------------------------------------
714 string_case_first(string,pattern) /* INTL */
715 register char *string; /* String. */
716 register char *pattern; /* Pattern, which may contain
717 * special characters. */
721 Tcl_UniChar ch1, ch2;
723 while (*string != 0) {
727 s += Tcl_UtfToUniChar(s, &ch1);
728 offset = Tcl_UtfToUniChar(p, &ch2);
729 if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) {
742 /* like eval_cases, but handles only a single cases that needs a real */
744 /* returns EXP_X where X is MATCH, NOMATCH, FULLBUFFER, TCLERRROR */
746 eval_case_string(interp,e,esPtr,o,last_esPtr,last_case,suffix)
750 struct eval_out *o; /* 'output' - i.e., final case of interest */
751 /* next two args are for debugging, when they change, reprint buffer */
752 ExpState **last_esPtr;
763 buffer = esPtr->buffer;
764 str = Tcl_GetStringFromObj(buffer, &length);
766 /* if ExpState or case changed, redisplay debug-buffer */
767 if ((esPtr != *last_esPtr) || e->Case != *last_case) {
768 expDiagLog("\r\nexpect%s: does \"",suffix);
769 expDiagLogU(expPrintify(str));
770 expDiagLog("\" (spawn_id %s) match %s ",esPtr->name,pattern_style[e->use]);
772 *last_case = e->Case;
775 if (e->use == PAT_RE) {
777 expDiagLogU(expPrintify(Tcl_GetString(e->pat)));
779 if (e->Case == CASE_NORM) {
780 flags = TCL_REG_ADVANCED;
782 flags = TCL_REG_ADVANCED | TCL_REG_NOCASE;
785 re = Tcl_GetRegExpFromObj(interp, e->pat, flags);
787 result = Tcl_RegExpExecObj(interp, re, buffer, 0 /* offset */,
788 -1 /* nmatches */, 0 /* eflags */);
794 * Retrieve the byte offset of the end of the
798 Tcl_RegExpGetInfo(re, &info);
799 o->match = Tcl_UtfAtIndex(str, info.matches[0].end) - str;
804 } else if (result == 0) {
806 } else { /* result < 0 */
807 return(EXP_TCLERROR);
809 } else if (e->use == PAT_GLOB) {
810 int match; /* # of bytes that matched */
813 expDiagLogU(expPrintify(Tcl_GetString(e->pat)));
816 match = Exp_StringCaseMatch(Tcl_GetString(buffer),
817 Tcl_GetString(e->pat),
818 (e->Case == CASE_NORM) ? 0 : 1,
830 } else if (e->use == PAT_EXACT) {
832 char *pat = Tcl_GetStringFromObj(e->pat, &patLength);
835 if (e->Case == CASE_NORM) {
836 p = strstr(str, pat);
838 p = string_case_first(str, pat);
842 expDiagLogU(expPrintify(Tcl_GetString(e->pat)));
845 e->simple_start = p - str;
847 o->match = patLength;
852 } else expDiagLogU(no);
853 } else if (e->use == PAT_NULL) {
855 expDiagLogU("null? ");
856 p = Tcl_UtfFindFirst(str, 0);
867 } else if (e->use == PAT_FULLBUFFER) {
868 expDiagLogU(Tcl_GetString(e->pat));
870 /* this must be the same test as in expIRead */
871 if ((expSizeGet(esPtr) + TCL_UTF_MAX >= esPtr->msize)
875 o->buffer = esPtr->buffer;
878 return(EXP_FULLBUFFER);
886 /* sets o.e if successfully finds a matching pattern, eof, timeout or deflt */
887 /* returns original status arg or EXP_TCLERROR */
889 eval_cases(interp,eg,esPtr,o,last_esPtr,last_case,status,esPtrs,mcount,suffix)
891 struct exp_cmd_descriptor *eg;
893 struct eval_out *o; /* 'output' - i.e., final case of interest */
894 /* next two args are for debugging, when they change, reprint buffer */
895 ExpState **last_esPtr;
898 ExpState *(esPtrs[]);
903 ExpState *em; /* ExpState of ecase */
906 if (o->e || status == EXP_TCLERROR || eg->ecd.count == 0) return(status);
908 if (status == EXP_TIMEOUT) {
909 for (i=0;i<eg->ecd.count;i++) {
910 e = eg->ecd.cases[i];
911 if (e->use == PAT_TIMEOUT || e->use == PAT_DEFAULT) {
917 } else if (status == EXP_EOF) {
918 for (i=0;i<eg->ecd.count;i++) {
919 e = eg->ecd.cases[i];
920 if (e->use == PAT_EOF || e->use == PAT_DEFAULT) {
921 struct exp_state_list *slPtr;
923 for (slPtr=e->i_list->state_list; slPtr ;slPtr=slPtr->next) {
925 if (expStateAnyIs(em) || em == esPtr) {
935 /* the top loops are split from the bottom loop only because I can't */
936 /* split'em further. */
938 /* The bufferful condition does not prevent a pattern match from */
939 /* occurring and vice versa, so it is scanned with patterns */
940 for (i=0;i<eg->ecd.count;i++) {
941 struct exp_state_list *slPtr;
944 e = eg->ecd.cases[i];
945 if (e->use == PAT_TIMEOUT ||
946 e->use == PAT_DEFAULT ||
947 e->use == PAT_EOF) continue;
949 for (slPtr = e->i_list->state_list; slPtr; slPtr = slPtr->next) {
951 /* if em == EXP_SPAWN_ID_ANY, then user is explicitly asking */
952 /* every case to be checked against every ExpState */
953 if (expStateAnyIs(em)) {
954 /* test against each spawn_id */
955 for (j=0;j<mcount;j++) {
956 status = eval_case_string(interp,e,esPtrs[j],o,
957 last_esPtr,last_case,suffix);
958 if (status != EXP_NOMATCH) return(status);
961 /* reject things immediately from wrong spawn_id */
962 if (em != esPtr) continue;
964 status = eval_case_string(interp,e,esPtr,o,last_esPtr,last_case,suffix);
965 if (status != EXP_NOMATCH) return(status);
973 ecases_remove_by_expi(interp,ecmd,exp_i)
975 struct exp_cmd_descriptor *ecmd;
980 /* delete every ecase dependent on it */
981 for (i=0;i<ecmd->ecd.count;) {
982 struct ecase *e = ecmd->ecd.cases[i];
983 if (e->i_list == exp_i) {
984 free_ecase(interp,e,0);
986 /* shift remaining elements down */
987 /* but only if there are any left */
988 if (i+1 != ecmd->ecd.count) {
989 memcpy(&ecmd->ecd.cases[i],
990 &ecmd->ecd.cases[i+1],
991 ((ecmd->ecd.count - i) - 1) *
992 sizeof(struct exp_cmd_descriptor *));
995 if (0 == ecmd->ecd.count) {
996 ckfree((char *)ecmd->ecd.cases);
1005 /* remove exp_i from list */
1007 exp_i_remove(interp,ei,exp_i)
1009 struct exp_i **ei; /* list to remove from */
1010 struct exp_i *exp_i; /* element to remove */
1012 /* since it's in middle of list, free exp_i by hand */
1013 for (;*ei; ei = &(*ei)->next) {
1017 exp_free_i(interp,exp_i,exp_indirect_update2);
1023 /* remove exp_i from list and remove any dependent ecases */
1025 exp_i_remove_with_ecases(interp,ecmd,exp_i)
1027 struct exp_cmd_descriptor *ecmd;
1028 struct exp_i *exp_i;
1030 ecases_remove_by_expi(interp,ecmd,exp_i);
1031 exp_i_remove(interp,&ecmd->i_list,exp_i);
1034 /* remove ecases tied to a single direct spawn id */
1036 ecmd_remove_state(interp,ecmd,esPtr,direct)
1038 struct exp_cmd_descriptor *ecmd;
1042 struct exp_i *exp_i, *next;
1043 struct exp_state_list **slPtr;
1045 for (exp_i=ecmd->i_list;exp_i;exp_i=next) {
1048 if (!(direct & exp_i->direct)) continue;
1050 for (slPtr = &exp_i->state_list;*slPtr;) {
1051 if (esPtr == ((*slPtr)->esPtr)) {
1052 struct exp_state_list *tmp = *slPtr;
1053 *slPtr = (*slPtr)->next;
1054 exp_free_state_single(tmp);
1056 /* if last bg ecase, disarm spawn id */
1057 if ((ecmd->cmdtype == EXP_CMD_BG) && (!expStateAnyIs(esPtr))) {
1059 if (esPtr->bg_ecount == 0) {
1060 exp_disarm_background_channelhandler(esPtr);
1061 esPtr->bg_interp = 0;
1067 slPtr = &(*slPtr)->next;
1070 /* if left with no ExpStates (and is direct), get rid of it */
1071 /* and any dependent ecases */
1072 if (exp_i->direct == EXP_DIRECT && !exp_i->state_list) {
1073 exp_i_remove_with_ecases(interp,ecmd,exp_i);
1078 /* this is called from exp_close to clean up the ExpState */
1080 exp_ecmd_remove_state_direct_and_indirect(interp,esPtr)
1084 ecmd_remove_state(interp,&exp_cmds[EXP_CMD_BEFORE],esPtr,EXP_DIRECT|EXP_INDIRECT);
1085 ecmd_remove_state(interp,&exp_cmds[EXP_CMD_AFTER],esPtr,EXP_DIRECT|EXP_INDIRECT);
1086 ecmd_remove_state(interp,&exp_cmds[EXP_CMD_BG],esPtr,EXP_DIRECT|EXP_INDIRECT);
1088 /* force it - explanation in exp_tk.c where this func is defined */
1089 exp_disarm_background_channelhandler_force(esPtr);
1092 /* arm a list of background ExpState's */
1094 state_list_arm(interp,slPtr)
1096 struct exp_state_list *slPtr;
1098 /* for each spawn id in list, arm if necessary */
1099 for (;slPtr;slPtr=slPtr->next) {
1100 ExpState *esPtr = slPtr->esPtr;
1101 if (expStateAnyIs(esPtr)) continue;
1103 if (esPtr->bg_ecount == 0) {
1104 exp_arm_background_channelhandler(esPtr);
1105 esPtr->bg_interp = interp;
1111 /* return TRUE if this ecase is used by this fd */
1113 exp_i_uses_state(exp_i,esPtr)
1114 struct exp_i *exp_i;
1117 struct exp_state_list *fdp;
1119 for (fdp = exp_i->state_list;fdp;fdp=fdp->next) {
1120 if (fdp->esPtr == esPtr) return 1;
1126 ecase_append(interp,ec)
1130 if (!ec->transfer) Tcl_AppendElement(interp,"-notransfer");
1131 if (ec->indices) Tcl_AppendElement(interp,"-indices");
1132 if (!ec->Case) Tcl_AppendElement(interp,"-nocase");
1134 if (ec->use == PAT_RE) Tcl_AppendElement(interp,"-re");
1135 else if (ec->use == PAT_GLOB) Tcl_AppendElement(interp,"-gl");
1136 else if (ec->use == PAT_EXACT) Tcl_AppendElement(interp,"-ex");
1137 Tcl_AppendElement(interp,Tcl_GetString(ec->pat));
1138 Tcl_AppendElement(interp,ec->body?Tcl_GetString(ec->body):"");
1141 /* append all ecases that match this exp_i */
1143 ecase_by_exp_i_append(interp,ecmd,exp_i)
1145 struct exp_cmd_descriptor *ecmd;
1146 struct exp_i *exp_i;
1149 for (i=0;i<ecmd->ecd.count;i++) {
1150 if (ecmd->ecd.cases[i]->i_list == exp_i) {
1151 ecase_append(interp,ecmd->ecd.cases[i]);
1157 exp_i_append(interp,exp_i)
1159 struct exp_i *exp_i;
1161 Tcl_AppendElement(interp,"-i");
1162 if (exp_i->direct == EXP_INDIRECT) {
1163 Tcl_AppendElement(interp,exp_i->variable);
1165 struct exp_state_list *fdp;
1167 /* if more than one element, add braces */
1168 if (exp_i->state_list->next)
1169 Tcl_AppendResult(interp," {",(char *)0);
1171 for (fdp = exp_i->state_list;fdp;fdp=fdp->next) {
1172 char buf[10]; /* big enough for a small int */
1173 sprintf(buf,"%d",fdp->esPtr);
1174 Tcl_AppendElement(interp,buf);
1177 if (exp_i->state_list->next)
1178 Tcl_AppendResult(interp,"} ",(char *)0);
1182 /* return current setting of the permanent expect_before/after/bg */
1184 expect_info(interp,ecmd,objc,objv)
1186 struct exp_cmd_descriptor *ecmd;
1188 Tcl_Obj *CONST objv[]; /* Argument objects. */
1190 struct exp_i *exp_i;
1192 int direct = EXP_DIRECT|EXP_INDIRECT;
1194 int all = FALSE; /* report on all fds */
1195 ExpState *esPtr = 0;
1197 static char *flags[] = {"-i", "-all", "-noindirect", (char *)0};
1198 enum flags {EXP_ARG_I, EXP_ARG_ALL, EXP_ARG_NOINDIRECT};
1200 /* start with 2 to skip over "cmdname -info" */
1201 for (i = 2;i<objc;i++) {
1203 * Allow abbreviations of switches and report an error if we
1204 * get an invalid switch.
1208 if (Tcl_GetIndexFromObj(interp, objv[i], flags, "flag", 0,
1209 &index) != TCL_OK) {
1212 switch ((enum flags) index) {
1216 Tcl_WrongNumArgs(interp, 1, objv,"-i spawn_id");
1223 case EXP_ARG_NOINDIRECT:
1224 direct &= ~EXP_INDIRECT;
1230 /* avoid printing out -i when redundant */
1231 struct exp_i *previous = 0;
1233 for (i=0;i<ecmd->ecd.count;i++) {
1234 if (previous != ecmd->ecd.cases[i]->i_list) {
1235 exp_i_append(interp,ecmd->ecd.cases[i]->i_list);
1236 previous = ecmd->ecd.cases[i]->i_list;
1238 ecase_append(interp,ecmd->ecd.cases[i]);
1244 if (!(esPtr = expStateCurrent(interp,0,0,0))) {
1247 } else if (!(esPtr = expStateFromChannelName(interp,iflag,0,0,0,"dummy"))) {
1248 /* not a valid ExpState so assume it is an indirect variable */
1249 Tcl_ResetResult(interp);
1250 for (i=0;i<ecmd->ecd.count;i++) {
1251 if (ecmd->ecd.cases[i]->i_list->direct == EXP_INDIRECT &&
1252 streq(ecmd->ecd.cases[i]->i_list->variable,iflag)) {
1253 ecase_append(interp,ecmd->ecd.cases[i]);
1259 /* print ecases of this direct_fd */
1260 for (exp_i=ecmd->i_list;exp_i;exp_i=exp_i->next) {
1261 if (!(direct & exp_i->direct)) continue;
1262 if (!exp_i_uses_state(exp_i,esPtr)) continue;
1263 ecase_by_exp_i_append(interp,ecmd,exp_i);
1269 /* Exp_ExpectGlobalObjCmd is invoked to process expect_before/after/background */
1272 Exp_ExpectGlobalObjCmd(clientData, interp, objc, objv)
1273 ClientData clientData;
1276 Tcl_Obj *CONST objv[]; /* Argument objects. */
1278 int result = TCL_OK;
1279 struct exp_i *exp_i, **eip;
1280 struct exp_state_list *slPtr; /* temp for interating over state_list */
1281 struct exp_cmd_descriptor eg;
1284 struct exp_cmd_descriptor *ecmd = (struct exp_cmd_descriptor *) clientData;
1286 if ((objc == 2) && exp_one_arg_braced(objv[1])) {
1287 return(exp_eval_with_one_arg(clientData,interp,objv));
1288 } else if ((objc == 3) && streq(Tcl_GetString(objv[1]),"-brace")) {
1289 Tcl_Obj *new_objv[2];
1290 new_objv[0] = objv[0];
1291 new_objv[1] = objv[2];
1292 return(exp_eval_with_one_arg(clientData,interp,new_objv));
1295 if (objc > 1 && (Tcl_GetString(objv[1])[0] == '-')) {
1296 if (exp_flageq("info",Tcl_GetString(objv[1])+1,4)) {
1297 return(expect_info(interp,ecmd,objc,objv));
1301 exp_cmd_init(&eg,ecmd->cmdtype,EXP_PERMANENT);
1303 if (TCL_ERROR == parse_expect_args(interp,&eg,EXP_SPAWN_ID_BAD,
1309 * visit each NEW direct exp_i looking for spawn ids.
1310 * When found, remove them from any OLD exp_i's.
1313 /* visit each exp_i */
1314 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1315 if (exp_i->direct == EXP_INDIRECT) continue;
1317 /* for each spawn id, remove it from ecases */
1318 for (slPtr=exp_i->state_list;slPtr;slPtr=slPtr->next) {
1319 ExpState *esPtr = slPtr->esPtr;
1321 /* validate all input descriptors */
1322 if (!expStateAnyIs(esPtr)) {
1323 if (!expStateCheck(interp,esPtr,1,1,"expect")) {
1329 /* remove spawn id from exp_i */
1330 ecmd_remove_state(interp,ecmd,esPtr,EXP_DIRECT);
1335 * For each indirect variable, release its old ecases and
1336 * clean up the matching spawn ids.
1337 * Same logic as in "expect_X delete" command.
1340 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1341 struct exp_i **old_i;
1343 if (exp_i->direct == EXP_DIRECT) continue;
1345 for (old_i = &ecmd->i_list;*old_i;) {
1348 if (((*old_i)->direct == EXP_DIRECT) ||
1349 (!streq((*old_i)->variable,exp_i->variable))) {
1350 old_i = &(*old_i)->next;
1354 ecases_remove_by_expi(interp,ecmd,*old_i);
1356 /* unlink from middle of list */
1360 exp_free_i(interp,tmp,exp_indirect_update2);
1363 /* if new one has ecases, update it */
1364 if (exp_i->ecount) {
1365 char *msg = exp_indirect_update1(interp,ecmd,exp_i);
1367 /* unusual way of handling error return */
1368 /* because of Tcl's variable tracing */
1369 strcpy(interp->result,msg);
1371 goto indirect_update_abort;
1375 /* empty i_lists have to be removed from global eg.i_list */
1376 /* before returning, even if during error */
1377 indirect_update_abort:
1380 * New exp_i's that have 0 ecases indicate fd/vars to be deleted.
1381 * Now that the deletions have been done, discard the new exp_i's.
1384 for (exp_i=eg.i_list;exp_i;) {
1385 struct exp_i *next = exp_i->next;
1387 if (exp_i->ecount == 0) {
1388 exp_i_remove(interp,&eg.i_list,exp_i);
1392 if (result == TCL_ERROR) goto cleanup;
1395 * arm all new bg direct fds
1398 if (ecmd->cmdtype == EXP_CMD_BG) {
1399 for (exp_i=eg.i_list;exp_i;exp_i=exp_i->next) {
1400 if (exp_i->direct == EXP_DIRECT) {
1401 state_list_arm(interp,exp_i->state_list);
1407 * now that old ecases are gone, add new ecases and exp_i's (both
1408 * direct and indirect).
1413 count = ecmd->ecd.count + eg.ecd.count;
1415 int start_index; /* where to add new ecases in old list */
1417 if (ecmd->ecd.count) {
1419 ecmd->ecd.cases = (struct ecase **)ckrealloc((char *)ecmd->ecd.cases, count * sizeof(struct ecase *));
1420 start_index = ecmd->ecd.count;
1422 /* append to beginning */
1423 ecmd->ecd.cases = (struct ecase **)ckalloc(eg.ecd.count * sizeof(struct ecase *));
1426 memcpy(&ecmd->ecd.cases[start_index],eg.ecd.cases,
1427 eg.ecd.count*sizeof(struct ecase *));
1428 ecmd->ecd.count = count;
1431 /* append exp_i's */
1432 for (eip = &ecmd->i_list;*eip;eip = &(*eip)->next) {
1433 /* empty loop to get to end of list */
1435 /* *exp_i now points to end of list */
1437 *eip = eg.i_list; /* connect new list to end of current list */
1440 if (result == TCL_ERROR) {
1441 /* in event of error, free any unreferenced ecases */
1442 /* but first, split up i_list so that exp_i's aren't */
1445 for (exp_i=eg.i_list;exp_i;) {
1446 struct exp_i *next = exp_i->next;
1450 free_ecases(interp,&eg,1);
1452 if (eg.ecd.cases) ckfree((char *)eg.ecd.cases);
1455 if (ecmd->cmdtype == EXP_CMD_BG) {
1456 exp_background_channelhandlers_run_all();
1462 /* adjusts file according to user's size request */
1476 * Resize buffer to user's request * 2 + 1.
1477 * x2: in case the match straddles two bufferfuls.
1478 * +1: for trailing null.
1481 new_msize = esPtr->umsize*2 + 1;
1483 if (new_msize != esPtr->msize) {
1484 string = Tcl_GetStringFromObj(esPtr->buffer, &length);
1485 if (length > new_msize) {
1487 * too much data, forget about data at beginning of buffer
1490 excessBytes = length - new_msize; /* initial guess */
1493 * Alas, string + excessBytes may be in the middle of a UTF char.
1494 * Find out for sure.
1496 excessGuess = string + excessBytes;
1497 for (p=string;;p=Tcl_UtfNext(p)) {
1498 if (p >= excessGuess) break;
1501 /* now we can calculate a valid # of excess bytes */
1502 excessBytes = p - string;
1503 newObj = Tcl_NewStringObj(string + excessBytes,length - excessBytes);
1509 /* first copy what's there */
1510 newObj = Tcl_NewStringObj(string,length);
1513 * Force object to allocate a buffer at least new_msize bytes long,
1514 * then reset correct string length.
1517 Tcl_SetObjLength(newObj,new_msize);
1518 Tcl_SetObjLength(newObj,length);
1520 Tcl_IncrRefCount(newObj);
1521 Tcl_DecrRefCount(esPtr->buffer);
1522 esPtr->buffer = newObj;
1524 esPtr->key = expect_key++;
1525 esPtr->msize = new_msize;
1532 expParityStrip(obj,offsetBytes)
1538 int changed = FALSE;
1540 for (p = Tcl_GetString(obj) + offsetBytes;*p;p++) {
1542 if (ch != *p) changed = TRUE;
1547 /* invalidate the unicode rep */
1548 if (obj->typePtr->freeIntRepProc) {
1549 obj->typePtr->freeIntRepProc(obj);
1555 /* This function is only used when debugging. It checks when a string's
1556 internal UTF is sane and whether an offset into the string appears to
1557 be at a UTF boundary.
1560 expValid(obj,offset)
1567 s = Tcl_GetStringFromObj(obj,&len);
1570 printf("offset (%d) > length (%d)\n",offset,len);
1575 /* first test for null terminator */
1578 printf("obj lacks null terminator\n");
1583 /* check for valid UTF sequence */
1587 s += Tcl_UtfToUniChar(s,&uc);
1589 printf("UTF out of sync with terminator\n");
1598 s += Tcl_UtfToUniChar(s,&uc);
1600 printf("UTF from offset out of sync with terminator\n");
1607 /* Strip UTF-encoded nulls from object, beginning at offset */
1609 expNullStrip(obj,offsetBytes)
1616 int newsize; /* size of obj after all nulls removed */
1618 src2 = src = dest = Tcl_GetString(obj) + offsetBytes;
1621 src += Tcl_UtfToUniChar(src,&uc);
1623 dest += Tcl_UniCharToUtf(uc,dest);
1626 newsize = offsetBytes + (dest - src2);
1627 Tcl_SetObjLength(obj,newsize);
1631 /* returns # of bytes until we see a newline at the end or EOF. */
1634 expReadNewLine(interp,esPtr,save_flags) /* INTL */
1647 exp_size = expSizeGet(esPtr);
1649 /* When we reach the limit, we will only read one char at a
1651 if (esPtr->umsize >= EXP_MATCH_STEP_LIMIT)
1656 if (exp_size + TCL_UTF_MAX >= esPtr->msize) {
1657 if (esPtr->umsize >= EXP_MATCH_LIMIT) {
1658 expDiagLogU("WARNING: interact buffer is full. probably your program\r\n");
1659 expDiagLogU("is not interactive or has a very long output line. The\r\n");
1660 expDiagLogU("current limit is " EXP_MATCH_LIMIT_QUOTE ".\r\n");
1661 expDiagLogU("Dumping first half of buffer in order to continue\r\n");
1662 expDiagLogU("Recommend you enlarge the buffer.\r\n");
1663 exp_buffer_shuffle(interp,esPtr,save_flags,EXPECT_OUT,"expect");
1667 esPtr->umsize += EXP_MATCH_INC;
1672 full_size = esPtr->msize - (size / TCL_UTF_MAX);
1673 size = Tcl_ReadChars(esPtr->channel,
1679 /* We try again if there are more to read and we haven't
1680 seen a newline at the end. */
1681 if (size == full_size) {
1682 str = Tcl_GetStringFromObj(esPtr->buffer, &size);
1683 if (str[size - 1] != '\n')
1688 /* It is even trickier. We got an error from read. We have
1689 to recover from it. Let's make sure the size of
1690 buffer is correct. It can be corrupted. */
1691 str = Tcl_GetString(esPtr->buffer);
1692 Tcl_SetObjLength(esPtr->buffer, strlen(str));
1701 /* returns # of bytes read or (non-positive) error of form EXP_XXX */
1702 /* returns 0 for end of file */
1703 /* If timeout is non-zero, set an alarm before doing the read, else assume */
1704 /* the read will complete immediately. */
1707 expIRead(interp,esPtr,timeout,save_flags) /* INTL */
1713 int cc = EXP_TIMEOUT;
1714 int size = expSizeGet(esPtr);
1718 if (size + TCL_UTF_MAX >= esPtr->msize)
1719 exp_buffer_shuffle(interp,esPtr,save_flags,EXPECT_OUT,"expect");
1720 size = expSizeGet(esPtr);
1725 alarm_fired = FALSE;
1728 signal(SIGALRM,sigalarm_handler);
1729 alarm((timeout > 0)?timeout:1);
1733 /* FIXME: If we ask less than what is available in the tcl buffer
1734 when tcl has seen EOF, we will throw away the remaining data
1735 since the next read will get EOF. Since expect is line-oriented,
1736 we exand our buffer to get EOF or the next newline at the end of
1737 the input buffer. I don't know if it is the right fix. H.J. */
1739 full_size = esPtr->msize - (size / TCL_UTF_MAX);
1740 cc = Tcl_ReadChars(esPtr->channel,
1746 /* It gets very tricky. There are more to read. We will expand
1747 our buffer and get EOF or a newline at the end unless the
1748 buffer length has been changed. */
1749 if (cc == full_size) {
1751 str = Tcl_GetStringFromObj(esPtr->buffer, &size);
1752 if (str[size - 1] != '\n') {
1753 if (esPtr->umsize_changed) {
1754 char buf[20]; /* big enough for 64bit int in hex. */
1755 snprintf(buf,sizeof(buf),"0x%x", esPtr->umsize);
1756 expDiagLogU("WARNING: interact buffer is not large enough to hold\r\n");
1757 expDiagLogU("all output. probably your program is not interactive or\r\n");
1758 expDiagLogU("has a very long output line. The current limit is ");
1760 expDiagLogU(".\r\n");
1763 cc = expReadNewLine(interp,esPtr,save_flags);
1770 i_read_errno = errno;
1776 /* check if alarm went off */
1777 if (i_read_errno == EINTR) {
1781 if (Tcl_AsyncReady()) {
1782 int rc = Tcl_AsyncInvoke(interp,TCL_OK);
1783 if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
1790 return count > 0 ? count : cc;
1794 * expRead() does the logical equivalent of a read() for the expect command.
1795 * This includes figuring out which descriptor should be read from.
1797 * The result of the read() is left in a spawn_id's buffer rather than
1798 * explicitly passing it back. Note that if someone else has modified a buffer
1799 * either before or while this expect is running (i.e., if we or some event has
1800 * called Tcl_Eval which did another expect/interact), expRead will also call
1801 * this a successful read (for the purposes if needing to pattern match against
1805 /* if it returns a negative number, it corresponds to a EXP_XXX result */
1806 /* if it returns a non-negative number, it means there is data */
1807 /* (0 means nothing new was actually read, but it should be looked at again) */
1809 expRead(interp,esPtrs,esPtrsMax,esPtrOut,timeout,key)
1811 ExpState *(esPtrs[]); /* If 0, then esPtrOut already known and set */
1812 int esPtrsMax; /* number of esPtrs */
1813 ExpState **esPtrOut; /* Out variable to leave new ExpState. */
1822 int tcl_set_flags; /* if we have to discard chars, this tells */
1823 /* whether to show user locally or globally */
1826 /* we already know the ExpState, just find out what happened */
1827 cc = exp_get_next_event_info(interp,*esPtrOut);
1828 tcl_set_flags = TCL_GLOBAL_ONLY;
1830 cc = exp_get_next_event(interp,esPtrs,esPtrsMax,esPtrOut,timeout,key);
1835 if (cc == EXP_DATA_NEW) {
1836 /* try to read it */
1837 cc = expIRead(interp,esPtr,timeout,tcl_set_flags);
1839 /* the meaning of 0 from i_read means eof. Muck with it a */
1840 /* little, so that from now on it means "no new data arrived */
1841 /* but it should be looked at again anyway". */
1844 } else if (cc > 0) {
1845 /* successfully read data */
1847 /* failed to read data - some sort of error was encountered such as
1848 * an interrupt with that forced an error return
1851 } else if (cc == EXP_DATA_OLD) {
1853 } else if (cc == EXP_RECONFIGURE) {
1854 return EXP_RECONFIGURE;
1857 if (cc == EXP_ABEOF) { /* abnormal EOF */
1858 /* On many systems, ptys produce EIO upon EOF - sigh */
1859 if (i_read_errno == EIO) {
1860 /* Sun, Cray, BSD, and others */
1862 } else if (i_read_errno == EINVAL) {
1863 /* Solaris 2.4 occasionally returns this */
1866 if (i_read_errno == EBADF) {
1867 exp_error(interp,"bad spawn_id (process died earlier?)");
1869 exp_error(interp,"i_read(spawn_id fd=%d): %s",esPtr->fdin,
1870 Tcl_PosixError(interp));
1871 if (esPtr->close_on_eof) {
1872 exp_close(interp,esPtr);
1875 return(EXP_TCLERROR);
1876 /* was goto error; */
1880 /* EOF, TIMEOUT, and ERROR return here */
1881 /* In such cases, there is no need to update screen since, if there */
1882 /* was prior data read, it would have been sent to the screen when */
1884 if (cc < 0) return (cc);
1890 size = expSizeGet(esPtr);
1891 if (size) write_count = size - esPtr->printed;
1892 else write_count = 0;
1896 * Show chars to user if they've requested it, UNLESS they're seeing it
1897 * already because they're typing it and tty driver is echoing it.
1898 * Also send to Diag and Log if appropriate.
1900 expLogInteractionU(esPtr,Tcl_GetString(esPtr->buffer) + esPtr->printed);
1903 * strip nulls from input, since there is no way for Tcl to deal with
1904 * such strings. Doing it here lets them be sent to the screen, just
1905 * in case they are involved in formatting operations
1907 if (esPtr->rm_nulls) size = expNullStrip(esPtr->buffer,esPtr->printed);
1908 esPtr->printed = size; /* count'm even if not logging */
1913 /* when buffer fills, copy second half over first and */
1914 /* continue, so we can do matches over multiple buffers */
1916 exp_buffer_shuffle(interp,esPtr,save_flags,array_name,caller_name) /* INTL */
1931 * allow user to see data we are discarding
1934 expDiagLog("%s: set %s(spawn_id) \"%s\"\r\n",
1935 caller_name,array_name,esPtr->name);
1936 Tcl_SetVar2(interp,array_name,"spawn_id",esPtr->name,save_flags);
1939 * The internal storage buffer object should only be referred
1940 * to by the channel that uses it. We always copy the contents
1941 * out of the object before passing the data to anyone outside
1942 * of these routines. This ensures that the object always has
1943 * a refcount of 1 so we can safely modify the contents in place.
1946 if (Tcl_IsShared(esPtr->buffer)) {
1947 panic("exp_buffer_shuffle called with shared buffer object");
1950 str = Tcl_GetStringFromObj(esPtr->buffer,&length);
1952 /* guess at the middle */
1953 middleGuess = str + length/2;
1955 /* crawl our way into the middle of the string
1956 * to make sure we are at a UTF char boundary
1959 /* TIP 27: We cast CONST away to allow the restoration the lostByte later on
1960 * See 'restore damage' below.
1963 for (p=str;*p;p = (char*) Tcl_UtfNext(p)) {
1964 if (p > middleGuess) break; /* ok, that's enough */
1968 * p is now at the beginning of a UTF char in the middle of the string
1972 * before doing move, show user data we are discarding
1976 /* temporarily stick null in middle of string */
1977 Tcl_SetObjLength(esPtr->buffer,skiplen);
1979 expDiagLog("%s: set %s(buffer) \"",caller_name,array_name);
1980 expDiagLogU(expPrintify(Tcl_GetString(esPtr->buffer)));
1981 expDiagLogU("\"\r\n");
1982 Tcl_SetVar2(interp,array_name,"buffer",Tcl_GetString(esPtr->buffer),
1991 * move 2nd half of string down to 1st half
1994 newlen = length - skiplen;
1995 memmove(str,p, newlen);
1997 Tcl_SetObjLength(esPtr->buffer,newlen);
1999 esPtr->printed -= skiplen;
2000 if (esPtr->printed < 0) esPtr->printed = 0;
2003 /* map EXP_ style return value to TCL_ style return value */
2004 /* not defined to work on TCL_OK */
2006 exp_tcl2_returnvalue(x)
2010 case TCL_ERROR: return EXP_TCLERROR;
2011 case TCL_RETURN: return EXP_TCLRET;
2012 case TCL_BREAK: return EXP_TCLBRK;
2013 case TCL_CONTINUE: return EXP_TCLCNT;
2014 case EXP_CONTINUE: return EXP_TCLCNTEXP;
2015 case EXP_CONTINUE_TIMER: return EXP_TCLCNTTIMER;
2016 case EXP_TCL_RETURN: return EXP_TCLRETTCL;
2020 /* map from EXP_ style return value to TCL_ style return values */
2022 exp_2tcl_returnvalue(x)
2026 case EXP_TCLERROR: return TCL_ERROR;
2027 case EXP_TCLRET: return TCL_RETURN;
2028 case EXP_TCLBRK: return TCL_BREAK;
2029 case EXP_TCLCNT: return TCL_CONTINUE;
2030 case EXP_TCLCNTEXP: return EXP_CONTINUE;
2031 case EXP_TCLCNTTIMER: return EXP_CONTINUE_TIMER;
2032 case EXP_TCLRETTCL: return EXP_TCL_RETURN;
2036 /* variables predefined by expect are retrieved using this routine
2037 which looks in the global space if they are not in the local space.
2038 This allows the user to localize them if desired, and also to
2039 avoid having to put "global" in procedure definitions.
2042 exp_get_var(interp,var)
2048 if (NULL != (val = Tcl_GetVar(interp,var,0 /* local */)))
2050 return(Tcl_GetVar(interp,var,TCL_GLOBAL_ONLY));
2057 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
2060 if (NULL != (t = exp_get_var(interp,EXPECT_TIMEOUT))) {
2061 tsdPtr->timeout = atoi(t);
2063 return(tsdPtr->timeout);
2066 /* make a copy of a linked list (1st arg) and attach to end of another (2nd
2069 update_expect_states(i_list,i_union)
2070 struct exp_i *i_list;
2071 struct exp_state_list **i_union;
2075 /* for each i_list in an expect statement ... */
2076 for (p=i_list;p;p=p->next) {
2077 struct exp_state_list *slPtr;
2079 /* for each esPtr in the i_list */
2080 for (slPtr=p->state_list;slPtr;slPtr=slPtr->next) {
2081 struct exp_state_list *tmpslPtr;
2082 struct exp_state_list *u;
2084 if (expStateAnyIs(slPtr->esPtr)) continue;
2086 /* check this one against all so far */
2087 for (u = *i_union;u;u=u->next) {
2088 if (slPtr->esPtr == u->esPtr) goto found;
2090 /* if not found, link in as head of list */
2091 tmpslPtr = exp_new_state(slPtr->esPtr);
2092 tmpslPtr->next = *i_union;
2093 *i_union = tmpslPtr;
2101 exp_cmdtype_printable(cmdtype)
2105 case EXP_CMD_FG: return("expect");
2106 case EXP_CMD_BG: return("expect_background");
2107 case EXP_CMD_BEFORE: return("expect_before");
2108 case EXP_CMD_AFTER: return("expect_after");
2111 return("unknown expect command");
2115 /* exp_indirect_update2 is called back via Tcl's trace handler whenever */
2116 /* an indirect spawn id list is changed */
2119 exp_indirect_update2(clientData, interp, name1, name2, flags)
2120 ClientData clientData;
2121 Tcl_Interp *interp; /* Interpreter containing variable. */
2122 char *name1; /* Name of variable. */
2123 char *name2; /* Second part of variable name. */
2124 int flags; /* Information about what happened. */
2128 struct exp_i *exp_i = (struct exp_i *)clientData;
2129 exp_configure_count++;
2130 msg = exp_indirect_update1(interp,&exp_cmds[exp_i->cmdtype],exp_i);
2132 exp_background_channelhandlers_run_all();
2138 exp_indirect_update1(interp,ecmd,exp_i)
2140 struct exp_cmd_descriptor *ecmd;
2141 struct exp_i *exp_i;
2143 struct exp_state_list *slPtr; /* temp for interating over state_list */
2146 * disarm any ExpState's that lose all their active spawn ids
2149 if (ecmd->cmdtype == EXP_CMD_BG) {
2150 /* clean up each spawn id used by this exp_i */
2151 for (slPtr=exp_i->state_list;slPtr;slPtr=slPtr->next) {
2152 ExpState *esPtr = slPtr->esPtr;
2154 if (expStateAnyIs(esPtr)) continue;
2156 /* silently skip closed or preposterous fds */
2157 /* since we're just disabling them anyway */
2158 /* preposterous fds will have been reported */
2159 /* by code in next section already */
2160 if (!expStateCheck(interp,slPtr->esPtr,1,0,"")) continue;
2162 /* check before decrementing, ecount may not be */
2163 /* positive if update is called before ecount is */
2164 /* properly synchronized */
2165 if (esPtr->bg_ecount > 0) {
2168 if (esPtr->bg_ecount == 0) {
2169 exp_disarm_background_channelhandler(esPtr);
2170 esPtr->bg_interp = 0;
2176 * reread indirect variable
2179 exp_i_update(interp,exp_i);
2182 * check validity of all fd's in variable
2185 for (slPtr=exp_i->state_list;slPtr;slPtr=slPtr->next) {
2186 /* validate all input descriptors */
2188 if (expStateAnyIs(slPtr->esPtr)) continue;
2190 if (!expStateCheck(interp,slPtr->esPtr,1,1,
2191 exp_cmdtype_printable(ecmd->cmdtype))) {
2192 static char msg[200];
2193 sprintf(msg,"%s from indirect variable (%s)",
2194 interp->result,exp_i->variable);
2199 /* for each spawn id in list, arm if necessary */
2200 if (ecmd->cmdtype == EXP_CMD_BG) {
2201 state_list_arm(interp,exp_i->state_list);
2208 expMatchProcess(interp, eo, cc, bg, detail)
2210 struct eval_out *eo; /* final case of interest */
2211 int cc; /* EOF, TIMEOUT, etc... */
2212 int bg; /* 1 if called from background handler, */
2216 ExpState *esPtr = 0;
2219 struct ecase *e = 0; /* points to current ecase */
2220 int match = -1; /* characters matched */
2221 char match_char; /* place to hold char temporarily */
2222 /* uprooted by a NULL */
2223 int result = TCL_OK;
2225 #define out(indexName, value) \
2226 expDiagLog("%s: set %s(%s) \"",detail,EXPECT_OUT,indexName); \
2227 expDiagLogU(expPrintify(value)); \
2228 expDiagLogU("\"\r\n"); \
2229 Tcl_SetVar2(interp, EXPECT_OUT,indexName,value,(bg ? TCL_GLOBAL_ONLY : 0));
2234 if (cc != EXP_TIMEOUT) {
2237 buffer = eo->buffer;
2239 } else if (cc == EXP_EOF) {
2240 /* read an eof but no user-supplied case */
2243 buffer = eo->buffer;
2247 char name[20], value[20];
2250 if (e && e->use == PAT_RE) {
2253 Tcl_RegExpInfo info;
2255 if (e->Case == CASE_NORM) {
2256 flags = TCL_REG_ADVANCED;
2258 flags = TCL_REG_ADVANCED | TCL_REG_NOCASE;
2261 re = Tcl_GetRegExpFromObj(interp, e->pat, flags);
2262 Tcl_RegExpGetInfo(re, &info);
2264 for (i=0;i<=info.nsubs;i++) {
2268 start = info.matches[i].start;
2269 end = info.matches[i].end-1;
2270 if (start == -1) continue;
2274 sprintf(name,"%d,start",i);
2275 sprintf(value,"%d",start);
2279 sprintf(name,"%d,end",i);
2280 sprintf(value,"%d",end);
2285 sprintf(name,"%d,string",i);
2286 val = Tcl_GetRange(buffer, start, end);
2287 expDiagLog("%s: set %s(%s) \"",detail,EXPECT_OUT,name);
2288 expDiagLogU(expPrintifyObj(val));
2289 expDiagLogU("\"\r\n");
2290 Tcl_SetVar2Ex(interp,EXPECT_OUT,name,val,(bg ? TCL_GLOBAL_ONLY : 0));
2292 } else if (e && (e->use == PAT_GLOB || e->use == PAT_EXACT)) {
2297 sprintf(value,"%d",e->simple_start);
2298 out("0,start",value);
2301 sprintf(value,"%d",e->simple_start + match - 1);
2306 str = Tcl_GetString(esPtr->buffer) + e->simple_start;
2307 /* temporarily null-terminate in middle */
2308 match_char = str[match];
2310 out("0,string",str);
2311 str[match] = match_char;
2313 /* redefine length of string that */
2314 /* matched for later extraction */
2315 match += e->simple_start;
2316 } else if (e && e->use == PAT_NULL && e->indices) {
2318 sprintf(value,"%d",match-1);
2319 out("0,start",value);
2321 sprintf(value,"%d",match-1);
2323 } else if (e && e->use == PAT_FULLBUFFER) {
2324 expDiagLogU("expect_background: full buffer\r\n");
2328 /* this is broken out of (match > 0) (above) since it can */
2329 /* that an EOF occurred with match == 0 */
2334 out("spawn_id",esPtr->name);
2336 str = Tcl_GetStringFromObj(esPtr->buffer, &length);
2337 /* Save buf[0..match] */
2338 /* temporarily null-terminate string in middle */
2339 match_char = str[match];
2342 /* remove middle-null-terminator */
2343 str[match] = match_char;
2345 /* "!e" means no case matched - transfer by default */
2346 if (!e || e->transfer) {
2347 /* delete matched chars from input buffer */
2348 esPtr->printed -= match;
2350 memmove(str,str+match,length-match);
2352 Tcl_SetObjLength(esPtr->buffer, length-match);
2355 if (cc == EXP_EOF) {
2356 /* exp_close() deletes all background bodies */
2357 /* so save eof body temporarily */
2358 if (body) Tcl_IncrRefCount(body);
2359 if (esPtr->close_on_eof) {
2360 exp_close(interp,esPtr);
2367 result = Tcl_EvalObjEx(interp,body,0);
2369 result = Tcl_EvalObjEx(interp,body,TCL_EVAL_GLOBAL);
2370 if (result != TCL_OK) Tcl_BackgroundError(interp);
2372 if (cc == EXP_EOF) Tcl_DecrRefCount(body);
2377 /* this function is called from the background when input arrives */
2380 exp_background_channelhandler(clientData,mask) /* INTL */
2381 ClientData clientData;
2384 char backup[EXP_CHANNELNAMELEN+1]; /* backup copy of esPtr channel name! */
2388 int cc; /* number of bytes returned in a single read */
2389 /* or negative EXP_whatever */
2390 struct eval_out eo; /* final case of interest */
2391 ExpState *last_esPtr; /* for differentiating when multiple esPtrs */
2392 /* to print out better debugging messages */
2393 int last_case; /* as above but for case */
2395 /* restore our environment */
2396 esPtr = (ExpState *)clientData;
2398 /* backup just in case someone zaps esPtr in the middle of our work! */
2399 strcpy(backup,esPtr->name);
2401 interp = esPtr->bg_interp;
2403 /* temporarily prevent this handler from being invoked again */
2404 exp_block_background_channelhandler(esPtr);
2407 * if mask == 0, then we've been called because the patterns changed not
2408 * because the waiting data has changed, so don't actually do any I/O
2413 esPtr->notifiedMask = mask;
2414 esPtr->notified = FALSE;
2415 cc = expRead(interp,(ExpState **)0,0,&esPtr,EXP_TIME_INFINITY,0);
2419 eo.e = 0; /* no final case yet */
2420 eo.esPtr = 0; /* no final file selected yet */
2421 eo.match = 0; /* nothing matched yet */
2423 /* force redisplay of buffer when debugging */
2426 if (cc == EXP_EOF) {
2428 } else if (cc < 0) { /* EXP_TCLERROR or any other weird value*/
2431 * if we were going to do this right, we should differentiate between
2432 * things like HP ioctl-open-traps that fall out here and should
2433 * rightfully be ignored and real errors that should be reported. Come
2434 * to think of it, the only errors will come from HP ioctl handshake
2438 /* normal case, got data */
2439 /* new data if cc > 0, same old data if cc == 0 */
2441 /* below here, cc as general status */
2445 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BEFORE],
2446 esPtr,&eo,&last_esPtr,&last_case,cc,&esPtr,1,"_background");
2447 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BG],
2448 esPtr,&eo,&last_esPtr,&last_case,cc,&esPtr,1,"_background");
2449 cc = eval_cases(interp,&exp_cmds[EXP_CMD_AFTER],
2450 esPtr,&eo,&last_esPtr,&last_case,cc,&esPtr,1,"_background");
2451 if (cc == EXP_TCLERROR) {
2452 /* only likely problem here is some internal regexp botch */
2453 Tcl_BackgroundError(interp);
2456 /* special eof code that cannot be done in eval_cases */
2457 /* or above, because it would then be executed several times */
2458 if (cc == EXP_EOF) {
2460 eo.match = expSizeGet(eo.esPtr);
2461 eo.buffer = eo.esPtr->buffer;
2462 expDiagLogU("expect_background: read eof\r\n");
2466 /* if we get here, there must not have been a match */
2471 expMatchProcess(interp, &eo, cc, 1 /* bg */,"expect_background");
2474 * Event handler will not call us back if there is more input
2475 * pending but it has already arrived. bg_status will be
2476 * "blocked" only if armed.
2480 * Connection could have been closed on us. In this case,
2481 * exitWhenBgStatusUnblocked will be 1 and we should disable the channel
2482 * handler and release the esPtr.
2485 /* First check that the esPtr is even still valid! */
2486 /* This ought to be sufficient. */
2487 if (0 == Tcl_GetChannel(interp,backup,(int *)0)) {
2488 expDiagLog("expect channel %s lost in background handler\n",backup);
2492 if ((!esPtr->freeWhenBgHandlerUnblocked) && (esPtr->bg_status == blocked)) {
2493 if (0 != (cc = expSizeGet(esPtr))) {
2498 exp_unblock_background_channelhandler(esPtr);
2499 if (esPtr->freeWhenBgHandlerUnblocked)
2500 expStateFree(esPtr);
2505 Exp_ExpectObjCmd(clientData, interp, objc, objv)
2506 ClientData clientData;
2509 Tcl_Obj *CONST objv[]; /* Argument objects. */
2511 int cc; /* number of chars returned in a single read */
2512 /* or negative EXP_whatever */
2513 ExpState *esPtr = 0;
2515 int i; /* misc temporary */
2516 struct exp_cmd_descriptor eg;
2517 struct exp_state_list *state_list; /* list of ExpStates to watch */
2518 struct exp_state_list *slPtr; /* temp for interating over state_list */
2520 int mcount; /* number of esPtrs to watch */
2522 struct eval_out eo; /* final case of interest */
2524 int result; /* Tcl result */
2526 time_t start_time_total; /* time at beginning of this procedure */
2527 time_t start_time = 0; /* time when restart label hit */
2528 time_t current_time = 0; /* current time (when we last looked)*/
2529 time_t end_time; /* future time at which to give up */
2531 ExpState *last_esPtr; /* for differentiating when multiple f's */
2532 /* to print out better debugging messages */
2533 int last_case; /* as above but for case */
2534 int first_time = 1; /* if not "restarted" */
2536 int key; /* identify this expect command instance */
2537 int configure_count; /* monitor exp_configure_count */
2539 int timeout; /* seconds */
2540 int remtime; /* remaining time in timeout */
2541 int reset_timer; /* should timer be reset after continue? */
2543 if ((objc == 2) && exp_one_arg_braced(objv[1])) {
2544 return(exp_eval_with_one_arg(clientData,interp,objv));
2545 } else if ((objc == 3) && streq(Tcl_GetString(objv[1]),"-brace")) {
2546 Tcl_Obj *new_objv[2];
2547 new_objv[0] = objv[0];
2548 new_objv[1] = objv[2];
2549 return(exp_eval_with_one_arg(clientData,interp,new_objv));
2552 time(&start_time_total);
2553 start_time = start_time_total;
2556 if (&StdinoutPlaceholder == (ExpState *)clientData) {
2557 clientData = (ClientData) expStdinoutGet();
2558 } else if (&DevttyPlaceholder == (ExpState *)clientData) {
2559 clientData = (ClientData) expDevttyGet();
2562 /* make arg list for processing cases */
2563 /* do it dynamically, since expect can be called recursively */
2565 exp_cmd_init(&eg,EXP_CMD_FG,EXP_TEMPORARY);
2568 if (TCL_ERROR == parse_expect_args(interp,&eg,
2569 (ExpState *)clientData,objc,objv))
2572 restart_with_update:
2573 /* validate all descriptors and flatten ExpStates into array */
2575 if ((TCL_ERROR == update_expect_states(exp_cmds[EXP_CMD_BEFORE].i_list,&state_list))
2576 || (TCL_ERROR == update_expect_states(exp_cmds[EXP_CMD_AFTER].i_list, &state_list))
2577 || (TCL_ERROR == update_expect_states(eg.i_list,&state_list))) {
2582 /* declare ourselves "in sync" with external view of close/indirect */
2583 configure_count = exp_configure_count;
2585 /* count and validate state_list */
2587 for (slPtr=state_list;slPtr;slPtr=slPtr->next) {
2589 /* validate all input descriptors */
2590 if (!expStateCheck(interp,slPtr->esPtr,1,1,"expect")) {
2596 /* make into an array */
2597 esPtrs = (ExpState **)ckalloc(mcount * sizeof(ExpState *));
2598 for (slPtr=state_list,i=0;slPtr;slPtr=slPtr->next,i++) {
2599 esPtrs[i] = slPtr->esPtr;
2603 if (first_time) first_time = 0;
2604 else time(&start_time);
2606 if (eg.timeout_specified_by_flag) {
2607 timeout = eg.timeout;
2609 /* get the latest timeout */
2610 timeout = get_timeout(interp);
2619 * end of restart code
2622 eo.e = 0; /* no final case yet */
2623 eo.esPtr = 0; /* no final ExpState selected yet */
2624 eo.match = 0; /* nothing matched yet */
2626 /* timeout code is a little tricky, be very careful changing it */
2627 if (timeout != EXP_TIME_INFINITY) {
2628 /* if exp_continue -continue_timer, do not update end_time */
2630 time(¤t_time);
2631 end_time = current_time + timeout;
2637 /* remtime and current_time updated at bottom of loop */
2641 if ((timeout != EXP_TIME_INFINITY) && (remtime < 0)) {
2644 cc = expRead(interp,esPtrs,mcount,&esPtr,remtime,key);
2648 if (cc == EXP_EOF) {
2650 } else if (cc == EXP_TIMEOUT) {
2651 expDiagLogU("expect: timed out\r\n");
2652 } else if (cc == EXP_RECONFIGURE) {
2653 reset_timer = FALSE;
2654 goto restart_with_update;
2655 } else if (cc < 0) { /* EXP_TCLERROR or any other weird value*/
2658 /* new data if cc > 0, same old data if cc == 0 */
2660 /* below here, cc as general status */
2663 /* force redisplay of buffer when debugging */
2667 cc = eval_cases(interp,&exp_cmds[EXP_CMD_BEFORE],
2668 esPtr,&eo,&last_esPtr,&last_case,cc,esPtrs,mcount,"");
2669 cc = eval_cases(interp,&eg,
2670 esPtr,&eo,&last_esPtr,&last_case,cc,esPtrs,mcount,"");
2671 cc = eval_cases(interp,&exp_cmds[EXP_CMD_AFTER],
2672 esPtr,&eo,&last_esPtr,&last_case,cc,esPtrs,mcount,"");
2673 if (cc == EXP_TCLERROR) goto error;
2674 /* special eof code that cannot be done in eval_cases */
2675 /* or above, because it would then be executed several times */
2676 if (cc == EXP_EOF) {
2678 eo.match = expSizeGet(eo.esPtr);
2679 eo.buffer = eo.esPtr->buffer;
2680 expDiagLogU("expect: read eof\r\n");
2682 } else if (cc == EXP_TIMEOUT) break;
2683 /* break if timeout or eof and failed to find a case for it */
2687 /* no match was made with current data, force a read */
2688 esPtr->force_read = TRUE;
2690 if (timeout != EXP_TIME_INFINITY) {
2691 time(¤t_time);
2692 remtime = end_time - current_time;
2699 result = exp_2tcl_returnvalue(cc);
2701 if (result != TCL_ERROR) {
2702 result = expMatchProcess(interp, &eo, cc, 0 /* not bg */,"expect");
2706 if (result == EXP_CONTINUE_TIMER) {
2707 reset_timer = FALSE;
2708 result = EXP_CONTINUE;
2711 if ((result == EXP_CONTINUE) && (configure_count == exp_configure_count)) {
2712 expDiagLogU("expect: continuing expect\r\n");
2717 exp_free_state(state_list);
2721 ckfree((char *)esPtrs);
2725 if (result == EXP_CONTINUE) {
2726 expDiagLogU("expect: continuing expect after update\r\n");
2727 goto restart_with_update;
2730 free_ecases(interp,&eg,0); /* requires i_lists to be avail */
2731 exp_free_i(interp,eg.i_list,exp_indirect_update2);
2738 Exp_TimestampCmd(clientData, interp, argc, argv)
2739 ClientData clientData;
2745 time_t seconds = -1;
2746 int gmt = FALSE; /* local time by default */
2748 Tcl_DString dstring;
2753 if (streq(*argv,"-format")) {
2755 if (!*argv) goto usage_error;
2758 } else if (streq(*argv,"-seconds")) {
2760 if (!*argv) goto usage_error;
2761 seconds = atoi(*argv);
2763 } else if (streq(*argv,"-gmt")) {
2769 if (argc) goto usage_error;
2771 if (seconds == -1) {
2775 Tcl_DStringInit(&dstring);
2779 tm = gmtime(&seconds);
2781 tm = localtime(&seconds);
2783 /* exp_strftime(interp->result,TCL_RESULT_SIZE,format,tm);*/
2784 exp_strftime(format,tm,&dstring);
2785 Tcl_DStringResult(interp,&dstring);
2787 sprintf(interp->result,"%ld",seconds);
2792 exp_error(interp,"args: [-seconds #] [-format format]");
2799 Exp_MatchMaxCmd(clientData,interp,argc,argv)
2800 ClientData clientData;
2806 ExpState *esPtr = 0;
2808 int Default = FALSE;
2812 for (;argc>0;argc--,argv++) {
2813 if (streq(*argv,"-d")) {
2815 } else if (streq(*argv,"-i")) {
2818 exp_error(interp,"-i needs argument");
2825 if (Default && chanName) {
2826 exp_error(interp,"cannot do -d and -i at the same time");
2832 if (!(esPtr = expStateCurrent(interp,0,0,0))) {
2837 if (!(esPtr = expStateFromChannelName(interp,chanName,0,0,0,"match_max")))
2844 size = exp_default_match_max;
2846 size = esPtr->umsize;
2848 sprintf(interp->result,"%d",size);
2853 exp_error(interp,"too many arguments");
2858 * All that's left is to set the size
2861 size = atoi(argv[0]);
2863 exp_error(interp,"must be positive");
2868 exp_default_match_max = size;
2869 exp_default_match_max_changed = 1;
2872 esPtr->umsize = size;
2873 esPtr->umsize_changed = 1;
2881 Exp_RemoveNullsCmd(clientData,interp,argc,argv)
2882 ClientData clientData;
2888 ExpState *esPtr = 0;
2890 int Default = FALSE;
2894 for (;argc>0;argc--,argv++) {
2895 if (streq(*argv,"-d")) {
2897 } else if (streq(*argv,"-i")) {
2900 exp_error(interp,"-i needs argument");
2907 if (Default && chanName) {
2908 exp_error(interp,"cannot do -d and -i at the same time");
2914 if (!(esPtr = expStateCurrent(interp,0,0,0)))
2917 if (!(esPtr = expStateFromChannelName(interp,chanName,0,0,0,"remove_nulls")))
2924 value = exp_default_rm_nulls;
2926 value = esPtr->rm_nulls;
2928 sprintf(interp->result,"%d",value);
2933 exp_error(interp,"too many arguments");
2937 /* all that's left is to set the value */
2938 value = atoi(argv[0]);
2939 if (value != 0 && value != 1) {
2940 exp_error(interp,"must be 0 or 1");
2944 if (Default) exp_default_rm_nulls = value;
2945 else esPtr->rm_nulls = value;
2952 Exp_ParityCmd(clientData,interp,argc,argv)
2953 ClientData clientData;
2959 ExpState *esPtr = 0;
2961 int Default = FALSE;
2965 for (;argc>0;argc--,argv++) {
2966 if (streq(*argv,"-d")) {
2968 } else if (streq(*argv,"-i")) {
2971 exp_error(interp,"-i needs argument");
2978 if (Default && chanName) {
2979 exp_error(interp,"cannot do -d and -i at the same time");
2985 if (!(esPtr = expStateCurrent(interp,0,0,0))) {
2989 if (!(esPtr = expStateFromChannelName(interp,chanName,0,0,0,"parity"))) {
2997 parity = exp_default_parity;
2999 parity = esPtr->parity;
3001 sprintf(interp->result,"%d",parity);
3006 exp_error(interp,"too many arguments");
3010 /* all that's left is to set the parity */
3011 parity = atoi(argv[0]);
3013 if (Default) exp_default_parity = parity;
3014 else esPtr->parity = parity;
3021 Exp_CloseOnEofCmd(clientData,interp,argc,argv)
3022 ClientData clientData;
3028 ExpState *esPtr = 0;
3030 int Default = FALSE;
3034 for (;argc>0;argc--,argv++) {
3035 if (streq(*argv,"-d")) {
3037 } else if (streq(*argv,"-i")) {
3040 exp_error(interp,"-i needs argument");
3047 if (Default && chanName) {
3048 exp_error(interp,"cannot do -d and -i at the same time");
3054 if (!(esPtr = expStateCurrent(interp,0,0,0))) {
3058 if (!(esPtr = expStateFromChannelName(interp,chanName,0,0,0,"close_on_eof"))) {
3066 close_on_eof = exp_default_close_on_eof;
3068 close_on_eof = esPtr->close_on_eof;
3070 sprintf(interp->result,"%d",close_on_eof);
3075 exp_error(interp,"too many arguments");
3079 /* all that's left is to set the close_on_eof */
3080 close_on_eof = atoi(argv[0]);
3082 if (Default) exp_default_close_on_eof = close_on_eof;
3083 else esPtr->close_on_eof = close_on_eof;
3088 #if DEBUG_PERM_ECASES
3089 /* This big chunk of code is just for debugging the permanent */
3093 struct exp_state_list *slPtr;
3096 printf("%d ",slPtr->esPtr);
3097 exp_fd_print(slPtr->next);
3102 struct exp_i *exp_i;
3105 printf("exp_i %x",exp_i);
3106 printf((exp_i->direct == EXP_DIRECT)?" direct":" indirect");
3107 printf((exp_i->duration == EXP_PERMANENT)?" perm":" tmp");
3108 printf(" ecount = %d\n",exp_i->ecount);
3109 printf("variable %s, value %s\n",
3110 ((exp_i->variable)?exp_i->variable:"--"),
3111 ((exp_i->value)?exp_i->value:"--"));
3112 printf("ExpStates: ");
3113 exp_fd_print(exp_i->state_list); printf("\n");
3114 exp_i_print(exp_i->next);
3118 exp_ecase_print(ecase)
3119 struct ecase *ecase;
3121 printf("pat <%s>\n",ecase->pat);
3122 printf("exp_i = %x\n",ecase->i_list);
3126 exp_ecases_print(ecd)
3127 struct exp_cases_descriptor *ecd;
3131 printf("%d cases\n",ecd->count);
3132 for (i=0;i<ecd->count;i++) exp_ecase_print(ecd->cases[i]);
3137 struct exp_cmd_descriptor *ecmd;
3139 printf("expect cmd type: %17s",exp_cmdtype_printable(ecmd->cmdtype));
3140 printf((ecmd->duration==EXP_PERMANENT)?" perm ": "tmp ");
3142 exp_ecases_print(&ecmd->ecd);
3143 exp_i_print(ecmd->i_list);
3149 exp_cmd_print(&exp_cmds[EXP_CMD_BEFORE]);
3150 exp_cmd_print(&exp_cmds[EXP_CMD_AFTER]);
3151 exp_cmd_print(&exp_cmds[EXP_CMD_BG]);
3156 cmdX(clientData, interp, argc, argv)
3157 ClientData clientData;
3165 #endif /*DEBUG_PERM_ECASES*/
3170 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
3172 tsdPtr->timeout = INIT_EXPECT_TIMEOUT;
3175 static struct exp_cmd_data
3177 {"expect", Exp_ExpectObjCmd, 0, (ClientData)0, 0},
3178 {"expect_after",Exp_ExpectGlobalObjCmd, 0, (ClientData)&exp_cmds[EXP_CMD_AFTER],0},
3179 {"expect_before",Exp_ExpectGlobalObjCmd,0, (ClientData)&exp_cmds[EXP_CMD_BEFORE],0},
3180 {"expect_user", Exp_ExpectObjCmd, 0, (ClientData)&StdinoutPlaceholder,0},
3181 {"expect_tty", Exp_ExpectObjCmd, 0, (ClientData)&DevttyPlaceholder,0},
3182 {"expect_background",Exp_ExpectGlobalObjCmd,0, (ClientData)&exp_cmds[EXP_CMD_BG],0},
3183 {"match_max", exp_proc(Exp_MatchMaxCmd), 0, 0},
3184 {"remove_nulls",exp_proc(Exp_RemoveNullsCmd), 0, 0},
3185 {"parity", exp_proc(Exp_ParityCmd), 0, 0},
3186 {"close_on_eof",exp_proc(Exp_CloseOnEofCmd), 0, 0},
3187 {"timestamp", exp_proc(Exp_TimestampCmd), 0, 0},
3191 exp_init_expect_cmds(interp)
3194 exp_create_commands(interp,cmd_data);
3198 Tcl_SetVar(interp,EXPECT_TIMEOUT,INIT_EXPECT_TIMEOUT_LIT,0);
3200 exp_cmd_init(&exp_cmds[EXP_CMD_BEFORE],EXP_CMD_BEFORE,EXP_PERMANENT);
3201 exp_cmd_init(&exp_cmds[EXP_CMD_AFTER ],EXP_CMD_AFTER, EXP_PERMANENT);
3202 exp_cmd_init(&exp_cmds[EXP_CMD_BG ],EXP_CMD_BG, EXP_PERMANENT);
3203 exp_cmd_init(&exp_cmds[EXP_CMD_FG ],EXP_CMD_FG, EXP_TEMPORARY);
3205 /* preallocate to one element, so future realloc's work */
3206 exp_cmds[EXP_CMD_BEFORE].ecd.cases = 0;
3207 exp_cmds[EXP_CMD_AFTER ].ecd.cases = 0;
3208 exp_cmds[EXP_CMD_BG ].ecd.cases = 0;
3210 pattern_style[PAT_EOF] = "eof";
3211 pattern_style[PAT_TIMEOUT] = "timeout";
3212 pattern_style[PAT_DEFAULT] = "default";
3213 pattern_style[PAT_FULLBUFFER] = "full buffer";
3214 pattern_style[PAT_GLOB] = "glob pattern";
3215 pattern_style[PAT_RE] = "regular expression";
3216 pattern_style[PAT_EXACT] = "exact string";
3217 pattern_style[PAT_NULL] = "null";
3220 Tcl_CreateCommand(interp,"x",
3221 cmdX,(ClientData)0,exp_deleteProc);
3228 signal(SIGALRM,sigalarm_handler);
3229 signal(SIGINT,sigint_handler);