 /*
  * Khoros: $Id: run.c,v 1.5 1992/03/25 17:29:56 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: run.c,v 1.5 1992/03/25 17:29:56 dkhoros Exp $";
#endif

 /*
  * $Log: run.c,v $
 * Revision 1.5  1992/03/25  17:29:56  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name:  run.c                                 <<<<
   >>>>                                                       <<<<
   >>>>   description:                                        <<<<
   >>>>                                                       <<<<
   >>>>      routines:  xvl_run_glyph()                       <<<<
   >>>>                 xvl_run_command()                     <<<<
   >>>>                 xvl_run_macro()                       <<<<
   >>>>                 xvl_run_control()                     <<<<
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
* Routine Name:  xvl_run_glyph
*
*      Purpose:  This routine is used to dispatch or execute
*		 a GLYPH.  The routine calls xvf_fork to run
*		 the glyph.  If for some reason the xvf_fork
*		 fails then the system will try to xvf_system().
*
*		 The only exception to this is if the process
*		 is of run type 'PARSERUN'.  This means that
*		 the routine is to be run by the parser and it's
*		 output used to update the parser.
*
*        Input:  glyph -	the GLYPH to run.
*
*
*   Written By: Mark Young
*
*************************************************************/

int xvl_run_glyph(glyph)

Glyph		*glyph;
{
	Workspace    *workspace;
	char	     *command, *hostname, machname[MaxLength];


	/*
	 *  Since this glyph is really not runnable we schedule glyph's
	 *  children for running and then return.
	 */
	workspace = glyph->workspace;
	if (glyph->exec_type == NORUN)
	{
	   xvl_restore_glyph(glyph);
	   xvl_schedule_glyph(glyph);
	   return(DISPATCH_GLYPH_FINISHED);
	}
	else if (xvl_check_if_glyphlist(glyph, workspace->running) == True)
	{
	   if (glyph->exec_type == RERUN)
	      xvl_stop_glyph(glyph);
	   else if (glyph->exec_type == ONERUN)
	   {
	      kill(glyph->pid, SIGCONT);
	      return(DISPATCH_GLYPH_FINISHED);
	   }
	}

	/*
	 *  Otherwise we dispatch the glyph and add a signal handler so that
	 *  we will be notified when the process has completed.
	 */
	XtMapWidget(glyph->stop);
	XRaiseWindow(XtDisplay(glyph->stop), XtWindow(glyph->stop));
	xvl_invert_glyph(glyph, True);

	hostname = xvl_get_machname(glyph, machname);
	if (!(command = form2command(workspace->glyphform, glyph->val.subform,
		hostname)))
	{
	   xvl_restore_glyph(glyph);
	   return(DISPATCH_EXEC_FAILED);
	}

	if (glyph->exec_type == PARSERUN)
	{
	   xvf_expression(workspace->glyphform, command);
	   xvl_restore_glyph(glyph);
	   xvl_schedule_glyph(glyph);
	   return(DISPATCH_GLYPH_FINISHED);
	}
	else
	{
	   /*
	    *  "xvl_dispatch_cb" will be called when the child is either
	    *  finished or killed.  The routine reverses the widget color
	    *  and remaps the start widget.  It also displays an error
	    *  message anything is printed on stderr.
	    */
	   if (!(glyph->pid = xvf_fork(command, xvl_dispatch_cb,(char *)glyph)))
	   {
	      xvf_system(command);
	      xvl_restore_glyph(glyph);
	      return(DISPATCH_GLYPH_FINISHED);
	   }
	   else
	   {
	      workspace->running = xvl_add_to_glyphlist(glyph,
			workspace->running);
	   }
	}
	free(command);


	if (glyph->exec_type == MULTIRUN)
	{
	   glyph->pid = 0;
	   xvl_restore_glyph(glyph);
	}

	if (glyph->run_type == SINK || (glyph->run_type == SOURCE &&
		glyph->output_list == NULL))
	   return(DISPATCH_GLYPH_FINISHED);
	else
	   return(DISPATCH_GLYPH_RUNNING);
}



/************************************************************
*
* Routine Name:  xvl_run_command
*
*      Purpose:  This routine is used to dispatch or execute
*		 a COMMAND.  The routine calls xvf_fork to run
*		 the glyph.  If for some reason the xvf_fork
*		 fails then the system will try to xvf_system().
*
*        Input:  glyph -	the GLYPH to run.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_run_command(glyph)

Glyph		*glyph;
{
	Workspace    *workspace;
	char	     exec[MaxLength], temp[MaxLength], machname[MaxLength],
		     *input, *output, *command, *machine;

	xvf_sub_form	 *subform;
	xvf_guide_button *guide;
	xvf_selection    *selection;
	Line_Info        lineinfo;


	if (glyph->pid != 0)
	{
	   xvl_stop_glyph(glyph);
	}

	/*
	 *  Otherwise we dispatch the glyph and add a signal handler so that
	 *  we will be notified when the process has completed.
	 */
	XtMapWidget(glyph->stop);
	XRaiseWindow(XtDisplay(glyph->stop), XtWindow(glyph->stop));
	xvl_invert_glyph(glyph, True);

	xvf_clear_line_info(&lineinfo);
	subform = glyph->val.subform;
	guide = xvf_search_sel_guide(subform);
	selection = guide->pane->sel_list;

	input = output = command = NULL;
	while (selection != NULL)
	{
	   xvl_parse_line(subform->db, selection->index, &lineinfo);
	   if (lineinfo.variable != NULL && lineinfo.literal != NULL)
	   {
	      if (strcmp(lineinfo.variable,"command") == 0)
	      {
		 command = xvf_strcpy(lineinfo.literal);
	      }
	      else if (strcmp(lineinfo.variable,"input") == 0 &&
			lineinfo.opt_sel == True)
	      {
		 input = xvf_strcpy(lineinfo.literal);
	      }
	      else if (strcmp(lineinfo.variable,"output") == 0 &&
			lineinfo.opt_sel == True)
	      {
		 output = xvf_strcpy(lineinfo.literal);
	      }
	   }
	   selection = selection->next;
	}

	exec[0] = '\0';
	if (input != NULL)
	{
	   (void) sprintf(temp,"kcp -i %s -o - | ", input);
	   strcpy(exec, temp);
	   free(input);
	}

	if (command == NULL)
	{
	   xvf_error_wait("Error! 'command' glyph requires a command to \
be specified in the 'command' string in order to run.", "xvl_run_command",NULL);
	   return(DISPATCH_GLYPH_FAILED);
	}
	strcat(exec, command);
	free(command);

	if (output != NULL)
	{
	   (void) sprintf(temp," > %s", output);
	   strcat(exec, temp);
	   free(output);
	}

	if ((machine = xvl_get_machname(glyph, machname)) != NULL)
	   (void) sprintf(temp, "kexec -m %s -c '%s'", machine, exec);
	else
	   strcpy(temp, exec);

	/*
	 *  "xvl_dispatch_cb" will be called when the child is either
	 *  finished or killed.  The routine reverses the widget color
	 *  and remaps the start widget.  It also displays an error
	 *  message anything is printed on stderr.
	 */
	workspace = glyph->workspace;
	if (!(glyph->pid = xvf_fork(temp, xvl_dispatch_cb, (char *) glyph)))
	{
	   glyph->pid = 0;
	   xvf_system(temp);
	   xvl_restore_glyph(glyph);
	   return(DISPATCH_GLYPH_FINISHED);
	}
	else
	{
	   workspace->running = xvl_add_to_glyphlist(glyph, workspace->running);
	}
	return(DISPATCH_GLYPH_RUNNING);
}



/************************************************************
*
* Routine Name:  xvl_run_macro
*
*      Purpose:  This routine is used to dispatch or execute
*		 a PROCEDURE.  The routine calls builds a list of
*		 GLYPHs and then calls autorun to execute the
*		 list.
*
*        Input:  glyph -	the GLYPH to run.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_run_macro(glyph)

Glyph		*glyph;
{
	Workspace *macro, *workspace;


	XtMapWidget(glyph->stop);
	XRaiseWindow(XtDisplay(glyph->stop), XtWindow(glyph->stop));
	xvl_invert_glyph(glyph, True);

	macro = glyph->val.macro;
	xvl_autorun(macro);

	/*
	 *  Add the workspace's list of currently running processes.
	 */
	workspace = glyph->workspace;
	workspace->running = xvl_add_to_glyphlist(glyph, workspace->running);
	return(DISPATCH_GLYPH_RUNNING);
}



/************************************************************
*
* Routine Name:  xvl_run_control
*
*      Purpose:  This routine is used to dispatch or execute
*		 a CONTROL.  The routine evaluates the appropriate
*		 control subform and updates the connections
*		 according to the type of control glyph.
*
*        Input:  glyph -	the GLYPH to run.
*
*
*   Written By: Mark Young
*
*************************************************************/


int xvl_run_control(glyph)

Glyph		*glyph;
{
	int status;


	/*
	 *  Since this glyph is really not runnable we won't invert the
	 *  glyph's run and stop button.
	 */
	if (glyph->exec_type != NORUN)
	{
	   XtMapWidget(glyph->stop);
	   XRaiseWindow(XtDisplay(glyph->stop), XtWindow(glyph->stop));
	}
	xvl_invert_glyph(glyph, True);
	xvl_control_disable(glyph);

	/*  Determine which Pane Button was selected  */
	if (strcmp(glyph->label_str, "count_loop") == 0)
	   status = xvl_run_control_count(glyph);

	else if (strcmp(glyph->label_str, "while_loop") == 0)
	   status = xvl_run_control_while(glyph);

	else if (strcmp(glyph->label_str, "if_else") == 0)
	   status = xvl_run_control_if(glyph);

	else if (strcmp(glyph->label_str, "merge") == 0)
	   status = xvl_run_control_merge(glyph);

	else if (strcmp(glyph->label_str, "trigger") == 0)
	   status = xvl_run_control_trigger(glyph);

	else if (strcmp(glyph->label_str, "break") == 0)
	   status = xvl_run_control_break(glyph);

	else if (strcmp(glyph->label_str, "expr") == 0)
	   status = xvl_run_control_expr(glyph);

	else if (strcmp(glyph->label_str, "switch") == 0)
	   status = xvl_run_control_switch(glyph);

	return(status);
}
