1 |
578 |
markom |
/* command.h - definitions for expect commands
|
2 |
|
|
|
3 |
|
|
Written by: Don Libes, NIST, 2/6/90
|
4 |
|
|
|
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.
|
8 |
|
|
*/
|
9 |
|
|
|
10 |
|
|
EXTERN struct exp_f * exp_update_master
|
11 |
|
|
_ANSI_ARGS_((Tcl_Interp *,int *,int,int));
|
12 |
|
|
EXTERN char * exp_get_var _ANSI_ARGS_((Tcl_Interp *,char *));
|
13 |
|
|
|
14 |
|
|
EXTERN int exp_default_match_max;
|
15 |
|
|
EXTERN int exp_default_parity;
|
16 |
|
|
EXTERN int exp_default_rm_nulls;
|
17 |
|
|
|
18 |
|
|
EXTERN int exp_one_arg_braced _ANSI_ARGS_((char *));
|
19 |
|
|
EXTERN int exp_eval_with_one_arg _ANSI_ARGS_((ClientData,
|
20 |
|
|
Tcl_Interp *,char **));
|
21 |
|
|
EXTERN void exp_lowmemcpy _ANSI_ARGS_((char *,char *,int));
|
22 |
|
|
|
23 |
|
|
EXTERN int exp_flageq_code _ANSI_ARGS_((char *,char *,int));
|
24 |
|
|
|
25 |
|
|
#define exp_flageq(flag,string,minlen) \
|
26 |
|
|
(((string)[0] == (flag)[0]) && (exp_flageq_code(((flag)+1),((string)+1),((minlen)-1))))
|
27 |
|
|
|
28 |
|
|
/* exp_flageq for single char flags */
|
29 |
|
|
#define exp_flageq1(flag,string) \
|
30 |
|
|
((string[0] == flag) && (string[1] == '\0'))
|
31 |
|
|
|
32 |
|
|
/*
|
33 |
|
|
* The type of the status returned by wait varies from UNIX system
|
34 |
|
|
* to UNIX system. The macro below defines it:
|
35 |
|
|
* (stolen from tclUnix.h)
|
36 |
|
|
*/
|
37 |
|
|
|
38 |
|
|
#define WAIT_STATUS_TYPE int
|
39 |
|
|
#if 0
|
40 |
|
|
#ifdef AIX
|
41 |
|
|
# define WAIT_STATUS_TYPE pid_t
|
42 |
|
|
#else
|
43 |
|
|
#ifndef NO_UNION_WAIT
|
44 |
|
|
# define WAIT_STATUS_TYPE union wait
|
45 |
|
|
#else
|
46 |
|
|
# define WAIT_STATUS_TYPE int
|
47 |
|
|
#endif
|
48 |
|
|
#endif /* AIX */
|
49 |
|
|
|
50 |
|
|
/* These macros are taken from tclUnix.h */
|
51 |
|
|
|
52 |
|
|
#undef WIFEXITED
|
53 |
|
|
#ifndef WIFEXITED
|
54 |
|
|
# define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0)
|
55 |
|
|
#endif
|
56 |
|
|
|
57 |
|
|
#undef WEXITSTATUS
|
58 |
|
|
#ifndef WEXITSTATUS
|
59 |
|
|
# define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
|
60 |
|
|
#endif
|
61 |
|
|
|
62 |
|
|
#undef WIFSIGNALED
|
63 |
|
|
#ifndef WIFSIGNALED
|
64 |
|
|
# define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff)))
|
65 |
|
|
#endif
|
66 |
|
|
|
67 |
|
|
#undef WTERMSIG
|
68 |
|
|
#ifndef WTERMSIG
|
69 |
|
|
# define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f)
|
70 |
|
|
#endif
|
71 |
|
|
|
72 |
|
|
#undef WIFSTOPPED
|
73 |
|
|
#ifndef WIFSTOPPED
|
74 |
|
|
# define WIFSTOPPED(stat) (((*((int *) &(stat))) & 0xff) == 0177)
|
75 |
|
|
#endif
|
76 |
|
|
|
77 |
|
|
#undef WSTOPSIG
|
78 |
|
|
#ifndef WSTOPSIG
|
79 |
|
|
# define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff)
|
80 |
|
|
#endif
|
81 |
|
|
|
82 |
|
|
#endif /* 0 */
|
83 |
|
|
|
84 |
|
|
/* These macros are suggested by the autoconf documentation. */
|
85 |
|
|
|
86 |
|
|
#undef WIFEXITED
|
87 |
|
|
#ifndef WIFEXITED
|
88 |
|
|
# define WIFEXITED(stat) (((stat) & 0xff) == 0)
|
89 |
|
|
#endif
|
90 |
|
|
|
91 |
|
|
#undef WEXITSTATUS
|
92 |
|
|
#ifndef WEXITSTATUS
|
93 |
|
|
# define WEXITSTATUS(stat) (((stat) >> 8) & 0xff)
|
94 |
|
|
#endif
|
95 |
|
|
|
96 |
|
|
#undef WIFSIGNALED
|
97 |
|
|
#ifndef WIFSIGNALED
|
98 |
|
|
# define WIFSIGNALED(stat) ((stat) && ((stat) == ((stat) & 0x00ff)))
|
99 |
|
|
#endif
|
100 |
|
|
|
101 |
|
|
#undef WTERMSIG
|
102 |
|
|
#ifndef WTERMSIG
|
103 |
|
|
# define WTERMSIG(stat) ((stat) & 0x7f)
|
104 |
|
|
#endif
|
105 |
|
|
|
106 |
|
|
#undef WIFSTOPPED
|
107 |
|
|
#ifndef WIFSTOPPED
|
108 |
|
|
# define WIFSTOPPED(stat) (((stat) & 0xff) == 0177)
|
109 |
|
|
#endif
|
110 |
|
|
|
111 |
|
|
#undef WSTOPSIG
|
112 |
|
|
#ifndef WSTOPSIG
|
113 |
|
|
# define WSTOPSIG(stat) (((stat) >> 8) & 0xff)
|
114 |
|
|
#endif
|
115 |
|
|
|
116 |
|
|
|
117 |
|
|
|
118 |
|
|
#define EXP_SPAWN_ID_ANY_VARNAME "any_spawn_id"
|
119 |
|
|
#define EXP_SPAWN_ID_ANY_LIT "-1"
|
120 |
|
|
#define EXP_SPAWN_ID_ANY -1
|
121 |
|
|
|
122 |
|
|
#define EXP_SPAWN_ID_ERROR_LIT "2"
|
123 |
|
|
#define EXP_SPAWN_ID_USER_LIT "0"
|
124 |
|
|
#define EXP_SPAWN_ID_USER 0
|
125 |
|
|
|
126 |
|
|
#define exp_is_stdinfd(x) ((x) == 0)
|
127 |
|
|
#define exp_is_devttyfd(x) ((x) == exp_dev_tty)
|
128 |
|
|
|
129 |
|
|
#define EXP_NOPID 0 /* Used when there is no associated pid to */
|
130 |
|
|
/* wait for. For example: */
|
131 |
|
|
/* 1) When fd opened by someone else, e.g., */
|
132 |
|
|
/* Tcl's open */
|
133 |
|
|
/* 2) When entry not in use */
|
134 |
|
|
/* 3) To tell user pid of "spawn -open" */
|
135 |
|
|
/* 4) stdin, out, error */
|
136 |
|
|
|
137 |
|
|
#define EXP_NOFD -1
|
138 |
|
|
|
139 |
|
|
/* these are occasionally useful to distinguish between various expect */
|
140 |
|
|
/* commands and are also used as array indices into the per-fd eg[] arrays */
|
141 |
|
|
#define EXP_CMD_BEFORE 0
|
142 |
|
|
#define EXP_CMD_AFTER 1
|
143 |
|
|
#define EXP_CMD_BG 2
|
144 |
|
|
#define EXP_CMD_FG 3
|
145 |
|
|
|
146 |
|
|
/* each process is associated with a 'struct exp_f'. An array of these */
|
147 |
|
|
/* ('exp_fs') keeps track of all processes. They are indexed by the true fd */
|
148 |
|
|
/* to the master side of the pty */
|
149 |
|
|
struct exp_f {
|
150 |
|
|
int *fd_ptr;
|
151 |
|
|
#if 0
|
152 |
|
|
struct exp_f **ptr; /* our own address to this exp_f */
|
153 |
|
|
/* since address can change, provide this indirect */
|
154 |
|
|
/* pointer for people (Tk) who require a fixed ptr */
|
155 |
|
|
#endif
|
156 |
|
|
int pid; /* pid or EXP_NOPID if no pid */
|
157 |
|
|
char *buffer; /* input buffer */
|
158 |
|
|
char *lower; /* input buffer in lowercase */
|
159 |
|
|
int size; /* current size of data */
|
160 |
|
|
int msize; /* size of buffer (true size is one greater
|
161 |
|
|
for trailing null) */
|
162 |
|
|
int umsize; /* user view of size of buffer */
|
163 |
|
|
int rm_nulls; /* if nulls should be stripped before pat matching */
|
164 |
|
|
int valid; /* if any of the other fields should be believed */
|
165 |
|
|
int user_closed;/* if user has issued "close" command or close has */
|
166 |
|
|
/* occurred implicitly */
|
167 |
|
|
int sys_closed; /* if close() has been called */
|
168 |
|
|
int user_waited;/* if user has issued "wait" command */
|
169 |
|
|
int sys_waited; /* if wait() (or variant) has been called */
|
170 |
|
|
WAIT_STATUS_TYPE wait; /* raw status from wait() */
|
171 |
|
|
int parity; /* strip parity if false */
|
172 |
|
|
int printed; /* # of characters written to stdout (if logging on) */
|
173 |
|
|
/* but not actually returned via a match yet */
|
174 |
|
|
int echoed; /* additional # of chars (beyond "printed" above) */
|
175 |
|
|
/* echoed back but not actually returned via a match */
|
176 |
|
|
/* yet. This supports interact -echo */
|
177 |
|
|
int key; /* unique id that identifies what command instance */
|
178 |
|
|
/* last touched this buffer */
|
179 |
|
|
int force_read; /* force read to occur (even if buffer already has */
|
180 |
|
|
/* data). This supports interact CAN_MATCH */
|
181 |
|
|
int fg_armed; /* If Tk_CreateFileHandler is active for responding */
|
182 |
|
|
/* to foreground events */
|
183 |
|
|
|
184 |
|
|
#if TCL_MAJOR_VERSION < 8
|
185 |
|
|
Tcl_File Master; /* corresponds to master fd */
|
186 |
|
|
Tcl_File Slave; /* corresponds to slave_fd */
|
187 |
|
|
Tcl_File MasterOutput; /* corresponds to tcl_output */
|
188 |
|
|
/*
|
189 |
|
|
* Following comment only applies to Tcl 7.6:
|
190 |
|
|
* Explicit fds aren't necessary now, but since the code is already
|
191 |
|
|
* here from before Tcl required Tcl_File, we'll continue using
|
192 |
|
|
* the old fds. If we ever port this code to a non-UNIX system,
|
193 |
|
|
* we'll dump the fds totally.
|
194 |
|
|
*/
|
195 |
|
|
#endif /* TCL_MAJOR_VERSION < 8 */
|
196 |
|
|
|
197 |
|
|
#ifdef __CYGWIN32__
|
198 |
|
|
Tcl_Channel channel; /* cygwin32 channel */
|
199 |
|
|
Tcl_FileProc *fileproc; /* Tcl_CreateFileHandler proc */
|
200 |
|
|
ClientData procdata; /* Tcl_CreateFileHandler data */
|
201 |
|
|
#endif
|
202 |
|
|
|
203 |
|
|
int slave_fd; /* slave fd if "spawn -pty" used */
|
204 |
|
|
#ifdef HAVE_PTYTRAP
|
205 |
|
|
char *slave_name;/* Full name of slave, i.e., /dev/ttyp0 */
|
206 |
|
|
#endif /* HAVE_PTYTRAP */
|
207 |
|
|
char *tcl_handle;/* If opened by someone else, i.e. Tcl's open */
|
208 |
|
|
int tcl_output; /* output fd if opened by someone else */
|
209 |
|
|
/* input fd is the index of this struct (see above) */
|
210 |
|
|
int leaveopen; /* If we should not call Tcl's close when we close - */
|
211 |
|
|
/* only relevant if Tcl does the original open */
|
212 |
|
|
Tcl_Interp *bg_interp; /* interp to process the bg cases */
|
213 |
|
|
int bg_ecount; /* number of background ecases */
|
214 |
|
|
enum {
|
215 |
|
|
blocked, /* blocked because we are processing the */
|
216 |
|
|
/* file handler */
|
217 |
|
|
armed, /* normal state when bg handler in use */
|
218 |
|
|
unarmed, /* no bg handler in use */
|
219 |
|
|
disarm_req_while_blocked /* while blocked, a request */
|
220 |
|
|
/* was received to disarm it. Rather than */
|
221 |
|
|
/* processing the request immediately, defer */
|
222 |
|
|
/* it so that when we later try to unblock */
|
223 |
|
|
/* we will see at that time that it should */
|
224 |
|
|
/* instead be disarmed */
|
225 |
|
|
} bg_status;
|
226 |
|
|
};
|
227 |
|
|
|
228 |
|
|
extern int exp_fd_max; /* highest fd ever used */
|
229 |
|
|
|
230 |
|
|
|
231 |
|
|
#define EXP_TEMPORARY 1 /* expect */
|
232 |
|
|
#define EXP_PERMANENT 2 /* expect_after, expect_before, expect_bg */
|
233 |
|
|
|
234 |
|
|
#define EXP_DIRECT 1
|
235 |
|
|
#define EXP_INDIRECT 2
|
236 |
|
|
|
237 |
|
|
EXTERN struct exp_f *exp_fs;
|
238 |
|
|
|
239 |
|
|
EXTERN struct exp_f * exp_fd2f _ANSI_ARGS_((Tcl_Interp *,int,int,int,char *));
|
240 |
|
|
EXTERN void exp_adjust _ANSI_ARGS_((struct exp_f *));
|
241 |
|
|
EXTERN void exp_buffer_shuffle _ANSI_ARGS_((Tcl_Interp *,struct exp_f *,int,char *,char *));
|
242 |
|
|
EXTERN int exp_close _ANSI_ARGS_((Tcl_Interp *,int));
|
243 |
|
|
EXTERN void exp_close_all _ANSI_ARGS_((Tcl_Interp *));
|
244 |
|
|
EXTERN void exp_ecmd_remove_fd_direct_and_indirect
|
245 |
|
|
_ANSI_ARGS_((Tcl_Interp *,int));
|
246 |
|
|
EXTERN void exp_trap_on _ANSI_ARGS_((int));
|
247 |
|
|
EXTERN int exp_trap_off _ANSI_ARGS_((char *));
|
248 |
|
|
|
249 |
|
|
EXTERN void exp_strftime();
|
250 |
|
|
|
251 |
|
|
#define exp_deleteProc (void (*)())0
|
252 |
|
|
#define exp_deleteObjProc (void (*)())0
|
253 |
|
|
|
254 |
|
|
EXTERN int expect_key;
|
255 |
|
|
EXTERN int exp_configure_count; /* # of times descriptors have been closed */
|
256 |
|
|
/* or indirect lists have been changed */
|
257 |
|
|
EXTERN int exp_nostack_dump; /* TRUE if user has requested unrolling of */
|
258 |
|
|
/* stack with no trace */
|
259 |
|
|
|
260 |
|
|
EXTERN void exp_init_pty _ANSI_ARGS_((void));
|
261 |
|
|
EXTERN void exp_pty_exit _ANSI_ARGS_((void));
|
262 |
|
|
EXTERN void exp_init_tty _ANSI_ARGS_((void));
|
263 |
|
|
EXTERN void exp_init_stdio _ANSI_ARGS_((void));
|
264 |
|
|
/*EXTERN void exp_init_expect _ANSI_ARGS_((Tcl_Interp *));*/
|
265 |
|
|
EXTERN void exp_init_spawn_ids _ANSI_ARGS_((void));
|
266 |
|
|
EXTERN void exp_init_spawn_id_vars _ANSI_ARGS_((Tcl_Interp *));
|
267 |
|
|
EXTERN void exp_init_trap _ANSI_ARGS_((void));
|
268 |
|
|
EXTERN void exp_init_unit_random _ANSI_ARGS_((void));
|
269 |
|
|
EXTERN void exp_init_sig _ANSI_ARGS_((void));
|
270 |
|
|
|
271 |
|
|
EXTERN int exp_tcl2_returnvalue _ANSI_ARGS_((int));
|
272 |
|
|
EXTERN int exp_2tcl_returnvalue _ANSI_ARGS_((int));
|
273 |
|
|
|
274 |
|
|
EXTERN void exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp *));
|
275 |
|
|
EXTERN int exp_string_to_signal _ANSI_ARGS_((Tcl_Interp *,char *));
|
276 |
|
|
|
277 |
|
|
EXTERN char *exp_onexit_action;
|
278 |
|
|
|
279 |
|
|
#define exp_new(x) (x *)malloc(sizeof(x))
|
280 |
|
|
|
281 |
|
|
struct exp_fd_list {
|
282 |
|
|
int fd;
|
283 |
|
|
struct exp_fd_list *next;
|
284 |
|
|
};
|
285 |
|
|
|
286 |
|
|
/* describes a -i flag */
|
287 |
|
|
struct exp_i {
|
288 |
|
|
int cmdtype; /* EXP_CMD_XXX. When an indirect update is */
|
289 |
|
|
/* triggered by Tcl, this helps tell us in what */
|
290 |
|
|
/* exp_i list to look in. */
|
291 |
|
|
int direct; /* if EXP_DIRECT, then the spawn ids have been given */
|
292 |
|
|
/* literally, else indirectly through a variable */
|
293 |
|
|
int duration; /* if EXP_PERMANENT, char ptrs here had to be */
|
294 |
|
|
/* malloc'd because Tcl command line went away - */
|
295 |
|
|
/* i.e., in expect_before/after */
|
296 |
|
|
char *variable;
|
297 |
|
|
char *value; /* if type == direct, this is the string that the */
|
298 |
|
|
/* user originally supplied to the -i flag. It may */
|
299 |
|
|
/* lose relevance as the fd_list is manipulated */
|
300 |
|
|
/* over time. If type == direct, this is the */
|
301 |
|
|
/* cached value of variable use this to tell if it */
|
302 |
|
|
/* has changed or not, and ergo whether it's */
|
303 |
|
|
/* necessary to reparse. */
|
304 |
|
|
|
305 |
|
|
int ecount; /* # of ecases this is used by */
|
306 |
|
|
|
307 |
|
|
struct exp_fd_list *fd_list;
|
308 |
|
|
struct exp_i *next;
|
309 |
|
|
};
|
310 |
|
|
|
311 |
|
|
EXTERN struct exp_i * exp_new_i_complex _ANSI_ARGS_((Tcl_Interp *,
|
312 |
|
|
char *, int, Tcl_VarTraceProc *));
|
313 |
|
|
EXTERN struct exp_i * exp_new_i_simple _ANSI_ARGS_((int,int));
|
314 |
|
|
EXTERN struct exp_fd_list *exp_new_fd _ANSI_ARGS_((int));
|
315 |
|
|
EXTERN void exp_free_i _ANSI_ARGS_((Tcl_Interp *,struct exp_i *,
|
316 |
|
|
Tcl_VarTraceProc *));
|
317 |
|
|
EXTERN void exp_free_fd _ANSI_ARGS_((struct exp_fd_list *));
|
318 |
|
|
EXTERN void exp_free_fd_single _ANSI_ARGS_((struct exp_fd_list *));
|
319 |
|
|
EXTERN void exp_i_update _ANSI_ARGS_((Tcl_Interp *,
|
320 |
|
|
struct exp_i *));
|
321 |
|
|
|
322 |
|
|
/*
|
323 |
|
|
* definitions for creating commands
|
324 |
|
|
*/
|
325 |
|
|
|
326 |
|
|
#define EXP_NOPREFIX 1 /* don't define with "exp_" prefix */
|
327 |
|
|
#define EXP_REDEFINE 2 /* stomp on old commands with same name */
|
328 |
|
|
|
329 |
|
|
/* a hack for easily supporting both Tcl 7 and 8 CreateCommand/Obj split */
|
330 |
|
|
/* Can be discarded with Tcl 7 is. */
|
331 |
|
|
#if TCL_MAJOR_VERSION < 8
|
332 |
|
|
#define exp_proc(cmdproc) cmdproc
|
333 |
|
|
#else
|
334 |
|
|
#define exp_proc(cmdproc) 0, cmdproc
|
335 |
|
|
#endif
|
336 |
|
|
|
337 |
|
|
struct exp_cmd_data {
|
338 |
|
|
char *name;
|
339 |
|
|
#if TCL_MAJOR_VERSION >= 8
|
340 |
|
|
Tcl_ObjCmdProc *objproc;
|
341 |
|
|
#endif
|
342 |
|
|
Tcl_CmdProc *proc;
|
343 |
|
|
ClientData data;
|
344 |
|
|
int flags;
|
345 |
|
|
};
|
346 |
|
|
|
347 |
|
|
EXTERN void exp_create_commands _ANSI_ARGS_((Tcl_Interp *,
|
348 |
|
|
struct exp_cmd_data *));
|
349 |
|
|
EXTERN void exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp *));
|
350 |
|
|
EXTERN void exp_init_expect_cmds _ANSI_ARGS_((Tcl_Interp *));
|
351 |
|
|
EXTERN void exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp *));
|
352 |
|
|
EXTERN void exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp *));
|
353 |
|
|
EXTERN void exp_init_interact_cmds _ANSI_ARGS_((Tcl_Interp *));
|
354 |
|
|
EXTERN void exp_init_tty_cmds();
|
355 |
|
|
|