/*---------------------------------------------------------------------
 * $Date: 2007-05-14 07:27:59 $		$Revision: 1.3 $
 *---------------------------------------------------------------------
 *             Copyright (c) 1992, Visual Edge Software Ltd.
 *
 * ALL  RIGHTS  RESERVED.  Permission  to  use,  copy,  modify,  and
 * distribute  this  software  and its documentation for any purpose
 * and  without  fee  is  hereby  granted,  provided  that the above
 * copyright  notice  appear  in  all  copies  and  that  both  that
 * copyright  notice and this permission notice appear in supporting
 * documentation,  and that  the name of Visual Edge Software not be
 * used  in advertising  or publicity  pertaining to distribution of
 * the software without specific, written prior permission. The year
 * included in the notice is the year of the creation of the work.
 *---------------------------------------------------------------------
 *   File_Description_Section

 070514		last modif

 *--------------------------------------------------------------------*/

#ifndef SP_SPMD_H
#define SP_SPMD_H

/*--- include files ---*/
#include "uxproto.h"
#include <sys/ipc.h>

#ifndef __USE_GNU
#define __USE_GNU
#endif

/* include file sysglue.h not there anymore in OSX 10.4 ...
#if defined(__Darwin__)
#include <netat/sysglue.h>
#endif
*/

#if defined(__Darwin__) || defined(__FreeBSD__) || defined(Cygwin)
#include <sys/types.h>
#include <sys/errno.h>

#include "msg.h" 				/* #include <sys/msg.h> */

#ifndef Cygwin
#include <sys/msgbuf.h>
#endif

#else
#include <sys/msg.h>
#endif


#include <sys/stat.h>	/* For S_IWUSR, S_IRUSR permission mode masks. */

#ifdef __cplusplus
extern "C" {			/* C++ compatability */
#endif /* __cplusplus */


/*--- macro symbolic constants ---*/
/*
 * message types:
 *	for protocol between application and Sub-Process Manager Daemon
*/
#define SPMD_CREATE	0x1
#define SPMD_INPUT	0x2	/* input (to sub-process, from application) */
#define SPMD_OUTPUT	0x4	/* output (from sub-process, to application) */
#define SPMD_DIED	0x8
#define SPMD_RSP	0x20	/* used to ACK or NACK _CREATE and/or _INPUT */
#define SPMD_EXIT	0x40	/* used when SPMD must exit */

#define SIZEOFTEXTMSG (MSGMAX - 10)	/* subtract 10 for safety */
#define SIZEOFMAXMSGBUF (MSGMAX + sizeof(long))

#define ACK  3
#define NACK 12

/* We can't select() on the msg queue, so we can't use XtAddInput ().
 * Instead we schedule a check every SpmdInterval millisecs. 
 * See spmd_read_msg()
*/
#define  SHORT_INTERVAL   100
#define  LONG_INTERVAL    500

#define UX_PREPARE_COMMAND UxSubprocMgr.prepare_command_m
#define UX_SET_PARENT_SIDE UxSubprocMgr.set_parent_side_m
#define UX_SETUP_PARENT_COMMUNICATION UxSubprocMgr.setup_parent_communication_m
#define UX_START_CHILD UxSubprocMgr.start_child_m
#define UX_SET_CHILD_SIDE UxSubprocMgr.set_child_side_m
#define UX_SETUP_CHILD_COMMUNICATION UxSubprocMgr.setup_child_communication_m
#define UX_SPMD_EXEC_SUBPROCESS UxSubprocMgr.exec_subprocess_m
#define UX_CLOSE_COMMUNICATION UxSubprocMgr.close_communication_m


/*--- macro functions ---*/
#ifdef DEBUG
#if defined(__STDC__) && !defined(apollo)
#define ASSERT(EX) if (!(EX)) \
                        fprintf(stderr, \
                        "Assert %s failed, File %s, Line %d\n", #EX, \
                               __FILE__, __LINE__)
#else
#                       define ASSERT(EX) if (!(EX)) \
                        fprintf(stderr, \
                        "Assert %s failed, File %s, Line %d\n", "EX", \
                               __FILE__, __LINE__)
#endif /* (__STDC__) && !(apollo) */

#else /*DEBUG*/
#define ASSERT(EX)
#endif /*DEBUG*/


/*--- types ---*/
typedef struct { 		/* Sub-Process Manager Daemon description */
	int spmd_pid;		/* process id */
	int spmd_cp_msqid;	/* daemon (child) -> app (parent) msg queue */
	int spmd_pc_msqid;	/* app (parent) -> daemon (child) msg queue */
	struct {		/* last message received from daemon */
		int  msgsiz;
		char *msgrp;	/* SPMD_OUTPUT ptr into spmd_output_t msg */

#if defined(FreeBSD) || defined(__Darwin__) || defined(Cygwin)
                struct mymsg *msgp;
#else
                struct msgbuf *msgp;
#endif
	} spmd_rcv_msg;

#define spmd_rmsgtyp spmd_rcv_msg.msgp->mtype
#define spmd_rmsgtxt spmd_rcv_msg.msgp->mtext
#define spmd_rmsgsiz spmd_rcv_msg.msgsiz
#define spmd_rmsgrp spmd_rcv_msg.msgrp
#define spmd_rmsgp spmd_rcv_msg.msgp
} spmd_info_t;

typedef struct
{
	int pid;
	int pty;
	int exit_status;
} spmd_pid_pty_t;


/*
 * message structures: these are the actual message formats used.
 * If fields are added to these structures, check that the size of the 
 * message sent with msgsnd is changed accordingly.
*/
typedef	struct 
{ long mtype; int pid; char output[SIZEOFTEXTMSG]; } spmd_output_t;

typedef	struct 
{ long mtype; int pid; char input[SIZEOFTEXTMSG]; }  spmd_input_t;

typedef	struct 
{ long mtype; int echo; char cmd[SIZEOFTEXTMSG]; } spmd_create_req;

typedef struct 
{ long mtype; int pid; int handle; int response; } spmd_create_rsp;

typedef	struct { long mtype; int pid; int status; } spmd_dead_msg;


/*--- external functions ---*/
extern int UxSpmdReadMsg UXPROTO(( long msgtyp ));
extern int UxSpmdCreateDaemon UXPROTO(( void ));
extern int UxExecSubprocess UXPROTO((SubprocInfo_t *sp, char *args));
extern int UxWhatSpIsDead UXPROTO((int *status));
extern void UxDestroySpmd UXPROTO((void));

/*--- external variables ---*/
extern spmd_info_t UxSpmd;

#ifdef __cplusplus
}  /* Close scope of 'extern "C"' declaration which encloses file. */
#endif /* __cplusplus */

#endif
