home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / CD32 / CD32_Support / examples / SA_Examples / cd / CDTest / simplerexx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-31  |  9.8 KB  |  415 lines

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