disable the unrecognized nls flag
[AROS-Contrib.git] / regina / rexxsaa.c
blobf7dd3a6bb1dba1c68a1ab93a26b7955629c38c15
1 /*
2 * The Regina Rexx Interpreter
3 * Copyright (C) 1993-1994 Anders Christensen <anders@pvv.unit.no>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * This file implements the client part of the SAA API when Regina
22 * is linked into a program using SAA API. There is one routine for
23 * each of the functions in SAA API, and the functionality is partly
24 * implemented here, and partly by calling subroutines in Regina.
25 * Note that the interface to Regina is as simple as possible, so that
26 * a multitude of different transport mechanisms can be used (although
27 * normal linking is probably the most common.
29 * The following SAA API functions is defined in this source file:
31 * RexxStart() --- execute Rexx code
32 * RexxRegisterSubcomExe() --- register subcommand handler
33 * RexxRegisterSubcomDll() --- ditto (from dynamic library)
34 * RexxQuerySubcom() --- query subcommand handler
35 * RexxDeregisterSubcom() --- deregister subcommand handler
36 * RexxVariablePool() --- handle Rexx variable manipulation
37 * RexxRegisterExitExe() --- register exit handler
38 * RexxRegisterExitDll() --- ditto (from dynamic library)
39 * RexxDeregisterExit() --- deregister exit handler
40 * RexxQueryExit() --- query exit handler
41 * RexxRegisterFunctionExe() --- register external function handler
42 * RexxRegisterFunctionDll() --- ditto (from dynamic library)
43 * RexxQueryFunction() --- query external function
44 * RexxDeregisterFunction() --- deregister external function
45 * RexxSetHalt() --- set Halt and Trace
46 * RexxCreateQueue() --- create named queued
47 * RexxDeleteQueue() --- delete named queued
48 * RexxQueryQueue() --- query named queued
49 * RexxAddQueue() --- add line to named queued
50 * RexxPullQueue() --- pull line from named queued
51 * RexxAddMacro() --- add a macro to macrospace
52 * RexxClearMacroSpace() --- remove all macros from macrospace
53 * RexxDropMacro() --- remove macro from macrospace
54 * RexxLoadMacroSpace() --- load macrospace macros from file
55 * RexxQueryMacro() --- find a macro's search order
56 * RexxReorderMacro() --- change the search order for a macro
57 * RexxSaveMacroSpace() --- save macrospace to file
59 * These functions are Regina extensions
60 * RexxFreeMemory() --- free memory allocated by Rexx API
61 * RexxAllocateMemory() --- allocate memory to be freed by Rexx API
62 * RexxCallBack() --- execute an internal procedure within the running script
63 * ReginaVersion() --- version information
64 * ReginaCleanup() --- generic cleanup routine
66 * These functions are all defined in the doc for SAA API. In addition,
67 * a number of calls in Regina are called, as well as a number of calls
68 * are defined for use by Regina. These all start with the prefix Ifc.
69 * First the one defined in rexxsaa.c, which can be called from other
70 * parts of Regina:
72 * IfcSubCmd() --- invoke a subcommand
73 * IfcDoExit() --- invoke a system exit handler
74 * IfcExecFunc() --- invoke an external function handler
75 * IfcExecFuncDll() --- invoke an external function handler in a DLL
77 * Then the functions which are defined elsewhere, which can be called
78 * by this source code:
80 * IfcExecScript() --- start to execute Rexx code
81 * IfcExecCallBack() --- start to execute Rexx procedure
82 * IfcVarPool() --- handle a variable manipulation request
83 * IfcRegFunc() --- register an external function name
84 * IfcDelFunc() --- deregister an external function name
85 * IfcQueryFunc() --- queries an external function name
86 * IfcAllocateMemory() --- allocate memory for API user
87 * IfcFreeMemory() --- free memory from API user
88 * IfcDeleteQueue() --- delete queue
89 * IfcAddQueue() --- add a line to the queue
90 * IfcPullQueue() --- pull a line off the queue
92 * All these routines are properly defined in the documentation for
93 * Regina. Other than the functions listed, the code in this file has
94 * been isolated as far as possible, and no functions specific to
95 * Regina is used, not even for memory allocation.
99 * We need to define these symbols in order to get the proper macros,
100 * datatypes, and declaration when including rexxsaa.h.
102 #define INCL_RXSHV
103 #define INCL_RXSUBCOM
104 #define INCL_RXFUNC
105 #define INCL_RXSYSEXIT
106 #define INCL_RXARI
107 #define INCL_RXQUEUE
108 #define INCL_RXMACRO
110 #include "regina_c.h"
112 #ifdef HAVE_CONFIG_H
113 # include "config.h"
114 #endif
117 * The rexxsaa.h header file defines the interface between this file and
118 * the client program which uses SAA API. The rxiface.h header file
119 * defines the interface between this file and Regina.
121 #include "configur.h"
123 * The following #define __REGINA_INTERNAL stops an error with MingW32
126 #define __REGINA_INTERNAL
127 #include "rexxsaa.h"
128 #include "defs.h"
129 #define DONT_TYPEDEF_PFN
130 #ifndef RXLIB
131 #define RXLIB
132 #endif
133 #include "rexx.h"
134 #if defined(DYNAMIC) && defined(HAVE_GCI)
135 # include "gci/gci.h"
136 #endif
137 #include "rxiface.h"
138 #include "extstack.h"
140 #include <limits.h>
141 #include <stdio.h>
142 #include <string.h>
143 #ifdef HAVE_UNISTD_H
144 # include <unistd.h>
145 #endif
146 #ifdef HAVE_ASSERT_H
147 # include <assert.h>
148 #endif
149 #include <stdlib.h>
150 #include <errno.h>
151 #include <fcntl.h>
152 #include <setjmp.h>
154 #if defined(__EPOC32__) || defined(__WINS__)
155 # ifdef APIRET
156 # undef APIRET
157 # endif
158 # define APIRET unsigned long
159 # ifdef APIENTRY
160 # undef APIENTRY
161 # endif
162 #else
163 # define EXPORT_C
164 #endif
166 typedef union {
167 RXFNCCAL_PARM fnccal ;
168 RXCMDHST_PARM cmdhst ;
169 RXMSQPLL_PARM msqpll ;
170 RXMSQPSH_PARM msqpsh ;
171 RXMSQSIZ_PARM msqsiz ;
172 RXMSQNAM_PARM msqnam ;
173 RXSIOSAY_PARM siosay ;
174 RXSIOTRC_PARM siotrc ;
175 RXSIOTRD_PARM siotrd ;
176 RXSIODTR_PARM siodtr ;
177 RXHLTTST_PARM hlttst ;
178 RXTRCTST_PARM trctst ;
179 RXENVGET_PARM envget ;
180 RXENVSET_PARM envset ;
181 RXCWDGET_PARM cwdget ;
182 RXCWDSET_PARM cwdset ;
183 } EXIT ;
185 /* The following value allows called programs to call "free" to the return
186 * parameters without destroying our stack.
188 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
190 typedef struct { /* rex_tsd: static variables of this module (thread-safe) */
191 struct ExitHandlers *CurrentHandlers ;
192 } rex_tsd_t; /* thread-specific but only needed by this module. see
193 * init_rexxsaa
196 #define EXT_FUNCS_COUNT (sizeof(rt->saafuncs) / sizeof(rt->saafuncs[0]))
198 struct ExitHandlers
200 RexxExitHandler *(Handlers[RXNOOFEXITS]) ; /* for RexxRegisterExitExe */
201 struct ExitHandlers *prev ;
205 * The following RXMAP_TYPE() macro maps from the SAA API macros holding
206 * the type of an invocation (function, subroutine or command), to its
207 * equivalent value in the internal interface of Regina (as defined in
208 * the file rxiface.h
210 #define RXMAP_TYPE(a) ((a)==RXCOMMAND ? RX_TYPE_COMMAND : \
211 (a)==RXFUNCTION ? RX_TYPE_FUNCTION : RX_TYPE_SUBROUTINE)
214 /* init_rexxsaa initializes the module.
215 * Currently, we set up the thread specific data.
216 * The function returns 1 on success, 0 if memory is short.
218 int init_rexxsaa( tsd_t *TSD )
220 rex_tsd_t *rt;
222 if (TSD->rex_tsd != NULL)
223 return(1);
225 if ( ( TSD->rex_tsd = MallocTSD( sizeof(rex_tsd_t) ) ) == NULL )
226 return(0);
227 rt = (rex_tsd_t *)TSD->rex_tsd;
228 memset( rt, 0, sizeof(rex_tsd_t) ); /* correct for all values */
229 return(1);
232 /* deinit_rexxsaa deinitializes the module and frees used memory blocks not
233 * allocated by the Malloc-Interface. There isn't anything to do currently.
235 void deinit_rexxsaa( tsd_t *TSD )
240 /* StartupInterface initializes the Rexx system once per thread. Values
241 * like __regina_get_tsd()->systeminfo are set. The true purpose of this
242 * function is to create an environment which allows the run of the
243 * interpreter. This is exactly the case when systeminfo exists. The last
244 * systeminfo is hopefully never deleted but that won't do any harm if we
245 * reinitialize the Rexx environment.
247 * There is a three-stage step to let a Rexx program run:
248 * 1) Initialize the runtime system and programming environment. This is
249 * done by __regina_get_tsd() done in GLOBAL_ENTRY_POINT().
250 * After this call you may use Malloc() and friends: basic things.
251 * 2) Initialize the Rexx system. This is done by
252 * setup_system() here or directly by any other caller of
253 * __regina_faked_main() or main():
254 * You are then allowed to access variables from the variable pool, load
255 * a Rexx program or just call a Rexx API function.
256 * Hint: The detection of this step is done as follows:
257 * Rexx_system_is_running = (__regina_get_tsd()->systeminfo != NULL);
258 * or a similar compare.
259 * 3) Load the Rexx program in memory.
260 * Although you don't know, what program is currently loaded, you can
261 * check if a program is loaded (and running) by checking:
262 * Program_running = (__regina_get_tsd()->systeminfo->tree.root != NULL);
263 * This step is done in RexxStart or by main()/__regina_faked_main() when
264 * called as a program.
265 * Never use __regina_get_tsd() when it is not needed, of course.
266 * This function should be called as GLOBAL_ENTRY_POINT() at the very
267 * start of the interpreter but after GLOBAL_ENTRY_POINT.
269 static void StartupInterface( tsd_t *TSD )
271 if (TSD->systeminfo != NULL)
272 return;
274 setup_system( TSD, 1 );
275 signal_setup( TSD );
280 * FillReq prepares a String with a given Length to be exported to an
281 * external application.
282 * The FillReq() function takes as parameter a pointer to a VarPool()
283 * request structure variable, and the definition of a string, and
284 * fill the content of the string into the request block. Note that the
285 * third parameter is gobbled up, so it can not be used or released by
286 * the calling function afterwards. Also, there are two macros defined,
287 * which gives a better access to the contents of the function
289 #define FillReqName(a,b,c) FillReq(a,b,c,1)
290 #define FillReqValue(a,b,c) FillReq(a,b,c,0)
292 static void FillReq( PSHVBLOCK Req, ULONG Length, const char *String, int name )
294 RXSTRING *string;
295 ULONG *strlen;
297 string = name ? &Req->shvname : &Req->shvvalue;
298 strlen = name ? &Req->shvnamelen : &Req->shvvaluelen;
300 * SAA DOCUMENTATION BREAKAGE:
301 * As stated in README.08h the OS/2 REXX modifies shvvaluelen instead of
302 * shvvalue.strlength (name in the same way). Some software out there
303 * relies on this behaviour. Sigh.
304 * Thus we assign the shv???len parts too, as ORexx does.
308 * If the string is undefined, set ->strptr to NULL. It is not required
309 * that the lengths parameters are set to zero, but I'll do this as
310 * nice gest to the users; someone is probably going to believe that
311 * this is how the data is returned.
312 * shvnamelen and shvvaluelen are read-only values describing the maximum
313 * size of the destination buffer, but see above at SAA DOCUMENTATION.
315 if ( (LONG)Length == RX_NO_STRING )
317 MAKERXSTRING( *string, NULL, 0 );
318 *strlen = 0;
319 return;
323 * If a string was supplied, use it, else allocate sufficient space.
324 * The then part of the if will just copy the data to the user-supplied
325 * return string data area, noting a truncation is one occurred.
327 if ( RXSTRPTR( *string ) )
330 * We need a terminator, therefore we need one byte more for allocation.
331 * We may come to the funny situation indicating a truncation but have
332 * copied all bytes from the string.
334 if ( *strlen <= Length )
336 Req->shvret |= RXSHV_TRUNC;
337 Length = *strlen;
339 else
341 string->strptr[Length] = '\0';
343 memcpy(string->strptr, String, Length );
344 string->strlength = Length;
346 * shvnamelen and shvvaluelen are read-only values describing the maximum
347 * size of the destination buffer, but see above at SAA DOCUMENTATION.
349 *strlen = Length;
351 else
354 * The else part of the if will allocate new space for the data, and
355 * fills in the data, or return a memory fault if data could not
356 * properly be allocated.
358 * We have to ASCII0-terminate the string silently
360 string->strptr = (char *)IfcAllocateMemory( Length + 1 );
361 if ( string->strptr )
363 if ( Length )
364 memcpy( string->strptr, String, Length );
365 string->strptr[Length] = '\0';
366 string->strlength = Length;
368 else
370 Req->shvret |= RXSHV_MEMFL;
372 * Set strlength for convenience.
374 string->strlength = 0;
375 Length = 0;
378 * shvnamelen and shvvaluelen are read-only values describing the maximum
379 * size of the destination buffer, but see above at SAA DOCUMENTATION.
381 *strlen = Length;
385 /* ======================================================================== */
387 /* RetLen and RetStr should point to {0,NULL}. They will be filled with
388 * freshly allocated values. A return value will always exist.
390 int IfcSubCmd( tsd_t *TSD, int EnvLen, const char *EnvStr,
391 int CmdLen, const char *CmdStr,
392 int *RetLen, char **RetStr )
394 RXSTRING Cmd, Ret ;
395 char *OldResult= NULL ;
396 USHORT Flags=0 ;
397 char *Command ;
398 char *EnvNam;
399 struct entry_point *Envir;
400 int rvalue=0, RCode=0, rc=RXEXIT_NOT_HANDLED ;
401 char subcmd_result[ILLEGAL_USE_SIZE+RXAUTOBUFLEN] ;
402 RXCMDHST_PARM cmdhst;
403 PUCHAR parm=NULL;
404 rex_tsd_t *rt;
406 rt = (rex_tsd_t *)TSD->rex_tsd;
408 Command = (char *)MallocTSD( CmdLen + 1);
409 memcpy(Command,CmdStr,CmdLen);
410 Command[CmdLen] = '\0';
411 memset( subcmd_result, 0, sizeof( subcmd_result ) ) ;
412 MAKERXSTRING( Cmd, Command, CmdLen ) ;
413 MAKERXSTRING( Ret, subcmd_result + ILLEGAL_USE_SIZE, RXAUTOBUFLEN) ;
414 OldResult = subcmd_result + ILLEGAL_USE_SIZE;
416 * Terminate the command string with nul character
418 Envir = subcom_hook( TSD, EnvStr , EnvLen ) ;
419 if ( rt->CurrentHandlers && rt->CurrentHandlers->Handlers[RXCMD] )
421 EnvNam = (char *)MallocTSD( EnvLen + 1 ) ;
422 memcpy(EnvNam, EnvStr, EnvLen ) ;
423 EnvNam[EnvLen] = '\0';
424 cmdhst.rxcmd_flags.rxfcfail = 0;
425 cmdhst.rxcmd_flags.rxfcerr = 0;
426 cmdhst.rxcmd_command = Cmd ;
427 cmdhst.rxcmd_address = (unsigned char *)EnvNam ;
428 cmdhst.rxcmd_addressl = (USHORT) EnvLen ;
429 cmdhst.rxcmd_retc = Ret;
430 cmdhst.rxcmd_dll = NULL;
431 cmdhst.rxcmd_dll_len = 0;
432 if ( Envir != NULL )
434 if ( Envir->lib != NULL )
436 cmdhst.rxcmd_dll = (unsigned char*) Str_val( Envir->lib->name ) ;
437 cmdhst.rxcmd_dll_len = Str_len( Envir->lib->name );
440 parm = (PUCHAR)&cmdhst;
441 rc = (*(rt->CurrentHandlers->Handlers[RXCMD]))(RXCMD, RXCMDHST, parm);
442 TSD->var_indicator = 0;
443 assert( rc==RXEXIT_HANDLED || rc==RXEXIT_NOT_HANDLED ||
444 rc==RXEXIT_RAISE_ERROR ) ;
445 if (cmdhst.rxcmd_flags.rxfcerr)
446 RCode = RXFLAG_ERROR ;
447 else if (cmdhst.rxcmd_flags.rxfcfail)
448 RCode = RXFLAG_FAILURE ;
449 else
450 RCode = RXFLAG_OK;
451 Ret = cmdhst.rxcmd_retc;
452 FreeTSD( EnvNam ) ;
454 if (rc == RXEXIT_NOT_HANDLED)
456 if ( Envir )
458 RexxSubcomHandler *handler;
459 handler = (RexxSubcomHandler *) Envir->addr;
460 MAKERXSTRING( Cmd, Command, CmdLen ) ;
461 if (Ret.strlength && OldResult != Ret.strptr) /* Ignore return values*/
462 IfcFreeMemory( Ret.strptr ) ;
463 MAKERXSTRING( Ret, subcmd_result + ILLEGAL_USE_SIZE, RXAUTOBUFLEN) ;
464 OldResult = subcmd_result + ILLEGAL_USE_SIZE ;
465 rvalue = handler( &Cmd, &Flags, &Ret ) ;
466 (void)rvalue; // FIXME: Should this be tested?
467 TSD->var_indicator = 0;
468 if (Flags==RXSUBCOM_OK)
469 RCode = RXFLAG_OK ;
470 else if (Flags==RXSUBCOM_ERROR)
471 RCode = RXFLAG_ERROR ;
472 else if (Flags==RXSUBCOM_FAILURE)
473 RCode = RXFLAG_FAILURE ;
474 else
475 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
477 else
479 RCode = RXFLAG_NOTREG ;
480 Ret.strlength = 0 ;
484 if (Ret.strlength)
486 *RetLen = Ret.strlength ;
487 *RetStr = (char *)MallocTSD( Ret.strlength ) ;
488 memcpy( *RetStr, Ret.strptr, Ret.strlength ) ;
490 else
492 *RetLen = 1 ;
493 *RetStr = (char *)MallocTSD( 1 ) ;
494 (*RetStr)[0] = '0' ;
497 if (Ret.strlength && OldResult != Ret.strptr)
498 IfcFreeMemory( Ret.strptr ) ;
500 FreeTSD(Command);
501 return RCode ;
504 /* IfcDoExit calls an exit handler with one of the following codes set in Code.
505 * The arguments may either be input or output or nothing but not both.
506 * Parameter INIT TERMIN PULL TRCIN STDOUT STDERR GETENV PUTENV
507 * ---------------------------------------------------------------------------------------
508 * InputLength NULL NULL set set NULL NULL set NULL
509 * InputString NULL NULL set set NULL NULL set NULL
510 * OutputLength1 0 0 0 0 set set set set
511 * OutputString1 NULL NULL NULL NULL set set set set
512 * OutputLength2 0 0 0 0 0 0 0 set
513 * OutputString2 NULL NULL NULL NULL NULL NULL NULL set
515 * Notes:
516 * 1) An output string should always be a fresh copy. Although it is not
517 * allowed the user program may destroy the contents.
518 * For this reason OutputString is not declared as const.
519 * OutputString should be 0-terminated (0 not counted in OutputLength).
520 * 2) An input string is normally NOT required. Just provide a position
521 * where to place the input to. Example:
522 * char *in = NULL;
523 * int inlen = 0;
524 * IfcDoExit(?,?,0,NULL,0,NULL,&inlen,&in);
525 * If the caller of this function provides a valid input string it is
526 * ignored on exit. This function always returns back a freshly allocated
527 * string in InputString (an empty string in case of errors).
528 * 3) The user may change or overwrite the outcome of an exit like the return
529 * values to functions. A user-allocated string will be freed.
531 int IfcDoExit( tsd_t *TSD, int Code,
532 int OutputLength1, char *OutputString1,
533 int OutputLength2, char *OutputString2,
534 int *InputLength, char **InputString )
536 int rc=0;
537 LONG SubCode=0, MainCode=0 ;
538 ULONG retlen=0;
539 char *retstr=NULL;
540 char *mustFree;
541 RXSIOSAY_PARM siosay;
542 RXSIOTRD_PARM siotrd;
543 RXSIODTR_PARM siodtr;
544 RXENVSET_PARM envset;
545 RXENVGET_PARM envget;
546 RXCWDSET_PARM cwdset;
547 RXCWDGET_PARM cwdget;
548 PEXIT parm=NULL;
549 rex_tsd_t *rt;
551 rt = (rex_tsd_t *)TSD->rex_tsd;
553 MAKERXSTRING( siodtr.rxsiodtr_retc, NULL, 0) ; /* Make compiler happy */
554 MAKERXSTRING( siotrd.rxsiotrd_retc, NULL, 0) ; /* Make compiler happy */
555 MAKERXSTRING( envget.rxenv_value, NULL, 0) ; /* Make compiler happy */
556 MAKERXSTRING( cwdget.rxcwd_value, NULL, 0) ; /* Make compiler happy */
558 switch (Code)
560 case RX_EXIT_STDERR:
561 case RX_EXIT_STDOUT:
562 assert(InputLength == NULL &&
563 InputString == NULL &&
564 OutputLength2 == 0 &&
565 OutputString2 == NULL &&
566 OutputLength2 == 0 &&
567 OutputString2 == NULL);
568 siosay.rxsio_string.strptr = OutputString1 ;
569 siosay.rxsio_string.strlength = OutputLength1 ;
570 parm = (PEXIT)&siosay;
571 SubCode = (Code==RX_EXIT_STDOUT) ? RXSIOSAY : RXSIOTRC ;
572 MainCode = RXSIO ;
574 break ;
576 case RX_EXIT_TRCIN:
577 assert(OutputLength1 == 0 &&
578 OutputString1 == NULL &&
579 InputLength != NULL &&
580 InputString != NULL &&
581 OutputLength2 == 0 &&
582 OutputString2 == NULL);
583 siodtr.rxsiodtr_retc.strlength = *InputLength ;
584 siodtr.rxsiodtr_retc.strptr = *InputString ;
585 parm = (PEXIT)&siodtr;
586 SubCode = RXSIODTR ;
587 MainCode = RXSIO ;
588 break ;
590 case RX_EXIT_PULL:
591 assert(OutputLength1 == 0 &&
592 OutputString1 == NULL &&
593 InputLength != NULL &&
594 InputString != NULL &&
595 OutputLength2 == 0 &&
596 OutputString2 == NULL);
597 siotrd.rxsiotrd_retc.strlength = *InputLength ;
598 siotrd.rxsiotrd_retc.strptr = *InputString ;
599 parm = (PEXIT)&siotrd;
600 SubCode = RXSIOTRD ;
601 MainCode = RXSIO ;
602 break ;
604 case RX_EXIT_INIT:
605 assert(OutputLength1 == 0 &&
606 OutputString1 == NULL &&
607 InputLength == NULL &&
608 InputString == NULL &&
609 OutputLength2 == 0 &&
610 OutputString2 == NULL);
611 MainCode = RXINI ;
612 SubCode = RXINIEXT ;
613 break ;
615 case RX_EXIT_TERMIN:
616 assert(OutputLength1 == 0 &&
617 OutputString1 == NULL &&
618 InputLength == NULL &&
619 InputString == NULL &&
620 OutputLength2 == 0 &&
621 OutputString2 == NULL);
622 MainCode = RXTER ;
623 SubCode = RXTEREXT ;
624 break ;
626 case RX_EXIT_SETENV:
627 assert(InputLength == NULL &&
628 InputString == NULL &&
629 OutputLength1 != 0 &&
630 OutputString1 != NULL &&
631 OutputLength2 != 0 &&
632 OutputString2 != NULL);
633 envset.rxenv_name.strptr = OutputString1 ;
634 envset.rxenv_name.strlength = OutputLength1 ;
635 envset.rxenv_value.strptr = OutputString2 ;
636 envset.rxenv_value.strlength = OutputLength2 ;
637 parm = (PEXIT)&envset;
638 MainCode = RXENV ;
639 SubCode = RXENVSET ;
640 break ;
642 case RX_EXIT_GETENV:
643 assert(OutputLength1 != 0 &&
644 OutputString1 != NULL &&
645 InputLength != NULL &&
646 InputString != NULL &&
647 OutputLength2 == 0 &&
648 OutputString2 == NULL);
649 envget.rxenv_value.strlength = *InputLength ;
650 envget.rxenv_value.strptr = *InputString ;
651 envget.rxenv_name.strptr = OutputString1 ;
652 envget.rxenv_name.strlength = OutputLength1 ;
653 parm = (PEXIT)&envget;
654 SubCode = RXENVGET ;
655 MainCode = RXENV ;
656 break ;
658 case RX_EXIT_SETCWD:
659 assert(InputLength == NULL &&
660 InputString == NULL &&
661 OutputLength1 != 0 &&
662 OutputString1 != NULL);
663 cwdset.rxcwd_value.strptr = OutputString1 ;
664 cwdset.rxcwd_value.strlength = OutputLength1 ;
665 parm = (PEXIT)&cwdset;
666 MainCode = RXENV ;
667 SubCode = RXCWDSET ;
668 break ;
670 case RX_EXIT_GETCWD:
671 assert(OutputLength1 == 0 &&
672 OutputString1 == NULL &&
673 InputLength != NULL &&
674 InputString != NULL &&
675 OutputLength2 == 0 &&
676 OutputString2 == NULL);
677 cwdget.rxcwd_value.strlength = *InputLength ;
678 cwdget.rxcwd_value.strptr = *InputString ;
679 parm = (PEXIT)&cwdget;
680 SubCode = RXCWDGET ;
681 MainCode = RXENV ;
682 break ;
684 default:
685 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
686 break;
689 assert( rt->CurrentHandlers->Handlers[MainCode] ) ;
691 rc = (*(rt->CurrentHandlers->Handlers[MainCode]))(MainCode, SubCode, parm);
692 TSD->var_indicator = 0;
693 assert( rc==RXEXIT_HANDLED || rc==RXEXIT_NOT_HANDLED ||
694 rc==RXEXIT_RAISE_ERROR ) ;
696 mustFree = NULL;
697 switch (Code)
699 case RX_EXIT_STDERR:
700 case RX_EXIT_STDOUT:
701 case RX_EXIT_INIT:
702 case RX_EXIT_TERMIN:
703 case RX_EXIT_SETENV:
704 case RX_EXIT_SETCWD:
705 break ;
707 case RX_EXIT_TRCIN:
708 retlen = siodtr.rxsiodtr_retc.strlength ;
709 retstr = siodtr.rxsiodtr_retc.strptr ;
710 mustFree = ( retstr != *InputString ) ? retstr : NULL;
711 break ;
713 case RX_EXIT_PULL:
714 retlen = siotrd.rxsiotrd_retc.strlength ;
715 retstr = siotrd.rxsiotrd_retc.strptr ;
716 mustFree = ( retstr != *InputString ) ? retstr : NULL;
717 break ;
719 case RX_EXIT_GETENV:
720 retlen = envget.rxenv_value.strlength ;
721 retstr = envget.rxenv_value.strptr ;
722 mustFree = ( retstr != *InputString ) ? retstr : NULL;
723 break ;
725 case RX_EXIT_GETCWD:
726 retlen = cwdget.rxcwd_value.strlength ;
727 retstr = cwdget.rxcwd_value.strptr ;
728 mustFree = ( retstr != *InputString ) ? retstr : NULL;
729 break ;
731 default:
732 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
735 if (rc==RXEXIT_HANDLED)
736 rc = RX_HOOK_NOPE ;
737 else if (rc==RXEXIT_NOT_HANDLED)
738 rc = RX_HOOK_GO_ON ;
739 else if (rc==RXEXIT_RAISE_ERROR)
740 rc = RX_HOOK_ERROR ;
742 if (InputLength != NULL) /* retlen and retstr forms a return string. */
744 if ((retlen == 0) || (retstr == NULL))
746 retlen = 0;
747 retstr = "";
750 /* Make a fresh copy, the user may change the value very fast. */
751 *InputString = (char *)MallocTSD( (retlen < 1) ? 1 : retlen );
752 memcpy(*InputString, retstr, retlen);
753 *InputLength = retlen;
756 if ( mustFree )
757 IfcFreeMemory( mustFree );
758 return rc ;
761 /* ================================================================ */
762 /* ================ general purpose API functions ================= */
764 /* You are not allowed to use TSD or __regina_get_tsd() here! */
765 EXPORT_C APIRET APIENTRY RexxFreeMemory(PVOID MemoryBlock )
767 if (!MemoryBlock)
768 return(RXFUNC_BADTYPE);
770 return IfcFreeMemory( MemoryBlock );
773 /* You are not allowed to use TSD or __regina_get_tsd() here! */
774 EXPORT_C PVOID APIENTRY RexxAllocateMemory(ULONG size )
776 return IfcAllocateMemory( size );
779 /* ================================================================ */
780 /* ================ in order to start Rexx scripts ================ */
782 EXPORT_C APIRET APIENTRY RexxStart(LONG ArgCount,
783 PRXSTRING ArgList,
784 PCSZ ProgName,
785 PRXSTRING Instore,
786 PCSZ EnvName,
787 LONG CallType,
788 PRXSYSEXIT Exits,
789 PSHORT ReturnCode,
790 PRXSTRING Result )
792 int cnt, RLength;
793 char *RString;
794 int ParLengths[MAX_ARGS_TO_REXXSTART];
795 const char *ParStrings[MAX_ARGS_TO_REXXSTART];
796 int ExitFlags;
797 int EnvNamLen;
798 const char *EnvNamStr;
799 int WhereCode,rc;
800 const char *SourcePtr;
801 const void *TinPtr;
802 unsigned long SourceLen,TinLen;
803 struct ExitHandlers *Handlers;
804 RexxExitHandler *handler;
805 struct entry_point *EnvPtr;
806 unsigned long instore_length;
807 void *instore_buf;
808 PCSZ ProgramName=ProgName;
809 tsd_t *TSD;
810 rex_tsd_t *rt;
811 int restricted = 0;
813 TSD = GLOBAL_ENTRY_POINT();
814 rt = (rex_tsd_t *)TSD->rex_tsd;
815 StartupInterface( TSD );
817 if ( ( ArgCount < 0 ) || ( ( ArgCount > 0 ) && ( ArgList == NULL ) ) )
818 return RXFUNC_BADTYPE;
819 if ( !ProgName )
820 return RXFUNC_BADTYPE;
822 * Check if running in restricted mode first.
824 if ( CallType & RXRESTRICTED )
826 restricted = 1;
827 CallType -= RXRESTRICTED;
829 if ( ( CallType != RXCOMMAND ) &&
830 ( CallType != RXSUBROUTINE ) &&
831 ( CallType != RXFUNCTION ) )
832 return RXFUNC_BADTYPE;
833 if ( ( CallType == RXCOMMAND ) && ( ArgCount > 1 ) )
834 return RX_START_TOOMANYP;
835 if ( ArgCount > (int) ( sizeof( ParLengths ) / sizeof( ParLengths[0] ) ) )
836 return RX_START_TOOMANYP;
838 if ( Instore )
840 if ( Instore[1].strptr && ( Instore[1].strlength < 1 ) )
841 return RX_START_BADP;
844 for ( cnt = 0; cnt < ArgCount; cnt++ )
846 ParLengths[cnt] = ArgList[cnt].strlength;
847 ParStrings[cnt] = ArgList[cnt].strptr;
848 if ( ParStrings[cnt] == NULL )
849 ParLengths[cnt] = RX_NO_STRING;
851 if ( Result != NULL )
853 RLength = (int) RXSTRLEN( *Result );
854 if ( ( RString = RXSTRPTR( *Result ) ) == NULL )
855 RLength = RX_NO_STRING;
857 else
859 RString = NULL;
860 RLength = RX_NO_STRING;
863 Handlers = (struct ExitHandlers *)TSD->MTMalloc( TSD, sizeof( struct ExitHandlers ) );
864 Handlers->prev = rt->CurrentHandlers;
865 rt->CurrentHandlers = Handlers;
866 for ( cnt = 0; cnt < RXNOOFEXITS; cnt++ )
867 rt->CurrentHandlers->Handlers[cnt] = NULL;
869 ExitFlags = 0;
870 for ( cnt = 0; Exits && ( Exits->sysexit_code != RXENDLST ); Exits++ )
872 if ( ( Exits->sysexit_name == NULL )
873 || ( strlen( Exits->sysexit_name ) == 0 ) )
874 return RX_START_BADP;
876 EnvPtr = exit_hook( TSD, Exits->sysexit_name,
877 strlen( Exits->sysexit_name ) );
878 if ( !EnvPtr )
879 continue;
881 handler = (RexxExitHandler *) EnvPtr->addr;
882 switch ( Exits->sysexit_code )
884 case RXSIO:
885 ExitFlags |= ( 1 << RX_EXIT_STDOUT ) | ( 1 << RX_EXIT_STDERR ) |
886 ( 1 << RX_EXIT_TRCIN ) | ( 1 << RX_EXIT_PULL );
887 rt->CurrentHandlers->Handlers[RXSIO] = handler;
888 break ;
890 case RXINI:
891 ExitFlags |= 1 << RX_EXIT_INIT;
892 rt->CurrentHandlers->Handlers[RXINI] = handler;
893 break ;
895 case RXTER:
896 ExitFlags |= 1 << RX_EXIT_TERMIN;
897 rt->CurrentHandlers->Handlers[RXTER] = handler;
898 break;
900 case RXCMD:
901 ExitFlags |= 1 << RX_EXIT_SUBCOM;
902 rt->CurrentHandlers->Handlers[RXCMD] = handler;
903 break;
905 case RXFNC:
906 ExitFlags |= 1 << RX_EXIT_FUNC;
907 rt->CurrentHandlers->Handlers[RXFNC] = handler;
908 break;
910 case RXENV:
911 ExitFlags |= ( 1 << RX_EXIT_GETENV ) | ( 1 << RX_EXIT_SETENV ) |
912 ( 1 << RX_EXIT_GETCWD ) | ( 1 << RX_EXIT_SETCWD );
913 rt->CurrentHandlers->Handlers[RXENV] = handler;
914 break;
916 default:
917 return RX_START_BADP;
921 if ( EnvName )
923 EnvNamLen = strlen( EnvName );
924 EnvNamStr = EnvName;
926 else
928 EnvNamLen = RX_NO_STRING;
929 EnvNamStr = NULL;
932 SourcePtr = NULL;
933 SourceLen = 0;
934 TinPtr = NULL;
935 TinLen = 0;
936 if ( Instore && Instore[1].strptr )
938 WhereCode = RX_TYPE_INSTORE;
939 TinPtr = Instore[1].strptr;
940 TinLen = Instore[1].strlength;
941 SourcePtr = Instore[0].strptr;
942 SourceLen = Instore[0].strlength;
944 else if ( Instore && Instore[0].strptr )
946 WhereCode = RX_TYPE_SOURCE;
947 SourcePtr = Instore[0].strptr;
948 SourceLen = Instore[0].strlength;
950 else if ( Instore )
951 WhereCode = RX_TYPE_MACRO;
952 else
953 WhereCode = RX_TYPE_EXTERNAL;
955 starttrace( TSD );
957 rc = IfcExecScript( TSD, strlen(ProgramName), ProgramName,
958 ArgCount, ParLengths, (const char **) ParStrings,
959 RXMAP_TYPE( CallType ), ExitFlags, EnvNamLen, EnvNamStr,
960 WhereCode, restricted, SourcePtr, SourceLen,
961 TinPtr, TinLen, &RLength, &RString,
962 &instore_buf, &instore_length);
963 Handlers = rt->CurrentHandlers;
964 rt->CurrentHandlers = Handlers->prev;
965 TSD->MTFree( TSD, Handlers );
967 if ( WhereCode == RX_TYPE_SOURCE )
969 Instore[1].strptr = (char *)instore_buf;
970 Instore[1].strlength = instore_length;
973 if ( ReturnCode )
975 if ( RLength > 0 )
976 *ReturnCode = (SHORT) atoi( RString );
977 else
978 *ReturnCode = 0;
981 if ( Result != NULL )
983 MAKERXSTRING( *Result, RString, RLength );
985 else
987 if ( RString != NULL )
988 IfcFreeMemory( RString );
992 * Close all open files.
994 CloseOpenFiles( TSD, fpdCLEAR );
995 if ( TSD->systeminfo->input_file != NULL )
997 Free_stringTSD( TSD->systeminfo->input_file );
998 TSD->systeminfo->input_file = NULL;
1000 free_orphaned_libs( TSD );
1002 return rc;
1006 * In opposite to the documentation we accept a NULL parameter of Result
1007 * silently.
1009 EXPORT_C APIRET APIENTRY RexxCallBack( PCSZ ProcedureName,
1010 LONG ArgCount,
1011 PRXSTRING ArgList,
1012 PSHORT ReturnCode,
1013 PRXSTRING Result )
1015 int rc, cnt, RLength;
1016 char *RString;
1017 int ParLengths[MAX_ARGS_TO_REXXSTART];
1018 const char *ParStrings[MAX_ARGS_TO_REXXSTART];
1019 tsd_t *TSD;
1022 * This can only be called with an active Rexx session running
1023 * and from the same thread as the interpreter is running in
1024 * The above is true UNLESS you have userd OPTIONS SINGLE_INTERPRETER
1026 TSD = getGlobalTSD();
1027 if ( TSD == NULL )
1028 TSD = __regina_get_tsd();
1030 if ( TSD == NULL || TSD->systeminfo == NULL )
1031 return RX_CB_NOTSTARTED;
1033 if ( ( ArgCount < 0 ) || ( ( ArgCount > 0 ) && ( ArgList == NULL ) ) )
1034 return RX_CB_BADP;
1035 if ( !ProcedureName )
1036 return RX_CB_BADP;
1038 if (ArgCount > (int) (sizeof( ParLengths ) / sizeof( ParLengths[0] ) ) )
1039 return RX_CB_TOOMANYP;
1041 for ( cnt = 0; cnt < ArgCount; cnt++ )
1043 ParLengths[cnt] = (int) RXSTRLEN( ArgList[cnt] );
1044 ParStrings[cnt] = RXSTRPTR( ArgList[cnt] );
1045 if ( ParStrings[cnt] == NULL )
1046 ParLengths[cnt] = RX_NO_STRING;
1048 if ( Result != NULL )
1050 RLength = (int) RXSTRLEN( *Result );
1051 if ( ( RString = RXSTRPTR( *Result ) ) == NULL )
1052 RLength = RX_NO_STRING;
1054 else
1056 RString = NULL;
1057 RLength = RX_NO_STRING;
1060 rc = IfcExecCallBack( TSD, strlen(ProcedureName), ProcedureName,
1061 ArgCount, ParLengths, (const char **) ParStrings,
1062 &RLength, &RString );
1063 if ( rc == RX_CODE_NOSUCH )
1064 rc = RX_CB_BADN;
1067 * Determine numeric return code and pass it back
1069 if ( ReturnCode )
1071 if ( RLength > 0 )
1072 *ReturnCode = (SHORT) atoi( RString );
1073 else
1074 *ReturnCode = 0;
1078 * Determine text return code and pass it back
1080 if ( Result != NULL )
1082 MAKERXSTRING( *Result, RString, RLength );
1084 else
1086 if ( RString != NULL )
1087 IfcFreeMemory( RString );
1090 return rc;
1094 /* ============================================================= */
1095 /* subcom handler subsystem */
1097 EXPORT_C APIRET APIENTRY RexxRegisterSubcomExe(PCSZ EnvName,
1098 #ifdef RX_WEAKTYPING
1099 PFN EntryPoint,
1100 #else
1101 RexxSubcomHandler *EntryPoint,
1102 #endif
1103 PUCHAR UserArea )
1105 tsd_t *TSD = getGlobalTSD();
1107 if ( TSD == NULL )
1108 TSD = GLOBAL_ENTRY_POINT();
1109 StartupInterface( TSD );
1112 * Perform sanity check on the parameters; UserArea may be NULL
1114 if ( !EnvName || !EntryPoint )
1115 return RXSUBCOM_BADTYPE;
1117 return IfcRegSubcom( TSD, EnvName, NULL, NULL, (PFN)EntryPoint, UserArea );
1121 EXPORT_C APIRET APIENTRY RexxRegisterSubcomDll(PCSZ EnvName,
1122 PCSZ ModuleName,
1123 PCSZ ProcedureName,
1124 PUCHAR UserArea,
1125 ULONG DropAuth )
1127 tsd_t *TSD = getGlobalTSD();
1129 if ( TSD == NULL )
1130 TSD = GLOBAL_ENTRY_POINT();
1131 StartupInterface( TSD );
1133 if ( !EnvName || !ModuleName || !ProcedureName )
1134 return RXSUBCOM_BADTYPE;
1135 if ( ( DropAuth != RXSUBCOM_DROPPABLE ) && ( DropAuth != RXSUBCOM_NONDROP ) )
1136 return RXSUBCOM_BADTYPE;
1138 return IfcRegSubcom( TSD, EnvName, ModuleName, ProcedureName, NULL,
1139 UserArea );
1143 EXPORT_C APIRET APIENTRY RexxQuerySubcom(PCSZ EnvName,
1144 PCSZ ModuleName,
1145 PUSHORT Flag,
1146 PUCHAR UserWord )
1148 int ret;
1149 tsd_t *TSD = getGlobalTSD();
1151 if ( TSD == NULL )
1152 TSD = GLOBAL_ENTRY_POINT();
1153 StartupInterface( TSD );
1155 if ( !EnvName || !Flag || !Flag )
1156 return RXSUBCOM_BADTYPE;
1158 if ( ( ret = IfcQuerySubcom( TSD, EnvName, ModuleName, UserWord ) ) ==
1159 RXSUBCOM_OK )
1160 *Flag = RXSUBCOM_ISREG;
1161 else
1162 *Flag = 0;
1164 return ret;
1167 EXPORT_C APIRET APIENTRY RexxDeregisterSubcom(PCSZ EnvName,
1168 PCSZ ModuleName )
1170 tsd_t *TSD = getGlobalTSD();
1172 if ( TSD == NULL )
1173 TSD = GLOBAL_ENTRY_POINT();
1174 StartupInterface( TSD );
1176 if ( !EnvName )
1177 return RXSUBCOM_BADTYPE;
1179 return IfcDelSubcom( TSD, EnvName, ModuleName );
1184 /* ============================================================ */
1185 /* Variable subsystem */
1186 /* JH 20-10-99 */ /* To make Direct setting of stems Direct and not Symbolic. */
1187 /****************************************************************************
1189 * JH 13/12/1999 (Original code changes on 20/10/1999)
1191 * BUG022 To make Direct setting of stems Direct and not Symbolic.
1192 * - Added checks for the direct variable functions RX_GETVAR and RX_SETVAR.
1193 * In the switch that determines what to do, based on the value passed in
1194 * shvcode, symbolics still fall through to the code that is under the
1195 * direct labels, but it sets a variable to denote that symbolic processing
1196 * is to take place. The direct section only sets this variable if it has
1197 * not been set before.
1198 * - Added new variable IVPcode (IfcVariablePool) that will contain the code
1199 * used to call IfcVariablePool(), instead of hard coding the parameter,
1201 * NB that this routine lumps the Drop's and Set's together, before calling
1202 * IfcVarPool(). At some point it might be better to pass the shvcode
1203 * value, rather than translating it and later performing additional
1204 * checks to split it back out.
1206 ****************************************************************************/
1207 EXPORT_C APIRET APIENTRY RexxVariablePool(PSHVBLOCK RequestBlockList )
1209 int Code=0, RetCode=0, IVPcode;
1210 int Lengths[2] ;
1211 int rc=0, allocated ;
1212 char *Strings[2] ;
1213 PSHVBLOCK Req=RequestBlockList ;
1214 tsd_t *TSD = getGlobalTSD();
1216 if ( TSD == NULL )
1217 TSD = GLOBAL_ENTRY_POINT();
1218 StartupInterface(TSD);
1220 if (!RequestBlockList) /* FGC: I assume we must have at least one param */
1221 return(RXFUNC_BADTYPE);
1223 if (TSD->systeminfo->tree.root==NULL) /* Doesn't the interpreter run? */
1224 return RXSHV_NOAVL ;
1226 RetCode = 0 ;
1228 for (;Req;Req=Req->shvnext)
1230 IVPcode = 0; /* Needed for a correct IVPcode on a second request */
1231 allocated = 0;
1232 switch (Req->shvcode)
1234 case RXSHV_SYDRO:
1235 case RXSHV_SYSET:
1236 IVPcode = RX_SETSVAR; /* JH 20-10-99 */
1237 case RXSHV_DROPV: /* MH 26-12-95 */
1238 case RXSHV_SET: /* MH 26-12-95 */
1240 IVPcode = IVPcode ? IVPcode : RX_SETVAR; /* JH 20-10-99 */
1241 Lengths[0] = Req->shvname.strlength ;
1242 Strings[0] = Req->shvname.strptr ;
1243 if (Req->shvcode==RXSHV_SYSET /* MH 26-12-95 */
1244 || Req->shvcode==RXSHV_SET) /* MH 26-12-95 */
1246 Lengths[1] = Req->shvvalue.strlength ;
1247 Strings[1] = Req->shvvalue.strptr ;
1249 else
1250 Lengths[1] = RX_NO_STRING ;
1252 Code = IfcVarPool( TSD, IVPcode, Lengths, Strings, &allocated );
1254 Req->shvret = RXSHV_OK ;
1255 if (Code==RX_CODE_NOVALUE)
1256 Req->shvret |= RXSHV_NEWV ;
1257 else if (Code==RX_CODE_INVNAME)
1258 Req->shvret |= RXSHV_BADN ;
1259 else if (Code!=RXSHV_OK)
1260 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1261 TSD->var_indicator=0;
1262 break ;
1264 case RXSHV_SYFET:
1265 IVPcode = RX_GETSVAR; /* JH 20-10-99 */
1266 case RXSHV_FETCH: /* MH 26-12-95 */
1268 IVPcode = IVPcode ? IVPcode : RX_GETVAR; /* JH 20-10-99 */
1269 Lengths[0] = Req->shvname.strlength ;
1270 Strings[0] = Req->shvname.strptr ;
1271 Code = IfcVarPool( TSD, IVPcode, Lengths, Strings, &allocated );
1273 Req->shvret = RXSHV_OK ;
1274 if (Code==RX_CODE_NOVALUE)
1275 Req->shvret |= RXSHV_NEWV ;
1276 else if (Code==RX_CODE_INVNAME)
1277 Req->shvret |= RXSHV_BADN ;
1278 else if (Code!=RXSHV_OK)
1279 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1280 FillReqValue( Req, Lengths[1], Strings[1] ) ;
1281 TSD->var_indicator=0;
1282 break ;
1285 case RXSHV_PRIV:
1287 Req->shvret = RXSHV_OK ;
1288 if (Req->shvname.strlength==4 && Req->shvname.strptr &&
1289 !strncmp(Req->shvname.strptr, "PARM", 4 ))
1291 rc = IfcVarPool( TSD, RX_CODE_PARAMS, Lengths, Strings, &allocated );
1292 FillReqValue( Req, Lengths[0], Strings[0] ) ;
1295 else if (Req->shvname.strlength>=5 && Req->shvname.strptr &&
1296 !strncmp(Req->shvname.strptr, "PARM.", 5 ))
1298 Lengths[0] = Req->shvname.strlength - 5 ;
1299 Strings[0] = Req->shvname.strptr + 5 ;
1301 rc = IfcVarPool( TSD, RX_CODE_PARAM, Lengths, Strings, &allocated );
1302 if (rc == RX_CODE_OK)
1303 FillReqValue( Req, Lengths[1], Strings[1] ) ;
1304 else
1305 Req->shvret |= RXSHV_BADN ;
1308 else
1310 int Code=0 ;
1311 if (Req->shvname.strptr)
1313 if (Req->shvname.strlength==7 &&
1314 !memcmp(Req->shvname.strptr, "QUENAME", 7))
1316 Code = RX_CODE_QUEUE ;
1318 else if (Req->shvname.strlength==7 &&
1319 !memcmp(Req->shvname.strptr, "VERSION", 7))
1321 Code = RX_CODE_VERSION ;
1323 else if (Req->shvname.strlength==6 &&
1324 !memcmp(Req->shvname.strptr, "SOURCE", 6))
1326 Code = RX_CODE_SOURCE ;
1328 else
1329 Req->shvret |= RXSHV_BADN ;
1331 if (!(Req->shvret & RXSHV_BADN))
1333 rc=IfcVarPool( TSD, Code, Lengths, Strings, &allocated );
1334 FillReqValue( Req, Lengths[0], Strings[0] ) ;
1337 else
1338 Req->shvret |= RXSHV_BADN ;
1340 break ;
1343 case RXSHV_NEXTV:
1345 int Items ;
1347 Req->shvret = RXSHV_OK ;
1348 Items = IfcVarPool( TSD, RX_NEXTVAR, Lengths, Strings, &allocated );
1349 assert( Items==0 || Items==2 ) ;
1351 if (Items==2)
1353 FillReqValue( Req, Lengths[1], Strings[1] ) ;
1354 FillReqName( Req, Lengths[0], Strings[0] ) ;
1356 else
1357 Req->shvret |= RXSHV_LVAR ;
1359 break ;
1362 default:
1363 Req->shvret = RXSHV_BADF ;
1365 if (allocated & 1) /* fixes bug 596686 */
1366 FreeTSD( Strings[0] );
1367 if (allocated & 2)
1368 FreeTSD( Strings[1] );
1369 RetCode |= ( Req->shvret & 0x007f ) ;
1372 return RetCode ;
1377 /* ================================================================ */
1378 /* system exit handler subsystem */
1380 EXPORT_C APIRET APIENTRY RexxRegisterExitExe(PCSZ EnvName,
1381 #ifdef RX_WEAKTYPING
1382 PFN EntryPoint,
1383 #else
1384 RexxExitHandler *EntryPoint,
1385 #endif
1386 PUCHAR UserArea )
1388 tsd_t *TSD = getGlobalTSD();
1390 if ( TSD == NULL )
1391 TSD = GLOBAL_ENTRY_POINT();
1392 StartupInterface( TSD );
1395 * Perform sanity check on the parameters; UserArea may be NULL
1397 if ( !EnvName || !EntryPoint )
1398 return RXEXIT_BADTYPE;
1400 return IfcRegExit( TSD, EnvName, NULL, NULL, (PFN)EntryPoint, UserArea );
1403 EXPORT_C APIRET APIENTRY RexxRegisterExitDll(PCSZ EnvName,
1404 PCSZ ModuleName,
1405 PCSZ ProcedureName,
1406 PUCHAR UserArea,
1407 ULONG DropAuth )
1409 tsd_t *TSD = getGlobalTSD();
1411 if ( TSD == NULL )
1412 TSD = GLOBAL_ENTRY_POINT();
1413 StartupInterface( TSD );
1415 if ( !EnvName || !ModuleName || !ProcedureName )
1416 return RXEXIT_BADTYPE;
1417 if ( ( DropAuth != RXEXIT_DROPPABLE ) && ( DropAuth != RXEXIT_NONDROP ) )
1418 return RXEXIT_BADTYPE;
1420 return IfcRegExit( TSD, EnvName, ModuleName, ProcedureName, NULL, UserArea );
1424 EXPORT_C APIRET APIENTRY RexxDeregisterExit(PCSZ EnvName,
1425 PCSZ ModuleName )
1427 tsd_t *TSD = getGlobalTSD();
1429 if ( TSD == NULL )
1430 TSD = GLOBAL_ENTRY_POINT();
1431 StartupInterface( TSD );
1433 if ( !EnvName )
1434 return RXEXIT_BADTYPE;
1436 return IfcDelExit( TSD, EnvName, ModuleName );
1439 EXPORT_C APIRET APIENTRY RexxQueryExit(PCSZ EnvName,
1440 PCSZ ModuleName,
1441 PUSHORT Flag,
1442 PUCHAR UserArea)
1444 int ret;
1445 tsd_t *TSD = getGlobalTSD();
1447 if ( TSD == NULL )
1448 TSD = GLOBAL_ENTRY_POINT();
1449 StartupInterface( TSD );
1451 if ( !EnvName || !Flag || !Flag )
1452 return RXEXIT_BADTYPE;
1454 if ( ( ret = IfcQueryExit( TSD, EnvName, ModuleName, UserArea ) ) ==
1455 RXEXIT_OK )
1456 *Flag = RXEXIT_ISREG;
1457 else
1458 *Flag = 0;
1460 return ret;
1463 /* =================================================================== */
1466 * This section contains the support for the external functions
1469 EXPORT_C APIRET APIENTRY RexxRegisterFunctionExe( PCSZ Name,
1470 #ifdef RX_WEAKTYPING
1471 PFN EntryPoint )
1472 #else
1473 RexxFunctionHandler *EntryPoint )
1474 #endif
1476 tsd_t *TSD = getGlobalTSD();
1478 if ( TSD == NULL )
1479 TSD = GLOBAL_ENTRY_POINT();
1480 StartupInterface( TSD );
1482 if ( !Name || !EntryPoint )
1483 return RXFUNC_BADTYPE;
1485 return IfcRegFunc( TSD, Name, NULL, NULL, (PFN)EntryPoint );
1488 EXPORT_C APIRET APIENTRY RexxRegisterFunctionDll( PCSZ ExternalName,
1489 PCSZ LibraryName,
1490 PCSZ InternalName )
1492 tsd_t *TSD = getGlobalTSD();
1494 if ( TSD == NULL )
1495 TSD = GLOBAL_ENTRY_POINT();
1496 StartupInterface( TSD );
1498 if ( !ExternalName || !LibraryName || !InternalName )
1499 return RXFUNC_BADTYPE;
1501 return IfcRegFunc( TSD, ExternalName, LibraryName, InternalName, NULL );
1504 EXPORT_C APIRET APIENTRY RexxQueryFunction( PCSZ Name )
1506 tsd_t *TSD = getGlobalTSD();
1508 if ( TSD == NULL )
1509 TSD = GLOBAL_ENTRY_POINT();
1510 StartupInterface( TSD );
1512 if ( !Name )
1513 return RXFUNC_BADTYPE;
1514 return IfcQueryFunc( TSD, Name );
1518 EXPORT_C APIRET APIENTRY RexxDeregisterFunction( PCSZ Name )
1520 tsd_t *TSD = getGlobalTSD();
1522 if ( TSD == NULL )
1523 TSD = GLOBAL_ENTRY_POINT();
1524 StartupInterface( TSD );
1526 if ( !Name )
1527 return RXFUNC_BADTYPE;
1529 return IfcDelFunc( TSD, Name );
1532 /* The caller of IfcFunctionExit should call this function with fresh copies of
1533 * Name and params to be bullet-proof. The called function MAY
1534 * change the values although this is illegal.
1536 static int IfcFunctionExit( tsd_t *TSD,
1537 PSZ Name,
1538 int Params,
1539 RXSTRING *params,
1540 PCSZ queuename,
1541 int queuelen,
1542 PRXSTRING Retstr,
1543 int *RCode,
1544 char called )
1546 int rc=0 ;
1547 RXFNCCAL_PARM fnccal;
1548 PUCHAR parm=NULL;
1549 rex_tsd_t *rt;
1551 rt = (rex_tsd_t *)TSD->rex_tsd;
1553 if ( rt->CurrentHandlers && rt->CurrentHandlers->Handlers[RXFNC] )
1555 fnccal.rxfnc_flags.rxfferr = 0;
1556 fnccal.rxfnc_flags.rxffnfnd = 0;
1557 fnccal.rxfnc_flags.rxffsub = (called) ? 1 : 0;
1558 fnccal.rxfnc_name = (unsigned char *)Name;
1559 fnccal.rxfnc_namel = (USHORT) strlen(Name);
1560 fnccal.rxfnc_que = (unsigned char *)queuename;
1561 fnccal.rxfnc_quel = (USHORT) queuelen;
1562 fnccal.rxfnc_argc = (USHORT) Params;
1563 fnccal.rxfnc_argv = params;
1564 fnccal.rxfnc_retc = *Retstr;
1565 parm = (PUCHAR)&fnccal;
1566 rc = (*(rt->CurrentHandlers->Handlers[RXFNC]))(RXFNC, RXFNCCAL, parm);
1567 TSD->var_indicator = 0;
1568 assert( rc==RXEXIT_HANDLED || rc==RXEXIT_NOT_HANDLED ||
1569 rc==RXEXIT_RAISE_ERROR ) ;
1570 if (rc == RXEXIT_HANDLED)
1572 if (fnccal.rxfnc_flags.rxfferr)
1573 *RCode = RXFLAG_ERROR ;
1574 else if (fnccal.rxfnc_flags.rxffnfnd)
1575 *RCode = RXFLAG_FAILURE ;
1576 else
1577 *RCode = RXFLAG_OK;
1579 *Retstr = fnccal.rxfnc_retc;
1580 return(rc);
1582 else
1584 return (RXEXIT_NOT_HANDLED);
1588 /* The caller of IfcExecFunc should call this function with fresh copies of
1589 * Name, Length and Strings to be bullet-proof. The called function MAY
1590 * change the values although this is illegal.
1591 * RetLength and RetString should point to {0,NULL}. They will be filled with
1592 * freshly allocated values if there are some.
1594 int IfcExecFunc( tsd_t *TSD,
1595 PFN Func,
1596 char *Name, int Params,
1597 int *Lengths, char **Strings,
1598 int queue_name_len, char *queue_name,
1599 int *RetLength, char **RetString,
1600 int *RC, char called, void *gci_info )
1602 int i=0, length=0, rc=0, RCode=0 ;
1603 RXSTRING *params, retstr ;
1604 char execfunc_result[ILLEGAL_USE_SIZE+RXAUTOBUFLEN] ;
1605 RexxFunctionHandler *FullFunc;
1607 assert( Name ) ;
1608 assert( Params >= 0 ) ;
1609 FullFunc = (RexxFunctionHandler *)Func;
1611 params = (RXSTRING *)MallocTSD( sizeof(RXSTRING)*Params ) ;
1612 for (i=0; i<Params; i++)
1614 length = Lengths[i] ;
1615 if (length==RX_NO_STRING)
1617 params[i].strptr = NULL ;
1618 params[i].strlength = 0 ;
1620 else
1622 params[i].strptr = Strings[i] ;
1623 params[i].strlength = length ;
1627 memset( execfunc_result, 0, sizeof( execfunc_result ) ) ;
1628 retstr.strptr = execfunc_result + ILLEGAL_USE_SIZE ;
1629 retstr.strlength = RXAUTOBUFLEN; /* MH 26-12-95 */
1631 rc = IfcFunctionExit( TSD, Name, Params, params, queue_name, queue_name_len,
1632 &retstr, &RCode, called );
1633 switch(rc)
1635 case RXEXIT_NOT_HANDLED:
1636 if ( Func == NULL )
1638 *RC = ERR_ROUTINE_NOT_FOUND;
1640 else
1642 #if defined(DYNAMIC) && defined(HAVE_GCI)
1643 if ( gci_info != NULL )
1644 rc = GCI_Dispatcher( TSD, (PFN)Func, gci_info, Params, params, &retstr );
1645 else
1646 #endif
1647 /* Func will inherit a possible return value in
1648 * retstr. This might be a problem, expect suspicious results
1649 * if the called functions are not error free.
1651 rc = (*(FullFunc))( Name, Params, params, queue_name, &retstr ) ;
1653 if (rc)
1654 *RC = ERR_INCORRECT_CALL;
1655 else
1656 *RC = 0;
1657 TSD->var_indicator = 0;
1659 break;
1660 case RXEXIT_HANDLED:
1661 if (RCode == RXFLAG_ERROR)
1662 *RC = ERR_INCORRECT_CALL;
1663 else if (RCode == RXFLAG_FAILURE)
1664 *RC = ERR_ROUTINE_NOT_FOUND;
1665 else
1666 *RC = 0;
1667 break;
1668 case RXEXIT_RAISE_ERROR:
1669 *RC = ERR_SYSTEM_FAILURE;
1670 break;
1673 FreeTSD( params ) ;
1675 if (!(*RC) && retstr.strptr)
1677 *RetString = (char *)MallocTSD( (retstr.strlength < 1) ? 1 : retstr.strlength ) ;
1678 memcpy( *RetString, retstr.strptr, retstr.strlength ) ;
1679 *RetLength = retstr.strlength ;
1681 else
1682 *RetLength = RX_NO_STRING ;
1684 if (retstr.strptr && retstr.strptr != execfunc_result + ILLEGAL_USE_SIZE)
1685 IfcFreeMemory( retstr.strptr ) ;
1687 return RX_CODE_OK ;
1690 int IfcHaveFunctionExit(const tsd_t *TSD)
1692 rex_tsd_t *rt;
1694 rt = (rex_tsd_t *)TSD->rex_tsd;
1695 if ( rt->CurrentHandlers && rt->CurrentHandlers->Handlers[RXFNC] )
1696 return 1;
1697 else
1698 return 0;
1701 /* ============================================================= */
1702 /* Asynchronous Rexx API interface */
1704 EXPORT_C APIRET APIENTRY RexxSetHalt(LONG dummyProcess,
1705 LONG dummyThread )
1707 tsd_t *TSD = getGlobalTSD();
1709 if ( TSD == NULL )
1710 TSD = GLOBAL_ENTRY_POINT();
1711 StartupInterface(TSD);
1713 * Perform sanity check on the parameters; is process id me ?
1715 set_rexx_halt( TSD );
1716 return RXARI_OK ;
1719 /* ============================================================= */
1720 /* Named queue interface */
1722 EXPORT_C APIRET APIENTRY RexxCreateQueue( PSZ Buffer,
1723 ULONG BuffLen,
1724 PSZ RequestedName,
1725 ULONG* DupFlag)
1727 int code;
1728 unsigned long dupflag = *DupFlag;
1729 tsd_t *TSD = getGlobalTSD();
1731 if ( TSD == NULL )
1732 TSD = GLOBAL_ENTRY_POINT();
1733 StartupInterface(TSD);
1735 TSD->called_from_saa = 1;
1736 code = IfcCreateQueue( TSD, RequestedName, (RequestedName) ? strlen( RequestedName): 0, Buffer, &dupflag, BuffLen );
1737 *DupFlag = (ULONG)dupflag;
1738 TSD->called_from_saa = 0;
1739 return code;
1742 EXPORT_C APIRET APIENTRY RexxDeleteQueue( PSZ QueueName )
1744 int code;
1745 tsd_t *TSD = getGlobalTSD();
1747 if ( TSD == NULL )
1748 TSD = GLOBAL_ENTRY_POINT();
1749 StartupInterface(TSD);
1751 TSD->called_from_saa = 1;
1752 if (!QueueName || !strlen(QueueName))
1753 code = RXQUEUE_BADQNAME;
1754 else
1755 code = IfcDeleteQueue( TSD, QueueName, strlen( QueueName ) );
1756 TSD->called_from_saa = 0;
1757 return code;
1760 EXPORT_C APIRET APIENTRY RexxQueryQueue( PSZ QueueName,
1761 ULONG* Count)
1763 int code;
1764 unsigned long count = *Count;
1765 tsd_t *TSD = getGlobalTSD();
1767 if ( TSD == NULL )
1768 TSD = GLOBAL_ENTRY_POINT();
1769 StartupInterface(TSD);
1771 TSD->called_from_saa = 1;
1772 if (!QueueName || !strlen(QueueName))
1773 code = RXQUEUE_BADQNAME;
1774 else
1775 code = IfcQueryQueue( TSD, QueueName, strlen( QueueName ), &count );
1776 *Count = (ULONG)count;
1777 TSD->called_from_saa = 0;
1778 return code;
1781 EXPORT_C APIRET APIENTRY RexxAddQueue( PSZ QueueName,
1782 PRXSTRING EntryData,
1783 ULONG AddFlag)
1785 int code;
1786 tsd_t *TSD = getGlobalTSD();
1788 if ( TSD == NULL )
1789 TSD = GLOBAL_ENTRY_POINT();
1790 StartupInterface(TSD);
1792 TSD->called_from_saa = 1;
1793 if (!QueueName || !strlen(QueueName))
1794 code = RXQUEUE_BADQNAME;
1795 else
1796 code = IfcAddQueue( TSD, QueueName, strlen( QueueName), EntryData->strptr, EntryData->strlength, AddFlag==RXQUEUE_LIFO );
1797 TSD->called_from_saa = 0;
1798 return code;
1801 EXPORT_C APIRET APIENTRY RexxPullQueue( PSZ QueueName,
1802 PRXSTRING DataBuf,
1803 PDATETIME TimeStamp,
1804 ULONG WaitFlag)
1806 int code;
1807 tsd_t *TSD = getGlobalTSD();
1809 if ( TSD == NULL )
1810 TSD = GLOBAL_ENTRY_POINT();
1811 StartupInterface( TSD );
1813 if ( WaitFlag != RXQUEUE_WAIT && WaitFlag != RXQUEUE_NOWAIT )
1814 return RXQUEUE_BADWAITFLAG;
1816 if ( DataBuf == NULL )
1817 return RXQUEUE_MEMFAIL;
1819 TSD->called_from_saa = 1;
1820 if ( !QueueName || !strlen( QueueName ) )
1821 code = RXQUEUE_BADQNAME;
1822 else
1824 unsigned long strlength = 0;
1825 code = IfcPullQueue( TSD,
1826 QueueName, strlen( QueueName ),
1827 &DataBuf->strptr, &strlength,
1828 WaitFlag==RXQUEUE_WAIT );
1829 DataBuf->strlength = strlength;
1830 if ( code == 0 )
1832 if ( TimeStamp )
1833 TimeStamp->valid = 0;
1836 TSD->called_from_saa = 0;
1837 return code;
1840 /* ============================================================= */
1841 /* MacroSpace Rexx API interface */
1843 EXPORT_C APIRET APIENTRY RexxAddMacro( PSZ FuncName,
1844 PSZ SourceFile,
1845 ULONG Position )
1847 return 0;
1850 EXPORT_C APIRET APIENTRY RexxDropMacro( PSZ FuncName)
1852 return 0;
1855 EXPORT_C APIRET APIENTRY RexxSaveMacroSpace( ULONG FuncCount,
1856 PSZ * FuncNames,
1857 PSZ MacroLibFile)
1859 return 0;
1862 EXPORT_C APIRET APIENTRY RexxLoadMacroSpace( ULONG FuncCount,
1863 PSZ * FuncNames,
1864 PSZ MacroLibFile)
1866 return 0;
1869 EXPORT_C APIRET APIENTRY RexxQueryMacro( PSZ FuncName,
1870 PUSHORT Position )
1872 return 0;
1875 EXPORT_C APIRET APIENTRY RexxReorderMacro( PSZ FuncName,
1876 ULONG Position )
1878 return 0;
1881 EXPORT_C APIRET APIENTRY RexxClearMacroSpace( VOID )
1883 return 0;
1886 /* ============================================================= */
1887 /* Regina extensions */
1888 /* see rexxsaa.h for a description */
1889 EXPORT_C APIRET APIENTRY ReginaVersion( PRXSTRING VersionString )
1891 char low[3];
1892 unsigned len;
1893 tsd_t *TSD = getGlobalTSD();
1895 if ( TSD == NULL )
1896 TSD = GLOBAL_ENTRY_POINT();
1897 StartupInterface(TSD);
1899 if (!VersionString)
1900 goto fastexit;
1902 if ( VersionString->strlength == 0 )
1904 if ( ( VersionString->strptr = (char *)IfcAllocateMemory( sizeof(PARSE_VERSION_STRING) ) ) == NULL )
1905 goto fastexit;
1906 VersionString->strlength = sizeof(PARSE_VERSION_STRING);
1909 if ((len = VersionString->strlength) > sizeof(PARSE_VERSION_STRING))
1910 len = sizeof(PARSE_VERSION_STRING);
1911 memcpy(VersionString->strptr,PARSE_VERSION_STRING,len);
1913 /* sizeof includes the terminating 0. Subtract it if we should. */
1914 if (len > sizeof(PARSE_VERSION_STRING) - 1)
1915 len = sizeof(PARSE_VERSION_STRING) - 1;
1916 VersionString->strlength = len;
1918 fastexit:
1919 low[0] = REGINA_VERSION_MINOR[0];
1920 if (low[0] == '0') /* atoi may have problems with leading zeros (octal) */
1922 low[0] = REGINA_VERSION_MINOR[1];
1923 low[1] = '\0';
1925 else
1926 low[1] = REGINA_VERSION_MINOR[1];
1927 low[2] = '\0';
1928 return( (atoi(REGINA_VERSION_MAJOR) << 8) | atoi(low) ) ;
1931 EXPORT_C APIRET APIENTRY ReginaCleanup( VOID )
1933 return( IfcReginaCleanup() );