/*===========================================================================
  Copyright (C) 1995-2010 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++ MIDAS monitor routines PREPH +++++++++++++++++++++++++++
.LANGUAGE  C
.IDENTIFICATION Module PREPH
.AUTHOR		K. Banse			ESO - Garching
.ENVIRONMENT  VMS and UNIX
.KEYWORDS
  MIDAS monitor, process control
.COMMENTS  
  holds INPREPA, START_IT, RUN_IT, STOP_IT, DCLOP, ASSIO, DCLDEM, HTERM, 
        CNTRLC, EXH, intmonit

.VERSION [1.00]  870710: initial vers. built from FORTRAN v. 4.30 as of 870311

 100608		last modif
----------------------------------------------------------------------------*/
 

#include <fileexts.h>
#include <osyparms.h>
#include <monitdef.h>
#include <midback.h>
#include <errno.h>
#include <oserror.h>

#include <fsydef.h>

#include <string.h>
#include <signal.h>			/* for symbolic signal names */


static char      keyfile[200];		/* full name of MID_WORK:FORGRxy.KEY */
static char      prefix[8];

#if vms
static int  ttchan, mbchan;	   /* old MONIT.TTCHAN, MONIT.MBCHAN */
static int   Cintr = 1;

static char      mbx[12];
static char      vmsbuf[200];	
static char      Userterm[20];

void START_IT();
#endif

int hostinfo();

/*

*/

void intmonit()

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
 interrupt routine for Cntrl/C in the monitor
.ALGORITHM
 clean up all the stuff from Midas procedures
.RETURNS
 nothing
-----------------------------------------------------------------------*/

{

#if vms
Cintr = 1;
#endif

MONIT.CTRLC = 1;                                /* indicate the interrupt */
osscatch(SIGINT,intmonit);                 /* reenable CntrlC catching */

}

/*

*/

void INPREPA()
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  link to the keyword file as a shared data structure
  set initial values for SYSCOM
  create subprocess FORGRxy and set up everything what's needed for
  communicating with that subprocess
.ALGORITHM
  create + map global section for keyword file + hold it until
  PREPA exits
.RETURNS
  nothing
---------------------------------------------------------------------------*/
 
{
int   iwa, mm, kk, stat, fastmem, ibuf[9];
register int  nr;

char  cbuf[40];
extern char DATA_PATH[328];
 
 

fastmem = myINIT(0);	/*  clean FCT and do other stuff like in  SCSPRO */


/*  init global data  */
 
MONIT.LEVEL = 0;
MONIT.COUNT = 0;
MONIT.INTERRUPT = 0;
MONIT.PAUSLEVL = -1;
MONIT.TOPLEVL = 0;
MONIT.CROSS_COUNT = 0;
MONIT.COMPILED = 0;
ERRORS.STATUS = 0;		/* init low level error status */
ERRORS.SYS = 0;			/* and for the Monitor */

MONIT.CTRLC = 0;

for (nr=0; nr<MAX_LEVEL; nr++)
   {
   MONIT.ECKO[nr] = 0;
   MONIT.MDEBUG[nr] = 0;
   MONIT.PDEBUG[nr] = 0;
   MONIT.PCODE[nr] = 0;
   MONIT.MXT[nr] = 0;
   MONIT.ENDT[nr] = 0;
   TRANSLATE[nr].PNTR[0] = NULL;
   TRANSLATE[nr].PNTR[1] = NULL;
   TRANSLATE[nr].LEN[0] = 0;
   TRANSLATE[nr].LEN[1] = 0;
   }
MONIT.MAXTIME = 0;
MONIT.ECKO[MAX_LEVEL] = 0;
MONIT.MDEBUG[MAX_LEVEL] = 0;
MONIT.PDEBUG[MAX_LEVEL] = 0;
MONIT.PROCESS = -1;			/* init to no_subprocess  */
MONIT.CMD_LIST_UPDA = 1;	/* => INITCOM will use update_cmd_list() */
 
(void) OSY_TRNLOG("PYMIDAS",cbuf,8,&stat);
if (strcmp(cbuf,"YES") == 0)		/* check, if this is PyMidas */
   {
   MONIT.ENV = 'P';
   (void) strcpy(FRONT.PROMPT,"*Midas ");
   FRONT.PEND = 7;
   }
else
   MONIT.ENV = 'N';

(void) strcpy(BATCH[0].CMND,"IF");	/* same order as in COMPILE !! */
(void) strcpy(BATCH[1].CMND,"ELSE");
(void) strcpy(BATCH[2].CMND,"ELSEIF");
(void) strcpy(BATCH[3].CMND,"ENDIF");
(void) strcpy(BATCH[4].CMND,"DO");
(void) strcpy(BATCH[5].CMND,"ENDDO");
 
(void) strcpy(PROC.FORMAT,"4.4  18.8 18.8 "); /* init interactive FORMAT */
	
FRAMACC('I',KAUX.OUT,0,&iwa);		/* init structure FRAME */


/*  set error_continue, error_log and error_display flag for the monitor  */
 
ERRO_CONT = 1;				/* continue always  */
ERRO_LOG = 0;				/* log nothing      */
ERRO_DISP = 0;				/* display nothing  */
ERRO_INDX = -1;				/* clear error message pointers  */
ERRO_OFF = 0;
 

/*  initialize CONTEXT structure */

kk = MAX_CONTXT * 8;
memset((void *)CONTXT.NAME,32,(size_t)kk);		/* clear context names */
CONTXT.NAME[kk] = '\0';			/* make sure we have an end marker */
CONTXT.STACK = 0;
CONTXT.BASE = 0;
for (nr=0; nr<MAX_CONTXT; nr++)
   {
   CONTXT.QUEUE[nr] = 0;
   CONTXT.pdirec[nr] = (char *) 0;
   }


/* prepare name of keyword file + open it  */
 
stat = OSY_TRNLOG("MID_WORK",keyfile,160,&kk);	 /* Decode default directory  */
if (stat != ERR_NORMAL)
   {
   (void) printf("we could not translate MID_WORK or MID_WORK > 160 char.\n\r");
   ospexit(1);
   }

#if vms
if (keyfile[kk-1] != FSY_DISKEND)
   {
   if (keyfile[kk-1] != FSY_DIREND)
      {
      keyfile[kk++] = FSY_DIREND;
      keyfile[kk] = '\0';
      }
   }
#else
if (keyfile[kk-1] != FSY_DIREND)
   {
   keyfile[kk++] = FSY_DIREND;
   keyfile[kk] = '\0';
   }
#endif
 
(void) strcpy(FRONT.STARTUP,keyfile);	/* save name of startup directory */
(void) strcpy(CPATH[0].STR,keyfile);		/* also in CPATH[0] */
(void) strcpy(EPATH[0].STR,keyfile);		/* also in EPATH[0] */
for (nr=1; nr<4; nr++)
   {
   CPATH[nr].STR[0] = '\0';			/* mark the end */
   EPATH[nr].STR[0] = '\0';			/* mark the end */
   }
 
 
/*  get foreground keys in  */
 
if (FRONT.ENV == '*')			/* Unix command line input */
   stat = MID_MOVKEY("IM","**");
else
   {
   (void) strcpy(&keyfile[kk],"FORGR  .KEY");
   keyfile[kk+5] = FRONT.DAZUNIT[0];
   keyfile[kk+6] = FRONT.DAZUNIT[1];
   stat = MID_MOVKEY("IM",keyfile);
   }
if (stat != ERR_NORMAL) ospexit(1);

stat = MID_LOG('I',FRONT.DAZUNIT,2); 		/* open the logfile  */
if (stat != ERR_NORMAL)
   {
   (void) strcpy(cbuf,"INPREPA/MID_LOG:");
   MID_ERROR("MIDAS",cbuf,stat,1);
   }

(void) strcpy(prefix,"FORGR  ");		/* will be used in DCLOP() */
prefix[5] = FRONT.DAZUNIT[0];
prefix[6] = FRONT.DAZUNIT[1];

 
/* save offsets for keys P1,...,P8  +  Q1, Q2, Q3 */
 
MONIT.POFF[0] = OFF_P1;
MONIT.POFF[1] = OFF_P2;
MONIT.POFF[2] = OFF_P3;
MONIT.POFF[3] = OFF_P4;
MONIT.POFF[4] = OFF_P5;
MONIT.POFF[5] = OFF_P6;
MONIT.POFF[6] = OFF_P7;
MONIT.POFF[7] = OFF_P8;
MONIT.POFF[8] = OFF_Q1;
MONIT.POFF[9] = OFF_Q2;
MONIT.POFF[10] = OFF_Q3;
	
KIWORDS[OFF_OUTFLG] = 99;			/* init keyword OUT$FLAG */
KIWORDS[OFF_OUTFLG+2] = -1;
(void) strcpy(&KCWORDS[OFF_OUTNAM]," yyy");

KIWORDS[OFF_MODE+6] = 0;		/* reset overall program level  */
KIWORDS[OFF_MONPAR+2] = KEY_MAXENT;	/* store no. of global + local keys */ 
KIWORDS[OFF_MONPAR+3] = LOC_MAXENT;
KIWORDS[OFF_MONPAR+18] = fastmem;	/* save FASTMEM option */
if (fastmem != 0)
   KIWORDS[OFF_MONPAR+19] = 2000;	/* set MP(20) = 4000 */

/* indicate if we're executed from PyMidas */
if (MONIT.ENV == 'P')
   {					/* indicate PyMidas in MID$SESS */
   KCWORDS[OFF_SESS+27] = 'P';
   KCWORDS[OFF_SESS+28] = 'Y';
   KCWORDS[OFF_SESS+29] = ' ';
   }
else
   {			
   KCWORDS[OFF_SESS+27] = KCWORDS[OFF_SESS+28] = KCWORDS[OFF_SESS+29] = ' ';
   }

/* initialize  keyword DATA_PATH */
memset((void *)&KCWORDS[OFF_DPATH],32,(size_t)319);
for (nr=0; nr<320; nr+=80) KCWORDS[OFF_DPATH+nr] = '^';
KCWORDS[OFF_DPATH+319] = '\0';
(void) strcpy(DATA_PATH,&KCWORDS[OFF_DPATH]);	/* copy also to DATA_PATH */

	
PIPE.CONT[0] = '\0'; 			/* clear PIPE(line) structure */
PIPE.EXE[0] = '\0'; 
PIPE.PROC[0] = '\0'; 
PIPE.INSTRUM[0] = '\0'; 

for (nr=0; nr<5; nr++)			/* clear REDIRECT structure  */
   REDIRECT[nr].OUTFLAG[0] = 99;


/*  clear default definitions + open file internal.cod  */
 
(void) PARDEFS('I'," ");
(void) INTERNAL("OPEN","COD",&mm);
	

if (KIWORDS[OFF_MODE] == 1 )
   mm = hostinfo(1,ibuf,cbuf,cbuf+16,cbuf+28);
else
   mm = hostinfo(0,ibuf,cbuf,cbuf+16,cbuf+28);


/*****************  VMS  ***********************/

#if vms

/*  get channel no. of user ASCII terminal and initialize terminal mode	 */
(void) OSY_TRNLOG("TT",Userterm,19,&kk);	/* Decode terminal name  */
(void) OSY_ASSIGN("TT",2,&ttchan);		/* as used in main process! */
	
KAUX.DCLINP = 0;
START_IT();				/* start up foreground process  */

#endif

/***********************************************/
	


osscatch(SIGINT,intmonit);	/* set up Control/C interrupt handler */
}

/*

*/

#if vms
 
void START_IT()
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  create subprocess FORGRxy
  and set up everything what's needed for communicating with that subprocess
.ALGORITHM
  use lots of system service calls
.RETURNS
  nothing
-----------------------------------------------------------------------*/
 
{
char	eqn[2][20], cbuf[200];
	
int   stat, mm, pid;
int   DCLDEM(), HTERM(), EXH();		/* external functions  */
 
 
stat = OSY_DCLEXH(EXH);			/* declare exit handler  */
if (stat != ERR_NORMAL)
   {
   printf("problems with exit handler/event_flag clearing...\n\r");
   ospexit(1);
   }
	
 
/*  Create mailboxes for DCL commands to foreground processes  */
 
(void) strcpy(mbx,"FORGR  _IN");
mbx[5] = FRONT.DAZUNIT[0];
mbx[6] = FRONT.DAZUNIT[1];
 
stat = OSY_CREMBX(mbx,&mbchan);
if (stat != ERR_NORMAL)
   {
   (void) printf("problems with mailbox creation...\n\r");
   ospexit(1);
   }
 
stat = OSY_TRNLOG(mbx,&eqn[0][0],20,&mm);	    /* get equivalence name  */
if (stat != ERR_NORMAL)
   {
   (void) printf("could not translate mailbox %s ...\n\r",mbx);
   ospexit(1);
   }
else
   eqn[0][mm] = '\0';
 
	
MONIT.PROCESS = 0;
 

/*  Enable AST for subprocess's first DCL input request   */
 
 
stat = OSY_ENAST(mbchan,"READATT",DCLDEM,0);
if (stat != ERR_NORMAL)
   {
   (void) printf("could not enable AST for mailbox, status = %x \n\r",stat);
   ospexit(1);
   }
	
/*  Create subprocess					     */
 
mbx[7] = '\0';			/* that's already the process name */
stat = OSY_SPAWN(&eqn[0][0],mbx,Userterm,&pid,HTERM,&mm); 
MONIT.PID = pid;
	
if (stat != ERR_NORMAL)
   {
   (void) printf("could not spawn subprocess - delete old FORGRxy process\n\r");
   ospexit(1);
   }
   
 
/* Hibernate until something happens  */
 
stat = OSY_HIBER();
if (stat != ERR_NORMAL)
   {
   (void) printf("problems with hibernating call, status = %x \n\r",stat);
   ospexit(1);
   }
  

/*  --- we only get here after having been woken up by the subprocess ---  */
 
	
sect_1000:
 
if (MONIT.PROCESS != 1 )  		/* has the subprocess died?  */
   {
   (void) printf(" subprocess %s has died...\n\r",mbx);
   ospexit(1);
   }
 
	
/*  Make subprocess assignments at user level  */
 
(void) strcpy(vmsbuf,Userterm);
ASSIO(vmsbuf,vmsbuf);
	
}

/*

*/
 
void RUN_IT(image)
	
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  run given image in a subprocess
.ALGORITHM
  enable CNTRL/C AST to terminate a foreground process
.RETURNS
  nothing
---------------------------------------------------------------------*/
 
char	*image   /*IN: image to be executed in the subprocess  */;
 
{
char	*dclpntr;
 
int   stat, mm, kk;
int   DCLDEM(), CNTRLC();
 
 
/*  Enable CTRL/C AST only for interactive foreground process  */
 
if (Cintr > 0)
   {
   if (KIWORDS[OFF_MODE+2] != 1)
     {
     mm = 0;
     stat = OSY_ENAST(ttchan,"CNTRLC",CNTRLC,0);
     if (stat != ERR_NORMAL)
        {
        (void) printf("could not enable AST for CNTRL_C, status = %x\n\r",stat);
        ospexit(1);
        }
      }
   MONIT.CTRLC = 0;                     /* just for compatibility */

   Cintr = 0;
   }
 
 
/*  check, that subprocess has not died   */
 
if (MONIT.PROCESS < 0)
   {
   (void) printf("RUN_IT: subprocess %s has died...\n\r",mbx);
   ospexit(1);
   }

 
/* image name or host opsys command?  */
 
if (*image == '$')
   {
   MONIT.PROCESS = 2;		/* host opsys command: set flag  */
   dclpntr = image;
   if (CGN_INDEXC(dclpntr,'@') > 0) KAUX.DCLINP = 1;
   }
else
   {
   MONIT.PROCESS = 3;	/* image: set flag + construct RUN command  */
   dclpntr = vmsbuf;
   if (MONIT.MDEBUG[MONIT.LEVEL] != 0)
      {
      if (MONIT.MDEBUG[MONIT.LEVEL] == 2)
         {
         (void) strcpy(dclpntr,"$RUN/DEBUG ");		/* with debugger */
         (void) strcpy(dclpntr+11,image);
         }
      else					/* get the current time first */
         {
         (void) sprintf(vmsbuf,"before %s",image);
         SCTPUT(vmsbuf);
         OSY_ASCTIM(vmsbuf);
         SCTPUT(vmsbuf);
         (void) strcpy(dclpntr,"$RUN/NODEBUG ");	/* without debugger */
         (void) strcpy(dclpntr+13,image);
         MONIT.PROCESS = 9;
         }
      }
   else
      {
      (void) strcpy(dclpntr,"$RUN/NODEBUG ");		/* without debugger */
      (void) strcpy(dclpntr+13,image);
      }

   /* write keywords out + command string into mailbox */
 
   fixout(1,MONIT.LEVEL);			/* close any ASCII out file */
   (void) MID_LOG('O',LINE.STR,2);		/* close logfile */
   (void) MID_MOVKEY("O",vmsbuf);		/* write keywords out  */
   }
	

DCLOP(dclpntr);
	

/* Enable AST for PREPA -> PROCESS mailbox read demand  */
 
stat = OSY_ENAST(mbchan,"READATT",DCLDEM,0);
if (stat != ERR_NORMAL)
   {
   (void) printf("could not enable AST for READATT, status = %x\n\r",stat);
   ospexit(1);
   }
 
	
/*  hibernate until something happens  */
 
stat = OSY_HIBER();
if (stat != ERR_NORMAL)
   {
   (void) printf("problems with hibernating call, status = %x\n\r",stat);
   ospexit(1);
   }
 
	
/*  --- we only get here after having been woken up by the subprocess ---   */
 
	
sect_1000:
 
if (MONIT.PROCESS >= 3)
   {
   (void) strcpy(vmsbuf,FRONT.STARTUP);	   /* get name of startup directory */
   kk = strlen(vmsbuf);
   (void) strcpy(&vmsbuf[kk],"FORGR  .KEY");
   vmsbuf[kk+5] = FRONT.DAZUNIT[0];
   vmsbuf[kk+6] = FRONT.DAZUNIT[1];
   (void) MID_MOVKEY("IM",vmsbuf); 		/* get keywords back  */
   (void) MID_LOG('I',FRONT.DAZUNIT,2);		/* open logfile again  */

   if (MONIT.PROCESS == 9)		/* get current time after execution */
      {
      (void) sprintf(vmsbuf,"after %s",image);
      SCTPUT(vmsbuf);
      OSY_ASCTIM(vmsbuf);
      SCTPUT(vmsbuf);
      }
   }
}

/*

*/
 
STOP_IT()
	
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  kill foreground subprocess;
.ALGORITHM
  PID is stored in MONIT.PID - use system service calls
.RETURNS
  nothing
----------------------------------------------------------------*/

{
int  stat;


/*  flush terminal I/O + delete process  */
 
(void) OSY_CANCEL(ttchan);
	
if (MONIT.PROCESS != -1)
   {
   stat = OSY_DELPRC(&MONIT.PID);	/* try to abort foreground process */
   if (stat != ERR_NORMAL)
      (void) printf("problems with process deletion, status = %x\n\r",stat);
   MONIT.PROCESS = -1;
   }
	
}

/*

*/
 
ASSIO(indev,outdev)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  assign the standard I/O streams for subprocess
.ALGORITHM
  use DCLOP to pass "$ASSIGN commands" to the subprocess
.RETURNS
  nothing
--------------------------------------------------------------------*/
	
char	*indev	/*IN: point to input device (with '\0')  */;
char	*outdev /*OUT: output device (with '\0')  */;
 
{
int  mm;
	
char	work[60];

	
DCLOP("$SET NOVERIFY");		/* Switch off verify in subprocess */
 
DCLOP("$SET NOON");		/* Prevent error exit  */
 
(void) strcpy(work,"$ASSIGN ");
(void) strcpy(&work[8],indev);
mm = strlen(work);
 
(void) strcpy(&work[mm]," SYS$COMMAND");	/* $ASSIGN indev SYS$COMMAND */
DCLOP(work);
(void) strcpy(&work[mm]," SYS$INPUT");		/* $ASSIGN indev SYS$INPUT  */
DCLOP(work);
(void) strcpy(&work[mm]," FOR$READ");		/* $ASSIGN indev FOR$READ  */
DCLOP(work);
(void) strcpy(&work[mm]," DBG$INPUT");		/* $ASSIGN indev DBG$INPUT  */
DCLOP(work);
(void) strcpy(&work[mm]," TT");		/*  $ASSIGN indev SYS$COMMAND  */
DCLOP(work);
 
(void) strcpy(&work[8],outdev);
mm = strlen(work);
(void) strcpy(&work[mm]," SYS$OUTPUT");	/*  $ASSIGN outdev SYS$OUTPUT  */
DCLOP(work);
	
}

/*

*/
 
DCLDEM()
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  service AST when subprocess requests next DCL command
.ALGORITHM
  wake up main process
.RETURNS
  nothing
---------------------------------------------------------------*/
 
{
int  stat;


/*  If first time, set subprocess status = created  */
 
if (MONIT.PROCESS == 0) MONIT.PROCESS = 1;

	
/* Wake the main process */
 
stat = OSY_WAKE();
if (stat != ERR_NORMAL)
   ospexit(1);
	
 
/*  for host (DCL) commands we may have to reset SYS$INPUT...  */
 
if (KAUX.DCLINP == 1)
   {
   KAUX.DCLINP = 0;
   (void) strcpy(vmsbuf,"$ASSIGN ");
   (void) strcpy(&vmsbuf[8],Userterm);
   (void) strcat(vmsbuf," SYS$INPUT");
   DCLOP(vmsbuf);
   }
	
}

/*

*/
 
HTERM()

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  service AST when subprocess terminates
.ALGORITHM
  wake up main process 
.RETURNS
  nothing
------------------------------------------------------------------*/

{
int  stat;

/*  Set the process status flag   */
 
MONIT.PROCESS = -1;
	
/*  Wake the main process if hibernating */
 
stat = OSY_WAKE();
 
if (stat != ERR_NORMAL)
   ospexit(1);
	
}

/*

*/
 
EXH(stat)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  kill subprocesses on forced exit of main process
.ALGORITHM
  will be called as EXH(stat) when main process crashes
  use OSY_DELPRC
.RETURNS
  nothing
------------------------------------------------------------------*/

int   *stat   /* IN:	status of exit  */;
 
{	
 
/*  Last chance to get rid of subprocesses  */
 
if (MONIT.PROCESS != -1)
   {
   *stat = OSY_DELPRC(&MONIT.PID);
   MONIT.PROCESS = -1;
   }
	
if (KIWORDS[OFF_AUX+7] == 1) ostraw(0);
 
}

/*

*/
 
DCLOP(dcl)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  pass DCL input to subprocess via mailbox
.ALGORITHM
  get mailbox from keyword CHANNEL + use system service calls
.RETURNS
  nothing
-------------------------------------------------------------------------*/

char	*dcl	/* IN: pointer to host command (terminated by '\0')  */;

 
{
int  stat;


/*  Write DCL command to mailbox  */
 
stat = OSY_WRCHAN(mbchan,dcl,(int)strlen(dcl));

if (stat != ERR_NORMAL) 
   {
   if (strncmp(dcl,"$RUN",4) == 0)
      {
      char  string[160];
      int   nr, m;

      for (nr=0; nr<4; nr++)
         {
         if (EPATH[nr].STR[0] == '\0') break;

         m = CGN_COPY(string,EPATH[nr].STR);
         (void) strcpy(&string[m],dcl);
         stat = OSY_WRCHAN(mbchan,string,(int)strlen(string));
         if (stat == ERR_NORMAL) return;
         }
      }
   (void) printf("problems with OSY_WRCHAN of %s ...\n\r",dcl);
   }

}

/*

*/
 
CNTRLC()
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  AST routine for CTRL/C
.ALGORITHM
  reset any procedure level, clear local keys + force exit of image in subproce
.RETURNS
  nothing
-----------------------------------------------------------------------*/
	
{
int  stat;


/* proceed unless subprocess isn't running a job  */
 
(void) strcpy(vmsbuf,"FORGR  ");
vmsbuf[5] = FRONT.DAZUNIT[0];
vmsbuf[6] = FRONT.DAZUNIT[1];
 
stat = OSY_FORCEX(vmsbuf);
if (stat != ERR_NORMAL) ospexit(1);

MONIT.CTRLC = 1;				/* indicate the interrupt */
Cintr = 1;

}

/*

*/
 
#else					/* Unix part */

void RUN_IT(image)
	
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  run given image in a subprocess
.ALGORITHM
  enable CNTRL/C AST to terminate a foreground process
.RETURNS
  nothing
---------------------------------------------------------------------*/
 
char	*image		/*IN: image to be executed in the subprocess  */;
 
{
int  kk, exec_stat;
long int   oshtime(), startsecs, elapsed;

char  cbuf[240], *cptr;




startsecs = 0L;

/* image name or host opsys command?  */
 
if (*image == '$')
   {
   MONIT.PROCESS = 2;		     /* host opsys command: set flag  */
   exec_stat = DCLOP(image);
   }

else
   {
   MONIT.PROCESS = 3;  /* image name: set flag + prepare execution of image */

   if (MONIT.MDEBUG[MONIT.LEVEL] != 0)
      {
      if (MONIT.MDEBUG[MONIT.LEVEL] == 2)	/* we use the debugger */
         {
         int  uni, nulo, iav;
         register int  nr;
         char debugflags[42], debugopt[42];

         nulo = -1;
         cptr = cbuf + 1;			/* have one byte in front */
         SCKRDC("MID$DEBUG",40,1,1,&iav,cptr,&uni,&nulo);
         cbuf[0] = '_';
         cbuf[40] = ' ';
         kk = CGN_INDEXC(cbuf,' ');
         cbuf[++kk] = '\0';
         if (cbuf[1] != '$')		/* debugger runs in host OS */
            {
            cbuf[0] = '$';
            cptr = cbuf;
            }
         SCKRDC("MID$DEBUG",40,2,1,&iav,debugflags,&uni,&nulo);
         SCKRDC("MID$DEBUG",40,3,1,&iav,debugopt,&uni,&nulo);
         if (debugflags[0] != '?')
            {
            for (nr=39; nr>0; nr--)
               {
               if (debugflags[nr] != ' ') break;
               }
            debugflags[++nr] = ' ';
            debugflags[++nr] = '\0';
            (void) strcat(cptr,debugflags);
            }
         (void) strcat(cptr,image);
         if (debugopt[0] != '?')
            {
            for (nr=39; nr>0; nr--)
               {
               if (debugopt[nr] != ' ') break;
               }
            debugopt[nr+1] = '\0';
            (void) strcat(cptr,"  ");
            (void) strcat(cptr,debugopt);
            }
         image = cptr;
         MONIT.PROCESS = 8;
         }
      else				/* get the current time first */
         {
         startsecs = oshtime();
         MONIT.PROCESS = 9;
         }
      }

   /* close logfile + write keywords out  */
 
   fixout(1,MONIT.LEVEL);			/* close any ASCII out file */
   (void) MID_LOG('O',LINE.STR,2);		/* close logfile */
   (void) MID_MOVKEY("O",cbuf);			/* write keywords out  */
 
					/* printf("image = %s\n",image); */
   exec_stat = DCLOP(image);

   /*  on return from subprocess move keyword stuff back in */
 
   if (FRONT.ENV == '*')		/* from Unix command line */
      (void) MID_MOVKEY("IM","**");	/* get keywords back in */
   else
      (void) MID_MOVKEY("IM",keyfile);	/* inside Midas */

   (void) MID_LOG('I',FRONT.DAZUNIT,2);               /* open logfile again */

   if (MONIT.PROCESS >= 8)		/* special treatment? */
      {
      if (MONIT.PROCESS == 9)		/* get current time after execution */
         {
         elapsed = oshtime();
         elapsed -= startsecs;
         (void) sprintf(cbuf,"elapsed time: %ld secs for %s",elapsed,image);
         SCTPUT(cbuf);
         }
      else
         return;
      }
   }

if (exec_stat != ERR_NORMAL)		/* now we can also log */
   {					/* errors from the execution */
   if (exec_stat == ERR_OPSSYS) 
      {
      char  *mypr, *osmsg();

      mypr = osmsg();
      (void) sprintf(KAUX.OUT,"(ERR) Problems in executing %s",image);
      SCTPUT(KAUX.OUT); 
      SCTPUT(mypr);
      kk = 888;
      }
   else					/* ERR_INPINV for timeout */
      {
      (void) sprintf(KAUX.OUT,"(ERR) %s timed out (%d seconds)",
                     image,MONIT.MAXTIME);
      SCTPUT(KAUX.OUT);
      kk = 998;
      }

   KIWORDS[OFF_PRSTAT] = kk;		/* store status and error source */
   KIWORDS[OFF_PRSTAT+1] = 100;		/* into key PROGSTAT */
   }
	
}

/*

*/
 
int DCLOP(dcl)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  start up subprocess to run executable
.ALGORITHM
  use system service
.RETURNS
  nothing
-------------------------------------------------------------------------*/
 
char	*dcl	/* IN: pointer to host command (terminated by '\0')  */;

{
int   pid, maxtime, stat;




maxtime = MONIT.MXT[MONIT.LEVEL];
if ((maxtime > 0) && (MONIT.LEVEL > 0))
   {
   long int   oshtime();

   maxtime = (int) (MONIT.ENDT[MONIT.LEVEL] - oshtime());
   if (maxtime < 1) return (ERR_INPINV);
   }

stat = OSY_SPAWN(0,dcl,prefix,maxtime,&pid);

if (MONIT.PROCESS == 2) 
   {
   KIWORDS[OFF_AUX+16] = stat;		/* host return status => AUX_MODE(17) */
   stat = ERR_NORMAL;
   }
else
   {
   if ( (stat != ERR_NORMAL) && (oserror == ENOENT) )
      {
      char  string[160];
      int   nr, m;

      for (nr=0; nr<4; nr++)
         {
         if (EPATH[nr].STR[0] != '\0') 
            {
            m = CGN_COPY(string,EPATH[nr].STR);
            (void) strcpy(&string[m],dcl);
            if ((stat = OSY_SPAWN(0,string,prefix,maxtime,&pid)) == ERR_NORMAL)
               break;
            }
         }
      }
   }

MONIT.PID = pid;
return (stat);
}
 

#endif

