/*	argcheck

Interface to routines for checking argument strings in command lines.

Usage:

    #include	<argcheck.h>

    arg_check (argument)

    char	*argument;	The argument string

Description:

Each argument string is compared against a list of valid arguments contained
in an argument list (the global variable arg_list is this array; see below). 
The comparison is made by a matching function (the global variable arg_match
points to this function; see below).  When a match occurs (the arg_match
function returns TRUE) the corresponding argument handler is called and
passed the argument string, and its return value is returned to the user. 
The argument handler is refered to by a function pointer paired with the
matched argument string in the arg_list. 

When the global variable arg_do_no is TRUE, a check is made for a "NO[_]"
prefix to the argument string.  When this prefix is encountered the global
variable arg_positive is set to FALSE (0), and the pointer to the argument
string is moved forward (on the stack, not affecting the user's value) past
the prefix.  The new argument string, effectively stripped of the negating
prefix, is used to scan the argument list of keywords for a match. When an
argument function handler is called, it may use arg_positive as appropriate. 
Since arg_positive is TRUE when the negating prefix is not present, the
typical use of this variable in an argument handler would be to set the value
of a logical flag.

If the scan of the argument list fails to produce a match, arg_check returns 
with the value FAILURE (0); otherwise, the value returned by the argument 
handler is returned to the user.

The argument list is a an array of structures of type ARG_HANDLE:

    typedef struct
	{
	char	*keyword;	The argument keyword to be matched
	int	(*function)();	The argument handler function
	}
	ARG_HANDLE;

>>> CAUTION <<< The user MUST create an initial argument list with the global 
name user_arguments.  The arg_list pointer is initialized with this external 
variable.

>>> CAUTION <<< The argument list MUST be terminated with a null entry.

Example:

    extern	first_function();
    extern	second_function();
    ...
    extern	last_function();

    ARG_HANDLE	user_arguments[] =
	{
	"FIRST_WORD", 	first_function,
	"SECOND_WORD",	second_function,
	...
	"LAST_WORD",	last_function,
	0,		0
	}

>>> WARNING <<< The argument handler function is called with this syntax:

    (*handle->function) (argument string);

    where
	handle - is a pointer to the current ARG_HANDLE structure in the 
	    argument list pointed to by arg_list.
	<argument string> - is the argument string the matched the keyword 
	    corrsponding to the function in the argument list.

The function that is used to match argument strings to argument list words is 
pointed to by arg_match.  The default function (strmatch) compares the
strings without regard to case.  If the argument keyword ends before the
argument string ends (i.e. the keyword matches the beginning of the
argument), a successful match has occured.  Checking for a string match fails
when corresponding characters are not the same, or the argument string ends
(i.e. the keyword is the minimal string that must be matched).

>>> CAUTION <<< The string comparison function MUST return TRUE if a match 
(by whatever definition) exits between the keyword string and the argument
string.  It must return FALSE otherwise.

>>> WARNING <<< The matching function is called with this syntax:

    (*arg_match) (handle->keyword, argument);

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

#include	<std.h>
#define	_ARG_CHECK_
#include	<argcheck.h>

IMPORTED ARG_HANDLE	user_arguments[];
ARG_HANDLE		*arg_list = user_arguments;
IMPORTED INTEGER	strmatch ();
INTFUNC			arg_match = strmatch;
LOGICAL			arg_do_no = TRUE;
LOGICAL			arg_positive = TRUE;


INTEGER
arg_check (argument)
STRING	argument;
{
REGISTER ARG_HANDLE	*handle;

#ifdef DEBUG
printf ("arg_check: %s\n", argument);
#endif

arg_positive = TRUE;

if (arg_do_no)
    {
    /*
    NO[_] prefix check:
    */
    if (toupper (*argument) == 'N' && toupper (*argument + 1) == 'O')
	{
	arg_positive = FALSE;
#ifdef DEBUG
printf ("\tNO prefix ...\n");
#endif
	/* Allow for optional '_' separator between NO and argument */
	argument = &argument[(argument[2] == '_') ? 3 : 2];
	}
    }
/*
Scan the argument list looking for a keyword match:
*/
for (handle = arg_list; handle->function; handle++)
    if ((*arg_match) (handle->keyword, argument))
	{
#ifdef DEBUG
printf ("\tMatch with keyword %s\n", handle->keyword);
#endif
	return ((*handle->function) (argument));
	}

#ifdef DEBUG
printf ("\tNo keyword match.\n");
#endif
return (FAILURE);	/* unknown */
}
