2 * Simple ARexx interface by Michael Sinz
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
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...
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>
21 #include <proto/exec.h>
22 #include <proto/alib.h>
23 #include <proto/rexxsyslib.h>
25 #include <rexx/storage.h>
26 #include <rexx/rxslib.h>
34 * The prototypes for the few ARexx functions we will call...
36 struct RexxMsg
*CreateRexxMsg(struct MsgPort
*,char *,char *);
37 void *CreateArgstring(char *,long);
38 void DeleteRexxMsg(struct RexxMsg
*);
39 void DeleteArgstring(char *);
40 BOOL
IsRexxMsg(struct Message
*);
43 * Pragmas for the above functions... (To make this all self-contained...)
44 * If you use RexxGlue.o, this is not needed...
46 * These are for Lattice C 5.x (Note the use of RexxContext->RexxSysBase)
48 #pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
49 #pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
50 #pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
51 #pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
52 #pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
55 * Prototypes for the RVI ARexx calls... (link with RexxVars.o)
57 __stdargs
long CheckRexxMsg(struct RexxMsg
*);
58 __stdargs
long GetRexxVar(struct RexxMsg
*,char *,char **);
59 __stdargs
long SetRexxVar(struct RexxMsg
*,char *,char *,long);
62 * Now, we have made the pragmas needed, let's get to work...
67 * A structure for the ARexx handler context
68 * This is *VERY* *PRIVATE* and should not be touched...
72 struct MsgPort
*ARexxPort
; /* The port messages come in at... */
73 struct Library
*RexxSysBase
; /* We will hide the library pointer here... */
74 long Outstanding
; /* The count of outstanding ARexx messages... */
75 char PortName
[24]; /* The port name goes here... */
76 char ErrorName
[28]; /* The name of the <base>.LASTERROR... */
77 char Extension
[8]; /* Default file name extension... */
80 #define AREXXCONTEXT struct ARexxContext *
82 #include "SimpleRexx.h"
85 * This function returns the port name of your ARexx port.
86 * It will return NULL if there is no ARexx port...
88 * This string is *READ ONLY* You *MUST NOT* modify it...
90 char *ARexxName(AREXXCONTEXT RexxContext
)
94 if (RexxContext
) tmp
=RexxContext
->PortName
;
99 * This function returns the signal mask that the Rexx port is
100 * using. It returns NULL if there is no signal...
102 * Use this signal bit in your Wait() loop...
104 ULONG
ARexxSignal(AREXXCONTEXT RexxContext
)
108 if (RexxContext
) tmp
=1L << (RexxContext
->ARexxPort
->mp_SigBit
);
113 * This function returns a structure that contains the commands sent from
114 * ARexx... You will need to parse it and return the structure back
115 * so that the memory can be freed...
117 * This returns NULL if there was no message...
119 struct RexxMsg
*GetARexxMsg(AREXXCONTEXT RexxContext
)
121 struct RexxMsg
*tmp
=NULL
;
125 if ((tmp
=(struct RexxMsg
*)GetMsg(RexxContext
->ARexxPort
)))
127 if (tmp
->rm_Node
.mn_Node
.ln_Type
==NT_REPLYMSG
)
130 * If we had sent a command, it would come this way...
132 * Since we don't in this simple example, we just throw
133 * away anything that looks "strange"
136 if (tmp
->rm_Result1
) flag
=TRUE
;
139 * Free the arguments and the message...
141 DeleteArgstring((UBYTE
*)tmp
->rm_Args
[0]);
143 RexxContext
->Outstanding
-=1;
146 * Return the error if there was one...
148 tmp
=flag
? REXX_RETURN_ERROR
: NULL
;
155 * Use this to return a ARexx message...
157 * If you wish to return something, it must be in the RString.
158 * If you wish to return an Error, it must be in the Error.
159 * If there is an error, the RString is ignored.
161 void ReplyARexxMsg(AREXXCONTEXT RexxContext
,struct RexxMsg
*rmsg
,
162 char *RString
,LONG Error
)
164 if (RexxContext
) if (rmsg
) if (rmsg
!=REXX_RETURN_ERROR
)
167 if (!(rmsg
->rm_Result1
=Error
))
170 * if you did not have an error we return the string
172 if (rmsg
->rm_Action
& (1L << RXFB_RESULT
)) if (RString
)
174 rmsg
->rm_Result2
=(IPTR
)CreateArgstring(RString
,
175 (LONG
)strlen(RString
));
180 * Reply the message to ARexx...
182 ReplyMsg((struct Message
*)rmsg
);
187 * This function will set an error string for the ARexx
188 * application in the variable defined as <appname>.LASTERROR
190 * Note that this can only happen if there is an ARexx message...
192 * This returns TRUE if it worked, FALSE if it did not...
194 short SetARexxLastError(AREXXCONTEXT RexxContext
,struct RexxMsg
*rmsg
,
199 if (RexxContext
) if (rmsg
) if (CheckRexxMsg(rmsg
))
202 * Note that SetRexxVar() has more than just a TRUE/FALSE
203 * return code, but for this "basic" case, we just care if
206 if (!SetRexxVar(rmsg
,RexxContext
->ErrorName
,ErrorString
,
207 (long)strlen(ErrorString
)))
216 * This function will send a string to ARexx...
218 * The default host port will be that of your task...
220 * If you set StringFile to TRUE, it will set that bit for the message...
222 * Returns TRUE if it send the message, FALSE if it did not...
224 short SendARexxMsg(AREXXCONTEXT RexxContext
,char *RString
,
227 struct MsgPort
*RexxPort
;
228 struct RexxMsg
*rmsg
;
231 if (RexxContext
) if (RString
)
233 if ((rmsg
=CreateRexxMsg(RexxContext
->ARexxPort
,
234 RexxContext
->Extension
,
235 RexxContext
->PortName
)))
237 rmsg
->rm_Action
=RXCOMM
| (StringFile
?
238 (1L << RXFB_STRING
):0);
239 if ((rmsg
->rm_Args
[0]=(IPTR
)CreateArgstring(RString
,
240 (LONG
)strlen(RString
))))
243 * We need to find the RexxPort and this needs
244 * to be done in a Forbid()
247 if ((RexxPort
=FindPort(RXSDIR
)))
250 * We found the port, so put the
251 * message to ARexx...
253 PutMsg(RexxPort
,(struct Message
*)rmsg
);
254 RexxContext
->Outstanding
+=1;
260 * No port, so clean up...
262 DeleteArgstring((UBYTE
*)rmsg
->rm_Args
[0]);
267 else DeleteRexxMsg(rmsg
);
274 * This function closes down the ARexx context that was opened
277 void FreeARexx(AREXXCONTEXT RexxContext
)
279 struct RexxMsg
*rmsg
;
284 * Clear port name so it can't be found...
286 RexxContext
->PortName
[0]='\0';
289 * Clean out any outstanding messages we had sent out...
291 while (RexxContext
->Outstanding
)
293 WaitPort(RexxContext
->ARexxPort
);
294 while ((rmsg
=GetARexxMsg(RexxContext
)))
296 if (rmsg
!=REXX_RETURN_ERROR
)
299 * Any messages that come now are blown
302 SetARexxLastError(RexxContext
,rmsg
,
304 ReplyARexxMsg(RexxContext
,rmsg
,
311 * Clean up the port and delete it...
313 if (RexxContext
->ARexxPort
)
315 while ((rmsg
=GetARexxMsg(RexxContext
)))
318 * Any messages that still are coming in are
319 * "dead" We just set the LASTERROR and
320 * reply an error of 100...
322 SetARexxLastError(RexxContext
,rmsg
,
324 ReplyARexxMsg(RexxContext
,rmsg
,NULL
,100);
326 DeletePort(RexxContext
->ARexxPort
);
330 * Make sure we close the library...
332 if (RexxContext
->RexxSysBase
)
334 CloseLibrary(RexxContext
->RexxSysBase
);
338 * Free the memory of the RexxContext
340 FreeMem(RexxContext
,sizeof(struct ARexxContext
));
345 * This routine initializes an ARexx port for your process
346 * This should only be done once per process. You must call it
347 * with a valid application name and you must use the handle it
348 * returns in all other calls...
350 * NOTE: The AppName should not have spaces in it...
351 * Example AppNames: "MyWord" or "FastCalc" etc...
352 * The name *MUST* be less that 16 characters...
353 * If it is not, it will be trimmed...
354 * The name will also be UPPER-CASED...
356 * NOTE: The Default file name extension, if NULL will be
357 * "rexx" (the "." is automatic)
359 AREXXCONTEXT
InitARexx(char *AppName
,char *Extension
)
361 AREXXCONTEXT RexxContext
=NULL
;
366 if ((RexxContext
=AllocMem(sizeof(struct ARexxContext
),
367 MEMF_PUBLIC
|MEMF_CLEAR
)))
369 if ((RexxContext
->RexxSysBase
=OpenLibrary("rexxsyslib.library",
373 * Set up the extension...
375 if (!Extension
) Extension
="rexx";
376 tmp
=RexxContext
->Extension
;
377 for (loop
=0;(loop
<7)&&(Extension
[loop
]);loop
++)
379 *tmp
++=Extension
[loop
];
384 * Set up a port name...
386 tmp
=RexxContext
->PortName
;
387 for (loop
=0;(loop
<16)&&(AppName
[loop
]);loop
++)
389 *tmp
++=toupper(AppName
[loop
]);
394 * Set up the last error RVI name...
396 * This is <appname>.LASTERROR
398 strcpy(RexxContext
->ErrorName
,RexxContext
->PortName
);
399 strcat(RexxContext
->ErrorName
,".LASTERROR");
401 /* We need to make a unique port name... */
403 for (count
=1,RexxContext
->ARexxPort
=(VOID
*)1;
404 RexxContext
->ARexxPort
;count
++)
409 sprintf(tmp
,"_%d",count
);
411 RexxContext
->ARexxPort
=
412 FindPort(RexxContext
->PortName
);
415 RexxContext
->ARexxPort
=CreatePort(
416 RexxContext
->PortName
,0);
420 if ( (!(RexxContext
->RexxSysBase
))
421 || (!(RexxContext
->ARexxPort
)) )
423 FreeARexx(RexxContext
);