home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d599 / rxilshell.lha / RxilShell / src.lzh / rxil_shell.c next >
C/C++ Source or Header  |  1992-01-30  |  18KB  |  582 lines

  1. /***************************************************************************
  2.  
  3.    Program:    
  4.    File:       Rxil_Shell.c
  5.    
  6.    Version:    V1.0
  7.    Date:       13.12.91
  8.    Function:   Provide a friendly shell for the Rxil ARexx library
  9.    
  10.    Copyright:  SciTech Software 1991
  11.    Author:     Andrew C. R. Martin
  12.    Address:    SciTech Software
  13.                23, Stag Leys,
  14.                Ashtead,
  15.                Surrey,
  16.                KT21 2TD.
  17.    Phone:      +44 (0372) 275775
  18.    EMail:      UUCP: cbmuk!cbmuka!scitec!amartin
  19.                JANET: andrew@uk.ac.ox.biop
  20.                
  21. ****************************************************************************
  22.  
  23.    This program is not in the public domain, but it may be freely copied
  24.    and distributed for no charge providing this header is included.
  25.    The code may be modified as required, but any modifications must be
  26.    documented so that the person responsible can be identified. If someone
  27.    else breaks this code, I don't want to be blamed for code that does not
  28.    work! The code may not be sold commercially without prior permission from
  29.    the author, although it may be given away free with commercial products,
  30.    providing it is made clear that this program is free and that the source
  31.    code is provided with the program.
  32.  
  33. ****************************************************************************
  34.  
  35.    Description:
  36.    ============
  37.    
  38. *  The Rxil library makes calls to ARexx far easier. Error handling, etc.
  39.    is done for the programmer. Rxil_Shell makes these calls even easier.
  40.    Some flexibility is missing from these calls (although, when needed,
  41.    this can be re-introduced by direct calls to Rxil or ARexx itself).
  42.  
  43.    
  44. *  The following Rxil routines have been modified:
  45.    
  46.    RxilCheckPort()      Fix to memory allocation. ARG0() macro was getting
  47.                         expanded wrongly causing MungWall hits.
  48.    display_message()    Changed call to AutoRequest() to use MyAutoRequest()
  49.                         which looks nicer under V1.3
  50.    RxilHandleReturn()   Given a second parameter to control internal display
  51.                         of returns from functions. Also returns a flag to
  52.                         indicate whether a return value was obtained.
  53.  
  54.  
  55. *  The Rexx command table, an array of RxilFunction's must be created and
  56.    passed to SetupREXX(). A line of NULL's and 0's is used to mark the end
  57.    of the table. For example:
  58.  
  59.    struct RxilFunction rexx_cmd_table[] = {
  60.       { "help",   &rexx_parse,      0, 10,   FALSE,   RXIL_PUBLIC },
  61.       { "quit",   &rexx_parse,      0, 10,   FALSE,   RXIL_PUBLIC },
  62.       { "command",&cmd_launch_cmd,  0,  1,   FALSE,   RXIL_PUBLIC },
  63.       { "func",   &cmd_launch_func, 0, 16,   FALSE,   RXIL_PUBLIC },
  64.       { NULL,     NULL,             0,  0,   FALSE,   0           }
  65.    };
  66.    
  67.    The structure members are:
  68.    (char *)    Command name (in lower case)
  69.    (void *)()  Function to be called for this command
  70.    int         Min number of arguments required
  71.    int         Max number of arguments required
  72.    BOOL        Should command matching be case sensitive
  73.    int         Privilege. RXIL_PUBLIC or RXIL_SECRET. Specifies which port
  74.                the command is valid from. If REXX_PUBLIC, command may be
  75.                executed through either port.
  76.  
  77.  
  78. *  The functions specified in the command table are called with a single
  79.    parameter, a pointer to a RexxMsg structure. The example command table
  80.    shows 2 calls to rexx_parse(). This implies an additional layer of
  81.    parsing is supplied by the client program. If required, the routine 
  82.    BuildComLine() may be called in such a parser to rebuild the command
  83.    line. The following example shows how this might be done:
  84.    
  85.    void rexx_parse(struct RexxMsg *rexxmsg)
  86.    {  char  buffer[200];
  87.    
  88.       BuildComLine(buffer);                        Rebuild the command line
  89.       Interpret(buffer);                           Call our own parser
  90.    }
  91.    
  92.  
  93. *  The only Rexx specific external which needs to be specified by the client
  94.    program (and then only if the client is interested in returns from 
  95.    macros) is:
  96.  
  97.    extern char *Rexx_return;
  98.  
  99. ****************************************************************************
  100.  
  101.    Usage:
  102.    ======
  103.    
  104.    SetupREXX(portname, extension, conspec, synch, comtab, startup)
  105.    ---------------------------------------------------------------
  106.    Input:   char                 *portname   Port name
  107.             char                 *extension  Default extension
  108.                                              NULL: "rexx"
  109.                                              else: taken a string pointer
  110.             char                 *conspec    Console spec for macros to use.
  111.                                              NULL: none (use CLI)
  112.                                              1:    default
  113.                                              else: taken a string pointer
  114.             int                  synch       Are macros to be synchronous?
  115.                                              0: Synchronous
  116.                                              1: Asynchronous
  117.             struct RxilFunction  comtab[]    ARexx command table (see above)
  118.             char                 *startup    Name of Startup macro
  119.                                              NULL: No startup
  120.    Returns: void
  121.    
  122.    Sets up public and private REXX ports and specifies various parameters
  123.    for Rexx. Also runs a startup macro if required; thus any other 
  124.    preparation routines should be called before SetupREXX().
  125.    comtab[] should be prepared as shown above.
  126.  
  127.  
  128.    ProcessReturns()
  129.    ----------------
  130.    Input:   void
  131.    Returns: void
  132.    
  133.    This routine is for programs which launch macros. Handles any ARexx 
  134.    invocation returns which may be back. Informs of any problems and
  135.    allocates and sets the Rexx_return string if a function returned
  136.    with a value.
  137.  
  138.  
  139.    CloseREXX(wind, force)
  140.    ----------------------
  141.    Input:   struct Window        *wind       Pointer to window
  142.             int                  force       0: Don't force;  1: Do force
  143.    Returns: int                              0: Didn't close; 1: Did
  144.    
  145.    Clean up all REXX stuff. Unless force is set, will ask whether it 
  146.    should proceed IF there are any macros waiting. This is done by posting
  147.    a requester in wind (or Workbench if wind is NULL).
  148.  
  149.  
  150.    LaunchCmd(buf)
  151.    --------------
  152.    Input:   char                 *buf        Command macro to be launched
  153.    Returns: void
  154.    
  155.    Launch a REXX command.
  156.  
  157.  
  158.    SetFuncParam(pos, string)
  159.    -------------------------
  160.    Input:   int                  pos         Parameter number (0--15)
  161.             char                 *string     Parameter string
  162.    Returns: int                              0: OK; 1: Failed
  163.    
  164.    Allocate space to put a function parameter and copy in the parameter
  165.    string. The name of the function to be called should be placed in
  166.    position 0. Returns 0 if succeeded; 1 if not
  167.  
  168.  
  169.    LaunchFunc()
  170.    ------------
  171.    Input:   void
  172.    Returns: void
  173.  
  174.    Launch a REXX function. Uses data created by calls to SetFuncParam()
  175.  
  176.  
  177.    RexxReturnUsed()
  178.    ----------------
  179.    Input:   void
  180.    Returns: void
  181.  
  182.    Free memory used for Rexx_return. Also sets Rexx_return back to NULL
  183.    so its value can be tested to see of we've got a value back from a
  184.    function call.
  185.  
  186.  
  187.    BuildComLine(buffer)
  188.    --------------------
  189.    Output:  char                 *buffer     Pointer to character string
  190.    Returns: void
  191.    
  192.    Rebuilds the command line into buffer (which must be pre-allocated).
  193.    This is useful if you want to parse commands separately from the
  194.    built-in parser.
  195.  
  196. ****************************************************************************
  197.  
  198.    Revision History:
  199.    =================
  200.  
  201. ***************************************************************************/
  202. /* Includes
  203. */
  204.  
  205. #include "rxil.h"
  206.  
  207. #include <graphics/gfxbase.h>
  208. #include <libraries/dos.h>
  209.  
  210. #include <stdio.h>
  211. #include <string.h>
  212. #include <stdlib.h>
  213. #include <math.h>
  214.  
  215. #ifdef LATTICE
  216. #include <proto/intuition.h>
  217. #endif
  218.  
  219. /************************************************************************/
  220. /* Intuition Externs
  221. */
  222.  
  223. extern   struct   IntuitionBase  *IntuitionBase;
  224. extern   struct   GfxBase        *GfxBase;
  225.  
  226. /************************************************************************/
  227. /* REXX-specific extern defines. These are required by other rxil routines
  228.    and/or by client code.
  229. */
  230.  
  231. /* This is the Rxil definition structure.
  232. */
  233. struct RxilDef *global_rdef = NULL;
  234.  
  235. /* This is used to place return values from functions
  236. */
  237. char *Rexx_return = NULL;
  238.  
  239. /************************************************************************/
  240. /* REXX-specific static defines. These are only required by routines
  241.    defined in this file.
  242. */
  243.  
  244. /* We provide one invocation structure for commands and one for functions.
  245.    These could be allocated and deallocated on the fly.
  246. */
  247. static struct RxilInvocation *rxi_func;
  248. static struct RxilInvocation *rxi_cmd;
  249.  
  250. /* This one is for the startup macro.  We want to retain it's pointer
  251.    even after it is launched so that we can recognise it when it 
  252.    terminates and handle it differently.
  253. */
  254. static struct RxilInvocation *rxi_startup;
  255.  
  256. /* This is used to build REXX function arguments
  257. */
  258. static char *RexxFuncBuf[16] = {NULL, NULL, NULL, NULL,
  259.                                 NULL, NULL, NULL, NULL,
  260.                                 NULL, NULL, NULL, NULL,
  261.                                 NULL, NULL, NULL, NULL};
  262.  
  263. /************************************************************************/
  264. /* Setup the REXX port
  265. */
  266. void SetupREXX(char *portname,   /* Port name */
  267.                char *extension,  /* Default extension 0: "rexx"         */
  268.                char *conspec,    /* CON: 0: none, 1: default, or string */
  269.                int  synch,       /* 0: Synchronous,   1: Asynchronous   */
  270.                struct RxilFunction comtab[],    /* REXX command table   */
  271.                char *startup)    /* Startup macro                       */
  272. {
  273.    /* Open rexx library and desired ports.
  274.       Only the PUBLIC port is needed if we're only receiving commands
  275.    */
  276.    global_rdef = RxilInit(RXIL_PUBLIC | RXIL_SECRET, portname);
  277.    if(global_rdef == NULL)
  278.    {
  279.       Die("Unable to init rexx");
  280.    }
  281.  
  282.    /* Initialise RxilDef to customise things.
  283.       Here, we could set
  284.          global_rdef->Flags
  285.       to turn features off.
  286.    */
  287.    global_rdef->Flags = RXIL_NO_ABORT;
  288.    
  289.    /* Set up console for commands or functions launced by this program.
  290.       If conspec was 0, we do this from a CLI;
  291.       if 1, we use a standard spec;
  292.       else, this is a pointer to a string for the required CON:
  293.    */
  294.    if(conspec == (char *)0L)
  295.       global_rdef->Console = NULL;
  296.    else if(conspec == (char *)1L)
  297.       global_rdef->Console = "CON:10/10/400/150/RexxCon";
  298.    else
  299.       global_rdef->Console = conspec;
  300.  
  301.  
  302.    /* Set the default extension for macros */
  303.    if(extension == (char *)0L)
  304.       global_rdef->Extension = "rexx";
  305.    else
  306.       global_rdef->Extension = extension;
  307.  
  308.    /* The port to use for launched commands.
  309.       REXX:    synchronous
  310.       AREXX:   asynchronous
  311.    */
  312.    if(synch == 0)
  313.       global_rdef->HostPort = "REXX";
  314.    else
  315.       global_rdef->HostPort = "AREXX";
  316.  
  317.    /* The command table we've created
  318.    */
  319.    global_rdef->CommandTable = &comtab[0];
  320.  
  321.  
  322.    /***
  323.       Pre-allocate the command and function some invocation structures.  
  324.       These could be allocated and de-allocated on-the-fly if desired.
  325.    ***/
  326.    rxi_cmd = RxilCreateRxi(NULL, RXCOMM);
  327.    if(rxi_cmd == NULL)
  328.    {
  329.       Die("Unable to allocate command_rxi");
  330.    }
  331.  
  332.    rxi_func = RxilCreateRxi(NULL, RXFUNC);
  333.    if( rxi_func == NULL )
  334.    {
  335.       Die("Unable to allocate function_rxi");
  336.    }
  337.  
  338.    /***
  339.       Run a startup macro when the program is invoked
  340.    ***/
  341.    rxi_startup = NULL;
  342.    if(startup)
  343.    {
  344.       rxi_startup = RxilCreateRxi(startup, RXCOMM);
  345.       if(rxi_startup == NULL)
  346.       {
  347.          /* We don't die, just give a message */
  348.          ReqMessage(NULL,"** Unable to allocate startup rxi **",0);
  349.       }
  350.       else
  351.       {
  352.          /* We don't need a console */
  353.          rxi_startup->Console = NULL;
  354.  
  355.          /* Now launch the macro */
  356.          if(RxilLaunch( rxi_startup ) != 0)
  357.          {
  358.             /* We don't die, just give a message */
  359.             ReqMessage(NULL,"** Unable to launch the startup macro **",0);
  360.          }
  361.       }
  362.    }
  363. }
  364.  
  365. /************************************************************************/
  366. /* This code is for programs which launch macros.
  367.    Handle any ARexx invocation returns which may be back.
  368. */
  369. void ProcessReturns(void)
  370. {
  371.    struct   RxilInvocation *rxi;
  372.  
  373.    while((rxi = RxilGetReturn()) != NULL)
  374.    {
  375. #ifdef DEBUG2
  376.       if(rxi->Type == RXCOMM)
  377.       {
  378.          printf("Command Invocation completed\n");
  379.       }
  380.       else
  381.       {
  382.          printf( "Function Invocation completed\n" );
  383.       }
  384. #endif
  385.  
  386.       if(rxi == rxi_startup)
  387.       {
  388.          /* This is our startup macro terminating.  We handle this 
  389.             differently since we don't want to display an error 
  390.             if not found (which the standard routine 
  391.             RxilHandleReturn() would do). We also want to de-allocate 
  392.             the RxilInvocation structure.
  393.          */
  394.  
  395.          /* Deallocate things, close console windows, etc.
  396.             Then free the structure.
  397.          */
  398.          if((rxi->RexxMsg->rm_Result1 != RC_WARN) ||
  399.             (rxi->RexxMsg->rm_Result2 != ERR10_001))
  400.          {
  401.             /* The error is not just "program not found".
  402.                It is a real error, so tell the user.
  403.                
  404.                ACRM: surely, this should be &&, not || !)
  405.             */
  406.             RxilHandleReturn(rxi, 1);
  407.          }
  408.          RxilCleanupReturn(rxi);
  409.          RxilDeleteRxi(rxi);
  410.          rxi_startup = NULL;     /* To be tidy... */
  411.       }
  412.       else
  413.       {
  414.          /* This is a macro other than the startup, so handle the 
  415.             return normally, telling the user about any problems.
  416.             Nothing will break if this code is removed...
  417.          */
  418.          if(Rexx_return) FreeMem(Rexx_return, (strlen(Rexx_return) + 2));
  419.          Rexx_return = NULL;
  420.          if(RxilHandleReturn(rxi, 0))
  421.          {
  422.             Rexx_return = (char *)
  423.                AllocMem((strlen((char *)(rxi->RexxMsg->rm_Result2)) + 2), 0L);
  424.             if(Rexx_return)
  425.                strcpy(Rexx_return, (char *)(rxi->RexxMsg->rm_Result2));
  426.          }
  427.  
  428.          /* Clean up: deallocate memory and close CON:   */
  429.          RxilCleanupReturn(rxi);
  430.       }
  431.    }
  432. }
  433.  
  434.  
  435. /************************************************************************/
  436. /* Clean up all REXX stuff. Unless force is set, will ask whether it 
  437.    should proceed if there are any macros waiting.
  438.    Returns 1 if it cleaned up OK; otherwise returns 0.
  439. */
  440. int CloseREXX(struct Window *wind,
  441.               int           force)
  442. {
  443.    int   cleanup = 1,
  444.          i;
  445.  
  446.    if(!force)
  447.    {
  448.       if(RxilPending())
  449.          cleanup = ReqMessage3(wind,"There are REXX commands pending"," ",
  450.                                     "Really quit?",1);
  451.    }
  452.  
  453.    if(cleanup)
  454.    {
  455.       /* Clean up the rxil stuff */
  456.       RxilCleanup(global_rdef);
  457.       global_rdef = NULL;
  458.       
  459.       /* Clean up additional rxil_shell stuff */
  460.       if(Rexx_return) FreeMem(Rexx_return, (strlen(Rexx_return) + 2));
  461.       Rexx_return = NULL;
  462.       
  463.       for(i=0; i<16; i++)
  464.       {
  465.          if(RexxFuncBuf[i] != NULL) 
  466.             FreeMem(RexxFuncBuf[i], (strlen(RexxFuncBuf[i]) + 2));
  467.          RexxFuncBuf[i] = NULL;
  468.       }
  469.       
  470.    }
  471.    
  472.    return(cleanup);
  473. }
  474.  
  475.    
  476.  
  477. /************************************************************************/
  478. /* Launch a REXX command
  479. */
  480. void LaunchCmd(char *buf)
  481. {
  482.    LONG rc;
  483.    
  484.    rxi_cmd->Name = buf;
  485.    rc = RxilLaunch( rxi_cmd );
  486.    if(rc)
  487.    {
  488.       char buffer[80];
  489.       sprintf(buffer,"Command launch returned %d",rc);
  490.       ReqMessage2(NULL,buf,buffer,0);
  491.    }
  492. }   
  493.  
  494. /************************************************************************/
  495. /* Allocate a space to put a function parameter
  496. */
  497. int SetFuncParam(int pos,
  498.                  char *string)
  499. {
  500.    if(pos < 0 || pos > 15) return(1);
  501.    
  502.    if(string != NULL)
  503.    {
  504.       /* If currently allocated, free it */
  505.       if(RexxFuncBuf[pos] != NULL) 
  506.          FreeMem(RexxFuncBuf[pos], (strlen(RexxFuncBuf[pos]) + 2));
  507.  
  508.       /* Reallocate for our string */
  509.       RexxFuncBuf[pos] = (char *)AllocMem((strlen(string) + 2), 0L);
  510.       if(RexxFuncBuf[pos] == NULL) Die("No memory for Rexx buffer");
  511.  
  512.       /* Copy in our string */
  513.       strcpy(RexxFuncBuf[pos], string);
  514.       
  515.       /* Free up the next position too */
  516.       if((pos + 1) < 16)
  517.       {
  518.          if(RexxFuncBuf[pos+1] != NULL) 
  519.             FreeMem(RexxFuncBuf[pos+1], (strlen(RexxFuncBuf[pos+1]) + 2));
  520.          RexxFuncBuf[pos+1] = NULL;
  521.       }
  522.    }
  523.    
  524.    return(0);
  525. }
  526.  
  527. /************************************************************************/
  528. /* Launch a REXX function
  529. */
  530. void LaunchFunc(void)
  531. {
  532.    int   i;
  533.    LONG  rc;
  534.    
  535.    /* Set the Name to point to our allocated function name string       */
  536.    rxi_func->Name = RexxFuncBuf[0];
  537.    
  538.    /* Set the FuncArg[] array to point to our allocated strings         */
  539.    for(i=1; i<16; i++)
  540.    {
  541.       /* First set to NULL */
  542.       rxi_func->FuncArg[i] = NULL;
  543.       
  544.       /* Break if this is the last one */
  545.       if(RexxFuncBuf[i] == NULL) break;
  546.       
  547.       /* Otherwise copy in the pointer */
  548.       rxi_func->FuncArg[i] = RexxFuncBuf[i];
  549.    }
  550.    
  551.    /* Launch the function */
  552.    rc = RxilLaunch( rxi_func );
  553.    if(rc) 
  554.    {
  555.       char  RexxFuncBuffer[80];
  556.       sprintf(RexxFuncBuffer,"Function launch returned %d",rc);
  557.       ReqMessage2(NULL,RexxFuncBuf,RexxFuncBuffer,0);
  558.    }
  559. }
  560.  
  561. /************************************************************************/
  562. /* Free memory used for Rexx_return.
  563. */
  564. void RexxReturnUsed(void)
  565. {
  566.    Rexx_return = NULL;
  567. }
  568.  
  569. /************************************************************************/
  570. /* Rebuild the command line if a separate command parser is being used
  571. */
  572. void BuildComLine(char *buffer)
  573. {
  574.    int   i;
  575.  
  576.    buffer[0] = '\0';
  577.    for(i=0; i<RXIL_ARGC; i++)
  578.    {
  579.       strcat(buffer, RXIL_ARGV(i));
  580.       strcat(buffer," ");
  581.    }
  582. }