/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1988 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
/* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* C version of a new cback.a for PopCLI */
/* This code should be put in the throwaway segment. It will clone the */
/* second segment of this process into an independent seglist, and do  */
/* a CreateProc for it.                                                */

#include <exec/types.h>
#include <exec/alerts.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/tasks.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/dos.h>

#include "cback.h"

/* Constants for the new process: */
#define PROCNAME  "PopCLI IV"
#define STACKSIZE 4096
#define PRIORITY  20

struct Segment {
	ULONG	sm_len;
	BPTR	sm_next;
};

/* Get a Task pointer from the MsgPort pointer returned by CreateProc */
#define GETTASK(m)	(((struct Task *)m)-1)

void __far _main(void);

void __asm start(register __a0 char *cmd, register __d0 char *cmdlen)
{
	struct DosLibrary	*DOSBase;
	struct Process		*us;
	struct MemList		memlist, *ml;
	struct Segment		*segment;
	char			*newseg;
	struct cbackstr		*msg;
	BPTR			cwd;
	int			sig;
	struct MsgPort		*procmsg;
	struct WBStartup	*wbmsg;
	BPTR			stdin;

	DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);
	
	us = (struct Process *)FindTask(0);

	msg = AllocMem( sizeof(struct cbackstr),
				MEMF_PUBLIC|MEMF_CLEAR );

	msg->msgpart.mn_Length = sizeof(struct cbackstr);

	cwd = us->pr_CurrentDir;
	if (us->pr_CLI)
	{
		/* Run from CLI. We need to duplicate the lock for the	*/
		/* current working directory.				*/
		cwd = DupLock(cwd);
		
		/* Find the _main()'s segment. We need to clone it      */
		/* KLUDGE WARNING: to find _main's segment, back up 8   */
		/* bytes from the address of _main.                     */
		segment = (struct Segment *)  (((char *)_main)-8);

		memlist.ml_NumEntries = 1;
		memlist.ml_ME[0].me_Reqs = MEMF_PUBLIC;
		memlist.ml_ME[0].me_Length = segment->sm_len;

		ml = AllocEntry( &memlist );
		newseg = (char *) ml->ml_ME[0].me_Addr;

		memcpy( newseg, (char *)(&(segment->sm_next)),
				segment->sm_len );
		*((long *)newseg) = 0;

		/* set up the message fields we now need */
		msg->stdout = Open("*", MODE_OLDFILE);
		msg->SyncProcess = us;
		msg->SyncSignal = sig = AllocSignal(-1);
		msg->cmd = cmd;
		msg->cmdlen = cmdlen;

		/* Start up the new proc */
		Forbid();
		procmsg = CreateProc(
					PROCNAME,
					PRIORITY,
					(BPTR)((ULONG)newseg>>2),
					STACKSIZE
					);
		if (procmsg)
		{
			AddTail( &(GETTASK(procmsg)->tc_MemEntry),
				 (struct Node *)ml );
		}
		Permit();

		/* Let 'em go, but wait until they let us go */
		if (procmsg && sig >= 0)
		{
			PutMsg( procmsg, (struct Message *)msg );
			Wait(1<<sig);
		}
	}
	else
	{
		/* We're a WorkBench process. Don't fork, but get the	*/
		/* workbench message and use stuff from it.		*/
		WaitPort( &us->pr_MsgPort );
		wbmsg = (struct WBStartup *)GetMsg( &us->pr_MsgPort );
		cwd = CurrentDir( wbmsg->sm_ArgList->wa_Lock );

		/* Stuff to get cmdline & stuff */

		stdin = Open( wbmsg->sm_ToolWindow, MODE_OLDFILE );

		/* Send ourselves the message, since we're going to be	*/
		/* waiting for it					*/
		PutMsg( &us->pr_MsgPort, (struct Message *)msg );

		/* Call the main routine */
		_main();
		
		Close(stdin);
		/* Forbid();   is this really necessary???? */
		ReplyMsg((struct Message *)wbmsg);
	}

	UnLock(cwd);
	CloseLibrary((struct Library *)DOSBase);
}

