/*
 * To obey the protocol, we must use NP_ExitCode to set up code that clears
 * the proc pointer, indicating that we ain't got a blanker any more.
 * In addition, This code sends a CTRL-C signal to the utility, so that it
 * will exit, so we need a pointer to our task. Finally, proc must be
 * protected by a semaphore, so that's out here as well.
 *
 * Copyright 1991, Mike Meyer
 * All Rights Reserved
 *
 * See the file "ShadowMaster:Distribution" for information on distribution.
 */

static struct Process *proc = NULL ;
static struct Task *me = NULL ;
static struct SignalSemaphore guard ;
#ifdef	LOOPS
#include <graphics/displayinfo.h>
#include <proto/intuition.h>
struct IntuitionBase *IntuitionBase ;
#endif

#define FIRST	1
#define REST	2
#define CLEANUP	3

/*
 * This is the starting point. It sets up the world, and calls your
 * utility routine (doutility()), then cleans up after itself when you
 * return. Nothing in here should need changing.
 *
 * This gets included into the utility file at the appropriate place.
 */
#define done(x)	do { status = x; goto out; } while (0) ;

int __saveds
start(void) {
	int status = RETURN_OK ;
#ifdef	LOOPS
	struct Screen	*screen = NULL ;
	static struct ColorSpec colors[] = {{0, 0, 0, 0}, {1, 0, 0, 0}, {-1} } ;
	static struct TagItem screen_tags[] = {
		{SA_Depth, 1},
		{SA_DisplayID, LORES_KEY},
		{SA_Quiet, TRUE},
		{SA_Colors, &colors},
		{TAG_END, 0}
		} ;
#endif
#ifdef	TEMPLATE
	struct RDArgs *args = NULL ;
#endif
	int tripno = FIRST ;

	proctags[0].ti_Data = 0 ;
	SysBase = *((struct ExecBase **) 4);
	if ((DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)) == NULL)
		done(RETURN_FAIL) ;
#ifdef	LOOPS
	if ((IntuitionBase = (struct IntuitionBase *)
	    OpenLibrary("intuition.library", 37)) == NULL)
		done(RETURN_FAIL) ;
#endif
	InitSemaphore(&guard) ;
	me = FindTask(0L) ;

	/* Do the magic that you do so well */
#ifdef	TEMPLATE
	if ((args = ReadArgs(TEMPLATE, opts, NULL)) == NULL)
		done(RETURN_ERROR) ;
#endif

	/* Let's get the show on the road... */
#ifdef	LOOPS
	for (;;) {
#endif
	proctags[1].ti_Data = (long) doutility(tripno) ;

#ifdef	LOOPS
	if (tripno != FIRST && proctags[1].ti_Data)
		screen = OpenScreenTagList(NULL, screen_tags) ;
	ObtainSemaphore(&guard) ;
	while (proc) {
		Signal((struct Task *) proc, SIGBREAKF_CTRL_C) ;
		ReleaseSemaphore(&guard) ;
		Wait(SIGBREAKF_CTRL_C) ;	/* From procend */
		ObtainSemaphore(&guard) ;
		}
	ReleaseSemaphore(&guard) ;
#endif

	if (proctags[1].ti_Data == NULL
	|| ((proctags[0].ti_Data = (long) LoadSeg((char *) proctags[1].ti_Data)) == NULL)
	/* At this point, proc isn't running, so we don't need a guard... */
	|| ((proc = CreateNewProc(proctags)) == NULL)) {
#ifdef	LOOPS
		doutility(CLEANUP) ;		/* So they can clean up */
#endif
		done(RETURN_FAIL) ;
		}

	proctags[0].ti_Data = NULL ;	/* The process will unload itself */

#ifdef	LOOPS
	if (screen) {
		Delay(1) ;		/* Force a task switch */
		CloseScreen(screen) ;
		}
	screen = NULL ;
	tripno = REST ;
	}
#else
	Wait(SIGBREAKF_CTRL_C) ;	/* Someone says die */

	ObtainSemaphore(&guard) ;
	while (proc) {
		Signal((struct Task *) proc, SIGBREAKF_CTRL_C) ;
		ReleaseSemaphore(&guard) ;
		Wait(SIGBREAKF_CTRL_C) ;	/* From procend */
		ObtainSemaphore(&guard) ;
		}
	ReleaseSemaphore(&guard) ;
#endif

	/* Here's how we exit this mess */
out:
	if (proctags[0].ti_Data) UnLoadSeg(proctags[1].ti_Data) ;
#ifdef	LOOPS
	if (screen) CloseScreen(screen) ;
#endif
#ifdef	TEMPLATE
	if (args) FreeArgs(args) ;
#endif
	if (DOSBase) CloseLibrary((struct Library *) DOSBase) ;
	return status ;
	}

/* Make sure we don't screw up any following code... */
#undef done

/* The routine that ends all procs */
static void __saveds
procend(void) {

	ObtainSemaphore(&guard) ;
	proc = NULL ;
	Signal(me, SIGBREAKF_CTRL_C) ;
	ReleaseSemaphore(&guard) ;
	}
