Blame exp_command.h

Packit a69f91
/* command.h - definitions for expect commands
Packit a69f91
Packit a69f91
Written by: Don Libes, NIST, 2/6/90
Packit a69f91
Packit a69f91
Design and implementation of this program was paid for by U.S. tax
Packit a69f91
dollars.  Therefore it is public domain.  However, the author and NIST
Packit a69f91
would appreciate credit if this program or parts of it are used.
Packit a69f91
*/
Packit a69f91
Packit a69f91
#ifdef HAVE_SYS_WAIT_H
Packit a69f91
  /* ISC doesn't def WNOHANG unless _POSIX_SOURCE is def'ed */
Packit a69f91
# ifdef WNOHANG_REQUIRES_POSIX_SOURCE
Packit a69f91
#  define _POSIX_SOURCE
Packit a69f91
# endif
Packit a69f91
# include <sys/wait.h>
Packit a69f91
# ifdef WNOHANG_REQUIRES_POSIX_SOURCE
Packit a69f91
#  undef _POSIX_SOURCE
Packit a69f91
# endif
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#ifdef __APPLE__
Packit a69f91
/* From: "Daniel A. Steffen" <steffen@ics.mq.edu.au> */
Packit a69f91
# undef panic
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#include <tclPort.h>
Packit a69f91
Packit a69f91
#define EXP_CHANNELNAMELEN (16 + TCL_INTEGER_SPACE)
Packit a69f91
Packit a69f91
EXTERN char *		exp_get_var _ANSI_ARGS_((Tcl_Interp *,char *));
Packit a69f91
Packit a69f91
EXTERN int exp_default_match_max;
Packit a69f91
EXTERN int exp_default_parity;
Packit a69f91
EXTERN int exp_default_rm_nulls;
Packit a69f91
EXTERN int exp_default_close_on_eof;
Packit a69f91
Packit a69f91
EXTERN int		exp_one_arg_braced _ANSI_ARGS_((Tcl_Obj *));
Packit a69f91
Packit a69f91
EXTERN Tcl_Obj*		exp_eval_with_one_arg _ANSI_ARGS_((ClientData,
Packit a69f91
				Tcl_Interp *, struct Tcl_Obj * CONST objv[]));
Packit a69f91
Packit a69f91
EXTERN void		exp_lowmemcpy _ANSI_ARGS_((char *,char *,int));
Packit a69f91
Packit a69f91
EXTERN int exp_flageq_code _ANSI_ARGS_((char *,char *,int));
Packit a69f91
Packit a69f91
#define exp_flageq(flag,string,minlen) \
Packit a69f91
(((string)[0] == (flag)[0]) && (exp_flageq_code(((flag)+1),((string)+1),((minlen)-1))))
Packit a69f91
Packit a69f91
/* exp_flageq for single char flags */
Packit a69f91
#define exp_flageq1(flag,string) \
Packit a69f91
	((string[0] == flag) && (string[1] == '\0'))
Packit a69f91
Packit a69f91
#define EXP_SPAWN_ID_USER		0
Packit a69f91
#define EXP_SPAWN_ID_ANY_LIT		"-1"
Packit a69f91
Packit a69f91
#define EXP_CHANNEL_PREFIX "exp"
Packit a69f91
#define EXP_CHANNEL_PREFIX_LENGTH 3
Packit a69f91
#define isExpChannelName(name) \
Packit a69f91
    (0 == strncmp(name,EXP_CHANNEL_PREFIX,EXP_CHANNEL_PREFIX_LENGTH))
Packit a69f91
Packit a69f91
#define exp_is_stdinfd(x)	((x) == 0)
Packit a69f91
#define exp_is_devttyfd(x)	((x) == exp_dev_tty)
Packit a69f91
Packit a69f91
#define EXP_NOPID	0	/* Used when there is no associated pid to */
Packit a69f91
				/* wait for.  For example: */
Packit a69f91
				/* 1) When fd opened by someone else, e.g., */
Packit a69f91
				/* Tcl's open */
Packit a69f91
				/* 2) When entry not in use */
Packit a69f91
				/* 3) To tell user pid of "spawn -open" */
Packit a69f91
				/* 4) stdin, out, error */
Packit a69f91
Packit a69f91
#define EXP_NOFD	-1
Packit a69f91
Packit a69f91
/* these are occasionally useful to distinguish between various expect */
Packit a69f91
/* commands and are also used as array indices into the per-fd eg[] arrays */
Packit a69f91
#define EXP_CMD_BEFORE	0
Packit a69f91
#define EXP_CMD_AFTER	1
Packit a69f91
#define EXP_CMD_BG	2
Packit a69f91
#define EXP_CMD_FG	3
Packit a69f91
Packit a69f91
/*
Packit a69f91
 * This structure describes per-instance state of an Exp channel.
Packit a69f91
 */
Packit a69f91
Packit a69f91
typedef struct ExpOrigin {
Packit a69f91
  int         refCount;       /* Number of times this channel is used. */
Packit a69f91
  Tcl_Channel channel_orig;   /* If opened by someone else, i.e. tcl::open */
Packit a69f91
} ExpOrigin;
Packit a69f91
Packit a69f91
Packit a69f91
typedef struct ExpUniBuf {
Packit a69f91
    Tcl_UniChar* buffer;    /* char buffer, holdings unicode chars (fixed width) */
Packit a69f91
    int          max;       /* number of CHARS the buffer has space for (== old msize) */
Packit a69f91
    int          use;       /* number of CHARS the buffer is currently holding */
Packit a69f91
    Tcl_Obj*     newchars;  /* Object to hold newly read characters */
Packit a69f91
} ExpUniBuf;
Packit a69f91
Packit a69f91
typedef struct ExpState {
Packit a69f91
    Tcl_Channel channel;	/* Channel associated with this file. */
Packit a69f91
    char name[EXP_CHANNELNAMELEN+1]; /* expect and interact set variables
Packit a69f91
				   to channel name, so for efficiency
Packit a69f91
				   cache it here */
Packit a69f91
    int fdin;		/* input fd */
Packit a69f91
    int fdout;		/* output fd - usually the same as fdin, although
Packit a69f91
			   may be different if channel opened by tcl::open */
Packit a69f91
    ExpOrigin* chan_orig;   /* If opened by someone else, i.e. tcl::open */
Packit a69f91
    int fd_slave;	/* slave fd if "spawn -pty" used */
Packit a69f91
Packit a69f91
    /* this may go away if we find it is not needed */
Packit a69f91
    /* it might be needed by inherited channels */
Packit a69f91
    int validMask;		/* OR'ed combination of TCL_READABLE,
Packit a69f91
				 * TCL_WRITABLE, or TCL_EXCEPTION: indicates
Packit a69f91
				 * which operations are valid on the file. */
Packit a69f91
Packit a69f91
    int pid;		/* pid or EXP_NOPID if no pid */
Packit a69f91
Packit a69f91
    ExpUniBuf input;    /* input buffer */
Packit a69f91
Packit a69f91
    int umsize;	        /* # of bytes (min) that is guaranteed to match */
Packit a69f91
			/* this comes from match_max command */
Packit a69f91
    int printed;	/* # of characters! written to stdout (if logging on) */
Packit a69f91
                        /* but not actually returned via a match yet */
Packit a69f91
    int echoed;	        /* additional # of characters (beyond "printed" above) */
Packit a69f91
                        /* echoed back but not actually returned via a match */
Packit a69f91
                        /* yet.  This supports interact -echo */
Packit a69f91
Packit a69f91
    int rm_nulls;	/* if nulls should be stripped before pat matching */
Packit a69f91
    int open;		/* if fdin/fdout open */
Packit a69f91
    int user_waited;    /* if user has issued "wait" command */
Packit a69f91
    int sys_waited;	/* if wait() (or variant) has been called */
Packit a69f91
    int registered;	/* if channel registered */
Packit a69f91
    WAIT_STATUS_TYPE wait;	/* raw status from wait() */
Packit a69f91
    int parity;	        /* if parity should be preserved */
Packit a69f91
    int close_on_eof;   /* if channel should be closed automatically on eof */
Packit a69f91
    int key;	        /* unique id that identifies what command instance */
Packit a69f91
                        /* last touched this buffer */
Packit a69f91
    int force_read;	/* force read to occur (even if buffer already has */
Packit a69f91
                        /* data).  This supports interact CAN_MATCH */
Packit a69f91
    int notified;	/* If Tcl_NotifyChannel has been called and we */
Packit a69f91
		        /* have not yet read from the channel. */
Packit a69f91
    int notifiedMask;	/* Mask reported when notified. */
Packit a69f91
Packit a69f91
    int fg_armed;	/* If we have requested Tk_CreateFileHandler to be */
Packit a69f91
			/* responding to foreground events.  Note that */
Packit a69f91
		        /* other handlers can have stolen it away so this */
Packit a69f91
			/* doesn't necessarily mean the handler is set.  */
Packit a69f91
			/* However, if fg_armed is 0, then the handlers */
Packit a69f91
			/* definitely needs to be set.  The significance of */
Packit a69f91
			/* this flag is so we can remember to turn it off. */
Packit a69f91
#ifdef HAVE_PTYTRAP
Packit a69f91
    char *slave_name;   /* Full name of slave, i.e., /dev/ttyp0 */
Packit a69f91
#endif /* HAVE_PTYTRAP */
Packit a69f91
    /* may go away */
Packit a69f91
    int leaveopen;	/* If we should not call Tcl's close when we close - */
Packit a69f91
                        /* only relevant if Tcl does the original open */
Packit a69f91
Packit a69f91
    Tcl_Interp *bg_interp;	/* interp to process the bg cases */
Packit a69f91
    int bg_ecount;		/* number of background ExpStates */
Packit a69f91
    enum {
Packit a69f91
	blocked,	/* blocked because we are processing the */
Packit a69f91
			/* file handler */
Packit a69f91
	armed,		/* normal state when bg handler in use */
Packit a69f91
	unarmed,	/* no bg handler in use */
Packit a69f91
	disarm_req_while_blocked	/* while blocked, a request */
Packit a69f91
				/* was received to disarm it.  Rather than */
Packit a69f91
				/* processing the request immediately, defer */
Packit a69f91
				/* it so that when we later try to unblock */
Packit a69f91
				/* we will see at that time that it should */
Packit a69f91
				/* instead be disarmed */
Packit a69f91
    } bg_status;
Packit a69f91
Packit a69f91
    /*
Packit a69f91
     * If the channel is freed while in the middle of a bg event handler,
Packit a69f91
     * remember that and defer freeing of the ExpState structure until
Packit a69f91
     * it is safe.
Packit a69f91
     */
Packit a69f91
    int freeWhenBgHandlerUnblocked;
Packit a69f91
Packit a69f91
    /* If channel is closed but not yet waited on, we tie up the fd by
Packit a69f91
     * attaching it to /dev/null.  We play this little game so that we
Packit a69f91
     * can embed the fd in the channel name.  If we didn't tie up the
Packit a69f91
     * fd, we'd get channel name collisions.  I'd consider naming the
Packit a69f91
     * channels independently of the fd, but this makes debugging easier.
Packit a69f91
     */
Packit a69f91
    int fdBusy;
Packit a69f91
Packit a69f91
    /* 
Packit a69f91
     * stdinout and stderr never go away so that our internal refs to them
Packit a69f91
     * don't have to be invalidated.  Having to worry about invalidating them
Packit a69f91
     * would be a major pain.  */
Packit a69f91
    int keepForever;
Packit a69f91
Packit a69f91
    /*  Remember that "reserved" esPtrs are no longer in use. */
Packit a69f91
    int valid;
Packit a69f91
    
Packit a69f91
    struct ExpState *nextPtr;	/* Pointer to next file in list of all
Packit a69f91
				 * file channels. */
Packit a69f91
} ExpState;
Packit a69f91
Packit a69f91
#define EXP_SPAWN_ID_BAD	((ExpState *)0)
Packit a69f91
Packit a69f91
#define EXP_TIME_INFINITY	-1
Packit a69f91
Packit a69f91
extern Tcl_ChannelType expChannelType;
Packit a69f91
Packit a69f91
#define EXP_TEMPORARY	1	/* expect */
Packit a69f91
#define EXP_PERMANENT	2	/* expect_after, expect_before, expect_bg */
Packit a69f91
Packit a69f91
#define EXP_DIRECT	1
Packit a69f91
#define EXP_INDIRECT	2
Packit a69f91
Packit a69f91
EXTERN void		expAdjust _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN int		expWriteChars _ANSI_ARGS_((ExpState *,char *,int));
Packit a69f91
EXTERN int		expWriteCharsUni _ANSI_ARGS_((ExpState *,Tcl_UniChar *,int));
Packit a69f91
EXTERN void		exp_buffer_shuffle _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,char *,char *));
Packit a69f91
EXTERN int		exp_close _ANSI_ARGS_((Tcl_Interp *,ExpState *));
Packit a69f91
EXTERN void		exp_close_all _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_ecmd_remove_fd_direct_and_indirect 
Packit a69f91
				_ANSI_ARGS_((Tcl_Interp *,int));
Packit a69f91
EXTERN void		exp_trap_on _ANSI_ARGS_((int));
Packit a69f91
EXTERN int		exp_trap_off _ANSI_ARGS_((char *));
Packit a69f91
Packit a69f91
EXTERN void		exp_strftime(char *format, const struct tm *timeptr,Tcl_DString *dstring);
Packit a69f91
Packit a69f91
#define exp_deleteProc (void (*)())0
Packit a69f91
#define exp_deleteObjProc (void (*)())0
Packit a69f91
Packit a69f91
EXTERN int expect_key;
Packit a69f91
EXTERN int exp_configure_count;	/* # of times descriptors have been closed */
Packit a69f91
				/* or indirect lists have been changed */
Packit a69f91
EXTERN int exp_nostack_dump;	/* TRUE if user has requested unrolling of */
Packit a69f91
				/* stack with no trace */
Packit a69f91
Packit a69f91
EXTERN void		exp_init_pty _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_pty_exit _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_init_tty _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_init_stdio _ANSI_ARGS_((void));
Packit a69f91
/*EXTERN void		exp_init_expect _ANSI_ARGS_((Tcl_Interp *));*/
Packit a69f91
EXTERN void		exp_init_spawn_ids _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_spawn_id_vars _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_trap _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_init_send _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_init_unit_random _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		exp_init_sig _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		expChannelInit _ANSI_ARGS_((void));
Packit a69f91
EXTERN int		expChannelCountGet _ANSI_ARGS_((void));
Packit a69f91
EXTERN int              expChannelStillAlive _ANSI_ARGS_((ExpState *, char *));
Packit a69f91
Packit a69f91
EXTERN int		exp_tcl2_returnvalue _ANSI_ARGS_((int));
Packit a69f91
EXTERN int		exp_2tcl_returnvalue _ANSI_ARGS_((int));
Packit a69f91
Packit a69f91
EXTERN void		exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN int		exp_string_to_signal _ANSI_ARGS_((Tcl_Interp *,char *));
Packit a69f91
Packit a69f91
EXTERN char *exp_onexit_action;
Packit a69f91
Packit a69f91
#define exp_new(x)	(x *)malloc(sizeof(x))
Packit a69f91
Packit a69f91
struct exp_state_list {
Packit a69f91
	ExpState *esPtr;
Packit a69f91
	struct exp_state_list *next;
Packit a69f91
};
Packit a69f91
Packit a69f91
/* describes a -i flag */
Packit a69f91
struct exp_i {
Packit a69f91
	int cmdtype;	/* EXP_CMD_XXX.  When an indirect update is */
Packit a69f91
			/* triggered by Tcl, this helps tell us in what */
Packit a69f91
			/* exp_i list to look in. */
Packit a69f91
	int direct;	/* if EXP_DIRECT, then the spawn ids have been given */
Packit a69f91
			/* literally, else indirectly through a variable */
Packit a69f91
	int duration;	/* if EXP_PERMANENT, char ptrs here had to be */
Packit a69f91
			/* malloc'd because Tcl command line went away - */
Packit a69f91
			/* i.e., in expect_before/after */
Packit a69f91
	char *variable;
Packit a69f91
	char *value;	/* if type == direct, this is the string that the */
Packit a69f91
			/* user originally supplied to the -i flag.  It may */
Packit a69f91
			/* lose relevance as the fd_list is manipulated */
Packit a69f91
			/* over time.  If type == direct, this is  the */
Packit a69f91
			/* cached value of variable use this to tell if it */
Packit a69f91
			/* has changed or not, and ergo whether it's */
Packit a69f91
			/* necessary to reparse. */
Packit a69f91
Packit a69f91
	int ecount;	/* # of ecases this is used by */
Packit a69f91
Packit a69f91
	struct exp_state_list *state_list;
Packit a69f91
	struct exp_i *next;
Packit a69f91
};
Packit a69f91
Packit a69f91
EXTERN struct exp_i *	exp_new_i_complex _ANSI_ARGS_((Tcl_Interp *,
Packit a69f91
					char *, int, Tcl_VarTraceProc *));
Packit a69f91
EXTERN struct exp_i *	exp_new_i_simple _ANSI_ARGS_((ExpState *,int));
Packit a69f91
EXTERN struct exp_state_list *exp_new_state _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN void		exp_free_i _ANSI_ARGS_((Tcl_Interp *,struct exp_i *,
Packit a69f91
					Tcl_VarTraceProc *));
Packit a69f91
EXTERN void		exp_free_state _ANSI_ARGS_((struct exp_state_list *));
Packit a69f91
EXTERN void		exp_free_state_single _ANSI_ARGS_((struct exp_state_list *));
Packit a69f91
EXTERN int		exp_i_update _ANSI_ARGS_((Tcl_Interp *,
Packit a69f91
					struct exp_i *));
Packit a69f91
Packit a69f91
/*
Packit a69f91
 * definitions for creating commands
Packit a69f91
 */
Packit a69f91
Packit a69f91
#define EXP_NOPREFIX	1	/* don't define with "exp_" prefix */
Packit a69f91
#define EXP_REDEFINE	2	/* stomp on old commands with same name */
Packit a69f91
Packit a69f91
#define exp_proc(cmdproc) 0, cmdproc
Packit a69f91
Packit a69f91
struct exp_cmd_data {
Packit a69f91
	char		*name;
Packit a69f91
	Tcl_ObjCmdProc	*objproc;
Packit a69f91
	Tcl_CmdProc	*proc;
Packit a69f91
	ClientData	data;
Packit a69f91
	int 		flags;
Packit a69f91
};
Packit a69f91
Packit a69f91
EXTERN void		exp_create_commands _ANSI_ARGS_((Tcl_Interp *,
Packit a69f91
						struct exp_cmd_data *));
Packit a69f91
EXTERN void		exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_expect_cmds _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_interact_cmds _ANSI_ARGS_((Tcl_Interp *));
Packit a69f91
EXTERN void		exp_init_tty_cmds();
Packit a69f91
Packit a69f91
EXTERN ExpState *	expStateCheck _ANSI_ARGS_((Tcl_Interp *,ExpState *,int,int,char *));
Packit a69f91
EXTERN ExpState *       expStateCurrent _ANSI_ARGS_((Tcl_Interp *,int,int,int));
Packit a69f91
EXTERN ExpState *       expStateFromChannelName _ANSI_ARGS_((Tcl_Interp *,char *,int,int,int,char *));
Packit a69f91
EXTERN void		expStateFree _ANSI_ARGS_((ExpState *));
Packit a69f91
Packit a69f91
EXTERN ExpState *	expCreateChannel _ANSI_ARGS_((Tcl_Interp *,int,int,int));
Packit a69f91
EXTERN ExpState *	expWaitOnAny _ANSI_ARGS_((void));
Packit a69f91
EXTERN ExpState *	expWaitOnOne _ANSI_ARGS_((void));
Packit a69f91
EXTERN void		expExpectVarsInit _ANSI_ARGS_((void));
Packit a69f91
EXTERN int		expStateAnyIs _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN int		expDevttyIs _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN int		expStdinoutIs _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN ExpState *	expStdinoutGet _ANSI_ARGS_((void));
Packit a69f91
EXTERN ExpState *	expDevttyGet _ANSI_ARGS_((void));
Packit a69f91
Packit a69f91
/* generic functions that really should be provided by Tcl */
Packit a69f91
#if 0 /* Redefined as macros. */
Packit a69f91
EXTERN int		expSizeGet _ANSI_ARGS_((ExpState *));
Packit a69f91
EXTERN int		expSizeZero _ANSI_ARGS_((ExpState *));
Packit a69f91
#else
Packit a69f91
#define expSizeGet(esPtr)  ((esPtr)->input.use)
Packit a69f91
#define expSizeZero(esPtr) (((esPtr)->input.use) == 0)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#define EXP_CMDINFO_CLOSE  "expect/cmdinfo/close"
Packit a69f91
#define EXP_CMDINFO_RETURN "expect/cmdinfo/return"
Packit a69f91

Packit a69f91
/*
Packit a69f91
 * Local Variables:
Packit a69f91
 * mode: c
Packit a69f91
 * c-basic-offset: 4
Packit a69f91
 * fill-column: 78
Packit a69f91
 * End:
Packit a69f91
 */