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