/***************************************************************************

Source code for RExpand (which is Copyright ©1996 Peter Liljenberg)

Version 1.0
Author: Peter Liljenberg, 1996.

This code is fully Public Domain: you can use it in any way you want as
long as you don't violate the copyright of the _program_ RExpand. This
means that you can use the code for inspiration, for help or as an example;
and you can even cut code out and include it in your own programs, as long
as you don't make a program which, basicly, is RExpand and release it. You
can make modifications or add features to RExpand for your own use (and
maybe some friends' as well), but I'd be grateful if you would send me the
modified code so I can make a new version with this stuff added. You will
get due credit for the changes. In the same way, I expect to get a mention
in the docs if you make a program with any help of this code.

If this code in any way cause damage or loss of data, I'm not responsible;
you are.

***************************************************************************/


#include "defs.h"

char VERSIONTAG[] = "$VER:RExpand 1.0 (" __DATE__ ")";

UBYTE			DEFPORTNAME[]	= "REXPAND";

STRPTR			PortName = DEFPORTNAME;
BPTR			DataDir;
struct List		DataFiles;
BOOL			NoDefFiles		= FALSE,
				WBStart			= FALSE;
struct RexxMsg	*Rexxmsg;
struct RDArgs	*Rxc;
struct Library	*RexxSysBase,
				*IconBase,
				*GfxBase,
				*IntuitionBase,
				*GadToolsBase;


int handlerexx(void);
int read_args(void);
int read_tools(struct WBStartup *wbmsg);
BOOL openlibs(void);
void WarnUser(STRPTR text, ...);

int
main(int argc, char **argv)
{
	struct MsgPort *rexxport;
	struct Node *node;
	int retval;
	BOOL keepgoing = TRUE;
	ULONG signal, rexxsignal;

	WBStart = !argc;

	if (!openlibs())
		return RETURN_FAIL;

	if (argc != 0) {
		/* Started from CLI */
		retval = read_args();
	} else {
		/* Started from WB */
		retval = read_tools((struct WBStartup *) argv);
	}

	if (!retval) {
		if (Rxc = AllocDosObjectTags(DOS_RDARGS, TAG_DONE)) {
			if (rexxport = CreatePort(PortName, 0)) {
				rexxsignal = 1L << rexxport->mp_SigBit;
	
				/* Message polling loop */
				while (keepgoing) {
					signal = Wait(rexxsignal | SIGBREAKF_CTRL_C);
					if (signal & SIGBREAKF_CTRL_C)
						keepgoing = FALSE;
					if (signal & rexxsignal)
						while (Rexxmsg = (struct RexxMsg *) GetMsg(rexxport)) {
							keepgoing = handlerexx();
							ReplyMsg((struct Message *) Rexxmsg);
						}
				}
	
				DeletePort(rexxport);
				retval = RETURN_OK;
			} else {
				WarnUser("Couldn't open rexx port \"%s\"", PortName);
				retval = RETURN_FAIL;
			}
			FreeDosObject(DOS_RDARGS, Rxc);
		} else {
			WarnUser("Not enough memory");
			retval = RETURN_FAIL;
		}
	}

	while (node = RemTail(&DataFiles)) {
		UnLock((BPTR) node->ln_Name);
		FreeMem(node, sizeof(struct Node));
	}

	if (DataDir)
		UnLock(DataDir);
	
	if (PortName != DEFPORTNAME)
		FreeMem(PortName, strlen(PortName) + 1);

	CloseLibrary(RexxSysBase);
	CloseLibrary(IconBase);
	CloseLibrary(GadToolsBase);
	CloseLibrary(GfxBase);
	CloseLibrary(IntuitionBase);

	return retval;
}

int
read_args(void)
{
	struct MsgPort *rexxport;
	struct Node *node;
	struct RDArgs *rda;
	int c;
	LONG args[CLI_ARG_SIZE] = { 0, 0, 0, 0 };
	STRPTR *str;

	NewList(&DataFiles);
	DataDir = NULL;

	if (!(rda = ReadArgs(CLI_TEMPLATE, args, NULL))) {
		PrintFault(IoErr(), "Expand failed: ");
		return RETURN_ERROR;
	}

	if (args[CLI_ARG_PORTNAME]) {
		if (PortName = AllocMem(strlen((STRPTR) args[CLI_ARG_PORTNAME]) + 1, MEMF_PUBLIC))
			strcpy(PortName, (STRPTR) args[CLI_ARG_PORTNAME]);
		else
			PortName = DEFPORTNAME;
	}

	/* Check for unique port name */
	Forbid();
	rexxport = FindPort(PortName);
	Permit();
	if (rexxport) {
		WarnUser("Port \"%s\" already exists", PortName);
		FreeArgs(rda);
		return RETURN_WARN;
	}

	if (args[CLI_ARG_DATADIR])
		DataDir = Lock((STRPTR) args[CLI_ARG_DATADIR], SHARED_LOCK);

	if (!DataDir)
		DataDir = Lock(DEFDATADIR, SHARED_LOCK);

	NoDefFiles = args[CLI_ARG_NODEFFILES];

	if (str = (STRPTR *) args[CLI_ARG_FILES])
		for (c = 0; str[c]; c++) {
			if (node = AllocMem(sizeof(struct Node), MEMF_PUBLIC | MEMF_CLEAR))
				if (node->ln_Name = (STRPTR) DDLock(str[c], DataDir))
					AddTail(&DataFiles, node);
				else
					FreeMem(node, sizeof(struct Node));
		}

	FreeArgs(rda);

	return 0;
}

int
read_tools(struct WBStartup *wbmsg)
{
	struct MsgPort *rexxport;
	BPTR olddir = -1;
	struct Node *node;
	struct WBArg *arg;
	struct DiskObject *dobj;
	STRPTR *tools, value;
	int c, retval = RETURN_OK;

	NewList(&DataFiles);
	DataDir = 0;
	NoDefFiles = FALSE;

	arg = wbmsg->sm_ArgList;
	if (arg->wa_Name) {
		if (arg->wa_Lock)
			olddir = CurrentDir(arg->wa_Lock);
		if (dobj = GetDiskObject(arg->wa_Name)) {
			tools = dobj->do_ToolTypes;

			if (value = FindToolType(tools, "PORTNAME")) {
				if (PortName = AllocMem(strlen(value) + 1, MEMF_PUBLIC))
					strcpy(PortName, value);
				else
					PortName = DEFPORTNAME;
			}

			/* Check for unique port name */
			Forbid();
			rexxport = FindPort(PortName);
			Permit();
			if (rexxport) {
				WarnUser("Port \"%s\" already exists", PortName);
				retval = RETURN_WARN;
			} else {
				if (value = FindToolType(tools, "DATADIR"))
					DataDir = Lock(value, SHARED_LOCK);
				else
					DataDir = Lock(DEFDATADIR, SHARED_LOCK);

				if (value = FindToolType(tools, "NODEFFILES"))
					NoDefFiles = TRUE;

				for (c = 0; tools[c]; c++)
					if (!strnicmp(tools[c], "FILE=", 5)) {
						if (node = AllocMem(sizeof(struct Node), MEMF_PUBLIC | MEMF_CLEAR))
							if (node->ln_Name = (STRPTR) DDLock(tools[c] + 5, DataDir))
								AddTail(&DataFiles, node);
							else
								FreeMem(node, sizeof(struct Node));
					}
			}
			FreeDiskObject(dobj);
		}

		if (olddir != -1)
			CurrentDir(olddir);
	}

	if (!DataDir)
		DataDir = Lock(DEFDATADIR, SHARED_LOCK);

	return retval;
}

BOOL
openlibs(void)
{
	if (IntuitionBase = OpenLibrary("intuition.library", 37)) {
		if (GfxBase = OpenLibrary("graphics.library", 37)) {
			if (GadToolsBase = OpenLibrary("gadtools.library", 37)) {
				if (RexxSysBase = OpenLibrary("rexxsyslib.library", 0)) {
					if (IconBase = OpenLibrary("icon.library", 37))
						return TRUE;
					else
						WarnUser("Couldn't open icon.library v37+");
					CloseLibrary(RexxSysBase);
				} else
					WarnUser("Couldn't open rexxsyslib.library");
				CloseLibrary(GadToolsBase);
			} else
				WarnUser("Couldn't open gadtools.library v37+");
			CloseLibrary(GfxBase);
		} else
			WarnUser("Couldn't open graphics.library v37+");
		CloseLibrary(IntuitionBase);
	} else
		WarnUser("You need at least OS 2.04 (v37) to use RExpand");

	return FALSE;
}

BPTR
DDLock(STRPTR filename, BPTR datadir)
{
	BPTR lock, olddir;

	lock = Lock(filename, SHARED_LOCK);
	if (!lock) {
		olddir = CurrentDir(datadir);
		lock = Lock(filename, SHARED_LOCK);
		CurrentDir(olddir);
	}

	return lock;
}

void
WarnUser(STRPTR text, ...)
{
	struct EasyStruct req = {
		sizeof(struct EasyStruct),
		0,
		"RExpand Error",
		text,
		"OK"
	};
	va_list args;

	va_start(args, text);

	if (WBStart && IntuitionBase)
		EasyRequest(NULL, &req, NULL, args);
	else {
		vprintf(text, args);
		putchar('\n');
	}

	va_end(args);
}

#ifdef _DCC
/* WB start routine (only for DICE) */
int wbmain(struct WBStartup *wbmsg) {
	return main(0, (char **) wbmsg);
}
#endif

