home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 545b.lha / RexxHS / rexxhs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-07  |  9.8 KB  |  362 lines

  1. /*
  2.  * rexxhs.c -- A simple ARexx function library that implements
  3.  *             support routines for implementing an ARexx command
  4.  *             host using an ARexx program.
  5.  *
  6.  *             This file is common to both SAS/C and Manx Aztec C.
  7.  *
  8.  *             Written by Eric Giguere for the AmigaWorld Tech Journal.
  9.  *             Function library skeleton is adapted from the one
  10.  *             found in the Amiga Programmer's Guide to ARexx.
  11.  */
  12.  
  13. #include <string.h>
  14. #include <ctype.h>
  15.  
  16. #include "arexx.h"
  17. #include "arexxsyslib.h"
  18. #include "rexxhs.h"
  19. #include <rexx/rexxio.h>
  20.  
  21. #if defined( LATTICE ) || defined( __SASC )
  22.     #define AREXXDISPATCH LONG __saveds __stdargs
  23. #else
  24.     #define AREXXDISPATCH LONG
  25. #endif
  26.  
  27. #define NULLCHAR '\0'
  28.  
  29. #define PROG_NOT_FOUND ERR10_001
  30. #define BAD_NUM_ARGS   ERR10_017
  31. #define FUNC_ERR       ERR10_012
  32.  
  33. /* Forward references */
  34.  
  35. static LONG ReplyToCall( struct Library *, struct RexxMsg *, char **, int );
  36. static LONG NumArgs( struct Library *, struct RexxMsg *, char **, int );
  37. static LONG IsFunctionCall( struct Library *, struct RexxMsg *, char **, int );
  38. static LONG ValidPkt( struct Library *, struct RexxMsg *, char **, int );
  39.  
  40. static BOOL         StrIEq( char *a, char *b );
  41. static struct List *FindPacket( struct RexxMsg *msg, struct RexxMsg *packet );
  42.  
  43. /*
  44.  * ARLibDispatch -- This is the "query" function for the function library.
  45.  *                  It receives a function request in the form of an
  46.  *                  RXFUNC message.  It returns the return code in D0
  47.  *                  and an argstring, if any, in A0.
  48.  */
  49.  
  50. AREXXDISPATCH ARLibDispatch( struct RexxMsg *msg, char **result_string )
  51.   {
  52.     LONG            retval;
  53.     int             nargs;
  54.     struct Library *RexxSysBase;
  55.     char           *fname;
  56.  
  57.     *result_string = NULL;
  58.  
  59.     if( !msg || ( msg->rm_Action & RXCODEMASK ) != RXFUNC )
  60.         return( PROG_NOT_FOUND );
  61.  
  62.     RexxSysBase = (void *) OpenLibrary( (UBYTE *) "rexxsyslib.library", 0L );
  63.  
  64.     if( !RexxSysBase )
  65.         return( PROG_NOT_FOUND );
  66.  
  67.     fname  = (char *) msg->rm_Args[0];
  68.     nargs  = ( msg->rm_Action & RXARGMASK );
  69.     retval = BAD_NUM_ARGS;
  70.  
  71.     /* Get the name of the function and the number of arguments */
  72.  
  73.     if( StrIEq( fname, "REPLYTOCALL" ) ){
  74.         if( nargs >= 2 && nargs <= 3 )
  75.             retval = ReplyToCall( RexxSysBase, msg, result_string, nargs );
  76.     } else if( StrIEq( fname, "NUMARGS" ) ){
  77.         if( nargs == 1 )
  78.             retval = NumArgs( RexxSysBase, msg, result_string, nargs );
  79.     } else if( StrIEq( fname, "ISFUNCTIONCALL" ) ){
  80.         if( nargs == 1 )
  81.             retval = IsFunctionCall( RexxSysBase, msg, result_string, nargs );
  82.     } else if( StrIEq( fname, "VALIDPKT" ) ){
  83.         if( nargs == 1 )
  84.             retval = ValidPkt( RexxSysBase, msg, result_string, nargs );
  85.     } else {
  86.         retval = PROG_NOT_FOUND;
  87.     }
  88.  
  89.     /* A function call should always return an argstring if it returns 0 */
  90.  
  91.     if( retval == RC_OK && *result_string == NULL )
  92.         *result_string = (char *) CreateArgstring( "", 0 );
  93.  
  94.     CloseLibrary( RexxSysBase );
  95.     return( retval );
  96.   }
  97.  
  98. /*
  99.  * ReplyToCall -- Reply to a message packet in the proper format.
  100.  *
  101.  *     REPLYTOCALL( packet, rc, [result] )
  102.  *
  103.  *             packet = message address as returned by GetPkt()
  104.  *             rc     = return code (an integer)
  105.  *             result = result string or secondary error
  106.  *
  107.  *     Very little error checking is done on the return code or the
  108.  *     secondary error...
  109.  */
  110.  
  111. static LONG ReplyToCall( struct Library *RexxSysBase, struct RexxMsg *msg,
  112.                          char **result_string, int nargs )
  113.   {
  114.     struct RexxMsg  *packet;
  115.     struct RexxMsg **arg1;
  116.     char            *arg2, *arg3;
  117.     long             rc;
  118.     struct List     *list;
  119.  
  120.     arg1  = (struct RexxMsg **) msg->rm_Args[1];
  121.     arg2  = (char *) msg->rm_Args[2];
  122.     arg3  = (char *) msg->rm_Args[3];
  123.  
  124.     if( !arg1 || !arg2 )
  125.         return( BAD_NUM_ARGS );
  126.  
  127.     /* We call FindPacket to make sure the packet is actually in
  128.        the ARexx program's list (i.e., was retrieved with WaitPkt) */
  129.  
  130.     packet = *arg1;
  131.     list   = FindPacket( msg, packet );
  132.  
  133.     if( !packet || !list ) goto return_0;
  134.     if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
  135.  
  136.     /*
  137.      * Set the packet's result fields appropriately...
  138.      */
  139.  
  140.     rc                 = atol( arg2 );
  141.     packet->rm_Result1 = rc;
  142.     packet->rm_Result2 = 0;
  143.  
  144.     if( rc == RC_OK ){
  145.         if( nargs > 2 && arg3 != NULL &&
  146.             ( packet->rm_Action & RXFF_RESULT ) != 0 ){
  147.             packet->rm_Result2 = (LONG) CreateArgstring( arg3,
  148.                                             LengthArgstring( arg3 ) );
  149.         }
  150.     } else {
  151.         if( nargs > 2 && arg3 != NULL )
  152.             packet->rm_Result2 = atol( arg3 );
  153.         else
  154.             packet->rm_Result2 = FUNC_ERR;
  155.     }
  156.  
  157.     /*
  158.      * Unlink from list and then send the packet off...
  159.      */
  160.  
  161.     Remove( (struct Node *) packet );
  162.     ReplyMsg( (struct Message *) packet );
  163.  
  164.     *result_string = CreateArgstring( "1", 1 );
  165.     return( RC_OK );
  166.  
  167.   return_0:
  168.     *result_string = CreateArgstring( "0", 1 );
  169.     return( RC_OK );
  170.   }
  171.  
  172. /*
  173.  * NumArgs -- Returns the number of arguments in a packet.  If the packet
  174.  *            is not a function call, then 0 is returned.
  175.  *
  176.  *        NUMARGS( packet )
  177.  */
  178.  
  179. static LONG NumArgs( struct Library *RexxSysBase, struct RexxMsg *msg,
  180.                      char **result_string, int nargs )
  181.   {
  182.     struct RexxMsg  *packet;
  183.     struct RexxMsg **arg1;
  184.     char             argbuf[3];
  185.     struct List     *list;
  186.     int              pargs;
  187.  
  188.     arg1 = (struct RexxMsg **) msg->rm_Args[1];
  189.  
  190.     if( !arg1 )
  191.         return( BAD_NUM_ARGS );
  192.  
  193.     packet = *arg1;
  194.     list   = FindPacket( msg, packet );
  195.  
  196.     if( !packet || !list ) goto return_0;
  197.     if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
  198.     if( ( packet->rm_Action & RXCODEMASK ) != RXFUNC ) goto return_0;
  199.  
  200.     pargs = ( packet->rm_Action & RXARGMASK );
  201.  
  202.     if( pargs < 10 ){
  203.         argbuf[0] = pargs + '0';
  204.         argbuf[1] = NULLCHAR;
  205.     } else {
  206.         argbuf[0] = '1';
  207.         argbuf[1] = ( pargs % 10 ) + '0';
  208.         argbuf[2] = NULLCHAR;
  209.     }
  210.  
  211.     *result_string = CreateArgstring( argbuf, strlen( argbuf ) );
  212.     return( RC_OK );
  213.  
  214.   return_0:
  215.  
  216.     *result_string = CreateArgstring( "0", 1 );
  217.     return( RC_OK );
  218.   }
  219.  
  220. /*
  221.  * IsFunctionCall -- Returns TRUE (1) if the packet is a function call.
  222.  *
  223.  *        ISFUNCTIONCALL( packet )
  224.  */
  225.  
  226. static LONG IsFunctionCall( struct Library *RexxSysBase, struct RexxMsg *msg,
  227.                             char **result_string, int nargs )
  228.   {
  229.     struct RexxMsg  *packet;
  230.     struct RexxMsg **arg1;
  231.     struct List     *list;
  232.  
  233.     arg1 = (struct RexxMsg **) msg->rm_Args[1];
  234.  
  235.     if( !arg1 )
  236.         return( BAD_NUM_ARGS );
  237.  
  238.     packet = *arg1;
  239.     list   = FindPacket( msg, packet );
  240.  
  241.     if( !packet || !list ) goto return_0;
  242.     if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
  243.     if( ( packet->rm_Action & RXCODEMASK ) != RXFUNC ) goto return_0;
  244.  
  245.     *result_string = CreateArgstring( "1", 1 );
  246.     return( RC_OK );
  247.  
  248.   return_0:
  249.  
  250.     *result_string = CreateArgstring( "0", 1 );
  251.     return( RC_OK );
  252.   }
  253.  
  254. /*
  255.  * ValidPkt -- Returns TRUE or FALSE depending upond whether the given
  256.  *             address is a valid message packet...
  257.  *
  258.  *        VALIDPKT( packet )
  259.  */
  260.  
  261. static LONG ValidPkt( struct Library *RexxSysBase, struct RexxMsg *msg,
  262.                       char **result_string, int nargs )
  263.   {
  264.     struct RexxMsg  *packet;
  265.     struct RexxMsg **arg1;
  266.     struct List     *list;
  267.  
  268.     arg1 = (struct RexxMsg **) msg->rm_Args[1];
  269.  
  270.     if( !arg1 )
  271.         return( BAD_NUM_ARGS );
  272.  
  273.     packet = *arg1;
  274.     list   = FindPacket( msg, packet );
  275.  
  276.     if( !packet || !list ) goto return_0;
  277.     if( packet->rm_Node.mn_Node.ln_Type == NT_REPLYMSG ) goto return_0;
  278.  
  279.     *result_string = CreateArgstring( "1", 1 );
  280.     return( RC_OK );
  281.  
  282.   return_0:
  283.  
  284.     *result_string = CreateArgstring( "0", 1 );
  285.     return( RC_OK );
  286.   }
  287.  
  288. /*
  289.  * StrEq -- Returns TRUE if two strings match.
  290.  */
  291.  
  292. static BOOL StrEq( char *a, char *b )
  293.   {
  294.     return( strcmp( a, b ) == 0 );
  295.   }
  296.  
  297. /*
  298.  * StrIEq -- Like StrEq, but case-insensitive.
  299.  */
  300.  
  301. static BOOL StrIEq( char *a, char *b )
  302.   {
  303.     while( *a != NULLCHAR && *b != NULLCHAR ){
  304.         if( tolower( *a ) != tolower( *b ) )
  305.             return( FALSE );
  306.  
  307.         ++a;
  308.         ++b;
  309.     }
  310.  
  311.     return( *a == *b );
  312.   }
  313.  
  314. /*
  315.  * FindPacket -- Given a packet address, check the message port lists
  316.  *               for the ARexx program and find the list to which
  317.  *               the packet belongs. (NULL if packet can't be found.)
  318.  *
  319.  *               This routine depends upon knowledge of Rexx's internal
  320.  *               structures, as described in the storage.h and rexxio.h
  321.  *               header files.  The task pointer is taken from the
  322.  *               RexxMsg that is passed to the function library.
  323.  */
  324.  
  325. static struct List *FindPacket( struct RexxMsg *msg, struct RexxMsg *packet )
  326.   {
  327.     struct RexxTask    *rt;
  328.     struct RexxMsg     *rmsg;
  329.     struct RexxMsgPort *port;
  330.  
  331.     if( !msg || !packet )
  332.         return( NULL );
  333.  
  334.     /* Get the ARexx program's global data structure */
  335.  
  336.     rt = (struct RexxTask *) msg->rm_TaskBlock;
  337.  
  338.     if( rt ){
  339.  
  340.         /* OK, search through the list of active message ports
  341.            for the ARexx program... */
  342.  
  343.         for( port = (void *) rt->rt_Header5.lh_Head;
  344.              port->rmp_Node.rr_Node.ln_Succ;
  345.              port = (void *) port->rmp_Node.rr_Node.ln_Succ ){
  346.  
  347.              /* For each port, search through the list of messages
  348.                 awaiting reply... */
  349.  
  350.              for( rmsg = (void * ) port->rmp_ReplyList.lh_Head;
  351.                   rmsg->rm_Node.mn_Node.ln_Succ;
  352.                   rmsg = (void *) rmsg->rm_Node.mn_Node.ln_Succ ){
  353.  
  354.                   if( rmsg == packet ){
  355.                       return( &port->rmp_ReplyList );
  356.                   }
  357.              }
  358.         }
  359.     }
  360.  
  361.     return( NULL );
  362.   }