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