home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 230.lha / ArexxFunctionHost / rexxfunchost.c < prev    next >
C/C++ Source or Header  |  1989-04-03  |  11KB  |  574 lines

  1. /*  RexxFuncHost.c   */
  2.  
  3.  
  4. /*        Copyright © 1989 by Donald T. Meyer
  5.  *        All Rights Reserved
  6.  *
  7.  *        This source code may be compiled and used in any software
  8.  *        product.
  9.  *        No portion of this source code is to be
  10.  *        re-distributed or sold for profit without the written
  11.  *        permission of the author, Donald T. Meyer.
  12.  *
  13.  *        Donald T. Meyer
  14.  *        Stormgate Software
  15.  *        4 Rustic Creek Court
  16.  *        St. Peters, MO  63376
  17.  *
  18.  *        BIX:    donmeyer
  19.  *        GEnie:    D.MEYER
  20.  *        PLINK:    Stormgate
  21.  */
  22.  
  23.  
  24.  
  25. #include <exec/types.h>
  26. #include <libraries/dos.h>
  27. #include <workbench/startup.h>
  28.  
  29. #include <proto/intuition.h>
  30. #include <proto/exec.h>
  31. #include <proto/dos.h>
  32.  
  33. #include <string.h>
  34. #include <stdlib.h>
  35.  
  36. #include "rexxfunchost.h"
  37.  
  38.  
  39.  
  40. /*------------------------------------------------------------------*/
  41. /*                    External Function Declarations                    */
  42. /*------------------------------------------------------------------*/
  43.  
  44. /* These are (better be!) in the user function module(s) */
  45.  
  46. char *client_init( void );
  47.  
  48. void client_cleanup( void );
  49.  
  50.  
  51.  
  52. /*------------------------------------------------------------------*/
  53. /*                    External Variable Declarations                    */
  54. /*------------------------------------------------------------------*/
  55.  
  56.  
  57. /* These are in the user function module */
  58.  
  59. extern char *hello_string;
  60. extern char *success_string;
  61. extern char *removal_string;
  62. extern char *redundant_string;
  63. extern char *noclone_string;
  64.  
  65. extern struct RexxFunction func_table[];
  66.  
  67. extern int hostpri;
  68. extern char *hostname;
  69.  
  70. extern BPTR _Backstdout;
  71. extern char *console_def_string;
  72.  
  73.  
  74.  
  75. /* Other misc. external variables. */
  76.  
  77. extern struct WBStartup *WBenchMsg;
  78.  
  79.  
  80.  
  81. /*------------------------------------------------------------------*/
  82. /*                    Local Function Declarations                        */
  83. /*------------------------------------------------------------------*/
  84.  
  85. static void openlibrarys( void );
  86. static void closelibrarys( void );
  87.  
  88. static void bailout( char *message, int rc );
  89.  
  90. static void cleanup( void );
  91.  
  92. static void init_port( void );
  93.  
  94. static void eventloop( void );
  95.  
  96. static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
  97.     STRPTR arg3 );
  98.  
  99. static void handle_message( struct RexxMsg *rexxmsg );
  100.  
  101. static void check_result( struct Rexxmsg *rexxmsg );
  102.  
  103. static void dispatch( struct RexxMsg *rexxmsg );
  104.  
  105. static void check_clone( int argc, char *argv[] );
  106.  
  107. static BOOL remove_clone( void );
  108.  
  109.  
  110.  
  111. /*------------------------------------------------------------------*/
  112. /*                    Variable Definitions                            */
  113. /*------------------------------------------------------------------*/
  114.  
  115. struct RxsLib *RexxSysBase = NULL;
  116.  
  117.  
  118. static struct MsgPort *hostport = NULL;
  119.  
  120. static BPTR message_console = NULL;
  121.  
  122. static BOOL finished = FALSE;
  123.  
  124. /* For detaching */
  125. long _BackGroundIO = 1;
  126.  
  127.  
  128.  
  129. /*------------------------------------------------------------------*/
  130. /*                    Functions                                        */
  131. /*------------------------------------------------------------------*/
  132.  
  133.  
  134. void main( int argc, char *argv[] )
  135. {
  136.     char *errmsg;
  137.  
  138.  
  139.     if( _Backstdout == NULL )
  140.     {
  141.         /* Probably child of workbench, open our own window */
  142.         /* Open a window to print hello and copyright stuff to */
  143.         message_console = Open( console_def_string, MODE_NEWFILE );
  144.  
  145.         /* After some thought, I decided to quit if we could not
  146.          * post our hello banner, etc.
  147.          * We could just as easily continue, but this _should_ never
  148.          * fail, so probably moot.
  149.          */
  150.         if( message_console == NULL )
  151.             bailout( NULL, 20 );
  152.     }
  153.     else
  154.     {
  155.         /* Send banner and error messages to the CLI that started us */
  156.         message_console = _Backstdout;
  157.     }
  158.  
  159.     openlibrarys();
  160.  
  161.     Write( message_console, hello_string, strlen(hello_string) );
  162.  
  163.     check_clone( argc, argv );
  164.  
  165.     init_port();
  166.  
  167.     /* Allow the client to do his initializations */
  168.     if(  ( errmsg = client_init() ) != NULL  )
  169.     {
  170.         bailout( errmsg, 20 );
  171.     }
  172.  
  173.     Write( message_console, success_string, strlen(success_string) );
  174.  
  175.     /* Done with window, close it */
  176.     Delay( 200 );
  177.     Close( message_console );
  178.     message_console = NULL;
  179.  
  180.     eventloop();
  181.  
  182.     cleanup();
  183.  
  184.     exit( 0 );
  185. }
  186.  
  187.  
  188.  
  189. static void eventloop( void )
  190. {
  191.     struct RexxMsg *rexxmsg;
  192.     ULONG flags;
  193.  
  194.  
  195.     while( ! finished )
  196.     {
  197.         flags = Wait(  ( 1L<<hostport->mp_SigBit ) | SIGBREAKF_CTRL_C  );
  198.  
  199.         if( flags & SIGBREAKF_CTRL_C )
  200.         {
  201.             /* Somebody wants us to quit.  Probably another us! */
  202.             finished = TRUE;
  203.  
  204.             /* Remove ourselves from the arexx library list */
  205.             to_rexx( (ULONG)RXREMLIB, hostname, NULL, NULL, NULL );
  206.  
  207.             /* Make port un-findable to all others just in case */
  208.             RemPort( hostport );
  209.             hostport->mp_Node.ln_Name = NULL;
  210.         }
  211.  
  212.         while( rexxmsg = (struct RexxMsg *)GetMsg( hostport ) )
  213.         {
  214.             if( IsRexxMsg(rexxmsg) )
  215.             {
  216.                 /* The message is from an ARexx program */
  217.  
  218.                 /* Default to a "not found" code. */
  219.                 rexxmsg->rm_Result1 = RC_WARN;
  220.                 rexxmsg->rm_Result2 = ERR10_001;
  221.  
  222.                 /* See if we have been told to close, and are just
  223.                  * flushing the message queue.
  224.                  */
  225.                 if( !finished )
  226.                 {
  227.                     /* Handle the message contents */
  228.                     handle_message( rexxmsg );
  229.                 }
  230.             }
  231.  
  232.             ReplyMsg( (struct Message *)rexxmsg );
  233.         }
  234.     }
  235. }
  236.  
  237.  
  238.  
  239. static void handle_message( struct RexxMsg *rexxmsg )
  240. {
  241.     if(  (rexxmsg->rm_Action & RXCODEMASK) != RXFUNC  )
  242.     {
  243.         /* Something else (probably a command invocation if
  244.          * our host port was set as the ARexx address).
  245.          * We want to respond only to function invocations.
  246.          */
  247.         return;
  248.     }
  249.  
  250.     dispatch( rexxmsg );
  251.  
  252.     check_result( rexxmsg );
  253. }
  254.  
  255.  
  256.  
  257. static void dispatch( struct RexxMsg *rexxmsg )
  258. {
  259.     int i, match = -1;
  260.     char *cmd;
  261.  
  262.  
  263.     cmd = ARG0(rexxmsg);
  264.  
  265.     for( i=0; func_table[i].fname != NULL; i++ )
  266.     {
  267.         if( func_table[i].caseflag == TRUE )
  268.         {
  269.             /* Case sensitive */
  270.             if(  strcmp( func_table[i].fname, cmd ) == 0  )
  271.             {
  272.                 /* A match */
  273.                 match = i;
  274.                 break;
  275.             }
  276.         }
  277.         else
  278.         {
  279.             /* Not case sensitive */
  280.             if(  stricmp( func_table[i].fname, cmd ) == 0  )
  281.             {
  282.                 /* A match */
  283.                 match = i;
  284.                 break;
  285.             }
  286.         }
  287.     }
  288.  
  289.     if( match == -1 )
  290.     {
  291.         /* No match found */
  292.         return;
  293.     }
  294.  
  295.     /* Found a match.  Let's do the argument checking */
  296.     if(   ( func_table[match].argcount != -1 ) &&
  297.         (  ( rexxmsg->rm_Action & RXARGMASK ) !=
  298.         func_table[match].argcount  )   )
  299.     {
  300.         /* Wrong number of args */
  301.         rexxmsg->rm_Result1 = RC_ERROR;
  302.         rexxmsg->rm_Result2 = ERR10_017;
  303.         return;
  304.     }
  305.  
  306.     /* Call the function. */
  307.     (*(func_table[match].func))(rexxmsg);
  308. }
  309.  
  310.  
  311.  
  312. static void check_result( struct RexxMsg *rexxmsg )
  313. {
  314.     /* Make sure that we don't return an argstring
  315.      * if one was not requested
  316.      */
  317.     if( rexxmsg->rm_Action & RXFF_RESULT )
  318.     {
  319.         /* Result string wanted */
  320.         return;
  321.     }
  322.  
  323.  
  324.     /* A result string was not requested.  Let's see if there is one */
  325.  
  326.     if( (rexxmsg->rm_Result1==0) && (rexxmsg->rm_Result2!=0) )
  327.     {
  328.         /* There is one, so we need to delete it. */
  329.         DeleteArgstring( (struct RexxArg *)(rexxmsg->rm_Result2) );
  330.         rexxmsg->rm_Result2 = 0;
  331.     }
  332. }
  333.  
  334.  
  335.  
  336. /* Open a public port and add it to the ARexx Library List.
  337.  */
  338.  
  339. static void init_port( void )
  340. {
  341.     /* Setup the public host port */
  342.     if(  ( hostport = CreatePort( hostname, 0L ) ) == NULL  )
  343.     {
  344.         bailout( "Unable to create message port", 20 );
  345.     }
  346.  
  347.     /* Add ourselves to the arexx library list */
  348.     if( to_rexx( (ULONG)RXADDFH, hostname, (STRPTR)hostpri, NULL, NULL )  )
  349.     {
  350.         /* Could not add our port to the library list */
  351.         bailout( "Unable to add self to ARexx library list", 20 );
  352.     }
  353. }
  354.  
  355.  
  356. /* This function does some fairly convoluted things involving
  357.  * terminating another previously running invocation of ourselves.
  358.  * Depending on wether we are launched from CLI or WorkBench and
  359.  * command line options (only if from the CLI of course).
  360.  * The logic is:
  361.  *
  362.  *        IF from WorkBench
  363.  *            IF already invoked
  364.  *                remove existing invocation
  365.  *                exit
  366.  *
  367.  *        IF from CLI
  368.  *            IF -q option
  369.  *                IF already invoked
  370.  *                    remove existing invocation
  371.  *                    exit
  372.  *                ELSE
  373.  *                    tell user there is no existing invocation
  374.  *                    exit
  375.  *            ELSE
  376.  *                IF already invoked
  377.  *                    tell user that we cannot install again
  378.  *                    exit
  379.  *
  380.  */
  381.  
  382. static void check_clone( int argc, char *argv[] )
  383. {
  384.     if( WBenchMsg )
  385.     {
  386.         /* We are running from workbench, see if we want to
  387.          * kill off the existing invocation.
  388.          */
  389.         if( remove_clone() )
  390.         {
  391.             /* There was and we did */
  392.             bailout( removal_string, 0 );
  393.         }
  394.             /* Else, there was no clone, continue execution. */ 
  395.     }
  396.     else
  397.     {
  398.         /* From the CLI.  If the argument "-q" is given, we try to kill
  399.          * the existing invocation.  Otherwise we just refuse
  400.          * to start another invocation.
  401.          */
  402.         if(  ( argc > 1 ) && ( stricmp(argv[1],"-q") == 0 )  )
  403.         {
  404.             /* User wants us to remove ourselves */
  405.             if( remove_clone() )
  406.             {
  407.                 /* There was and we did */
  408.                 bailout( removal_string, 0 );
  409.             }
  410.             else
  411.             {
  412.                 /* There was no previous invocation */
  413.                 bailout( noclone_string, 5 );
  414.             }
  415.         }
  416.         else
  417.         {
  418.             /* The user is trying to invoke us. */
  419.             if(  FindPort( hostname )  )
  420.             {
  421.                 /* But we already exist */
  422.                 bailout( redundant_string, 5 );
  423.             }
  424.         }
  425.     }
  426. }
  427.  
  428.  
  429.  
  430. /* If thereis already another instance of ourselves running, kill it
  431.  * and return TRUE, otherwise return FALSE.
  432.  */
  433.  
  434. static BOOL remove_clone( void )
  435. {
  436.     struct MsgPort *otherport;
  437.  
  438.  
  439.     if(   (  otherport = FindPort( hostname )  ) != NULL  )
  440.     {
  441.         /* Yes, we are */
  442.         Signal( otherport->mp_SigTask, SIGBREAKF_CTRL_C );
  443.         return( TRUE );
  444.     }
  445.  
  446.     return( FALSE );
  447. }
  448.  
  449.  
  450.  
  451. static void openlibrarys( void )
  452. {
  453.     /*   ARexx library   */
  454.     if(  ! ( RexxSysBase = (struct RxsLib *)OpenLibrary( RXSNAME, 0L) )  )
  455.     {
  456.         bailout( "Unable to open the ARexx Library", 20 );
  457.     }
  458. }
  459.  
  460.  
  461.  
  462. static void closelibrarys( void )
  463. {
  464.     if( RexxSysBase )
  465.         CloseLibrary( (struct Library *)RexxSysBase );
  466. }
  467.  
  468.  
  469.  
  470. static void cleanup( void )
  471. {
  472.     client_cleanup();
  473.  
  474.     /* Remove ourselves from the arexx library list */
  475.     to_rexx( (ULONG)RXREMLIB, hostname, NULL, NULL, NULL );
  476.  
  477.     if( hostport )
  478.         DeletePort( hostport );
  479.  
  480.     closelibrarys();
  481.  
  482.     if( message_console )
  483.         Close( message_console );
  484. }
  485.  
  486.  
  487.  
  488.  
  489. static void bailout( char *message, int rc )
  490. {
  491.     if( message_console )
  492.     {
  493.         Write( message_console, message, strlen(message) );
  494.         Delay( 200 );
  495.     }
  496.  
  497.     cleanup();
  498.  
  499.     exit( rc );
  500. }
  501.  
  502.  
  503.  
  504. static int to_rexx( ULONG cmd, STRPTR arg0, STRPTR arg1, STRPTR arg2,
  505.     STRPTR arg3 )
  506. {
  507.     struct MsgPort *rmast;
  508.     struct RexxMsg *rexxmsg;
  509.  
  510.  
  511.     /* Allocate a packet to send to rexxmaster */
  512.     rexxmsg = CreateRexxMsg( NULL, NULL, NULL );
  513.     if( rexxmsg == NULL )
  514.     {
  515.         return( 1 );
  516.     }
  517.  
  518.     rexxmsg->rm_Action = cmd | (1L<<RXFB_NONRET);
  519.  
  520.     rexxmsg->rm_Args[0] = arg0;
  521.     rexxmsg->rm_Args[1] = arg1;
  522.     rexxmsg->rm_Args[2] = arg2;
  523.     rexxmsg->rm_Args[3] = arg3;
  524.  
  525.     Forbid();
  526.     if(  rmast = FindPort( "REXX" )  )
  527.     {
  528.         PutMsg( rmast, (struct Message *)rexxmsg );
  529.     }
  530.     Permit();
  531.  
  532.     if( rmast == NULL )
  533.     {
  534.         /* we could not find the REXX port, this failed! */
  535.         DeleteRexxMsg( rexxmsg );
  536.         return( 2 );
  537.     }
  538.  
  539.     return( 0 );
  540. }
  541.  
  542.  
  543.  
  544. /* This can be called to handle the details of placing a result
  545.  * string into the rexx message packet as the result Argstring.
  546.  * This will deal with inability to allocate the Argstring.
  547.  * If the string pointer is NULL, a general failure code will
  548.  * be set.
  549.  */
  550.  
  551. void SetResultString( struct RexxMsg *rexxmsg, char *string )
  552. {
  553.     if( string )
  554.     {
  555.         rexxmsg->rm_Result1 = RC_OK;
  556.         rexxmsg->rm_Result2 =
  557.             (ULONG)CreateArgstring( string, strlen(string) );
  558.  
  559.         if( rexxmsg->rm_Result2 == NULL )
  560.         {
  561.             /* Unable to create the argstring */
  562.             rexxmsg->rm_Result1 = RC_ERROR;
  563.             rexxmsg->rm_Result2 = ERR10_012;
  564.         }
  565.     }
  566.     else
  567.     {
  568.         /* Result string is null, set general failure code */
  569.         rexxmsg->rm_Result1 = RC_ERROR;
  570.         rexxmsg->rm_Result2 = ERR10_012;
  571.     }
  572. }
  573.  
  574.