home *** CD-ROM | disk | FTP | other *** search
- /*
- * rexxhs.c -- A simple ARexx function library that implements
- * support routines for implementing an ARexx command
- * host using an ARexx program.
- *
- * This file is common to both SAS/C and Manx Aztec C.
- *
- * Written by Eric Giguere for the AmigaWorld Tech Journal.
- * Function library skeleton is adapted from the one
- * found in the Amiga Programmer's Guide to ARexx.
- */
-
- #include <string.h>
- #include <ctype.h>
-
- #include "arexx.h"
- #include "arexxsyslib.h"
- #include "rexxhs.h"
- #include <rexx/rexxio.h>
-
- #if defined( LATTICE ) || defined( __SASC )
- #define AREXXDISPATCH LONG __saveds __stdargs
- #else
- #define AREXXDISPATCH LONG
- #endif
-
- #define NULLCHAR '\0'
-
- #define PROG_NOT_FOUND ERR10_001
- #define BAD_NUM_ARGS ERR10_017
- #define FUNC_ERR ERR10_012
-
- /* Forward references */
-
- static LONG ReplyToCall( struct Library *, struct RexxMsg *, char **, int );
- static LONG NumArgs( struct Library *, struct RexxMsg *, char **, int );
- static LONG IsFunctionCall( struct Library *, struct RexxMsg *, char **, int );
- static LONG ValidPkt( struct Library *, struct RexxMsg *, char **, int );
-
- static BOOL StrIEq( char *a, char *b );
- static struct List *FindPacket( struct RexxMsg *msg, struct RexxMsg *packet );
-
- /*
- * ARLibDispatch -- This is the "query" function for the function library.
- * It receives a function request in the form of an
- * RXFUNC message. It returns the return code in D0
- * and an argstring, if any, in A0.
- */
-
- AREXXDISPATCH ARLibDispatch( struct RexxMsg *msg, char **result_string )
- {
- LONG retval;
- int nargs;
- struct Library *RexxSysBase;
- char *fname;
-
- *result_string = NULL;
-
- if( !msg || ( msg->rm_Action & RXCODEMASK ) != RXFUNC )
- return( PROG_NOT_FOUND );
-
- RexxSysBase = (void *) OpenLibrary( (UBYTE *) "rexxsyslib.library", 0L );
-
- if( !RexxSysBase )
- return( PROG_NOT_FOUND );
-
- fname = (char *) msg->rm_Args[0];
- nargs = ( msg->rm_Action & RXARGMASK );
- retval = BAD_NUM_ARGS;
-
- /* Get the name of the function and the number of arguments */
-
- if( StrIEq( fname, "REPLYTOCALL" ) ){
- if( nargs >= 2 && nargs <= 3 )
- retval = ReplyToCall( RexxSysBase, msg, result_string, nargs );
- } else if( StrIEq( fname, "NUMARGS" ) ){
- if( nargs == 1 )
- retval = NumArgs( RexxSysBase, msg, result_string, nargs );
- } else if( StrIEq( fname, "ISFUNCTIONCALL" ) ){
- if( nargs == 1 )
- retval = IsFunctionCall( RexxSysBase, msg, result_string, nargs );
- } else if( StrIEq( fname, "VALIDPKT" ) ){
- if( nargs == 1 )
- retval = ValidPkt( RexxSysBase, msg, result_string, nargs );
- } else {
- retval = PROG_NOT_FOUND;
- }
-
- /* A function call should always return an argstring if it returns 0 */
-
- if( retval == RC_OK && *result_string == NULL )
- *result_string = (char *) CreateArgstring( "", 0 );
-
- CloseLibrary( RexxSysBase );
- return( retval );
- }
-
- /*
- * ReplyToCall -- Reply to a message packet in the proper format.
- *
- * REPLYTOCALL( packet, rc, [result] )
- *
- * packet = message address as returned by GetPkt()
- * rc = return code (an integer)
- * result = result string or secondary error
- *
- * Very little error checking is done on the return code or the
- * secondary error...
- */
-
- static LONG ReplyToCall( struct Library *RexxSysBase, struct RexxMsg *msg,
- char **result_string, int nargs )
- {
- struct RexxMsg *packet;
- struct RexxMsg **arg1;
- char *arg2, *arg3;
- long rc;
- struct List *list;
-
- arg1 = (struct RexxMsg **) msg->rm_Args[1];
- arg2 = (char *) msg->rm_Args[2];
- arg3 = (char *) msg->rm_Args[3];
-
- if( !arg1 || !arg2 )
- return( BAD_NUM_ARGS );
-
- /* We call FindPacket to make sure the packet is actually in
- the ARexx program's list (i.e., was retrieved with WaitPkt) */
-
- packet = *arg1;
- list = FindPacket( msg, packet );
-
- if( !packet || !list ) goto return_0;
- if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
-
- /*
- * Set the packet's result fields appropriately...
- */
-
- rc = atol( arg2 );
- packet->rm_Result1 = rc;
- packet->rm_Result2 = 0;
-
- if( rc == RC_OK ){
- if( nargs > 2 && arg3 != NULL &&
- ( packet->rm_Action & RXFF_RESULT ) != 0 ){
- packet->rm_Result2 = (LONG) CreateArgstring( arg3,
- LengthArgstring( arg3 ) );
- }
- } else {
- if( nargs > 2 && arg3 != NULL )
- packet->rm_Result2 = atol( arg3 );
- else
- packet->rm_Result2 = FUNC_ERR;
- }
-
- /*
- * Unlink from list and then send the packet off...
- */
-
- Remove( (struct Node *) packet );
- ReplyMsg( (struct Message *) packet );
-
- *result_string = CreateArgstring( "1", 1 );
- return( RC_OK );
-
- return_0:
- *result_string = CreateArgstring( "0", 1 );
- return( RC_OK );
- }
-
- /*
- * NumArgs -- Returns the number of arguments in a packet. If the packet
- * is not a function call, then 0 is returned.
- *
- * NUMARGS( packet )
- */
-
- static LONG NumArgs( struct Library *RexxSysBase, struct RexxMsg *msg,
- char **result_string, int nargs )
- {
- struct RexxMsg *packet;
- struct RexxMsg **arg1;
- char argbuf[3];
- struct List *list;
- int pargs;
-
- arg1 = (struct RexxMsg **) msg->rm_Args[1];
-
- if( !arg1 )
- return( BAD_NUM_ARGS );
-
- packet = *arg1;
- list = FindPacket( msg, packet );
-
- if( !packet || !list ) goto return_0;
- if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
- if( ( packet->rm_Action & RXCODEMASK ) != RXFUNC ) goto return_0;
-
- pargs = ( packet->rm_Action & RXARGMASK );
-
- if( pargs < 10 ){
- argbuf[0] = pargs + '0';
- argbuf[1] = NULLCHAR;
- } else {
- argbuf[0] = '1';
- argbuf[1] = ( pargs % 10 ) + '0';
- argbuf[2] = NULLCHAR;
- }
-
- *result_string = CreateArgstring( argbuf, strlen( argbuf ) );
- return( RC_OK );
-
- return_0:
-
- *result_string = CreateArgstring( "0", 1 );
- return( RC_OK );
- }
-
- /*
- * IsFunctionCall -- Returns TRUE (1) if the packet is a function call.
- *
- * ISFUNCTIONCALL( packet )
- */
-
- static LONG IsFunctionCall( struct Library *RexxSysBase, struct RexxMsg *msg,
- char **result_string, int nargs )
- {
- struct RexxMsg *packet;
- struct RexxMsg **arg1;
- struct List *list;
-
- arg1 = (struct RexxMsg **) msg->rm_Args[1];
-
- if( !arg1 )
- return( BAD_NUM_ARGS );
-
- packet = *arg1;
- list = FindPacket( msg, packet );
-
- if( !packet || !list ) goto return_0;
- if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
- if( ( packet->rm_Action & RXCODEMASK ) != RXFUNC ) goto return_0;
-
- *result_string = CreateArgstring( "1", 1 );
- return( RC_OK );
-
- return_0:
-
- *result_string = CreateArgstring( "0", 1 );
- return( RC_OK );
- }
-
- /*
- * ValidPkt -- Returns TRUE or FALSE depending upond whether the given
- * address is a valid message packet...
- *
- * VALIDPKT( packet )
- */
-
- static LONG ValidPkt( struct Library *RexxSysBase, struct RexxMsg *msg,
- char **result_string, int nargs )
- {
- struct RexxMsg *packet;
- struct RexxMsg **arg1;
- struct List *list;
-
- arg1 = (struct RexxMsg **) msg->rm_Args[1];
-
- if( !arg1 )
- return( BAD_NUM_ARGS );
-
- packet = *arg1;
- list = FindPacket( msg, packet );
-
- if( !packet || !list ) goto return_0;
- if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
-
- *result_string = CreateArgstring( "1", 1 );
- return( RC_OK );
-
- return_0:
-
- *result_string = CreateArgstring( "0", 1 );
- return( RC_OK );
- }
-
- /*
- * StrEq -- Returns TRUE if two strings match.
- */
-
- static BOOL StrEq( char *a, char *b )
- {
- return( strcmp( a, b ) == 0 );
- }
-
- /*
- * StrIEq -- Like StrEq, but case-insensitive.
- */
-
- static BOOL StrIEq( char *a, char *b )
- {
- while( *a != NULLCHAR && *b != NULLCHAR ){
- if( tolower( *a ) != tolower( *b ) )
- return( FALSE );
-
- ++a;
- ++b;
- }
-
- return( *a == *b );
- }
-
- /*
- * FindPacket -- Given a packet address, check the message port lists
- * for the ARexx program and find the list to which
- * the packet belongs. (NULL if packet can't be found.)
- *
- * This routine depends upon knowledge of Rexx's internal
- * structures, as described in the storage.h and rexxio.h
- * header files. The task pointer is taken from the
- * RexxMsg that is passed to the function library.
- */
-
- static struct List *FindPacket( struct RexxMsg *msg, struct RexxMsg *packet )
- {
- struct RexxTask *rt;
- struct RexxMsg *rmsg;
- struct RexxMsgPort *port;
-
- if( !msg || !packet )
- return( NULL );
-
- /* Get the ARexx program's global data structure */
-
- rt = (struct RexxTask *) msg->rm_TaskBlock;
-
- if( rt ){
-
- /* OK, search through the list of active message ports
- for the ARexx program... */
-
- for( port = (void *) rt->rt_Header5.lh_Head;
- port->rmp_Node.rr_Node.ln_Succ;
- port = (void *) port->rmp_Node.rr_Node.ln_Succ ){
-
- /* For each port, search through the list of messages
- awaiting reply... */
-
- for( rmsg = (void * ) port->rmp_ReplyList.lh_Head;
- rmsg->rm_Node.mn_Node.ln_Succ;
- rmsg = (void *) rmsg->rm_Node.mn_Node.ln_Succ ){
-
- if( rmsg == packet ){
- return( &port->rmp_ReplyList );
- }
- }
- }
- }
-
- return( NULL );
- }