/* init.c */

/*		Copyright © 1989 by Donald T. Meyer, Stormgate Software
 *		All Rights Reserved
 */



#include "rxil.h"

#include <exec/memory.h>

#include <string.h>



static void unique_name( char portname[] );

struct RxsLib *RexxSysBase = NULL;

static char library_version_string[] = RXIL_VERSION_STRING;



/* NAME
 *		RxilInit
 *
 * SYNOPSIS
 *		rdef = RxilInit( flags, portname );
 *
 *		struct RxilDef *rdef;
 *
 *		ULONG flags;
 *		char *portname;
 *
 * FUNCTION
 *		Open the ARexx library and setup our message ports.  Then
 *		allocate a RxilDef structure and do some default initialization
 *		of it.
 *		The portname will have a unique "instance" number appended
 *		to it in the format "<name>_#<n>" where <name> is the string as
 *		specified in the portname argument, and <n> is a decimal number
 *		from 1-99 inclusive.  This feature may be inhibited by setting
 *		the RXIL_AS_IS flag.
 *
 *		Even though this may fail, that should probably not be fatal
 *		since the ARexx functionality is optional.  The RxilCheckPort()
 *		function is smart enough to just return if the rexx initialization
 *		was not successsfull.  Not to mention that RxilCheckPort() should
 *		never get called since the rexx_sig_bit mask should be zero.
 *
 * INPUTS
 *		flags		These are various defined constants which control
 *					which ports get opened and other various aspects
 *					of port initialization.
 *
 *		portname	This is the name to use for the public ARexx port
 *					that commands will be received at.  It is suggested
 *					that this be in uppercase and contain no spaces.
 *					Maximum length is 40 characters, as set by the
 *					defined constant RXIL_MAX_PORTNAME_LEN.
 *					See discussion above about instance numbers.
 *
 * RESULT
 *		A pointer to a RxilDef structure.  Return is NULL for failure
 *		to initialize the ARexx ports.
 *
 * SIDES
 *
 * HISTORY
 *		01-Aug-89	Creation.
 *		23-Sep-89	Changed "flags" arg from int to ULONG
 *		26-Sep-89	Sets the (new) version string pointer.
 *		01-Oct-89	Changed PublicPort name storage from a pointer to
 *					a character array.  Added "instance" numbering.
 *					Added check on portname length.
 *
 * BUGS
 * 		This should probably share one signal bit between both ports
 *		to avoid "hogging" signal bits.
 *
 * SEE ALSO
 *		RxilCleanup(), RXIL_AS_IS, RXIL_MAX_PORTNAME_LEN
 */

struct RxilDef *RxilInit( ULONG flags, char *portname )
{
	char buf[24];
	struct RxilDef *rdef;


	if(  ( strlen(portname) < 1 ) ||
		( strlen(portname) > RXIL_MAX_PORTNAME_LEN )  )
	{
		/* Portname is of an invalid length */
		return( NULL );
	}


	rdef = AllocMem( sizeof(struct RxilDef), MEMF_PUBLIC | MEMF_CLEAR );
	if( rdef == NULL )
	{
		return( NULL );
	}


	/* Default initialization of the new RxilDef structure */

	rdef->Console = NULL;
	rdef->Extension = "rexx";
	rdef->HostPort = "REXX";


	strcpy( rdef->PortName, portname );
	if(  FlagIsClear( flags, RXIL_AS_IS )  )
	{
		/* Make sure the public port name is unique */
		unique_name( rdef->PortName );
	}

	/*   Open Rexx library   */
	RexxSysBase = (struct RxsLib *)OpenLibrary( RXSNAME, 0L );
	if( RexxSysBase == NULL )
	{
		FreeMem( rdef, sizeof(struct RxilDef) );
		return( NULL );
	}


	if(  FlagIsSet( flags, RXIL_PUBLIC )  )
	{
		/* Setup our public port */

		rdef->PublicPort = CreatePort( rdef->PortName, 1L );
		if( rdef->PublicPort == NULL )
		{
			CloseLibrary( (struct Library *)RexxSysBase );
			RexxSysBase = NULL;
			FreeMem( rdef, sizeof(struct RxilDef) );
			return( NULL );
		}

		rdef->SigBit |= 1L << (rdef->PublicPort->mp_SigBit);
	}


	if(  FlagIsSet( flags, RXIL_SECRET )  )
	{
		/* Setup our secret port */
		strcpy( rdef->SecretPortName, rdef->PortName );
		strcat( rdef->SecretPortName, "_PRIVATE_" );
		stcul_d( buf, (long)FindTask(NULL) );
		strcat( rdef->SecretPortName, buf );
 
		rdef->SecretPort = CreatePort( rdef->SecretPortName, 1L );
		if( rdef->SecretPort == NULL )
		{
			/* Failure */
			if( rdef->PublicPort )
			{
				RxilDeletePort( rdef->PublicPort );
				rdef->PublicPort = NULL;
			}

			CloseLibrary( (struct Library *)RexxSysBase );
			RexxSysBase = NULL;

			rdef->SigBit = 0;

			FreeMem( rdef, sizeof(struct RxilDef) );

			return( NULL );
		}

		rdef->SigBit |= 1L << (rdef->SecretPort->mp_SigBit);
	}


	/* Set the version string pointer. */
	rdef->Version = &library_version_string[0];


	return( rdef );
}



/*
 *		This will take the port name in the buffer, and add a sequential
 *		invocation number to it to insure uniqueness.
 *
 *		Note that this will increase the length of the given string!
 *		Make sure that the buffer is at least 4 characters longer than
 *		the original string.
 */

static void unique_name( char portname[] )
{
	char buf[RXIL_MAX_PORTNAME_LEN+10], buf2[4];
	unsigned int i;


	for( i=1; i<100; i++ )
	{
		strcpy( buf, portname );		/* Orig. name "APP" (example) */
		strcat( buf, "_#" );			/* "APP_#" */
		stcu_d( buf2, i );
		strcat( buf, buf2 );			/* "APP_#1" */

		if(  FindPort( buf ) == NULL  )
		{
			/* Okay, this name does not exist.  Let's use it. */
			strcpy( portname, buf );
			return;
		}
	}


	/* Amazing!  If we actually get here, there are already 99 instances
	 * of this program running.  I cannot imagine ever getting here. :-)
	 * If we do, then I guess we'll just collide...
	 */
}

