/* dispatch.c */

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



#include "rxil.h"

#include <string.h>



/* NAME
 *		RxilDispatch
 *
 * SYNOPSIS
 *		RxilDispatch( rexxmsg, cmd );
 *
 *		struct RexxMsg *rexxmsg;
 *		char *cmd;
 *
 * FUNCTION
 *		This is really an "internal" function which is used by
 *		the RxilCheckPort() function to dispatch commands.
 *
 *		It is not static, since it may be usefull by itself, or
 *		it may desireable to replace it with a custom version
 *		in some applications.  This can be done simply by overriding
 *		it, rather than editing the library itself.
 *
 *		This is NOT a "safe" call, since it should never be called
 *		directly from client code.
 *		It is however safe if the client fails to initialize the command
 *		table pointer.
 *
 *
 * INPUTS
 *		rexxmsg = pointer to the RexxMsg structure for the command we
 *			are dispatching.
 *		cmd = the command name string.
 *
 * RESULT
 *		None
 *
 * SIDES
 *
 * HISTORY
 *		01-Aug-89	Creation.
 *		26-Sep-89	Changed to use maximum and minimum argcounts.
 *
 * BUGS
 *
 * SEE ALSO
 *		RxilCheckPort()
 */

void RxilDispatch( struct RexxMsg *rexxmsg, char *cmd )
{
	unsigned int i;
	int match = -1;
	unsigned int argcount;


	/* Make call "safe" even if RxilInit() failed */
	if( global_rdef->CommandTable == NULL )
	{
		/* This is an unlikely mistake on the client's part, but
		 * let's fail gracefully just in case.
		 */
		rexxmsg->rm_Result1 = RXERR_UNKNOWN_CMD;
		return;
	}


	for( i=0; global_rdef->CommandTable[i].Name != NULL; i++ )
	{
		if( global_rdef->CommandTable[i].CaseFlag == TRUE )
		{
			/* Case sensitive */
			if(  strcmp( global_rdef->CommandTable[i].Name, cmd ) == 0  )
			{
				/* A match */
				match = i;
				break;
			}
		}
		else
		{
			/* Not case sensitive */
			if(  stricmp( global_rdef->CommandTable[i].Name, cmd ) == 0  )
			{
				/* A match */
				match = i;
				break;
			}
		}
	}

	if( match == -1 )
	{
		/* No match found */
		rexxmsg->rm_Result1 = RXERR_UNKNOWN_CMD;
		return;
	}


	/* Check privilege level */
	if( global_rdef->CommandTable[match].Privilege >
		global_rdef->FromRexx )
	{
		/* Not from the correct port! */
		rexxmsg->rm_Result1 = RXERR_NOT_A_HARMLESS_CMD;
		return;
	}


	/* Are we locked?  If so, we respond only to commands
	 * received at the secret port.
	 */
	if(  ( global_rdef->LockCount != 0 ) &&
		( global_rdef->FromRexx < RXIL_SECRET )  )
	{
		rexxmsg->rm_Result1 = RXERR_BUSY;
		return;
	}

#if 0
	/* Do the argument checking */
	if(  ( global_rdef->CommandTable[match].ArgCount != RXIL_NO_ARGCHECK ) &&
		( (global_rdef->ArgCount-1) !=
		global_rdef->CommandTable[match].ArgCount )  )
	{
		/* Wrong number of args */
		rexxmsg->rm_Result1 = RXERR_ARG_COUNT;
		return;
	}
#endif


	/* Do the argument checking */

	argcount = global_rdef->ArgCount - 1;	/* This is -1 since ArgCount
											 * includes the command name
											 * itself.  This is in keeping
											 * with the 'C' conventions
											 * for argc and argv.
											 */

	if( argcount < global_rdef->CommandTable[match].MinArgs )
	{
		/* Wrong number of args */
		rexxmsg->rm_Result1 = RXERR_NO_ARGUMENT;
		return;
	}

	if( argcount > global_rdef->CommandTable[match].MaxArgs )
	{
		/* Wrong number of args */
		rexxmsg->rm_Result1 = RXERR_TOO_MANY_ARGS;
		return;
	}


	/* Call the function. */
	(*(global_rdef->CommandTable[match].Func))(rexxmsg);
}

