Fixed compatibility of output.
[AROS.git] / test / rexx / simplerexx / SimpleRexx.c
blobba6c722846f40d29d58753bc542c29a894d8e5a8
1 /*
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
8 * here.
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>
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdio.h>
32 #if 0
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...
64 #endif
67 * A structure for the ARexx handler context
68 * This is *VERY* *PRIVATE* and should not be touched...
70 struct ARexxContext
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)
92 char *tmp=NULL;
94 if (RexxContext) tmp=RexxContext->PortName;
95 return(tmp);
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)
106 ULONG tmp=0;
108 if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
109 return(tmp);
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;
122 short flag;
124 if (RexxContext)
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"
135 flag=FALSE;
136 if (tmp->rm_Result1) flag=TRUE;
139 * Free the arguments and the message...
141 DeleteArgstring((UBYTE *)tmp->rm_Args[0]);
142 DeleteRexxMsg(tmp);
143 RexxContext->Outstanding-=1;
146 * Return the error if there was one...
148 tmp=flag ? REXX_RETURN_ERROR : NULL;
151 return(tmp);
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)
166 rmsg->rm_Result2=0;
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,
195 char *ErrorString)
197 short OkFlag=FALSE;
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
204 * it works or not.
206 if (!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,
207 (long)strlen(ErrorString)))
209 OkFlag=TRUE;
212 return(OkFlag);
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,
225 short StringFile)
227 struct MsgPort *RexxPort;
228 struct RexxMsg *rmsg;
229 short flag=FALSE;
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()
246 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;
255 flag=TRUE;
257 else
260 * No port, so clean up...
262 DeleteArgstring((UBYTE *)rmsg->rm_Args[0]);
263 DeleteRexxMsg(rmsg);
265 Permit();
267 else DeleteRexxMsg(rmsg);
270 return(flag);
274 * This function closes down the ARexx context that was opened
275 * with InitARexx...
277 void FreeARexx(AREXXCONTEXT RexxContext)
279 struct RexxMsg *rmsg;
281 if (RexxContext)
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
300 * away...
302 SetARexxLastError(RexxContext,rmsg,
303 "99: Port Closed!");
304 ReplyARexxMsg(RexxContext,rmsg,
305 NULL,100);
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,
323 "99: Port Closed!");
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;
362 short loop;
363 short count;
364 char *tmp;
366 if ((RexxContext=AllocMem(sizeof(struct ARexxContext),
367 MEMF_PUBLIC|MEMF_CLEAR)))
369 if ((RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",
370 0)))
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];
381 *tmp='\0';
384 * Set up a port name...
386 tmp=RexxContext->PortName;
387 for (loop=0;(loop<16)&&(AppName[loop]);loop++)
389 *tmp++=toupper(AppName[loop]);
391 *tmp='\0';
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... */
402 Forbid();
403 for (count=1,RexxContext->ARexxPort=(VOID *)1;
404 RexxContext->ARexxPort;count++)
406 #if 0
407 stci_d(tmp,count);
408 #else
409 sprintf(tmp,"_%d",count);
410 #endif
411 RexxContext->ARexxPort=
412 FindPort(RexxContext->PortName);
415 RexxContext->ARexxPort=CreatePort(
416 RexxContext->PortName,0);
417 Permit();
420 if ( (!(RexxContext->RexxSysBase))
421 || (!(RexxContext->ARexxPort)) )
423 FreeARexx(RexxContext);
424 RexxContext=NULL;
427 return(RexxContext);