
#include <stdlib.h>		/* calloc */
#include <string.h>		/* strlen  &  stpcpy*/
#include <dos.h>		/* getpath */
#include <exec/types.h>
#include <exec/execbase.h>	/* for SysBase */
#include <exec/memory.h>	/* MEMF_PUBLIC etc */
#include <dos/dos.h>		/* BADDR and MKBADDR etc */
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <workbench/startup.h>	/* Workbench startup message structure */
#include <proto/all.h>

#define CLI	struct CommandLineInterface *
#define PR	struct Process *

extern struct ExecBase *SysBase;
extern struct DosLibrary *DOSBase;

char VERSION[] = "$VER: CEDIT 1.1 © David M. Balean 31.3.93\n";

struct DosInfo *dinfo;		/* For the device list */


struct CedMessage
	{
	struct Message	my_msg;
	WORD		argc;
	char		**argv;
	}c_message;


#define c_argc	c_message.argc
#define c_argv	c_message.argv


struct WBArg c_WB_args[11];		/* BPTR lock, char *name */


char cmdtxt[] = "run >NIL: <NIL: CED:CED";

char commandstring[4000];


BOOL RFlag;			/* Gets initialized to zero = FALSE */


/* Prototypes */
VOID main(int argc, char *argv[]);
struct DeviceNode *FindAssNode(char *name);
APTR DosAlloc(LONG size);
VOID DosFree(LONG *ptr);
struct DeviceNode *CreateAssNode(char *name, BPTR lock);
VOID SlashPath(char *path);


VOID main(int argc, char *argv[])
{
LONG *thisnode;

struct WBArg *wb_args, *CWB_args;

char *pos, *p1, *p2, *cedname;

char **argptr1, **argptr2;


BPTR lock, oldlock, duplock, fh;
LONG j;

char WBpath[256];

char *params;

struct MsgPort *c_port, *myport;

WORD NumArgs;


cedname = &cmdtxt[20];	/* = "CED" upper/lower case same to AmigaDOS */
dinfo = (struct DosInfo *)BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info);

c_argv = argv;

if ((c_argc = NumArgs = argc) == 0)
	{


	((PR)(SysBase->ThisTask))->pr_ConsoleTask = NULL;

/* EDC will only load 9 files at once, 10 includes progname */

	j = ((struct WBStartup *)argv)->sm_NumArgs;
	if (j > 10)
		j = 10;

	c_argc = j;


	wb_args = ((struct WBStartup *)argv)->sm_ArgList;

	CWB_args = &c_WB_args[0];
	c_argv = (char **)CWB_args;

	for (; j; j--, CWB_args++, wb_args++)
		{
		CWB_args->wa_Lock = wb_args->wa_Lock;
		CWB_args->wa_Name  = wb_args->wa_Name;
		}

	}

if (!(params = calloc(4000,1)))	/* Lots of memory!  Could be BSS memory */
	exit(EXIT_FAILURE);



/* Get path of this process */
getpath( ((PR)(SysBase->ThisTask))->pr_CurrentDir, WBpath );
SlashPath(WBpath);


j = c_argc;
argptr1 = argptr2 = c_argv;	/* &c_argv[0]; */

argptr1++;			/* Point to wa_Name or next arg */
argptr2++;			/* Point to wa_Name or next arg */




if (NumArgs == 0)		/* If WB Start */
	argptr2++;		/* Points to next arg */


pos = params;



if (j == 1)			/* Insert path only */
	{
	*argptr1 = pos;
	c_argc++;
	strcpy(pos,WBpath);


	}



else

	{
/* Fix up the args */

	while (--j)
		{


		p1 = *argptr2++;	/* It points to a lock if WB start */
		argptr1++;		/* Next arg */

		if (NumArgs == 0)	/* If from WB */
			{

			lock = (BPTR)p1;

			getpath(lock,WBpath);
			SlashPath(WBpath);

			p1 = *argptr2++;	/* Now points to wa_Name */
			}

		p2 = p1;			/* Point to name */

		while ((*p2) && (*p2 != ':'))
			p2++;

		if (*p2)			/* If a colon */
			{


			argptr1[-1] = p1;	/* Save this name in last arg */
			continue;		/* AGAIN */
			}


			

		if (*p1 == '-')		/* Only -r or -R allowed from Ed */
			{

			if (p1[2] != '\0')
				continue;		/* AGAIN */


			if ((p1[1] == 'r') || (p1[1] == 'R'))
				{
				RFlag = TRUE;
				continue;	/* AGAIN */
				}
			}


		argptr1[-1] = pos;
		pos = stpcpy(pos,WBpath);	/* Copy in path		*/
		pos = stpcpy(pos,p1);		/* Append name		*/
		pos++;				/* Skip the zero byte	*/

		}

	}






/* If we started from WB we need to find ced's path because NO PATH!	*/
/* Execute() needs to inherit a path to find ced anywhere other than	*/
/* the current path or the C: directory.				*/


if (!(FindAssNode(cedname)))		/* Is CED: assigned already?	*/
	{

	Forbid();		/* Just in case... */

	if (argc == 0)

/* WB start, get WB's task (WB must have been started from CLI!) */
		thisnode = (ULONG *)FindTask("Workbench");


	else

/* CLI start, use this cli's task */
		thisnode = (ULONG *)(SysBase->ThisTask);

	thisnode = BADDR(((PR)thisnode)->pr_CLI);

/* Now get the pointer to first path node */
	thisnode = BADDR((( CLI )(thisnode))->cli_CommandDir);

/*
I'm NOT SURE about this:
A CLI path node, each node is 3 4byte quantities 
pathnode[0] = size in bytes of this node (=12)
pathnode[1] = BPTR to next pathnode[1] or zero if last node
pathnode[2] = BPTR to lock
I can't actually find it documented but it must be somewhere.  D.M.B.
*/


	while (thisnode)
		{
		oldlock = CurrentDir(thisnode[1]);

		if (lock = Lock(cedname, ACCESS_READ))
			{
/* FOUND IT! */

			UnLock(lock);

/* Copy the lock for the assign; the copy mustn't be destroyed! */
			duplock = DupLock(thisnode[1]);

/* Assign CED: to it's directory, don't worry about failure */
			CreateAssNode(cedname,duplock);

			CurrentDir(oldlock);
			break;
			}

		CurrentDir(oldlock);


/* NOTE: oldlock mustn't be UnLocked....  This seems to crash things!	*/
/* What CurrentDir seems to do is to return the actual lock, not a copy	*/
/* No memory gets lost by leaving it because it was there already.	*/

		thisnode = BADDR(*thisnode);	/* Points to next node */
		}

	Permit();
	}



/* NOTE: The 1st arg is a lock if from WB, otherwise progname */

if (c_port = FindPort("ced_port"))

	{


	if (!RFlag)				/* Nameless port */
	    if (myport = CreatePort("",0))	/* Don't want to be found! */
		{
		c_message.my_msg.mn_Node.ln_Type = NT_MESSAGE;	/* =5 */
		c_message.my_msg.mn_Length = sizeof(struct CedMessage);
		c_message.my_msg.mn_ReplyPort = myport;


		PutMsg(c_port, (struct Message *)&c_message);
		WaitPort(myport);
		DeletePort(myport);
		}
	}


else	/* We can't find ced-port */

	{


	pos = stpcpy(commandstring,cmdtxt);  /* pos points to terminal zero */

	argptr1 = c_argv;		/* (skip 1st arg) a2 = c_argv + 1 */
	argptr1++;

	j = c_argc;
	j--;

	for (; j > 0; j--)
		{
		*pos++ = ' ';		/*	space instead of zero	*/
		p1 = *argptr1++;	/*	address of this arg	*/
		*pos++ = '"';		/*	quote			*/
		pos = stpcpy(pos,p1);	/*	copy in the arg		*/
		*pos++ = '"';		/*	quote			*/
		*pos = '\0';		/*	zero terminate		*/
		}


/* Too bad if we can't get NIL: */

	if (fh = Open("NIL:",MODE_OLDFILE))
		{



/* Too bad if it fails, we don't want to know! */
		Execute(commandstring,fh,fh);
		Close(fh);
		}
	}


exit(EXIT_SUCCESS);	/* And clears memory from calloc & malloc etc. */
}




/***************************************************
 * Make sure path is properly terminated as a path *
 * with either ':' for volume or '/' for directory *
 ***************************************************/

VOID SlashPath(char *path)
{
char *p1, *p2;

/* Point to last character, not the zero byte */
p2 = path + strlen(path) - 1;


/* Check if already volume or directory termination */

if ((*p2 != '/') && (*p2++ != ':'))	/* p2 now points to zero byte */
	{
	for (p1 = path; *p1 && (*p1 != ':'); p1++) ;

/* p1 now points to either ':' or a zero byte */
/* As there wasn't a ':' terminator, there has to be more in this case */

	if (*p1)			/* If it points to ':' */
		*p2++ = '/';		/* Put slash at the end */

	else	*p2++ = ':';		/* Put ':' at the end */

	*(p2) = '\0';			/* Zero terminate */
	}
 return;
}



/****************************************************************
 * Find if the string is already assigned.			*
 * The name is without the ':'					*
 * NOTE: names in DeviceNode->dn_Name MUST be zero terminated.	*
 ****************************************************************/

struct DeviceNode *FindAssNode(char *name)
{

struct DeviceNode *thisnode;
char *b;


Forbid();				/* Just in case! */
thisnode = BADDR(dinfo->di_DevInfo);

while (thisnode)
	{
	if (thisnode->dn_Type == DLT_DIRECTORY)  /* Compare strings */
		if ((*(b = BADDR(thisnode->dn_Name))) == strlen(name))
			if (stricmp(++b, name) == 0)
				break;

	thisnode = BADDR(thisnode->dn_Next);
	}

Permit();
return(thisnode);
}




/*
 NOTE:
 DOS memory blocks contain their length in the 1st long word.
 The pointer to it points to the 2nd long word which is it's actual start.
*/

/*******************************
 * Allocate a Dos memory block *
 *******************************/

/*  NOTE: APTR has been re-defined as void *   */

APTR DosAlloc(LONG size)
{
LONG *ptr;
LONG len;

/* Length MUST be in long words, AllocMem does this anyway...	*/
/* Must add length of 1 long word for the block length.		*/

/***********************************************************************
	AllocMem does the following: 
		addq	#7,d0
		andi.w	#$fff8,d0
	This makes the length a multiple of 8 bytes i.e. 2 long words
	so this is a waste of time unless requesting a zero length!...

	(len = (size + 7) & ~3L;		NOT REQUIRED
*************************************************************************/

if (ptr = AllocMem((len = size + sizeof(LONG)), MEMF_PUBLIC | MEMF_CLEAR))
	*ptr++ = len;	/* Insert length, address of next long word */
return(ptr);
}


/***************************
 * Free a Dos memory block *
 ***************************/

VOID DosFree(LONG *ptr)
{
FreeMem(--ptr, *ptr);
}




/********************************************
 * Create and insert ASSIGN in the DOS list *
 * The name is without the ':'		    *
 * The lock must not be 'UnLock'ed !!	    *
 ********************************************/

struct DeviceNode *CreateAssNode(char *name, BPTR lock)

{   
struct DeviceNode *assnode;
LONG len;
char *bs;

if (!(assnode = DosAlloc(sizeof(struct DeviceNode))))
	return(NULL);

len = strlen(name);

if (!(bs = DosAlloc(len+2)))		/* + Length byte and zero byte */
	{
	DosFree((LONG *)assnode);
	return(NULL);
	}

assnode->dn_Name = MKBADDR(bs);		/* Convert to BCPL type */
assnode->dn_Type = DLT_DIRECTORY;
*bs++ = len;

strcpy(bs, name);			/* Copy in the assign name */

assnode->dn_Lock = lock;
assnode->dn_Task = ((struct FileLock *)BADDR(lock))->fl_Task;


/* This part is critical...  Something else could also be accessing this */
Forbid();
assnode->dn_Next = dinfo->di_DevInfo;	/* Place at head of list */
dinfo->di_DevInfo = MKBADDR(assnode);
Permit();

return(assnode);			/* Return node address */
}


/* END OF FILE */
