home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d539 / simplerexx.lha / SimpleRexx / SimpleRexx.c < prev    next >
C/C++ Source or Header  |  1991-08-26  |  10KB  |  420 lines

  1. /*
  2.  * Simple ARexx interface by Michael Sinz
  3.  *
  4.  * This is a very "Simple" interface to the world of ARexx...
  5.  * For more complex interfaces into ARexx, it is best that you
  6.  * understand the functions that are provided by ARexx.
  7.  * In many cases they are more powerful than what is presented
  8.  * here.
  9.  *
  10.  * This code is fully re-entrant and self-contained other than
  11.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  12.  * library which is also self-contained...
  13.  */
  14.  
  15. #include    <exec/types.h>
  16. #include    <exec/nodes.h>
  17. #include    <exec/lists.h>
  18. #include    <exec/ports.h>
  19. #include    <exec/memory.h>
  20.  
  21. #include    <proto/exec.h>
  22.  
  23. #include    <rexx/storage.h>
  24. #include    <rexx/rxslib.h>
  25.  
  26. #include    <string.h>
  27. #include    <ctype.h>
  28.  
  29. /*
  30.  * The prototypes for the few ARexx functions we will call...
  31.  */
  32. struct RexxMsg *CreateRexxMsg(struct MsgPort *,char *,char *);
  33. void *CreateArgstring(char *,long);
  34. void DeleteRexxMsg(struct RexxMsg *);
  35. void DeleteArgstring(char *);
  36. BOOL IsRexxMsg(struct Message *);
  37.  
  38. /*
  39.  * Pragmas for the above functions...  (To make this all self-contained...)
  40.  * If you use RexxGlue.o, this is not needed...
  41.  *
  42.  * These are for Lattice C 5.x  (Note the use of RexxContext->RexxSysBase)
  43.  */
  44. #pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
  45. #pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
  46. #pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
  47. #pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
  48. #pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
  49.  
  50. /*
  51.  * Prototypes for the RVI ARexx calls...  (link with RexxVars.o)
  52.  */
  53. __stdargs long CheckRexxMsg(struct RexxMsg *);
  54. __stdargs long GetRexxVar(struct RexxMsg *,char *,char **);
  55. __stdargs long SetRexxVar(struct RexxMsg *,char *,char *,long);
  56.  
  57. /*
  58.  * Now, we have made the pragmas needed, let's get to work...
  59.  */
  60.  
  61. /*
  62.  * A structure for the ARexx handler context
  63.  * This is *VERY* *PRIVATE* and should not be touched...
  64.  */
  65. struct    ARexxContext
  66. {
  67. struct    MsgPort    *ARexxPort;    /* The port messages come in at... */
  68. struct    Library    *RexxSysBase;    /* We will hide the library pointer here... */
  69.     long    Outstanding;    /* The count of outstanding ARexx messages... */
  70.     char    PortName[24];    /* The port name goes here... */
  71.     char    ErrorName[28];    /* The name of the <base>.LASTERROR... */
  72.     char    Extension[8];    /* Default file name extension... */
  73. };
  74.  
  75. #define    AREXXCONTEXT    struct ARexxContext *
  76.  
  77. #include    "SimpleRexx.h"
  78.  
  79. /*
  80.  * This function returns the port name of your ARexx port.
  81.  * It will return NULL if there is no ARexx port...
  82.  *
  83.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  84.  */
  85. char *ARexxName(AREXXCONTEXT RexxContext)
  86. {
  87. register    char    *tmp=NULL;
  88.  
  89.     if (RexxContext) tmp=RexxContext->PortName;
  90.     return(tmp);
  91. }
  92.  
  93. /*
  94.  * This function returns the signal mask that the Rexx port is
  95.  * using.  It returns NULL if there is no signal...
  96.  *
  97.  * Use this signal bit in your Wait() loop...
  98.  */
  99. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  100. {
  101. register    ULONG    tmp=NULL;
  102.  
  103.     if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  104.     return(tmp);
  105. }
  106.  
  107. /*
  108.  * This function returns a structure that contains the commands sent from
  109.  * ARexx...  You will need to parse it and return the structure back
  110.  * so that the memory can be freed...
  111.  *
  112.  * This returns NULL if there was no message...
  113.  */
  114. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  115. {
  116. register    struct    RexxMsg    *tmp=NULL;
  117. register        short    flag;
  118.  
  119.     if (RexxContext)
  120.         if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
  121.     {
  122.         if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
  123.         {
  124.             /*
  125.              * If we had sent a command, it would come this way...
  126.              *
  127.              * Since we don't in this simple example, we just throw
  128.              * away anything that looks "strange"
  129.              */
  130.             flag=FALSE;
  131.             if (tmp->rm_Result1) flag=TRUE;
  132.  
  133.             /*
  134.              * Free the arguments and the message...
  135.              */
  136.             DeleteArgstring(tmp->rm_Args[0]);
  137.             DeleteRexxMsg(tmp);
  138.             RexxContext->Outstanding-=1;
  139.  
  140.             /*
  141.              * Return the error if there was one...
  142.              */
  143.             tmp=flag ? REXX_RETURN_ERROR : NULL;
  144.         }
  145.     }
  146.     return(tmp);
  147. }
  148.  
  149. /*
  150.  * Use this to return a ARexx message...
  151.  *
  152.  * If you wish to return something, it must be in the RString.
  153.  * If you wish to return an Error, it must be in the Error.
  154.  * If there is an error, the RString is ignored.
  155.  */
  156. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  157.             char *RString,LONG Error)
  158. {
  159.     if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
  160.     {
  161.         rmsg->rm_Result2=0;
  162.         if (!(rmsg->rm_Result1=Error))
  163.         {
  164.             /*
  165.              * if you did not have an error we return the string
  166.              */
  167.             if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
  168.             {
  169.                 rmsg->rm_Result2=(LONG)CreateArgstring(RString,
  170.                             (LONG)strlen(RString));
  171.             }
  172.         }
  173.  
  174.         /*
  175.          * Reply the message to ARexx...
  176.          */
  177.         ReplyMsg((struct Message *)rmsg);
  178.     }
  179. }
  180.  
  181. /*
  182.  * This function will set an error string for the ARexx
  183.  * application in the variable defined as <appname>.LASTERROR
  184.  *
  185.  * Note that this can only happen if there is an ARexx message...
  186.  *
  187.  * This returns TRUE if it worked, FALSE if it did not...
  188.  */
  189. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  190.             char *ErrorString)
  191. {
  192. register    short    OkFlag=FALSE;
  193.  
  194.     if (RexxContext) if (rmsg) if (CheckRexxMsg(rmsg))
  195.     {
  196.         /*
  197.          * Note that SetRexxVar() has more than just a TRUE/FALSE
  198.          * return code, but for this "basic" case, we just care if
  199.          * it works or not.
  200.          */
  201.         if (!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,
  202.                         (long)strlen(ErrorString)))
  203.         {
  204.             OkFlag=TRUE;
  205.         }
  206.     }
  207.     return(OkFlag);
  208. }
  209.  
  210. /*
  211.  * This function will send a string to ARexx...
  212.  *
  213.  * The default host port will be that of your task...
  214.  *
  215.  * If you set StringFile to TRUE, it will set that bit for the message...
  216.  *
  217.  * Returns TRUE if it send the message, FALSE if it did not...
  218.  */
  219. short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
  220.             short StringFile)
  221. {
  222. register    struct    MsgPort    *RexxPort;
  223. register    struct    RexxMsg    *rmsg;
  224. register        short    flag=FALSE;
  225.  
  226.     if (RexxContext) if (RString)
  227.     {
  228.         if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
  229.                     RexxContext->Extension,
  230.                     RexxContext->PortName))
  231.         {
  232.             rmsg->rm_Action=RXCOMM | (StringFile ?
  233.                             (1L << RXFB_STRING):0);
  234.             if (rmsg->rm_Args[0]=CreateArgstring(RString,
  235.                             (LONG)strlen(RString)))
  236.             {
  237.                 /*
  238.                  * We need to find the RexxPort and this needs
  239.                  * to be done in a Forbid()
  240.                  */
  241.                 Forbid();
  242.                 if (RexxPort=FindPort(RXSDIR))
  243.                 {
  244.                     /*
  245.                      * We found the port, so put the
  246.                      * message to ARexx...
  247.                      */
  248.                     PutMsg(RexxPort,(struct Message *)rmsg);
  249.                     RexxContext->Outstanding+=1;
  250.                     flag=TRUE;
  251.                 }
  252.                 else
  253.                 {
  254.                     /*
  255.                      * No port, so clean up...
  256.                      */
  257.                     DeleteArgstring(rmsg->rm_Args[0]);
  258.                     DeleteRexxMsg(rmsg);
  259.                 }
  260.                 Permit();
  261.             }
  262.             else DeleteRexxMsg(rmsg);
  263.         }
  264.     }
  265.     return(flag);
  266. }
  267.  
  268. /*
  269.  * This function closes down the ARexx context that was opened
  270.  * with InitARexx...
  271.  */
  272. void FreeARexx(AREXXCONTEXT RexxContext)
  273. {
  274. register    struct    RexxMsg    *rmsg;
  275.  
  276.     if (RexxContext)
  277.     {
  278.         /*
  279.          * Clear port name so it can't be found...
  280.          */
  281.         RexxContext->PortName[0]='\0';
  282.  
  283.         /*
  284.          * Clean out any outstanding messages we had sent out...
  285.          */
  286.         while (RexxContext->Outstanding)
  287.         {
  288.             WaitPort(RexxContext->ARexxPort);
  289.             while (rmsg=GetARexxMsg(RexxContext))
  290.             {
  291.                 if (rmsg!=REXX_RETURN_ERROR)
  292.                 {
  293.                     /*
  294.                      * Any messages that come now are blown
  295.                      * away...
  296.                      */
  297.                     SetARexxLastError(RexxContext,rmsg,
  298.                                 "99: Port Closed!");
  299.                     ReplyARexxMsg(RexxContext,rmsg,
  300.                             NULL,100);
  301.                 }
  302.             }
  303.         }
  304.  
  305.         /*
  306.          * Clean up the port and delete it...
  307.          */
  308.         if (RexxContext->ARexxPort)
  309.         {
  310.             while (rmsg=GetARexxMsg(RexxContext))
  311.             {
  312.                 /*
  313.                  * Any messages that still are coming in are
  314.                  * "dead"  We just set the LASTERROR and
  315.                  * reply an error of 100...
  316.                  */
  317.                 SetARexxLastError(RexxContext,rmsg,
  318.                             "99: Port Closed!");
  319.                 ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  320.             }
  321.             DeletePort(RexxContext->ARexxPort);
  322.         }
  323.  
  324.         /*
  325.          * Make sure we close the library...
  326.          */
  327.         if (RexxContext->RexxSysBase)
  328.         {
  329.             CloseLibrary(RexxContext->RexxSysBase);
  330.         }
  331.  
  332.         /*
  333.          * Free the memory of the RexxContext
  334.          */
  335.         FreeMem(RexxContext,sizeof(struct ARexxContext));
  336.     }
  337. }
  338.  
  339. /*
  340.  * This routine initializes an ARexx port for your process
  341.  * This should only be done once per process.  You must call it
  342.  * with a valid application name and you must use the handle it
  343.  * returns in all other calls...
  344.  *
  345.  * NOTE:  The AppName should not have spaces in it...
  346.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  347.  *        The name *MUST* be less that 16 characters...
  348.  *        If it is not, it will be trimmed...
  349.  *        The name will also be UPPER-CASED...
  350.  *
  351.  * NOTE:  The Default file name extension, if NULL will be
  352.  *        "rexx"  (the "." is automatic)
  353.  */
  354. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  355. {
  356. register    AREXXCONTEXT    RexxContext=NULL;
  357. register    short        loop;
  358. register    short        count;
  359. register    char        *tmp;
  360.  
  361.     if (RexxContext=AllocMem(sizeof(struct ARexxContext),
  362.                     MEMF_PUBLIC|MEMF_CLEAR))
  363.     {
  364.         if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",
  365.                                 NULL))
  366.         {
  367.             /*
  368.              * Set up the extension...
  369.              */
  370.             if (!Extension) Extension="rexx";
  371.             tmp=RexxContext->Extension;
  372.             for (loop=0;(loop<7)&&(Extension[loop]);loop++)
  373.             {
  374.                 *tmp++=Extension[loop];
  375.             }
  376.             *tmp='\0';
  377.  
  378.             /*
  379.              * Set up a port name...
  380.              */
  381.             tmp=RexxContext->PortName;
  382.             for (loop=0;(loop<16)&&(AppName[loop]);loop++)
  383.             {
  384.                 *tmp++=toupper(AppName[loop]);
  385.             }
  386.             *tmp='\0';
  387.  
  388.             /*
  389.              * Set up the last error RVI name...
  390.              *
  391.              * This is <appname>.LASTERROR
  392.              */
  393.             strcpy(RexxContext->ErrorName,RexxContext->PortName);
  394.             strcat(RexxContext->ErrorName,".LASTERROR");
  395.  
  396.             /* We need to make a unique port name... */
  397.             Forbid();
  398.             for (count=1,RexxContext->ARexxPort=(VOID *)1;
  399.                         RexxContext->ARexxPort;count++)
  400.             {
  401.                 stci_d(tmp,count);
  402.                 RexxContext->ARexxPort=
  403.                         FindPort(RexxContext->PortName);
  404.             }
  405.  
  406.             RexxContext->ARexxPort=CreatePort(
  407.                         RexxContext->PortName,NULL);
  408.             Permit();
  409.         }
  410.  
  411.         if (    (!(RexxContext->RexxSysBase))
  412.              ||    (!(RexxContext->ARexxPort))    )
  413.         {
  414.             FreeARexx(RexxContext);
  415.             RexxContext=NULL;
  416.         }
  417.     }
  418.     return(RexxContext);
  419. }
  420.