/*****************  dcc_back.c  ******************
 *                                               *
 *                                               *
 *                  IconAuthor                   *
 *                                               *
 *                  © by Koessi                  *
 *                                               *
 *             Thursday, 13 Aug 1992             *
 *                                               *
 *                                               *
 *************************************************/

/*  USAGE:
 *
 *  place dcc_back.o in DLIB:
 *
 *  use '-ldcc_back.o' as additional option to DCC
 *
 *  or #include "dcc_back.c" into your code
 *
 *
 *  DESCRIPTION:
 *
 *  it overrides the internal _main() lib-function called by c.o
 *  before calling main()
 *
 *  it patches the seglist and creates its own code as a new process
 *  calling DOS' CreateProc
 *
 *  this is done while Forbid() is used to prevend the new process
 *  from starting before the loader has ended, which returns to the
 *  called CLI via exec's Exit() function
 *
 *  the new process will have NULL as its pr_CLI-field, so it will
 *  just get the original directory as its current directory and
 *  start main()
 *
 *  on _exit() DICE's c.o calls _AutoInit1, which will jsr to x_exit(),
 *  that checks for seg to UnLoadSeg() the used memory
 *
 *  ******** works fine with DOS&WB2.0 on A3000 *********
 *
 *  if the program is started from WorkBench, _main() will behave as usual
 *  calling wbmain() with WBStartup _WBMsg as its parameter
 *
 *
 *  BUGS:
 *
 *  unusable with -r (resident) option
 *  some bytes lost in space (just the commandline or its copy ?)
 *
 *
 *  CREDITS:
 *
 *  Bill Barton - who did 'spawn' (found on RPD #103) - thanx
 *
 *  AUTHOR:
 *
 *  Koessi - phone germany 02192 7630
 *
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <lib/bcpl.h>
#include <lib/misc.h>

typedef struct CommandLineInterface CLI;
typedef struct Process              Process;

extern  LONG              *__MemList;
extern  struct WBStartup  *_WBMsg;
extern  struct ExecBase   *SysBase;

LONG   seg        = 0;
BOOL   clistart   = 0;
BPTR   t_cdir     = 0;
char **avv        = 0;
SHORT  acc        = 0;
CLI   *cli        = 0;
LONG  *x_MemList  = 0;

__stkargs void
_main(short len, char *arg)
{
  Process *proc = (Process *) SysBase->ThisTask;

  if (proc->pr_Task.tc_Node.ln_Type == NT_PROCESS)
  {
    if (cli = BTOC(proc->pr_CLI, CLI))
    {
      seg = cli->cli_Module;
      char  *cname  = BTOC(cli->cli_CommandName, char *);
      char  *copy   = malloc(len + 1);  /* alloc space for cmdline's copy   */

      _slow_bcopy(arg, copy, len);      /* copy cmdline  */
      copy[len] = '\0';
      acc = _parseargs1(copy, len);     /* count parameters                 */
      avv = malloc((acc + 2) << 2);     /* alloc char *array                */
      _parseargs2(copy, avv + 1, acc);  /* fill array */
      ++acc;              /* include arg0    */

      if (cname)          /* copy BCPL-String  */
      {
        len = *cname;     /* leading length */
        arg = malloc(len + 1);  /* alloc space for cmdname's copy           */
        _slow_bcopy(cname + 1, arg, len);
        arg[len] = 0;     /* copy cmdname */
      }

      avv[0]    = arg;    /* fill array  */
      avv[acc]  = 0;
      t_cdir = DupLock(proc->pr_CurrentDir);
      clistart = 1;       /* flag clistart */
      if (SysBase->LibNode.lib_Version > 36)
        CacheClearU();    /* good for 020/030/040  */
      Forbid();           /* prevent starting new task until this is gone away */
      if (CreateProc(avv[0], 0L, seg, cli->cli_DefaultStack << 2))
      {
        cli->cli_Module = 0;
        x_MemList = __MemList;
        __MemList = 0;
      }
      exit(0);
    }                     /* endif proc->pr_CLI */
    else
    {
      if (clistart)       /* now detached process */
      {
        clistart = 0;
        CurrentDir(t_cdir);
        exit(main(acc, avv));   /* overrides c.a */
      }
      else
        /* workbench start */
      {
        WaitPort(&proc->pr_MsgPort);
        _WBMsg = (void *)GetMsg(&proc->pr_MsgPort);
        exit(wbmain(_WBMsg));
      }
    }
  }                       /* if NT_PROCESS */
  Exit(20);
}
__autoexit void
x_exit(void)
{
  if (!_WBMsg)
  {
    if (seg && !clistart)
    {
      UnLock(t_cdir);
      long **item;

      while (item = (long **)x_MemList)
      {
        x_MemList = (long *)*x_MemList;
        FreeMem(item, item[1]);
      }
      Forbid();
      UnLoadSeg(seg);
    }
  }
}

