/*
 * WBStart-Handler.c   V1.0
 *
 * Handler code
 *
 * (c) 1991 by Stefan Becker
 *
 */
#include "WBStart.h"
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/icon_protos.h>
#include <workbench/icon.h>
#include <workbench/workbench.h>
#include <stdlib.h>
#include <string.h>

/* Global data */
void _waitwbmsg(void);
struct Library *IconBase;
static struct MsgPort *HandlerPort;
static ULONG wbactive=0;            /* Number of active WB processes */
static char Version[]="$VER: WBStart-Handler V1.0 (24.11.1991)";

/* Start tool as a WB process */
static BOOL StartProgram(struct WBStartMsg *msg)
{
 char *name=msg->wbsm_Name;      /* Program name */
 BPTR fl;                        /* AmigaDOS file handle */
 register struct WBStartup *wbs; /* WBStartup message for tool */
 struct DiskObject *tdob;        /* Tool icon */
 LONG ssize;                     /* StackSize, default */
 struct MsgPort *proc;           /* Process descriptor for tool */
 struct WBArg *wbad,*wbas;       /* Pointers to WB arguments */
 char *proname=NULL;             /* Name of Project icon */
 int i;

 /* Allocate memory for WBStartup */
 if (!(wbs=calloc(sizeof(struct WBStartup)+
                  sizeof(struct WBArg)*(msg->wbsm_NumArgs+2),1)))
  return (FALSE);

 /* Change to tool's directory */
 fl=CurrentDir(msg->wbsm_DirLock);

 /* Is it a project? */
 if (tdob=GetDiskObject(name))
  if (tdob->do_Type==WBPROJECT)
   {
    proname=name;                      /* Save original name */
    name=strdup(tdob->do_DefaultTool); /* Get name of default tool */
    FreeDiskObject(tdob);
    if (!name) goto se1;               /* Enough memory? */
    tdob=GetDiskObject(name);          /* Get icon of the default tool */
   }

 /* Is it a tool? */
 ssize=msg->wbsm_Stack;
 if (tdob)
  {
   if (tdob->do_Type==WBTOOL)          /* Only tools supply this information */
    {
     if (tdob->do_ToolWindow) wbs->sm_ToolWindow=strdup(tdob->do_ToolWindow);
     if (tdob->do_StackSize>ssize) ssize=tdob->do_StackSize;
    }

   FreeDiskObject(tdob);
  }
 if (ssize<4096) ssize=4096; /* Minimum stack size is 4096 Bytes! */
 ssize=(ssize+3)&(~3);       /* Stack size must be a multiple of 4! */

 /* Load tool code */
 if (!(wbs->sm_Segment=LoadSeg(name))) goto se2;

 /* Build WBStartup message */
 /* wbs->sm_Message.mn_Node.ln_Type=NT_MESSAGE; PutMsg() does this for us! */
 wbs->sm_Message.mn_ReplyPort=HandlerPort;
 wbs->sm_Message.mn_Length=sizeof(struct WBStartup);
 wbs->sm_NumArgs=msg->wbsm_NumArgs+1;
 wbs->sm_ArgList=wbs+1;             /* WBArg array starts after WBStartup */

 /* Initialize WBArg pointers */
 wbas=msg->wbsm_ArgList;
 wbad=wbs->sm_ArgList;

 /* 1. argument is the tool itself! */
 if (!(wbad->wa_Lock=DupLock(msg->wbsm_DirLock))) goto se3;
 if (!(wbad->wa_Name=strdup(name))) goto se4;
 wbad++;

 /* If tool is a project, add it as 2. parameter to the WBArg list */
 if (proname)
  {
   if (!(wbad->wa_Lock=DupLock(msg->wbsm_DirLock))) goto se4;
   if (!(wbad->wa_Name=strdup(proname))) goto se4;
   wbad++;
   wbs->sm_NumArgs++;
  }

 /* Copy WB arguments */
 for (i=msg->wbsm_NumArgs; i; i--,wbas++,wbad++)
  {
   if (!(wbad->wa_Lock=DupLock(wbas->wa_Lock)))
    {
     wbad--;             /* Skip parameters, which don't support a lock */
     wbs->sm_NumArgs--;
     continue;           /* Next parameter */
    }

   /* Sanity check for name string... Enforcer is watching you! */
   if (!wbas->wa_Name || !(wbad->wa_Name=strdup(wbas->wa_Name))) goto se4;
  }

 /* Create process */
 if (!(wbs->sm_Process=CreateProc(wbs->sm_ArgList->wa_Name,msg->wbsm_Prio,
                                  wbs->sm_Segment,ssize)))
  goto se4;

 /* Send WBStartup message to tool */
 PutMsg(wbs->sm_Process,(struct Message *) wbs);
 if (proname) free(name);       /* If project, then free default tool name */
 CurrentDir(fl);                /* Change to old directory */
 wbactive++;                    /* Tool started! */
 return(TRUE);

 /* An error occurred. Free all resources */
se4: wbas=wbs->sm_ArgList;
     for (i=wbs->sm_NumArgs; i; i--,wbas++)
      {
       UnLock(wbas->wa_Lock);
       if (wbas->wa_Name) free(wbas->wa_Name);
      }
se3: UnLoadSeg(wbs->sm_Segment);
se2: if (proname) free(name);
se1: CurrentDir(fl);
     free(wbs);
     return(FALSE);
}

__stkargs void _main(int arglen, char *argptr)
{
 ULONG gotsigs,wsig,psig;
 BOOL notend=TRUE;

 /* Open icon.library */
 if (!(IconBase=OpenLibrary(ICONNAME,0))) return;

 /* Create message port */
 if (!(HandlerPort=CreateMsgPort()))
  {
   CloseLibrary(IconBase);
   return;
  }

 /* Make port public */
 HandlerPort->mp_Node.ln_Pri=0;
 HandlerPort->mp_Node.ln_Name=WBS_PORTNAME;
 AddPort(HandlerPort);

 /* Init signal masks */
 psig=1L<<HandlerPort->mp_SigBit;
 wsig=psig|SIGBREAKF_CTRL_C;

 /* Main event loop */
 while (notend)
  {
   /* Wait on event */
   gotsigs=Wait(wsig);

   /* Got a message at our port? */
   if (gotsigs&psig)
    {
     struct WBStartMsg *msg;

     /* Process all messages */
     while (msg=GetMsg(HandlerPort))
      if (msg->wbsm_Msg.mn_Node.ln_Type==NT_REPLYMSG) /* Replied message? */
       {
        /* This is the death message from a tool we started some time ago */
        struct WBStartup *wbs=(struct WBStartup *) msg;
        struct WBArg *wa=wbs->sm_ArgList;
        int i=wbs->sm_NumArgs;

        while (i--)
         {
          UnLock(wa->wa_Lock);      /* Free WB argument */
          if (wa->wa_Name) free(wa->wa_Name);
          wa++;
         }

        if (wbs->sm_ToolWindow)     /* Free tool window specification */
         free(wbs->sm_ToolWindow);

        UnLoadSeg(wbs->sm_Segment); /* Unload code */
        free(wbs);                  /* Free WBStartup */
        wbactive--;                 /* One tool closed down */
       }
      else
       {
        /* We got a new message. Handle and reply it. */
        msg->wbsm_Stack=StartProgram(msg);
        ReplyMsg((struct Message *) msg);
       }
    }

   /* Received a CTRL-C? */
   if ((gotsigs&SIGBREAKF_CTRL_C) && !wbactive) notend=FALSE;
  }

 /* Exit handler */
 RemPort(HandlerPort);
 DeleteMsgPort(HandlerPort);
 CloseLibrary(IconBase);
 return;

 /* NOT REACHED */
 _waitwbmsg();    /* Force linking of WB startup code */
}
