1 /* command.h - definitions for 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.
10 #ifdef HAVE_SYS_WAIT_H
11 /* ISC doesn't def WNOHANG unless _POSIX_SOURCE is def'ed */
12 # ifdef WNOHANG_REQUIRES_POSIX_SOURCE
13 # define _POSIX_SOURCE
15 # include <sys/wait.h>
16 # ifdef WNOHANG_REQUIRES_POSIX_SOURCE
22 /* From: "Daniel A. Steffen" <steffen@ics.mq.edu.au> */
28 #define EXP_CHANNELNAMELEN (16 + TCL_INTEGER_SPACE)
30 EXTERN char * exp_get_var _ANSI_ARGS_((Tcl_Interp *,char *));
32 EXTERN int exp_default_match_max;
33 EXTERN int exp_default_parity;
34 EXTERN int exp_default_rm_nulls;
35 EXTERN int exp_default_close_on_eof;
37 EXTERN int exp_one_arg_braced _ANSI_ARGS_((Tcl_Obj *));
39 EXTERN Tcl_Obj* exp_eval_with_one_arg _ANSI_ARGS_((ClientData,
40 Tcl_Interp *, struct Tcl_Obj * CONST objv[]));
42 EXTERN void exp_lowmemcpy _ANSI_ARGS_((char *,char *,int));
44 EXTERN int exp_flageq_code _ANSI_ARGS_((char *,char *,int));
46 #define exp_flageq(flag,string,minlen) \
47 (((string)[0] == (flag)[0]) && (exp_flageq_code(((flag)+1),((string)+1),((minlen)-1))))
49 /* exp_flageq for single char flags */
50 #define exp_flageq1(flag,string) \
51 ((string[0] == flag) && (string[1] == '\0'))
53 #define EXP_SPAWN_ID_USER 0
54 #define EXP_SPAWN_ID_ANY_LIT "-1"
56 #define EXP_CHANNEL_PREFIX "exp"
57 #define EXP_CHANNEL_PREFIX_LENGTH 3
58 #define isExpChannelName(name) \
59 (0 == strncmp(name,EXP_CHANNEL_PREFIX,EXP_CHANNEL_PREFIX_LENGTH))
61 #define exp_is_stdinfd(x) ((x) == 0)
62 #define exp_is_devttyfd(x) ((x) == exp_dev_tty)
64 #define EXP_NOPID 0 /* Used when there is no associated pid to */
65 /* wait for. For example: */
66 /* 1) When fd opened by someone else, e.g., */
68 /* 2) When entry not in use */
69 /* 3) To tell user pid of "spawn -open" */
70 /* 4) stdin, out, error */
74 /* these are occasionally useful to distinguish between various expect */
75 /* commands and are also used as array indices into the per-fd eg[] arrays */
76 #define EXP_CMD_BEFORE 0
77 #define EXP_CMD_AFTER 1
82 * This structure describes per-instance state of an Exp channel.
85 typedef struct ExpOrigin {
86 int refCount; /* Number of times this channel is used. */
87 Tcl_Channel channel_orig; /* If opened by someone else, i.e. tcl::open */
91 typedef struct ExpUniBuf {
92 Tcl_UniChar* buffer; /* char buffer, holdings unicode chars (fixed width) */
93 int max; /* number of CHARS the buffer has space for (== old msize) */
94 int use; /* number of CHARS the buffer is currently holding */
95 Tcl_Obj* newchars; /* Object to hold newly read characters */
98 typedef struct ExpState {
99 Tcl_Channel channel; /* Channel associated with this file. */
100 char name[EXP_CHANNELNAMELEN+1]; /* expect and interact set variables
101 to channel name, so for efficiency
103 int fdin; /* input fd */
104 int fdout; /* output fd - usually the same as fdin, although
105 may be different if channel opened by tcl::open */
106 ExpOrigin* chan_orig; /* If opened by someone else, i.e. tcl::open */
107 int fd_slave; /* slave fd if "spawn -pty" used */
109 /* this may go away if we find it is not needed */
110 /* it might be needed by inherited channels */
111 int validMask; /* OR'ed combination of TCL_READABLE,
112 * TCL_WRITABLE, or TCL_EXCEPTION: indicates
113 * which operations are valid on the file. */
115 int pid; /* pid or EXP_NOPID if no pid */
117 ExpUniBuf input; /* input buffer */
119 int umsize; /* # of bytes (min) that is guaranteed to match */
120 /* this comes from match_max command */
121 int printed; /* # of characters! written to stdout (if logging on) */
122 /* but not actually returned via a match yet */
123 int echoed; /* additional # of characters (beyond "printed" above) */
124 /* echoed back but not actually returned via a match */
125 /* yet. This supports interact -echo */
127 int rm_nulls; /* if nulls should be stripped before pat matching */
128 int open; /* if fdin/fdout open */
129 int user_waited; /* if user has issued "wait" command */
130 int sys_waited; /* if wait() (or variant) has been called */
131 int registered; /* if channel registered */
132 WAIT_STATUS_TYPE wait; /* raw status from wait() */
133 int parity; /* if parity should be preserved */
134 int close_on_eof; /* if channel should be closed automatically on eof */
135 int key; /* unique id that identifies what command instance */
136 /* last touched this buffer */
137 int force_read; /* force read to occur (even if buffer already has */
138 /* data). This supports interact CAN_MATCH */
139 int notified; /* If Tcl_NotifyChannel has been called and we */
140 /* have not yet read from the channel. */
141 int notifiedMask; /* Mask reported when notified. */
143 int fg_armed; /* If we have requested Tk_CreateFileHandler to be */
144 /* responding to foreground events. Note that */
145 /* other handlers can have stolen it away so this */
146 /* doesn't necessarily mean the handler is set. */
147 /* However, if fg_armed is 0, then the handlers */
148 /* definitely needs to be set. The significance of */
149 /* this flag is so we can remember to turn it off. */
151 char *slave_name; /* Full name of slave, i.e., /dev/ttyp0 */
152 #endif /* HAVE_PTYTRAP */
154 int leaveopen; /* If we should not call Tcl's close when we close - */
155 /* only relevant if Tcl does the original open */
157 Tcl_Interp *bg_interp; /* interp to process the bg cases */
158 int bg_ecount; /* number of background ExpStates */
160 blocked, /* blocked because we are processing the */
162 armed, /* normal state when bg handler in use */
163 unarmed, /* no bg handler in use */
164 disarm_req_while_blocked /* while blocked, a request */
165 /* was received to disarm it. Rather than */
166 /* processing the request immediately, defer */
167 /* it so that when we later try to unblock */
168 /* we will see at that time that it should */
169 /* instead be disarmed */
173 * If the channel is freed while in the middle of a bg event handler,
174 * remember that and defer freeing of the ExpState structure until
177 int freeWhenBgHandlerUnblocked;
179 /* If channel is closed but not yet waited on, we tie up the fd by
180 * attaching it to /dev/null. We play this little game so that we
181 * can embed the fd in the channel name. If we didn't tie up the
182 * fd, we'd get channel name collisions. I'd consider naming the
183 * channels independently of the fd, but this makes debugging easier.
188 * stdinout and stderr never go away so that our internal refs to them
189 * don't have to be invalidated. Having to worry about invalidating them
190 * would be a major pain. */
193 /* Remember that "reserved" esPtrs are no longer in use. */
196 struct ExpState *nextPtr; /* Pointer to next file in list of all
200 #define EXP_SPAWN_ID_BAD ((ExpState *)0)
202 #define EXP_TIME_INFINITY -1
204 extern Tcl_ChannelType expChannelType;
206 #define EXP_TEMPORARY 1 /* expect */
207 #define EXP_PERMANENT 2 /* expect_after, expect_before, expect_bg */
210 #define EXP_INDIRECT 2
212 EXTERN void expAdjust _ANSI_ARGS_((ExpState *));
213 EXTERN int expWriteChars _ANSI_ARGS_((ExpState *,char *,int));
214 EXTERN int expWriteCharsUni _ANSI_ARGS_((ExpState *,Tcl_UniChar *,int));
215 EXTERN void exp_buffer_shuffle _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,char *,char *));
216 EXTERN int exp_close _ANSI_ARGS_((Tcl_Interp *,ExpState *));
217 EXTERN void exp_close_all _ANSI_ARGS_((Tcl_Interp *));
218 EXTERN void exp_ecmd_remove_fd_direct_and_indirect
219 _ANSI_ARGS_((Tcl_Interp *,int));
220 EXTERN void exp_trap_on _ANSI_ARGS_((int));
221 EXTERN int exp_trap_off _ANSI_ARGS_((char *));
223 EXTERN void exp_strftime(char *format, const struct tm *timeptr,Tcl_DString *dstring);
225 #define exp_deleteProc (void (*)())0
226 #define exp_deleteObjProc (void (*)())0
228 EXTERN int expect_key;
229 EXTERN int exp_configure_count; /* # of times descriptors have been closed */
230 /* or indirect lists have been changed */
231 EXTERN int exp_nostack_dump; /* TRUE if user has requested unrolling of */
232 /* stack with no trace */
234 EXTERN void exp_init_pty _ANSI_ARGS_((void));
235 EXTERN void exp_pty_exit _ANSI_ARGS_((void));
236 EXTERN void exp_init_tty _ANSI_ARGS_((void));
237 EXTERN void exp_init_stdio _ANSI_ARGS_((void));
238 /*EXTERN void exp_init_expect _ANSI_ARGS_((Tcl_Interp *));*/
239 EXTERN void exp_init_spawn_ids _ANSI_ARGS_((Tcl_Interp *));
240 EXTERN void exp_init_spawn_id_vars _ANSI_ARGS_((Tcl_Interp *));
241 EXTERN void exp_init_trap _ANSI_ARGS_((void));
242 EXTERN void exp_init_send _ANSI_ARGS_((void));
243 EXTERN void exp_init_unit_random _ANSI_ARGS_((void));
244 EXTERN void exp_init_sig _ANSI_ARGS_((void));
245 EXTERN void expChannelInit _ANSI_ARGS_((void));
246 EXTERN int expChannelCountGet _ANSI_ARGS_((void));
248 EXTERN int exp_tcl2_returnvalue _ANSI_ARGS_((int));
249 EXTERN int exp_2tcl_returnvalue _ANSI_ARGS_((int));
251 EXTERN void exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp *));
252 EXTERN int exp_string_to_signal _ANSI_ARGS_((Tcl_Interp *,char *));
254 EXTERN char *exp_onexit_action;
256 #define exp_new(x) (x *)malloc(sizeof(x))
258 struct exp_state_list {
260 struct exp_state_list *next;
263 /* describes a -i flag */
265 int cmdtype; /* EXP_CMD_XXX. When an indirect update is */
266 /* triggered by Tcl, this helps tell us in what */
267 /* exp_i list to look in. */
268 int direct; /* if EXP_DIRECT, then the spawn ids have been given */
269 /* literally, else indirectly through a variable */
270 int duration; /* if EXP_PERMANENT, char ptrs here had to be */
271 /* malloc'd because Tcl command line went away - */
272 /* i.e., in expect_before/after */
274 char *value; /* if type == direct, this is the string that the */
275 /* user originally supplied to the -i flag. It may */
276 /* lose relevance as the fd_list is manipulated */
277 /* over time. If type == direct, this is the */
278 /* cached value of variable use this to tell if it */
279 /* has changed or not, and ergo whether it's */
280 /* necessary to reparse. */
282 int ecount; /* # of ecases this is used by */
284 struct exp_state_list *state_list;
288 EXTERN struct exp_i * exp_new_i_complex _ANSI_ARGS_((Tcl_Interp *,
289 char *, int, Tcl_VarTraceProc *));
290 EXTERN struct exp_i * exp_new_i_simple _ANSI_ARGS_((ExpState *,int));
291 EXTERN struct exp_state_list *exp_new_state _ANSI_ARGS_((ExpState *));
292 EXTERN void exp_free_i _ANSI_ARGS_((Tcl_Interp *,struct exp_i *,
293 Tcl_VarTraceProc *));
294 EXTERN void exp_free_state _ANSI_ARGS_((struct exp_state_list *));
295 EXTERN void exp_free_state_single _ANSI_ARGS_((struct exp_state_list *));
296 EXTERN int exp_i_update _ANSI_ARGS_((Tcl_Interp *,
300 * definitions for creating commands
303 #define EXP_NOPREFIX 1 /* don't define with "exp_" prefix */
304 #define EXP_REDEFINE 2 /* stomp on old commands with same name */
306 #define exp_proc(cmdproc) 0, cmdproc
308 struct exp_cmd_data {
310 Tcl_ObjCmdProc *objproc;
316 EXTERN void exp_create_commands _ANSI_ARGS_((Tcl_Interp *,
317 struct exp_cmd_data *));
318 EXTERN void exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp *));
319 EXTERN void exp_init_expect_cmds _ANSI_ARGS_((Tcl_Interp *));
320 EXTERN void exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp *));
321 EXTERN void exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp *));
322 EXTERN void exp_init_interact_cmds _ANSI_ARGS_((Tcl_Interp *));
323 EXTERN void exp_init_tty_cmds();
325 EXTERN ExpState * expStateCheck _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,int,char *));
326 EXTERN ExpState * expStateCurrent _ANSI_ARGS_((Tcl_Interp *,int,int,int));
327 EXTERN ExpState * expStateFromChannelName _ANSI_ARGS_((Tcl_Interp *,char *,int,int,int,char *));
328 EXTERN void expStateFree _ANSI_ARGS_((ExpState *));
330 EXTERN ExpState * expCreateChannel _ANSI_ARGS_((Tcl_Interp *,int,int,int));
331 EXTERN ExpState * expWaitOnAny _ANSI_ARGS_((void));
332 EXTERN ExpState * expWaitOnOne _ANSI_ARGS_((void));
333 EXTERN void expExpectVarsInit _ANSI_ARGS_((void));
334 EXTERN int expStateAnyIs _ANSI_ARGS_((ExpState *));
335 EXTERN int expDevttyIs _ANSI_ARGS_((ExpState *));
336 EXTERN int expStdinoutIs _ANSI_ARGS_((ExpState *));
337 EXTERN ExpState * expStdinoutGet _ANSI_ARGS_((void));
338 EXTERN ExpState * expDevttyGet _ANSI_ARGS_((void));
340 /* generic functions that really should be provided by Tcl */
341 #if 0 /* Redefined as macros. */
342 EXTERN int expSizeGet _ANSI_ARGS_((ExpState *));
343 EXTERN int expSizeZero _ANSI_ARGS_((ExpState *));
345 #define expSizeGet(esPtr) ((esPtr)->input.use)
346 #define expSizeZero(esPtr) (((esPtr)->input.use) == 0)
349 #define EXP_CMDINFO_CLOSE "expect/cmdinfo/close"
350 #define EXP_CMDINFO_RETURN "expect/cmdinfo/return"