/*
 *  SIGNAL.C    A program to allow processes created by RUN EXECUTE to
 *              signal their parent processes (to indicate that they have
 *              completed their tasks, or are ready to start, etc).
 *
 *              Used in conjunction with WAITFOR.C
 *
 *              Copyright (c) 1989 by Davide P. Cervone, all rights reserved.
 */

#include <exec/types.h>
#include <exec/ports.h>
#include <libraries/dos.h>
#include <proto/exec.h>

#define MAXCOUNT            10      /* Number of times to try to find port */
#define COUNTWAIT           100     /* Ticks to wait between tries */

#define ERROR_NONE           0      /* Normal exit status */
#define ERROR_CANCELLED     10      /* User pressed CTRL-C to cancel */
#define ERROR_BADPORTNAME   11      /* No port name on command line */
#define ERROR_PORTNOTFOUND  12      /* Specified port not found */

#define SIGBREAKF_ANY\
   (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)

/*
 *  DoExit()
 *
 *  General purpose exit routine.  In this case, since there's nothing
 *  special that needs to be cleaned up, just call _exit() with the 
 *  proper return status.  EXECUTE files will report the error codes, 
 *  but interactive users will get no message
 */

#define DoExit(status)  _exit(status)

extern struct MsgPort *FindPort();
extern long SetSignal();


/*
 *  CheckForCTRLC()
 *
 *  Checks to see if CTRL-C (or D,E or F) have been pressed.
 */

static int CheckForCTRLC()
{
   long theSignals;
   
   theSignals = SetSignal(0L,0L);
   return(theSignals & SIGBREAKF_ANY);
}

/*
 *  _main()
 *
 *  Replaces the standard Lattice _main routine (since no IO is performed
 *  we don't nee the usual overhead).  _main expects the command line 
 *  (as entered by the user, including with the program) to be on the
 *  stack as its PortName argument.
 *
 *  First clear the DOS signals, in case any are set from before.
 *  Check that the port name exists, and skip over the command name
 *  in the command line, and any leading blanks.  The port name will
 *  be whatever remains on the command line, including blanks and
 *  special characters.
 *
 *  Next, look for the specified port.  If it is not found, increment
 *  count and wait a few seconds before trying again.  Only try as MAXCOUNT
 *  times, and error exit if the port can't be found in that many tries.
 *
 *  If the port was found, signal the task.  Note that no actual message
 *  is passed.  The message port simply acts as a convenient holding place
 *  for the signal and the name of the port.  The waiting process simply
 *  removes the port when it receives the signal.
 *
 */

void _main(PortName)
char *PortName;
{
   struct MsgPort *thePort = NULL;
   int count;
   
   SetSignal(0L,SIGBREAKF_ANY);

   if (PortName == NULL) DoExit(ERROR_BADPORTNAME);
   
   while (*PortName != '\0' && *PortName != ' ') PortName++;
   if (*PortName == '\0' || *PortName == '\n') DoExit(ERROR_BADPORTNAME);
   while (*(++PortName) == ' ');

   for (count=0; count < MAXCOUNT && thePort == NULL; count++)
   {
      thePort = FindPort(PortName);
      if (thePort == NULL)
      {
         Delay(COUNTWAIT);
         if (CheckForCTRLC()) DoExit(ERROR_CANCELLED);
      }
   }

   if (thePort == NULL) DoExit(ERROR_PORTNOTFOUND);
   
   Signal(thePort->mp_SigTask,(1<<thePort->mp_SigBit));
   DoExit(ERROR_NONE);
}
