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
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.
103 #define INCL_RXSUBCOM
105 #define INCL_RXSYSEXIT
110 #include "regina_c.h"
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
129 #define DONT_TYPEDEF_PFN
134 #if defined(DYNAMIC) && defined(HAVE_GCI)
135 # include "gci/gci.h"
138 #include "extstack.h"
154 #if defined(__EPOC32__) || defined(__WINS__)
158 # define APIRET unsigned long
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
;
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
196 #define EXT_FUNCS_COUNT (sizeof(rt->saafuncs) / sizeof(rt->saafuncs[0]))
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
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
)
222 if (TSD
->rex_tsd
!= NULL
)
225 if ( ( TSD
->rex_tsd
= MallocTSD( sizeof(rex_tsd_t
) ) ) == NULL
)
227 rt
= (rex_tsd_t
*)TSD
->rex_tsd
;
228 memset( rt
, 0, sizeof(rex_tsd_t
) ); /* correct for all values */
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
)
274 setup_system( TSD
, 1 );
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
)
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 );
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
;
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.
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
)
364 memcpy( string
->strptr
, String
, Length
);
365 string
->strptr
[Length
] = '\0';
366 string
->strlength
= Length
;
370 Req
->shvret
|= RXSHV_MEMFL
;
372 * Set strlength for convenience.
374 string
->strlength
= 0;
378 * shvnamelen and shvvaluelen are read-only values describing the maximum
379 * size of the destination buffer, but see above at SAA DOCUMENTATION.
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
)
395 char *OldResult
= NULL
;
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
;
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;
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
;
451 Ret
= cmdhst
.rxcmd_retc
;
454 if (rc
== RXEXIT_NOT_HANDLED
)
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
)
470 else if (Flags
==RXSUBCOM_ERROR
)
471 RCode
= RXFLAG_ERROR
;
472 else if (Flags
==RXSUBCOM_FAILURE
)
473 RCode
= RXFLAG_FAILURE
;
475 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
479 RCode
= RXFLAG_NOTREG
;
486 *RetLen
= Ret
.strlength
;
487 *RetStr
= (char *)MallocTSD( Ret
.strlength
) ;
488 memcpy( *RetStr
, Ret
.strptr
, Ret
.strlength
) ;
493 *RetStr
= (char *)MallocTSD( 1 ) ;
497 if (Ret
.strlength
&& OldResult
!= Ret
.strptr
)
498 IfcFreeMemory( Ret
.strptr
) ;
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
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:
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
)
537 LONG SubCode
=0, MainCode
=0 ;
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
;
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 */
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
;
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
;
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
;
605 assert(OutputLength1
== 0 &&
606 OutputString1
== NULL
&&
607 InputLength
== NULL
&&
608 InputString
== NULL
&&
609 OutputLength2
== 0 &&
610 OutputString2
== NULL
);
616 assert(OutputLength1
== 0 &&
617 OutputString1
== NULL
&&
618 InputLength
== NULL
&&
619 InputString
== NULL
&&
620 OutputLength2
== 0 &&
621 OutputString2
== NULL
);
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
;
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
;
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
;
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
;
685 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
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
) ;
708 retlen
= siodtr
.rxsiodtr_retc
.strlength
;
709 retstr
= siodtr
.rxsiodtr_retc
.strptr
;
710 mustFree
= ( retstr
!= *InputString
) ? retstr
: NULL
;
714 retlen
= siotrd
.rxsiotrd_retc
.strlength
;
715 retstr
= siotrd
.rxsiotrd_retc
.strptr
;
716 mustFree
= ( retstr
!= *InputString
) ? retstr
: NULL
;
720 retlen
= envget
.rxenv_value
.strlength
;
721 retstr
= envget
.rxenv_value
.strptr
;
722 mustFree
= ( retstr
!= *InputString
) ? retstr
: NULL
;
726 retlen
= cwdget
.rxcwd_value
.strlength
;
727 retstr
= cwdget
.rxcwd_value
.strptr
;
728 mustFree
= ( retstr
!= *InputString
) ? retstr
: NULL
;
732 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
735 if (rc
==RXEXIT_HANDLED
)
737 else if (rc
==RXEXIT_NOT_HANDLED
)
739 else if (rc
==RXEXIT_RAISE_ERROR
)
742 if (InputLength
!= NULL
) /* retlen and retstr forms a return string. */
744 if ((retlen
== 0) || (retstr
== NULL
))
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
;
757 IfcFreeMemory( mustFree
);
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
)
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
,
794 int ParLengths
[MAX_ARGS_TO_REXXSTART
];
795 const char *ParStrings
[MAX_ARGS_TO_REXXSTART
];
798 const char *EnvNamStr
;
800 const char *SourcePtr
;
802 unsigned long SourceLen
,TinLen
;
803 struct ExitHandlers
*Handlers
;
804 RexxExitHandler
*handler
;
805 struct entry_point
*EnvPtr
;
806 unsigned long instore_length
;
808 PCSZ ProgramName
=ProgName
;
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
;
820 return RXFUNC_BADTYPE
;
822 * Check if running in restricted mode first.
824 if ( CallType
& RXRESTRICTED
)
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
;
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
;
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
;
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
) );
881 handler
= (RexxExitHandler
*) EnvPtr
->addr
;
882 switch ( Exits
->sysexit_code
)
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
;
891 ExitFlags
|= 1 << RX_EXIT_INIT
;
892 rt
->CurrentHandlers
->Handlers
[RXINI
] = handler
;
896 ExitFlags
|= 1 << RX_EXIT_TERMIN
;
897 rt
->CurrentHandlers
->Handlers
[RXTER
] = handler
;
901 ExitFlags
|= 1 << RX_EXIT_SUBCOM
;
902 rt
->CurrentHandlers
->Handlers
[RXCMD
] = handler
;
906 ExitFlags
|= 1 << RX_EXIT_FUNC
;
907 rt
->CurrentHandlers
->Handlers
[RXFNC
] = handler
;
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
;
917 return RX_START_BADP
;
923 EnvNamLen
= strlen( EnvName
);
928 EnvNamLen
= RX_NO_STRING
;
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
;
951 WhereCode
= RX_TYPE_MACRO
;
953 WhereCode
= RX_TYPE_EXTERNAL
;
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
;
976 *ReturnCode
= (SHORT
) atoi( RString
);
981 if ( Result
!= NULL
)
983 MAKERXSTRING( *Result
, RString
, RLength
);
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
);
1006 * In opposite to the documentation we accept a NULL parameter of Result
1009 EXPORT_C APIRET APIENTRY
RexxCallBack( PCSZ ProcedureName
,
1015 int rc
, cnt
, RLength
;
1017 int ParLengths
[MAX_ARGS_TO_REXXSTART
];
1018 const char *ParStrings
[MAX_ARGS_TO_REXXSTART
];
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();
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
) ) )
1035 if ( !ProcedureName
)
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
;
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
)
1067 * Determine numeric return code and pass it back
1072 *ReturnCode
= (SHORT
) atoi( RString
);
1078 * Determine text return code and pass it back
1080 if ( Result
!= NULL
)
1082 MAKERXSTRING( *Result
, RString
, RLength
);
1086 if ( RString
!= NULL
)
1087 IfcFreeMemory( RString
);
1094 /* ============================================================= */
1095 /* subcom handler subsystem */
1097 EXPORT_C APIRET APIENTRY
RexxRegisterSubcomExe(PCSZ EnvName
,
1098 #ifdef RX_WEAKTYPING
1101 RexxSubcomHandler
*EntryPoint
,
1105 tsd_t
*TSD
= getGlobalTSD();
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
,
1127 tsd_t
*TSD
= getGlobalTSD();
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
,
1143 EXPORT_C APIRET APIENTRY
RexxQuerySubcom(PCSZ EnvName
,
1149 tsd_t
*TSD
= getGlobalTSD();
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
) ) ==
1160 *Flag
= RXSUBCOM_ISREG
;
1167 EXPORT_C APIRET APIENTRY
RexxDeregisterSubcom(PCSZ EnvName
,
1170 tsd_t
*TSD
= getGlobalTSD();
1173 TSD
= GLOBAL_ENTRY_POINT();
1174 StartupInterface( TSD
);
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
;
1211 int rc
=0, allocated
;
1213 PSHVBLOCK Req
=RequestBlockList
;
1214 tsd_t
*TSD
= getGlobalTSD();
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
;
1228 for (;Req
;Req
=Req
->shvnext
)
1230 IVPcode
= 0; /* Needed for a correct IVPcode on a second request */
1232 switch (Req
->shvcode
)
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
;
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;
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;
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] ) ;
1305 Req
->shvret
|= RXSHV_BADN
;
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
;
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] ) ;
1338 Req
->shvret
|= RXSHV_BADN
;
1347 Req
->shvret
= RXSHV_OK
;
1348 Items
= IfcVarPool( TSD
, RX_NEXTVAR
, Lengths
, Strings
, &allocated
);
1349 assert( Items
==0 || Items
==2 ) ;
1353 FillReqValue( Req
, Lengths
[1], Strings
[1] ) ;
1354 FillReqName( Req
, Lengths
[0], Strings
[0] ) ;
1357 Req
->shvret
|= RXSHV_LVAR
;
1363 Req
->shvret
= RXSHV_BADF
;
1365 if (allocated
& 1) /* fixes bug 596686 */
1366 FreeTSD( Strings
[0] );
1368 FreeTSD( Strings
[1] );
1369 RetCode
|= ( Req
->shvret
& 0x007f ) ;
1377 /* ================================================================ */
1378 /* system exit handler subsystem */
1380 EXPORT_C APIRET APIENTRY
RexxRegisterExitExe(PCSZ EnvName
,
1381 #ifdef RX_WEAKTYPING
1384 RexxExitHandler
*EntryPoint
,
1388 tsd_t
*TSD
= getGlobalTSD();
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
,
1409 tsd_t
*TSD
= getGlobalTSD();
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
,
1427 tsd_t
*TSD
= getGlobalTSD();
1430 TSD
= GLOBAL_ENTRY_POINT();
1431 StartupInterface( TSD
);
1434 return RXEXIT_BADTYPE
;
1436 return IfcDelExit( TSD
, EnvName
, ModuleName
);
1439 EXPORT_C APIRET APIENTRY
RexxQueryExit(PCSZ EnvName
,
1445 tsd_t
*TSD
= getGlobalTSD();
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
) ) ==
1456 *Flag
= RXEXIT_ISREG
;
1463 /* =================================================================== */
1466 * This section contains the support for the external functions
1469 EXPORT_C APIRET APIENTRY
RexxRegisterFunctionExe( PCSZ Name
,
1470 #ifdef RX_WEAKTYPING
1473 RexxFunctionHandler
*EntryPoint
)
1476 tsd_t
*TSD
= getGlobalTSD();
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
,
1492 tsd_t
*TSD
= getGlobalTSD();
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();
1509 TSD
= GLOBAL_ENTRY_POINT();
1510 StartupInterface( TSD
);
1513 return RXFUNC_BADTYPE
;
1514 return IfcQueryFunc( TSD
, Name
);
1518 EXPORT_C APIRET APIENTRY
RexxDeregisterFunction( PCSZ Name
)
1520 tsd_t
*TSD
= getGlobalTSD();
1523 TSD
= GLOBAL_ENTRY_POINT();
1524 StartupInterface( TSD
);
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
,
1547 RXFNCCAL_PARM fnccal
;
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
;
1579 *Retstr
= fnccal
.rxfnc_retc
;
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
,
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
;
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 ;
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
);
1635 case RXEXIT_NOT_HANDLED
:
1638 *RC
= ERR_ROUTINE_NOT_FOUND
;
1642 #if defined(DYNAMIC) && defined(HAVE_GCI)
1643 if ( gci_info
!= NULL
)
1644 rc
= GCI_Dispatcher( TSD
, (PFN
)Func
, gci_info
, Params
, params
, &retstr
);
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
) ;
1654 *RC
= ERR_INCORRECT_CALL
;
1657 TSD
->var_indicator
= 0;
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
;
1668 case RXEXIT_RAISE_ERROR
:
1669 *RC
= ERR_SYSTEM_FAILURE
;
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
;
1682 *RetLength
= RX_NO_STRING
;
1684 if (retstr
.strptr
&& retstr
.strptr
!= execfunc_result
+ ILLEGAL_USE_SIZE
)
1685 IfcFreeMemory( retstr
.strptr
) ;
1690 int IfcHaveFunctionExit(const tsd_t
*TSD
)
1694 rt
= (rex_tsd_t
*)TSD
->rex_tsd
;
1695 if ( rt
->CurrentHandlers
&& rt
->CurrentHandlers
->Handlers
[RXFNC
] )
1701 /* ============================================================= */
1702 /* Asynchronous Rexx API interface */
1704 EXPORT_C APIRET APIENTRY
RexxSetHalt(LONG dummyProcess
,
1707 tsd_t
*TSD
= getGlobalTSD();
1710 TSD
= GLOBAL_ENTRY_POINT();
1711 StartupInterface(TSD
);
1713 * Perform sanity check on the parameters; is process id me ?
1715 set_rexx_halt( TSD
);
1719 /* ============================================================= */
1720 /* Named queue interface */
1722 EXPORT_C APIRET APIENTRY
RexxCreateQueue( PSZ Buffer
,
1728 unsigned long dupflag
= *DupFlag
;
1729 tsd_t
*TSD
= getGlobalTSD();
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;
1742 EXPORT_C APIRET APIENTRY
RexxDeleteQueue( PSZ QueueName
)
1745 tsd_t
*TSD
= getGlobalTSD();
1748 TSD
= GLOBAL_ENTRY_POINT();
1749 StartupInterface(TSD
);
1751 TSD
->called_from_saa
= 1;
1752 if (!QueueName
|| !strlen(QueueName
))
1753 code
= RXQUEUE_BADQNAME
;
1755 code
= IfcDeleteQueue( TSD
, QueueName
, strlen( QueueName
) );
1756 TSD
->called_from_saa
= 0;
1760 EXPORT_C APIRET APIENTRY
RexxQueryQueue( PSZ QueueName
,
1764 unsigned long count
= *Count
;
1765 tsd_t
*TSD
= getGlobalTSD();
1768 TSD
= GLOBAL_ENTRY_POINT();
1769 StartupInterface(TSD
);
1771 TSD
->called_from_saa
= 1;
1772 if (!QueueName
|| !strlen(QueueName
))
1773 code
= RXQUEUE_BADQNAME
;
1775 code
= IfcQueryQueue( TSD
, QueueName
, strlen( QueueName
), &count
);
1776 *Count
= (ULONG
)count
;
1777 TSD
->called_from_saa
= 0;
1781 EXPORT_C APIRET APIENTRY
RexxAddQueue( PSZ QueueName
,
1782 PRXSTRING EntryData
,
1786 tsd_t
*TSD
= getGlobalTSD();
1789 TSD
= GLOBAL_ENTRY_POINT();
1790 StartupInterface(TSD
);
1792 TSD
->called_from_saa
= 1;
1793 if (!QueueName
|| !strlen(QueueName
))
1794 code
= RXQUEUE_BADQNAME
;
1796 code
= IfcAddQueue( TSD
, QueueName
, strlen( QueueName
), EntryData
->strptr
, EntryData
->strlength
, AddFlag
==RXQUEUE_LIFO
);
1797 TSD
->called_from_saa
= 0;
1801 EXPORT_C APIRET APIENTRY
RexxPullQueue( PSZ QueueName
,
1803 PDATETIME TimeStamp
,
1807 tsd_t
*TSD
= getGlobalTSD();
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
;
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
;
1833 TimeStamp
->valid
= 0;
1836 TSD
->called_from_saa
= 0;
1840 /* ============================================================= */
1841 /* MacroSpace Rexx API interface */
1843 EXPORT_C APIRET APIENTRY
RexxAddMacro( PSZ FuncName
,
1850 EXPORT_C APIRET APIENTRY
RexxDropMacro( PSZ FuncName
)
1855 EXPORT_C APIRET APIENTRY
RexxSaveMacroSpace( ULONG FuncCount
,
1862 EXPORT_C APIRET APIENTRY
RexxLoadMacroSpace( ULONG FuncCount
,
1869 EXPORT_C APIRET APIENTRY
RexxQueryMacro( PSZ FuncName
,
1875 EXPORT_C APIRET APIENTRY
RexxReorderMacro( PSZ FuncName
,
1881 EXPORT_C APIRET APIENTRY
RexxClearMacroSpace( VOID
)
1886 /* ============================================================= */
1887 /* Regina extensions */
1888 /* see rexxsaa.h for a description */
1889 EXPORT_C APIRET APIENTRY
ReginaVersion( PRXSTRING VersionString
)
1893 tsd_t
*TSD
= getGlobalTSD();
1896 TSD
= GLOBAL_ENTRY_POINT();
1897 StartupInterface(TSD
);
1902 if ( VersionString
->strlength
== 0 )
1904 if ( ( VersionString
->strptr
= (char *)IfcAllocateMemory( sizeof(PARSE_VERSION_STRING
) ) ) == NULL
)
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
;
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];
1926 low
[1] = REGINA_VERSION_MINOR
[1];
1928 return( (atoi(REGINA_VERSION_MAJOR
) << 8) | atoi(low
) ) ;
1931 EXPORT_C APIRET APIENTRY
ReginaCleanup( VOID
)
1933 return( IfcReginaCleanup() );