1/* command.h - definitions for expect commands
2
3Written by: Don Libes, NIST, 2/6/90
4
5Design and implementation of this program was paid for by U.S. tax
6dollars.  Therefore it is public domain.  However, the author and NIST
7would appreciate credit if this program or parts of it are used.
8*/
9
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
14# endif
15# include <sys/wait.h>
16# ifdef WNOHANG_REQUIRES_POSIX_SOURCE
17#  undef _POSIX_SOURCE
18# endif
19#endif
20
21#ifdef __APPLE__
22/* From: "Daniel A. Steffen" <steffen@ics.mq.edu.au> */
23# undef panic
24#endif
25
26#include <tclPort.h>
27
28#define EXP_CHANNELNAMELEN (16 + TCL_INTEGER_SPACE)
29
30EXTERN char *		exp_get_var _ANSI_ARGS_((Tcl_Interp *,char *));
31
32EXTERN int exp_default_match_max;
33EXTERN int exp_default_parity;
34EXTERN int exp_default_rm_nulls;
35EXTERN int exp_default_close_on_eof;
36
37EXTERN int		exp_one_arg_braced _ANSI_ARGS_((Tcl_Obj *));
38
39EXTERN Tcl_Obj*		exp_eval_with_one_arg _ANSI_ARGS_((ClientData,
40				Tcl_Interp *, struct Tcl_Obj * CONST objv[]));
41
42EXTERN void		exp_lowmemcpy _ANSI_ARGS_((char *,char *,int));
43
44EXTERN int exp_flageq_code _ANSI_ARGS_((char *,char *,int));
45
46#define exp_flageq(flag,string,minlen) \
47(((string)[0] == (flag)[0]) && (exp_flageq_code(((flag)+1),((string)+1),((minlen)-1))))
48
49/* exp_flageq for single char flags */
50#define exp_flageq1(flag,string) \
51	((string[0] == flag) && (string[1] == '\0'))
52
53#define EXP_SPAWN_ID_USER		0
54#define EXP_SPAWN_ID_ANY_LIT		"-1"
55
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))
60
61#define exp_is_stdinfd(x)	((x) == 0)
62#define exp_is_devttyfd(x)	((x) == exp_dev_tty)
63
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., */
67				/* Tcl's open */
68				/* 2) When entry not in use */
69				/* 3) To tell user pid of "spawn -open" */
70				/* 4) stdin, out, error */
71
72#define EXP_NOFD	-1
73
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
78#define EXP_CMD_BG	2
79#define EXP_CMD_FG	3
80
81/*
82 * This structure describes per-instance state of an Exp channel.
83 */
84
85typedef 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 */
88} ExpOrigin;
89
90
91typedef 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 */
96} ExpUniBuf;
97
98typedef 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
102				   cache it here */
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 */
108
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. */
114
115    int pid;		/* pid or EXP_NOPID if no pid */
116
117    ExpUniBuf input;    /* input buffer */
118
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 */
126
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. */
142
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. */
150#ifdef HAVE_PTYTRAP
151    char *slave_name;   /* Full name of slave, i.e., /dev/ttyp0 */
152#endif /* HAVE_PTYTRAP */
153    /* may go away */
154    int leaveopen;	/* If we should not call Tcl's close when we close - */
155                        /* only relevant if Tcl does the original open */
156
157    Tcl_Interp *bg_interp;	/* interp to process the bg cases */
158    int bg_ecount;		/* number of background ExpStates */
159    enum {
160	blocked,	/* blocked because we are processing the */
161			/* file handler */
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 */
170    } bg_status;
171
172    /*
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
175     * it is safe.
176     */
177    int freeWhenBgHandlerUnblocked;
178
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.
184     */
185    int fdBusy;
186
187    /*
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.  */
191    int keepForever;
192
193    /*  Remember that "reserved" esPtrs are no longer in use. */
194    int valid;
195
196    struct ExpState *nextPtr;	/* Pointer to next file in list of all
197				 * file channels. */
198} ExpState;
199
200#define EXP_SPAWN_ID_BAD	((ExpState *)0)
201
202#define EXP_TIME_INFINITY	-1
203
204extern Tcl_ChannelType expChannelType;
205
206#define EXP_TEMPORARY	1	/* expect */
207#define EXP_PERMANENT	2	/* expect_after, expect_before, expect_bg */
208
209#define EXP_DIRECT	1
210#define EXP_INDIRECT	2
211
212EXTERN void		expAdjust _ANSI_ARGS_((ExpState *));
213EXTERN int		expWriteChars _ANSI_ARGS_((ExpState *,char *,int));
214EXTERN int		expWriteCharsUni _ANSI_ARGS_((ExpState *,Tcl_UniChar *,int));
215EXTERN void		exp_buffer_shuffle _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,char *,char *));
216EXTERN int		exp_close _ANSI_ARGS_((Tcl_Interp *,ExpState *));
217EXTERN void		exp_close_all _ANSI_ARGS_((Tcl_Interp *));
218EXTERN void		exp_ecmd_remove_fd_direct_and_indirect
219				_ANSI_ARGS_((Tcl_Interp *,int));
220EXTERN void		exp_trap_on _ANSI_ARGS_((int));
221EXTERN int		exp_trap_off _ANSI_ARGS_((char *));
222
223EXTERN void		exp_strftime(char *format, const struct tm *timeptr,Tcl_DString *dstring);
224
225#define exp_deleteProc (void (*)())0
226#define exp_deleteObjProc (void (*)())0
227
228EXTERN int expect_key;
229EXTERN int exp_configure_count;	/* # of times descriptors have been closed */
230				/* or indirect lists have been changed */
231EXTERN int exp_nostack_dump;	/* TRUE if user has requested unrolling of */
232				/* stack with no trace */
233
234EXTERN void		exp_init_pty _ANSI_ARGS_((void));
235EXTERN void		exp_pty_exit _ANSI_ARGS_((void));
236EXTERN void		exp_init_tty _ANSI_ARGS_((void));
237EXTERN void		exp_init_stdio _ANSI_ARGS_((void));
238/*EXTERN void		exp_init_expect _ANSI_ARGS_((Tcl_Interp *));*/
239EXTERN void		exp_init_spawn_ids _ANSI_ARGS_((Tcl_Interp *));
240EXTERN void		exp_init_spawn_id_vars _ANSI_ARGS_((Tcl_Interp *));
241EXTERN void		exp_init_trap _ANSI_ARGS_((void));
242EXTERN void		exp_init_send _ANSI_ARGS_((void));
243EXTERN void		exp_init_unit_random _ANSI_ARGS_((void));
244EXTERN void		exp_init_sig _ANSI_ARGS_((void));
245EXTERN void		expChannelInit _ANSI_ARGS_((void));
246EXTERN int		expChannelCountGet _ANSI_ARGS_((void));
247
248EXTERN int		exp_tcl2_returnvalue _ANSI_ARGS_((int));
249EXTERN int		exp_2tcl_returnvalue _ANSI_ARGS_((int));
250
251EXTERN void		exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp *));
252EXTERN int		exp_string_to_signal _ANSI_ARGS_((Tcl_Interp *,char *));
253
254EXTERN char *exp_onexit_action;
255
256#define exp_new(x)	(x *)malloc(sizeof(x))
257
258struct exp_state_list {
259	ExpState *esPtr;
260	struct exp_state_list *next;
261};
262
263/* describes a -i flag */
264struct exp_i {
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 */
273	char *variable;
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. */
281
282	int ecount;	/* # of ecases this is used by */
283
284	struct exp_state_list *state_list;
285	struct exp_i *next;
286};
287
288EXTERN struct exp_i *	exp_new_i_complex _ANSI_ARGS_((Tcl_Interp *,
289					char *, int, Tcl_VarTraceProc *));
290EXTERN struct exp_i *	exp_new_i_simple _ANSI_ARGS_((ExpState *,int));
291EXTERN struct exp_state_list *exp_new_state _ANSI_ARGS_((ExpState *));
292EXTERN void		exp_free_i _ANSI_ARGS_((Tcl_Interp *,struct exp_i *,
293					Tcl_VarTraceProc *));
294EXTERN void		exp_free_state _ANSI_ARGS_((struct exp_state_list *));
295EXTERN void		exp_free_state_single _ANSI_ARGS_((struct exp_state_list *));
296EXTERN int		exp_i_update _ANSI_ARGS_((Tcl_Interp *,
297					struct exp_i *));
298
299/*
300 * definitions for creating commands
301 */
302
303#define EXP_NOPREFIX	1	/* don't define with "exp_" prefix */
304#define EXP_REDEFINE	2	/* stomp on old commands with same name */
305
306#define exp_proc(cmdproc) 0, cmdproc
307
308struct exp_cmd_data {
309	char		*name;
310	Tcl_ObjCmdProc	*objproc;
311	Tcl_CmdProc	*proc;
312	ClientData	data;
313	int 		flags;
314};
315
316EXTERN void		exp_create_commands _ANSI_ARGS_((Tcl_Interp *,
317						struct exp_cmd_data *));
318EXTERN void		exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp *));
319EXTERN void		exp_init_expect_cmds _ANSI_ARGS_((Tcl_Interp *));
320EXTERN void		exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp *));
321EXTERN void		exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp *));
322EXTERN void		exp_init_interact_cmds _ANSI_ARGS_((Tcl_Interp *));
323EXTERN void		exp_init_tty_cmds();
324
325EXTERN ExpState *	expStateCheck _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,int,char *));
326EXTERN ExpState *       expStateCurrent _ANSI_ARGS_((Tcl_Interp *,int,int,int));
327EXTERN ExpState *       expStateFromChannelName _ANSI_ARGS_((Tcl_Interp *,char *,int,int,int,char *));
328EXTERN void		expStateFree _ANSI_ARGS_((ExpState *));
329
330EXTERN ExpState *	expCreateChannel _ANSI_ARGS_((Tcl_Interp *,int,int,int));
331EXTERN ExpState *	expWaitOnAny _ANSI_ARGS_((void));
332EXTERN ExpState *	expWaitOnOne _ANSI_ARGS_((void));
333EXTERN void		expExpectVarsInit _ANSI_ARGS_((void));
334EXTERN int		expStateAnyIs _ANSI_ARGS_((ExpState *));
335EXTERN int		expDevttyIs _ANSI_ARGS_((ExpState *));
336EXTERN int		expStdinoutIs _ANSI_ARGS_((ExpState *));
337EXTERN ExpState *	expStdinoutGet _ANSI_ARGS_((void));
338EXTERN ExpState *	expDevttyGet _ANSI_ARGS_((void));
339
340/* generic functions that really should be provided by Tcl */
341#if 0 /* Redefined as macros. */
342EXTERN int		expSizeGet _ANSI_ARGS_((ExpState *));
343EXTERN int		expSizeZero _ANSI_ARGS_((ExpState *));
344#else
345#define expSizeGet(esPtr)  ((esPtr)->input.use)
346#define expSizeZero(esPtr) (((esPtr)->input.use) == 0)
347#endif
348
349#define EXP_CMDINFO_CLOSE  "expect/cmdinfo/close"
350#define EXP_CMDINFO_RETURN "expect/cmdinfo/return"
351
352/*
353 * Local Variables:
354 * mode: c
355 * c-basic-offset: 4
356 * fill-column: 78
357 * End:
358 */
359