2 static char *RCSid
= "$Id$";
5 * The Regina Rexx Interpreter
6 * Copyright (C) 1993-1994 Anders Christensen <anders@pvv.unit.no>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * This file implements the client part of the SAA API when Regina
25 * is linked into a program using SAA API. There is one routine for
26 * each of the functions in SAA API, and the functionality is partly
27 * implemented here, and partly by calling subroutines in Regina.
28 * Note that the interface to Regina is as simple as possible, so that
29 * a multitude of different transport mechanisms can be used (although
30 * normal linking is probably the most common.
32 * The following SAA API functions is defined in this source file:
34 * RexxStart() --- execute Rexx code
35 * RexxRegisterSubcomExe() --- register subcommand handler
36 * RexxRegisterSubcomDll() --- ditto (not yet implemented)
37 * RexxQuerySubcom() --- query subcommand handler
38 * RexxDeregisterSubcom() --- deregister subcommand handler
39 * RexxVariablePool() --- handle Rexx variable manipulation
40 * RexxRegisterExitExe() --- register exit handler
41 * RexxRegisterExitDll() --- ditto (not yet implemented)
42 * RexxDeregisterExit() --- deregister exit handler
43 * RexxQueryExit() --- query exit handler
44 * RexxRegisterFunctionExe() --- register external function handler
45 * RexxRegisterFunctionDll() --- ditto (from dynamic library)
46 * RexxQueryFunction() --- query external function
47 * RexxDeregisterFunction() --- deregister external function
48 * RexxSetHalt() --- set Halt and Trace
49 * RexxCreateQueue() --- create named queued
50 * RexxDeleteQueue() --- delete named queued
51 * RexxQueryQueue() --- query named queued
52 * RexxAddQueue() --- add line to named queued
53 * RexxPullQueue() --- pull line from named queued
54 * RexxAddMacro() --- add a macro to macrospace
55 * RexxClearMacroSpace() --- remove all macros from macrospace
56 * RexxDropMacro() --- remove macro from macrospace
57 * RexxLoadMacroSpace() --- load macrospace macros from file
58 * RexxQueryMacro() --- find a macro's search order
59 * RexxReorderMacro() --- change the search order for a macro
60 * RexxSaveMacroSpace() --- save macrospace to file
61 * RexxFreeMemory() --- free memory allocated by Rexx API
62 * RexxAllocateMemory() --- allocate memory to be freed by Rexx API
64 * These functions are all defined in the doc for SAA API. In addition,
65 * a number of calls in Regina are called, as well as a number of calls
66 * are defined for use by Regina. These all start with the prefix Ifc.
67 * First the one defined in rexxsaa.c, which can be called from other
70 * IfcSubCmd() --- invoke a subcommand
71 * IfcDoExit() --- invoke a system exit handler
72 * IfcExecFunc() --- invoke an external function handler
73 * IfcExecFuncDll() --- invoke an external function handler in a DLL
75 * Then the functions which are defined elsewhere, which can be called
76 * by this source code:
78 * IfcExecScript() --- start to execute Rexx code
79 * IfcVarPool() --- handle a variable manipulation request
80 * IfcRegFunc() --- register an external function name
81 * IfcDelFunc() --- deregister an external function name
82 * IfcQueryFunc() --- queries an external function name
83 * IfcAllocateMemory() --- allocate memory for API user
84 * IfcFreeMemory() --- free memory from API user
85 * IfcDeleteQueue() --- delete queue
86 * IfcAddQueue() --- add a line to the queue
87 * IfcPullQueue() --- pull a line off the queue
89 * All these routines are properly defined in the documentation for
90 * Regina. Other than the functions listed, the code in this file has
91 * been isolated as far as possible, and no functions specific to
92 * Regina is used, not even for memory allocation.
96 * We need to define these symbols in order to get the proper macros,
97 * datatypes, and declaration when including rexxsaa.h.
100 #define INCL_RXSUBCOM
102 #define INCL_RXSYSEXIT
111 * The rexxsaa.h header file defines the interface between this file and
112 * the client program which uses SAA API. The rxiface.h header file
113 * defines the interface between this file and Regina.
115 #include "configur.h"
117 * The following #define __REGINA_INTERNAL stops an error with MingW32
120 #define __REGINA_INTERNAL
123 #define DONT_TYPEDEF_PFN
129 #include "extstack.h"
146 #if defined(__EPOC32__) || defined(__WINS__)
150 # define APIRET unsigned long
159 struct funcbox2
*next
, *prev
;
161 RexxFunctionHandler
*entry
;
165 /* The following value allows called programs to call "free" to the return
166 * parameters without destroying our stack.
168 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
170 typedef struct { /* rex_tsd: static variables of this module (thread-safe) */
171 struct funcbox2
* saafuncs
[133];
172 struct ExitHandlers
*CurrentHandlers
;
173 struct EnvBox
* FirstEnv
;
174 struct EnvBox
* FirstExit
;
175 } rex_tsd_t
; /* thread-specific but only needed by this module. see
179 #define EXT_FUNCS_COUNT (sizeof(rt->saafuncs) / sizeof(rt->saafuncs[0]))
182 * The struct EnvBox datatype holds the definition of any subcommand
183 * handler (i.e. an 'environment'). It is intended as an double-linked
184 * list of entries, though performence concerns may force a change in
185 * this structure later. It contains the name of the environment, and
186 * an eight byte dataarea of user defined data. The same datastructure
187 * is also used for holding the symbol table of external functions.
189 * This may prove a problem in the future, since the number of external
190 * functions are generally much larger than the number of subcommand
191 * handlers. Thus, different datastructures may be necessary to acheive
192 * maximum performance.
196 struct EnvBox
*prev
, *next
; /* double linked list pointers */
197 char *EnvName
; /* environment/function name */
198 unsigned hash
; /* hash value of the EnvName */
199 unsigned char UserData
[8] ; /* user defined data area */
201 PFN EntryPnt
; /* external function entry point */
202 RexxSubcomHandler
*SubCom
; /* subcommand handler entry point */
208 RexxExitHandler
*(Handlers
[RXNOOFEXITS
]) ; /* for RexxRegisterExitExe */
209 struct ExitHandlers
*prev
;
215 * The following MAP_TYPE() macro maps from the SAA API macros holding
216 * the type of an invocation (function, subroutine or command), to its
217 * equivalent value in the internal interface of Regina (as defined in
220 #define MAP_TYPE(a) ((a)==RXCOMMAND ? RX_TYPE_COMMAND : \
221 (a)==RXFUNCTION ? RX_TYPE_FUNCTION : RX_TYPE_SUBROUTINE)
224 /* init_rexxsaa initializes the module.
225 * Currently, we set up the thread specific data.
226 * The function returns 1 on success, 0 if memory is short.
228 int init_rexxsaa( tsd_t
*TSD
)
232 if (TSD
->rex_tsd
!= NULL
)
235 if ((rt
= TSD
->rex_tsd
= MallocTSD(sizeof(rex_tsd_t
))) == NULL
)
237 memset(rt
,0,sizeof(rex_tsd_t
)); /* correct for all values */
241 /* deinit_rexxsaa deinitializes the module and frees used memory blocks not
242 * allocated by the Malloc-Interface. There isn't anything to do currently.
244 void deinit_rexxsaa( tsd_t
*TSD
)
249 /* StartupInterface initializes the Rexx system once per thread. Values like
250 * like __regina_get_tsd()->systeminfo are set. The true purpose of this
251 * function is to create an environment which allows the run of the
252 * interpreter. This is exactly the case when systeminfo exists. The last
253 * systeminfo is hopefully never deleted but that won't do any harm if we
254 * reinitialize the Rexx environment.
256 * There is a three-stage step to let a Rexx program run:
257 * 1) Initialize the runtime system and programming environment. This is
258 * done by __regina_get_tsd() done in GLOBAL_ENTRY_POINT().
259 * After this call you may use Malloc() and friends: basic things.
260 * 2) Initialize the Rexx system. This is done by
261 * __regina_faked_main() here or directly by any other caller of
262 * __regina_faked_main() or main():
263 * You are then allowed to access variables from the variable pool, load
264 * a Rexx program or just call a Rexx API function.
265 * Hint: The detection of this step is done as follows:.
266 * Rexx_system_is_running = (__regina_get_tsd()->systeminfo != NULL);
267 * or a similar compare.
268 * 3) Load the Rexx program in memory.
269 * Although you don't know, what program is currently loaded, you can
270 * check if a program is loaded (and running) by checking:
271 * Program_running = (__regina_get_tsd()->systeminfo->tree.root != NULL);
272 * This step is done in RexxStart or by main()/__regina_faked_main() when
273 * called as a program.
274 * Never use __regina_get_tsd() when it is not needed, of course.
275 * This function should be called as GLOBAL_ENTRY_POINT() at the very
276 * start of the interpreter but after GLOBAL_ENTRY_POINT.
278 static void StartupInterface(tsd_t
*TSD
)
280 /* The following value won't change and is const */
281 static char *args
[] = { "regina", "-Ci,foo", NULL
} ;
283 if (TSD
->systeminfo
!= NULL
)
286 __regina_faked_main( 2, args
) ;
291 * FillReq prepares a String with a given Length to be exported to an
292 * external application.
293 * The FillReq() function takes as parameter a pointer to a VarPool()
294 * request structure variable, and the definition of a string, and
295 * fill the content of the string into the request block. Note that the
296 * third parameter is gobbled up, so it can not be used or released by
297 * the calling function afterwards. Also, there are two macros defined,
298 * which gives a better access to the contents of the function
300 #define FillReqName(a,b,c) FillReq(a,b,c,1)
301 #define FillReqValue(a,b,c) FillReq(a,b,c,0)
303 static void FillReq( PSHVBLOCK Req
, ULONG Length
, const char *String
, int type
)
305 RXSTRING
*string
=NULL
;
309 string
= type
? &(Req
->shvname
) : &(Req
->shvvalue
) ;
310 strlen
= type
? &(Req
->shvnamelen
) : &(Req
->shvvaluelen
) ;
313 * If the string is undefined, set ->strptr to NULL. It is not required
314 * that the lengths parameters are set to zero, but I'll do this as
315 * nice gest to the users; someone is probably going to believe that
316 * this is how the data is returned.
318 if (Length
== RX_NO_STRING
)
320 string
->strptr
= NULL
;
321 *strlen
= string
->strlength
= 0 ;
326 * If a string was supplied, use it, else allocate sufficient space.
327 * The then part of the if will just copy the data to the user-supplied
328 * return string data area, noting a truncation is one occurred.
334 Req
->shvret
|= RXSHV_TRUNC
;
337 *strlen
= SaveLength
;
341 memcpy(string
->strptr
, String
, Length
) ;
342 string
->strlength
= Length
;
347 * The else part of the if will allocate new space for the data, and
348 * fills in the data, or return a memory fault if data could not
349 * properly be allocated.
351 * Some mallocs do not allow for a size of 0, so simply set the
352 * return length to 0 and don't attempt to do the malloc.
356 string
->strptr
= (char *)IfcAllocateMemory( Length
) ;
359 memcpy( string
->strptr
, String
, Length
) ;
360 string
->strlength
= Length
;
364 Req
->shvret
|= RXSHV_MEMFL
;
368 /* allocate at least 1 byte */
369 string
->strptr
= (char *)IfcAllocateMemory( 1 ) ;
373 string
->strlength
= Length
;
377 Req
->shvret
|= RXSHV_MEMFL
;
382 /* ========================================================================
383 * Here starts the section for maintaining the list of environments
384 * supported by this environment. There are several routines using
385 * the functions in this section, the routines defined here are:
387 * FindEnv() --- retrieves a pointer to a environment box.
389 * Actually, it used to be more, one to insert and one to delete.
390 * However, in order to save code, these was moved into the routines
391 * where they were called (they were used only once). The functions
392 * into which the code was moved are RexxRegisterSubcomExe(), and
393 * RexxDeregisterSubcom(). To improve modularization, and to
394 * ease the introduction of a new datastructure, the code should
395 * probably be extracted and inserted in this section.
399 #define BOX_IS_ENVIR 0
400 #define BOX_IS_EXIT 1
403 * Find a particular environment, and return a pointer to a struct
404 * containing information about that environment. If it is not found,
405 * a pointer to NULL is returned.
407 #define FindEnvir(a,b) FindBox(TSD,a,b,BOX_IS_ENVIR)
408 #define FindExit(a,b) FindBox(TSD,a,b,BOX_IS_EXIT)
410 static struct EnvBox
*FindBox( const tsd_t
*TSD
, const char *Env
, int EnvLen
, int type
)
417 bptr
= ((type
==BOX_IS_ENVIR
) ? rt
->FirstEnv
: rt
->FirstExit
) ;
419 h
= hashvalue(Env
, EnvLen
);
420 for (; bptr
; bptr
=bptr
->next
)
424 if (memcmp(bptr
->EnvName
,Env
,EnvLen
) == 0)
431 #define AddEnvir(a,b,c,d) AddBox(TSD,a,b,c,d,BOX_IS_ENVIR)
432 #define AddExit(a,b,c,d) AddBox(TSD,a,b,c,d,BOX_IS_EXIT)
434 static struct EnvBox
*AddBox( const tsd_t
*TSD
, const char *EnvName
, int EnvLen
,
435 const void *UserArea
, PFN EntryPoint
, int type
)
437 struct EnvBox
*NewBox
;
438 struct EnvBox
**first
;
442 first
= (type
==BOX_IS_ENVIR
) ? &rt
->FirstEnv
: &rt
->FirstExit
;
443 NewBox
= MallocTSD( sizeof( struct EnvBox
) ) ; /* This is not exported */
447 NewBox
->EnvName
= MallocTSD( EnvLen
+1 ) ; /* This is not exported */
448 if (!NewBox
->EnvName
)
454 NewBox
->prev
= NULL
;
455 NewBox
->next
= (*first
) ;
457 (*first
)->prev
= NewBox
;
460 memcpy( NewBox
->EnvName
, EnvName
, EnvLen
) ;
461 NewBox
->EnvName
[EnvLen
] = '\0';
462 NewBox
->hash
= hashvalue(EnvName
, EnvLen
);
463 NewBox
->u
.EntryPnt
= EntryPoint
;
465 memcpy( NewBox
->UserData
, UserArea
, 8 ) ;
467 memset( NewBox
->UserData
, 0x00, 8 ) ;
473 #define RemoveExit(a,b) RemoveBox(TSD,a,b,BOX_IS_EXIT)
474 #define RemoveEnvir(a,b) RemoveBox(TSD,a,b,BOX_IS_ENVIR)
476 static int RemoveBox( const tsd_t
*TSD
, const char *EnvName
, int EnvLen
, int type
)
478 struct EnvBox
*OldBox
;
479 struct EnvBox
**First
;
483 OldBox
= FindBox( TSD
, EnvName
, EnvLen
, type
) ;
486 First
= (type
==BOX_IS_ENVIR
) ? &rt
->FirstEnv
: &rt
->FirstExit
;
488 OldBox
->prev
->next
= OldBox
->next
;
490 OldBox
->next
->prev
= OldBox
->prev
;
491 if ((*First
)==OldBox
)
492 (*First
) = OldBox
->prev
;
494 FreeTSD( OldBox
->EnvName
) ;
501 /* RetLen and RetStr should point to {0,NULL}. They will be filled with
502 * freshly allocated values. A return value will always exist.
504 int IfcSubCmd( const tsd_t
*TSD
, int EnvLen
, const char *EnvStr
,
505 int CmdLen
, const char *CmdStr
,
506 int *RetLen
, char **RetStr
)
509 char *OldResult
= NULL
;
513 struct EnvBox
*Envir
=NULL
;
514 int rvalue
=0, RCode
=0, rc
=RXEXIT_NOT_HANDLED
;
515 char subcmd_result
[ILLEGAL_USE_SIZE
+RXAUTOBUFLEN
] ;
516 RXCMDHST_PARM cmdhst
;
522 Command
= MallocTSD( CmdLen
+ 1);
523 memcpy(Command
,CmdStr
,CmdLen
);
524 Command
[CmdLen
] = '\0';
525 memset( subcmd_result
, 0, sizeof( subcmd_result
) ) ;
526 MAKERXSTRING( Cmd
, Command
, CmdLen
) ;
527 MAKERXSTRING( Ret
, subcmd_result
+ ILLEGAL_USE_SIZE
, RXAUTOBUFLEN
) ;
528 OldResult
= subcmd_result
+ ILLEGAL_USE_SIZE
;
530 * Terminate the command string with nul character
532 if ( rt
->CurrentHandlers
&& rt
->CurrentHandlers
->Handlers
[RXCMD
] )
534 EnvNam
= MallocTSD( EnvLen
+ 1 ) ;
535 memcpy(EnvNam
, EnvStr
, EnvLen
) ;
536 EnvNam
[EnvLen
] = '\0';
537 cmdhst
.rxcmd_flags
.rxfcfail
= 0;
538 cmdhst
.rxcmd_flags
.rxfcerr
= 0;
539 cmdhst
.rxcmd_command
= Cmd
;
540 cmdhst
.rxcmd_address
= EnvNam
;
541 cmdhst
.rxcmd_addressl
= (USHORT
) EnvLen
;
542 cmdhst
.rxcmd_retc
= Ret
;
543 cmdhst
.rxcmd_dll
= NULL
;
544 cmdhst
.rxcmd_dll_len
= 0;
545 parm
= (PUCHAR
)&cmdhst
;
546 rc
= (*(rt
->CurrentHandlers
->Handlers
[RXCMD
]))(RXCMD
, RXCMDHST
, parm
);
547 assert( rc
==RXEXIT_HANDLED
|| rc
==RXEXIT_NOT_HANDLED
||
548 rc
==RXEXIT_RAISE_ERROR
) ;
549 if (cmdhst
.rxcmd_flags
.rxfcerr
)
550 RCode
= RXFLAG_ERROR
;
551 else if (cmdhst
.rxcmd_flags
.rxfcfail
)
552 RCode
= RXFLAG_FAILURE
;
555 Ret
= cmdhst
.rxcmd_retc
;
558 if (rc
== RXEXIT_NOT_HANDLED
)
560 Envir
= FindEnvir( EnvStr
, EnvLen
) ;
563 MAKERXSTRING( Cmd
, Command
, CmdLen
) ;
564 if (Ret
.strlength
&& OldResult
!= Ret
.strptr
) /* Ignore return values*/
565 IfcFreeMemory( Ret
.strptr
) ;
566 MAKERXSTRING( Ret
, subcmd_result
+ ILLEGAL_USE_SIZE
, RXAUTOBUFLEN
) ;
567 OldResult
= subcmd_result
+ ILLEGAL_USE_SIZE
;
568 rvalue
= (*(Envir
->u
.SubCom
))( &Cmd
, &Flags
, &Ret
) ;
569 if (Flags
==RXSUBCOM_OK
)
571 else if (Flags
==RXSUBCOM_ERROR
)
572 RCode
= RXFLAG_ERROR
;
573 else if (Flags
==RXSUBCOM_FAILURE
)
574 RCode
= RXFLAG_FAILURE
;
576 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
580 RCode
= RXFLAG_NOTREG
;
587 *RetLen
= Ret
.strlength
;
588 *RetStr
= MallocTSD( Ret
.strlength
) ;
589 memcpy( *RetStr
, Ret
.strptr
, Ret
.strlength
) ;
594 *RetStr
= MallocTSD( 1 ) ;
598 if (Ret
.strlength
&& OldResult
!= Ret
.strptr
)
599 IfcFreeMemory( Ret
.strptr
) ;
605 /* IfcDoExit calls an exit handler with one of the following codes set in Code.
606 * The arguments may either be input or output or nothing but not both.
607 * Parameter INIT TERMIN PULL TRCIN STDOUT STDERR GETENV PUTENV
608 * ---------------------------------------------------------------------------------------
609 * InputLength NULL NULL set set NULL NULL set NULL
610 * InputString NULL NULL set set NULL NULL set NULL
611 * OutputLength1 0 0 0 0 set set set set
612 * OutputString1 NULL NULL NULL NULL set set set set
613 * OutputLength2 0 0 0 0 0 0 0 set
614 * OutputString2 NULL NULL NULL NULL NULL NULL NULL set
617 * 1) An output string should always be a fresh copy. Although it is not
618 * allowed the user program may destroy the contents.
619 * For this reason OutputString is not declared as const.
620 * OutputString should be 0-terminated (0 not counted in OutputLength).
621 * 2) An input string is normally NOT required. Just provide a position
622 * where to place the input to. Example:
625 * IfcDoExit(?,?,0,NULL,0,NULL,&inlen,&in);
626 * If the caller of this function provides a valid input string it is
627 * ignored on exit. This function always returns back a freshly allocated
628 * string in InputString (an empty string in case of errors).
630 int IfcDoExit( const tsd_t
*TSD
, int Code
,
631 int OutputLength1
, char *OutputString1
,
632 int OutputLength2
, char *OutputString2
,
633 int *InputLength
, char **InputString
)
636 LONG SubCode
=0, MainCode
=0 ;
639 RXSIOSAY_PARM siosay
;
640 RXSIOTRD_PARM siotrd
;
641 RXSIODTR_PARM siodtr
;
642 RXENVSET_PARM envset
;
643 RXENVGET_PARM envget
;
649 MAKERXSTRING( siodtr
.rxsiodtr_retc
, NULL
, 0) ; /* Make compiler happy */
650 MAKERXSTRING( siotrd
.rxsiotrd_retc
, NULL
, 0) ; /* Make compiler happy */
651 MAKERXSTRING( envget
.rxenv_value
, NULL
, 0) ; /* Make compiler happy */
657 assert(InputLength
== NULL
&&
658 InputString
== NULL
&&
659 OutputLength2
== 0 &&
660 OutputString2
== NULL
&&
661 OutputLength2
== 0 &&
662 OutputString2
== NULL
);
663 siosay
.rxsio_string
.strptr
= OutputString1
;
664 siosay
.rxsio_string
.strlength
= OutputLength1
;
665 parm
= (PEXIT
)&siosay
;
666 SubCode
= (Code
==RX_EXIT_STDOUT
) ? RXSIOSAY
: RXSIOTRC
;
672 assert(OutputLength1
== 0 &&
673 OutputString1
== NULL
&&
674 InputLength
!= NULL
&&
675 InputString
!= NULL
&&
676 OutputLength2
== 0 &&
677 OutputString2
== NULL
);
678 siodtr
.rxsiodtr_retc
.strlength
= *InputLength
;
679 siodtr
.rxsiodtr_retc
.strptr
= *InputString
;
680 parm
= (PEXIT
)&siodtr
;
686 assert(OutputLength1
== 0 &&
687 OutputString1
== NULL
&&
688 InputLength
!= NULL
&&
689 InputString
!= NULL
&&
690 OutputLength2
== 0 &&
691 OutputString2
== NULL
);
692 siotrd
.rxsiotrd_retc
.strlength
= *InputLength
;
693 siotrd
.rxsiotrd_retc
.strptr
= *InputString
;
694 parm
= (PEXIT
)&siotrd
;
700 assert(OutputLength1
== 0 &&
701 OutputString1
== NULL
&&
702 InputLength
== NULL
&&
703 InputString
== NULL
&&
704 OutputLength2
== 0 &&
705 OutputString2
== NULL
);
711 assert(OutputLength1
== 0 &&
712 OutputString1
== NULL
&&
713 InputLength
== NULL
&&
714 InputString
== NULL
&&
715 OutputLength2
== 0 &&
716 OutputString2
== NULL
);
722 assert(InputLength
== NULL
&&
723 InputString
== NULL
&&
724 OutputLength2
!= 0 &&
725 OutputString2
!= NULL
&&
726 OutputLength2
!= 0 &&
727 OutputString2
!= NULL
);
728 envset
.rxenv_name
.strptr
= OutputString1
;
729 envset
.rxenv_name
.strlength
= OutputLength1
;
730 envset
.rxenv_value
.strptr
= OutputString2
;
731 envset
.rxenv_value
.strlength
= OutputLength2
;
732 parm
= (PEXIT
)&envset
;
739 assert(OutputLength1
!= 0 &&
740 OutputString1
!= NULL
&&
741 InputLength
!= NULL
&&
742 InputString
!= NULL
&&
743 OutputLength2
== 0 &&
744 OutputString2
== NULL
);
745 envget
.rxenv_value
.strlength
= *InputLength
;
746 envget
.rxenv_value
.strptr
= *InputString
;
747 envget
.rxenv_name
.strptr
= OutputString1
;
748 envget
.rxenv_name
.strlength
= OutputLength1
;
749 parm
= (PEXIT
)&envget
;
755 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
759 assert( rt
->CurrentHandlers
->Handlers
[MainCode
] ) ;
761 rc
= (*(rt
->CurrentHandlers
->Handlers
[MainCode
]))(MainCode
, SubCode
, parm
);
762 assert( rc
==RXEXIT_HANDLED
|| rc
==RXEXIT_NOT_HANDLED
||
763 rc
==RXEXIT_RAISE_ERROR
) ;
775 retlen
= siodtr
.rxsiodtr_retc
.strlength
;
776 retstr
= siodtr
.rxsiodtr_retc
.strptr
;
780 retlen
= siotrd
.rxsiotrd_retc
.strlength
;
781 retstr
= siotrd
.rxsiotrd_retc
.strptr
;
785 retlen
= envget
.rxenv_value
.strlength
;
786 retstr
= envget
.rxenv_value
.strptr
;
790 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
793 if (rc
==RXEXIT_HANDLED
)
795 else if (rc
==RXEXIT_NOT_HANDLED
)
797 else if (rc
==RXEXIT_RAISE_ERROR
)
800 if (InputLength
!= NULL
) /* retlen and retstr forms a return string. */
802 if ((retlen
== 0) || (retstr
== NULL
))
808 /* Make a fresh copy, the user may change the value very fast. */
809 *InputString
= MallocTSD( (retlen
< 1) ? 1 : retlen
);
810 memcpy(*InputString
, retstr
, retlen
);
811 *InputLength
= retlen
;
817 /* ================================================================ */
818 /* ================ general purpose API functions ================= */
820 /* You are not allowed to use TSD or __regina_get_tsd() here! */
821 EXPORT_C APIRET APIENTRY
RexxFreeMemory(PVOID MemoryBlock
)
824 return(RXFUNC_BADTYPE
);
826 return IfcFreeMemory( MemoryBlock
);
829 /* You are not allowed to use TSD or __regina_get_tsd() here! */
830 EXPORT_C PVOID APIENTRY
RexxAllocateMemory(ULONG size
)
832 return IfcAllocateMemory( size
);
835 /* ================================================================ */
836 /* ================ in order to start Rexx scripts ================ */
838 EXPORT_C APIRET APIENTRY
RexxStart(LONG ArgCount
,
848 int cnt
=0, RLength
=0 ;
851 const char *ParStrings
[32] ;
854 const char *EnvNamStr
;
855 int WhereCode
=0, rc
=0 ;
856 const char *SourcePtr
;
858 unsigned long SourceLen
, TinLen
;
859 struct ExitHandlers
*Handlers
=NULL
;
860 RexxExitHandler
*handler
=NULL
;
861 struct EnvBox
*EnvPtr
=NULL
;
863 unsigned long instore_length
= 0;
864 void *instore_buf
= NULL
;
865 PCSZ ProgramName
=ProgName
;
870 TSD
= GLOBAL_ENTRY_POINT();
872 StartupInterface(TSD
);
874 if ((ArgCount
< 0) || ((ArgCount
> 0) && (ArgList
== NULL
)))
875 return(RXFUNC_BADTYPE
);
877 return(RXFUNC_BADTYPE
);
879 * Check if running in restricted mode first.
881 if ( CallType
& RXRESTRICTED
)
884 CallType
-= RXRESTRICTED
;
886 if ((CallType
!= RXCOMMAND
) &&
887 (CallType
!= RXSUBROUTINE
) &&
888 (CallType
!= RXFUNCTION
))
889 return(RXFUNC_BADTYPE
);
890 if ((CallType
== RXCOMMAND
) && (ArgCount
> 1))
891 return(RX_START_TOOMANYP
);
892 if (ArgCount
> sizeof(ParLengths
) / sizeof(ParLengths
[0]) )
893 return(RX_START_TOOMANYP
);
897 /* MH 2602 if (Instore[1].strptr && Instore[1].strlength < sizeof(int)) */
898 if (Instore
[1].strptr
&& Instore
[1].strlength
< 1)
899 return RX_START_BADP
;
902 if (ArgCount
> sizeof(ParLengths
) / sizeof(ParLengths
[0]) )
903 ArgCount
= sizeof(ParLengths
) / sizeof(ParLengths
[0]) ;
904 for (cnt
=0; cnt
<ArgCount
; cnt
++)
906 ParLengths
[cnt
] = ArgList
[cnt
].strlength
;
907 ParStrings
[cnt
] = ArgList
[cnt
].strptr
;
908 if (ParStrings
[cnt
]==NULL
)
909 ParLengths
[cnt
] = RX_NO_STRING
;
912 Handlers
= TSD
->MTMalloc( TSD
, sizeof( struct ExitHandlers
)) ;
913 Handlers
->prev
= rt
->CurrentHandlers
;
914 rt
->CurrentHandlers
= Handlers
;
915 for (cnt
=0; cnt
<RXNOOFEXITS
; cnt
++)
916 rt
->CurrentHandlers
->Handlers
[cnt
] = NULL
;
918 ExitFlags
= 0x00000000 ;
919 for (cnt
=0; Exits
&& Exits
->sysexit_code
!=RXENDLST
; Exits
++ )
921 if ( Exits
->sysexit_name
== NULL
922 || strlen( Exits
->sysexit_name
) == 0 )
923 return(RX_START_BADP
);
925 EnvPtr
= FindExit( Exits
->sysexit_name
, strlen(Exits
->sysexit_name
) ) ;
929 /* Sigh ... Definition requires some strange casting */
930 handler
= (RexxExitHandler
*)(EnvPtr
->u
.EntryPnt
) ;
931 switch (Exits
->sysexit_code
)
934 ExitFlags
|= (1<<RX_EXIT_STDOUT
) | (1<<RX_EXIT_STDERR
) |
935 (1<<RX_EXIT_TRCIN
) | (1<<RX_EXIT_PULL
) ;
936 rt
->CurrentHandlers
->Handlers
[RXSIO
] = handler
;
940 ExitFlags
|= (1<<RX_EXIT_INIT
) ;
941 rt
->CurrentHandlers
->Handlers
[RXINI
] = handler
;
945 ExitFlags
|= (1<<RX_EXIT_TERMIN
) ;
946 rt
->CurrentHandlers
->Handlers
[RXTER
] = handler
;
950 ExitFlags
|= (1<<RX_EXIT_SUBCOM
) ;
951 rt
->CurrentHandlers
->Handlers
[RXCMD
] = handler
;
955 ExitFlags
|= (1<<RX_EXIT_FUNC
) ;
956 rt
->CurrentHandlers
->Handlers
[RXFNC
] = handler
;
960 ExitFlags
|= (1<<RX_EXIT_GETENV
) | (1<<RX_EXIT_SETENV
) ;
961 rt
->CurrentHandlers
->Handlers
[RXENV
] = handler
;
965 return(RX_START_BADP
);
971 EnvNamLen
= strlen(EnvName
) ;
972 EnvNamStr
= EnvName
;
976 EnvNamLen
= RX_NO_STRING
;
984 if (Instore
&& Instore
[1].strptr
)
986 WhereCode
= RX_TYPE_INSTORE
;
987 TinPtr
= Instore
[1].strptr
;
988 TinLen
= Instore
[1].strlength
;
989 SourcePtr
= Instore
[0].strptr
;
990 SourceLen
= Instore
[0].strlength
;
992 else if (Instore
&& Instore
[0].strptr
)
994 WhereCode
= RX_TYPE_SOURCE
;
995 SourcePtr
= Instore
[0].strptr
;
996 SourceLen
= Instore
[0].strlength
;
999 WhereCode
= RX_TYPE_MACRO
;
1001 WhereCode
= RX_TYPE_EXTERNAL
;
1004 rc
= IfcExecScript( strlen(ProgramName
), ProgramName
,
1005 ArgCount
, ParLengths
, (const char **) ParStrings
, MAP_TYPE(CallType
),
1006 ExitFlags
, EnvNamLen
, EnvNamStr
, WhereCode
, restricted
,
1007 SourcePtr
, SourceLen
, TinPtr
, TinLen
,
1008 &RLength
, &RString
, &instore_buf
, &instore_length
) ;
1009 Handlers
= rt
->CurrentHandlers
;
1010 rt
->CurrentHandlers
= Handlers
->prev
;
1011 TSD
->MTFree( TSD
, Handlers
) ;
1013 if (WhereCode
== RX_TYPE_SOURCE
)
1015 Instore
[1].strptr
= instore_buf
;
1016 Instore
[1].strlength
= instore_length
;
1019 if (RLength
!=RX_NO_STRING
)
1020 ResValue
= atoi( RString
) ;
1025 *ReturnCode
= (SHORT
) ResValue
; /* FGC */
1029 if (!Result
->strptr
|| (int)Result
->strlength
>=RLength
+1)
1031 Result
->strlength
= RLength
;
1032 Result
->strptr
= RString
;
1036 Result
->strlength
= RLength
;
1037 memcpy( Result
->strptr
, RString
, RLength
+1 ) ;
1038 IfcFreeMemory( RString
) ;
1042 IfcFreeMemory( RString
) ;
1045 * Remove any internal queues and any connection to
1048 purge_stacks( TSD
);
1050 * Close all open files and reset Regina's internal file table
1052 purge_filetable( TSD
);
1055 * Free internal memory allocations
1057 #if defined(FLISTS) && defined(SINGLE_THREADED)
1058 purge_flists( TSD
);
1066 /* ============================================================= */
1067 /* subcom handler subsystem */
1069 EXPORT_C APIRET APIENTRY
RexxRegisterSubcomExe(PCSZ EnvName
,
1076 TSD
= GLOBAL_ENTRY_POINT();
1077 StartupInterface(TSD
);
1080 * Perform sanity check on the parameters; UserArea may be NULL
1082 if (!EnvName
|| !EntryPoint
)
1083 return RXSUBCOM_BADTYPE
;
1085 EnvLen
= strlen( EnvName
) ;
1086 if (EnvLen
>MAXENVNAMELEN
)
1087 return RXSUBCOM_NOTREG
;
1089 if (FindEnvir( EnvName
, EnvLen
))
1090 return RXSUBCOM_NOTREG
;
1092 if (!AddEnvir( EnvName
, strlen(EnvName
) , UserArea
, EntryPoint
))
1093 return RXSUBCOM_NOEMEM
;
1095 return RXSUBCOM_OK
;
1099 EXPORT_C APIRET APIENTRY
RexxRegisterSubcomDll(PCSZ EnvName
,
1107 TSD
= GLOBAL_ENTRY_POINT();
1108 StartupInterface(TSD
);
1110 if (!EnvName
|| !ModuleName
|| !ProcedureName
)
1111 return(RXSUBCOM_BADTYPE
);
1113 /* not yet functional */
1114 return RXSUBCOM_NOTREG
;
1118 EXPORT_C APIRET APIENTRY
RexxQuerySubcom(PCSZ EnvName
,
1120 PUSHORT Flag
, /* Who knows what this is used for ... */
1124 struct EnvBox
*eptr
=NULL
;
1127 TSD
= GLOBAL_ENTRY_POINT();
1128 StartupInterface(TSD
);
1130 if (!EnvName
|| !Flag
)
1131 return(RXFUNC_BADTYPE
);
1133 /* ModuleName is not yet functional */
1135 eptr
= FindEnvir( EnvName
, strlen(EnvName
) ) ;
1140 memcpy( UserWord
, eptr
->UserData
, 8 ) ;
1143 ret
= RXSUBCOM_NOTREG
;
1145 *Flag
= 0; /* what else to give it ? */
1150 EXPORT_C APIRET APIENTRY
RexxDeregisterSubcom(PCSZ EnvName
,
1155 TSD
= GLOBAL_ENTRY_POINT();
1156 StartupInterface(TSD
);
1159 return(RXSUBCOM_BADTYPE
);
1161 /* ModuleName is not yet functional */
1163 if (RemoveEnvir( EnvName
, strlen(EnvName
) ))
1164 return RXSUBCOM_NOTREG
;
1166 return RXSUBCOM_OK
;
1171 /* ============================================================ */
1172 /* Variable subsystem */
1173 /* JH 20-10-99 */ /* To make Direct setting of stems Direct and not Symbolic. */
1174 /****************************************************************************
1176 * JH 13/12/1999 (Original code changes on 20/10/1999)
1178 * BUG022 To make Direct setting of stems Direct and not Symbolic.
1179 * - Added checks for the direct variable functions RX_GETVAR and RX_SETVAR.
1180 * In the switch that determines what to do, based on the value passed in
1181 * shvcode, symbolics still fall through to the code that is under the
1182 * direct labels, but it sets a variable to denote that symbolic processing
1183 * is to take place. The direct section only sets this variable if it has
1184 * not been set before.
1185 * - Added new variable IVPcode (IfcVariablePool) that will contain the code
1186 * used to call IfcVariablePool(), instead of hard coding the parameter,
1188 * NB that this routine lumps the Drop's and Set's together, before calling
1189 * IfcVarPool(). At some point it might be better to pass the shvcode
1190 * value, rather than translating it and later performing additional
1191 * checks to split it back out.
1193 ****************************************************************************/
1194 EXPORT_C APIRET APIENTRY
RexxVariablePool(PSHVBLOCK RequestBlockList
)
1196 int Code
=0, RetCode
=0, IVPcode
;
1200 PSHVBLOCK Req
=RequestBlockList
;
1204 TSD
= GLOBAL_ENTRY_POINT();
1206 StartupInterface(TSD
);
1208 if (!RequestBlockList
) /* FGC: I assume we must have at least one param */
1209 return(RXFUNC_BADTYPE
);
1211 if (TSD
->systeminfo
->tree
.root
==NULL
) /* Doesn't the interpreter run? */
1212 return RXSHV_NOAVL
;
1216 for (;Req
;Req
=Req
->shvnext
)
1218 IVPcode
= 0; /* Needed for a correct IVPcode on a second request */
1219 switch (Req
->shvcode
)
1223 IVPcode
= RX_SETSVAR
; /* JH 20-10-99 */
1224 case RXSHV_DROPV
: /* MH 26-12-95 */
1225 case RXSHV_SET
: /* MH 26-12-95 */
1227 IVPcode
= IVPcode
? IVPcode
: RX_SETVAR
; /* JH 20-10-99 */
1228 Lengths
[0] = Req
->shvname
.strlength
;
1229 Strings
[0] = Req
->shvname
.strptr
;
1230 if (Req
->shvcode
==RXSHV_SYSET
/* MH 26-12-95 */
1231 || Req
->shvcode
==RXSHV_SET
) /* MH 26-12-95 */
1233 Lengths
[1] = Req
->shvvalue
.strlength
;
1234 Strings
[1] = Req
->shvvalue
.strptr
;
1237 Lengths
[1] = RX_NO_STRING
;
1239 Code
= IfcVarPool( TSD
, IVPcode
, Lengths
, Strings
) ; /* JH 20-10-99 */
1241 Req
->shvret
= RXSHV_OK
;
1242 if (Code
==RX_CODE_NOVALUE
)
1243 Req
->shvret
|= RXSHV_NEWV
;
1244 else if (Code
==RX_CODE_INVNAME
)
1245 Req
->shvret
|= RXSHV_BADN
;
1246 else if (Code
!=RXSHV_OK
)
1247 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1248 TSD
->var_indicator
=0;
1252 IVPcode
= RX_GETSVAR
; /* JH 20-10-99 */
1253 case RXSHV_FETCH
: /* MH 26-12-95 */
1255 IVPcode
= IVPcode
? IVPcode
: RX_GETVAR
; /* JH 20-10-99 */
1256 Lengths
[0] = Req
->shvname
.strlength
;
1257 Strings
[0] = Req
->shvname
.strptr
;
1258 /* FIXME, FGC: This two lines are unnecessary
1259 Lengths[1] = Req->shvvalue.strlength ;
1260 Strings[1] = Req->shvvalue.strptr ; */
1261 Code
= IfcVarPool( TSD
, IVPcode
, Lengths
, Strings
) ; /* JH 20-10-99 */
1263 Req
->shvret
= RXSHV_OK
;
1264 if (Code
==RX_CODE_NOVALUE
)
1265 Req
->shvret
|= RXSHV_NEWV
;
1266 else if (Code
==RX_CODE_INVNAME
)
1267 Req
->shvret
|= RXSHV_BADN
;
1268 else if (Code
!=RXSHV_OK
)
1269 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1270 FillReqValue( Req
, Lengths
[1], Strings
[1] ) ;
1271 TSD
->var_indicator
=0;
1277 Req
->shvret
= RXSHV_OK
;
1278 if (Req
->shvname
.strlength
==4 && Req
->shvname
.strptr
&&
1279 !strncmp(Req
->shvname
.strptr
, "PARM", 4 ))
1281 rc
= IfcVarPool( TSD
, RX_CODE_PARAMS
, Lengths
, Strings
) ;
1282 FillReqValue( Req
, Lengths
[0], Strings
[0] ) ;
1285 else if (Req
->shvname
.strlength
>=5 && Req
->shvname
.strptr
&&
1286 !strncmp(Req
->shvname
.strptr
, "PARM.", 5 ))
1288 Lengths
[0] = Req
->shvname
.strlength
- 5 ;
1289 Strings
[0] = Req
->shvname
.strptr
+ 5 ;
1291 rc
= IfcVarPool( TSD
, RX_CODE_PARAM
, Lengths
, Strings
) ;
1292 if (rc
== RX_CODE_OK
)
1293 FillReqValue( Req
, Lengths
[1], Strings
[1] ) ;
1295 Req
->shvret
|= RXSHV_BADN
;
1301 if (Req
->shvname
.strptr
)
1303 if (Req
->shvname
.strlength
==7 &&
1304 !memcmp(Req
->shvname
.strptr
, "QUENAME", 7))
1306 Code
= RX_CODE_QUEUE
;
1308 else if (Req
->shvname
.strlength
==7 &&
1309 !memcmp(Req
->shvname
.strptr
, "VERSION", 7))
1311 Code
= RX_CODE_VERSION
;
1313 else if (Req
->shvname
.strlength
==6 &&
1314 !memcmp(Req
->shvname
.strptr
, "SOURCE", 6))
1316 Code
= RX_CODE_SOURCE
;
1319 Req
->shvret
|= RXSHV_BADN
;
1321 if (!Req
->shvret
| RXSHV_BADN
)
1323 rc
=IfcVarPool( TSD
, Code
, Lengths
, Strings
) ;
1324 FillReqValue( Req
, Lengths
[0], Strings
[0] ) ;
1328 Req
->shvret
|= RXSHV_BADN
;
1337 Req
->shvret
= RXSHV_OK
;
1338 Items
= IfcVarPool( TSD
, RX_NEXTVAR
, Lengths
, Strings
) ;
1339 assert( Items
==0 || Items
==2 ) ;
1343 FillReqValue( Req
, Lengths
[1], Strings
[1] ) ;
1344 FillReqName( Req
, Lengths
[0], Strings
[0] ) ;
1347 Req
->shvret
|= RXSHV_LVAR
;
1353 Req
->shvret
= RXSHV_BADF
;
1356 RetCode
|= ( Req
->shvret
& 0x007f ) ;
1364 /* ================================================================ */
1365 /* system exit handler subsystem */
1367 EXPORT_C APIRET APIENTRY
RexxRegisterExitExe(PCSZ EnvName
,
1374 TSD
= GLOBAL_ENTRY_POINT();
1375 StartupInterface(TSD
);
1377 if (!EnvName
|| !EntryPoint
)
1378 return RXEXIT_BADTYPE
;
1380 EnvLen
= strlen( EnvName
) ;
1381 if (EnvLen
>MAXENVNAMELEN
)
1382 return RXEXIT_NOTREG
;
1384 if (FindExit( EnvName
, EnvLen
))
1385 return RXEXIT_NOTREG
;
1387 if (!AddExit( EnvName
, EnvLen
, UserArea
, EntryPoint
))
1388 return RXEXIT_NOEMEM
;
1393 EXPORT_C APIRET APIENTRY
RexxRegisterExitDll(PCSZ EnvName
,
1401 TSD
= GLOBAL_ENTRY_POINT();
1402 StartupInterface(TSD
);
1404 if (!EnvName
|| !ModuleName
|| !ProcedureName
)
1405 return(RXFUNC_BADTYPE
);
1406 /* not yet functional */
1407 return RXEXIT_NOTREG
;
1411 EXPORT_C APIRET APIENTRY
RexxDeregisterExit(PCSZ EnvName
,
1416 TSD
= GLOBAL_ENTRY_POINT();
1417 StartupInterface(TSD
);
1420 return(RXFUNC_BADTYPE
);
1422 /* Ignore ModuleName, it may be NULL in case of an Exe-handler */
1424 if (RemoveExit(EnvName
, strlen(EnvName
) ))
1425 return RXEXIT_NOTREG
;
1430 EXPORT_C APIRET APIENTRY
RexxQueryExit(PCSZ EnvName
,
1436 struct EnvBox
*EnvPtr
=NULL
;
1439 TSD
= GLOBAL_ENTRY_POINT();
1440 StartupInterface(TSD
);
1442 if (!EnvName
|| !Flag
)
1443 return(RXEXIT_BADTYPE
);
1445 EnvPtr
= FindExit( EnvName
, strlen( EnvName
) ) ;
1446 if ( EnvPtr
== NULL
)
1448 *Flag
= RXEXIT_NOTREG
;
1456 memcpy( UserArea
, EnvPtr
->UserData
, 8 ) ;
1461 /* =================================================================== */
1464 * This section contains the support for the external functions
1467 static struct funcbox2
*findfunc( const tsd_t
*TSD
, const char *name
)
1469 struct funcbox2
*fptr
=NULL
;
1475 hash
= hashvalue( name
, -1 ) ;
1476 hashbox
= hash
% EXT_FUNCS_COUNT
;
1477 for (fptr
=rt
->saafuncs
[hashbox
]; fptr
; fptr
=fptr
->prev
)
1478 if (fptr
->hash
== hash
)
1479 if (!strcmp(name
, fptr
->name
))
1485 static int delfunc2( const tsd_t
*TSD
, const char *name
)
1487 struct funcbox2
*old
=NULL
;
1492 old
= findfunc( TSD
, name
) ;
1494 return RXFUNC_NOTREG
;
1496 hashbox
= hashvalue( name
, -1 ) % EXT_FUNCS_COUNT
;
1497 FreeTSD( old
->name
) ;
1498 if (old
==rt
->saafuncs
[hashbox
])
1499 rt
->saafuncs
[hashbox
] = old
->prev
;
1501 old
->next
->prev
= old
->prev
;
1504 old
->prev
->next
= old
->next
;
1510 static int addfunc2( const tsd_t
*TSD
, const char *name
, RexxFunctionHandler
*EntryPoint
)
1512 struct funcbox2
*new=NULL
;
1518 if (findfunc( TSD
, name
))
1519 return RXFUNC_DEFINED
;
1521 new = MallocTSD( sizeof(struct funcbox2
) ) ;
1523 return RXFUNC_NOMEM
;
1525 new->name
= MallocTSD( strlen( name
)+1 ) ;
1529 return RXFUNC_NOMEM
;
1532 strcpy( new->name
, name
) ;
1533 hash
= hashvalue( new->name
, -1 ) ;
1534 hashbox
= hash
% EXT_FUNCS_COUNT
;
1536 new->entry
= EntryPoint
;
1539 new->prev
= rt
->saafuncs
[hashbox
] ;
1540 if (rt
->saafuncs
[hashbox
])
1541 rt
->saafuncs
[hashbox
]->next
= new ;
1542 rt
->saafuncs
[hashbox
] = new ;
1548 EXPORT_C APIRET APIENTRY
RexxRegisterFunctionExe( PCSZ Name
,
1556 TSD
= GLOBAL_ENTRY_POINT();
1557 StartupInterface(TSD
);
1559 if (!Name
|| !EntryPoint
)
1560 return(RXFUNC_BADTYPE
);
1562 if ((upper_name
= MallocTSD( strlen(Name
)+1) ) == NULL
)
1563 return(RXFUNC_NOMEM
);
1564 strcpy(upper_name
,Name
);
1565 for (i
=0;i
<(int) strlen(upper_name
);i
++)
1566 *(upper_name
+i
) = (char) toupper(*(upper_name
+i
));
1567 code
= addfunc2( TSD
, upper_name
, (RexxFunctionHandler
*)EntryPoint
) ;
1568 FreeTSD( upper_name
);
1572 code
= IfcRegFunc( TSD
, Name
) ;
1574 case RX_CODE_OK
: code
= RXFUNC_OK
; break;
1575 case RX_CODE_NOMEM
: code
= RXFUNC_NOMEM
; break;
1578 assert( code
==RXFUNC_OK
) ; /* A simple "if (code!=RXFUNC_OK)delfunc2()"
1585 EXPORT_C APIRET APIENTRY
RexxRegisterFunctionDll( PCSZ ExternalName
,
1591 TSD
= GLOBAL_ENTRY_POINT();
1592 StartupInterface(TSD
);
1594 if (!ExternalName
|| !LibraryName
|| !InternalName
)
1595 return(RXFUNC_BADTYPE
);
1596 return ((ULONG
)IfcRegDllFunc(TSD
,ExternalName
,LibraryName
,InternalName
));
1599 EXPORT_C APIRET APIENTRY
RexxQueryFunction( PCSZ Name
)
1603 TSD
= GLOBAL_ENTRY_POINT();
1604 StartupInterface(TSD
);
1607 return(RXFUNC_BADTYPE
);
1608 return ( IfcQueryFunc( TSD
, Name
) ) ? RXFUNC_NOTREG
: RXFUNC_OK
;
1612 EXPORT_C APIRET APIENTRY
RexxDeregisterFunction( PCSZ Name
)
1617 TSD
= GLOBAL_ENTRY_POINT();
1618 StartupInterface(TSD
);
1620 return(RXFUNC_BADTYPE
);
1621 if ((rc
= delfunc2(TSD
, Name
)) != RXFUNC_OK
)
1623 return (IfcDelFunc(TSD
, Name
)) ? RXFUNC_NOTREG
: RXFUNC_OK
;
1626 /* The caller of IfcFunctionExit should call this function with fresh copies of
1627 * Name and params to be bullet-proof. The called function MAY
1628 * change the values although this is illegal.
1630 static int IfcFunctionExit(const tsd_t
*TSD
,
1640 RXFNCCAL_PARM fnccal
;
1648 if ( rt
->CurrentHandlers
&& rt
->CurrentHandlers
->Handlers
[RXFNC
] )
1650 len
= strlen( queuename
) ;
1651 qname
= MallocTSD( len
+ 1 ) ;
1652 memcpy( qname
, queuename
, len
+ 1 ) ;
1653 fnccal
.rxfnc_flags
.rxfferr
= 0;
1654 fnccal
.rxfnc_flags
.rxffnfnd
= 0;
1655 fnccal
.rxfnc_flags
.rxffsub
= (called
) ? 1 : 0;
1656 fnccal
.rxfnc_name
= (unsigned char *)Name
;
1657 fnccal
.rxfnc_namel
= (USHORT
) strlen(Name
);
1658 fnccal
.rxfnc_que
= qname
;
1659 fnccal
.rxfnc_quel
= (USHORT
) len
;
1660 fnccal
.rxfnc_argc
= (USHORT
) Params
;
1661 fnccal
.rxfnc_argv
= params
;
1662 fnccal
.rxfnc_retc
= *Retstr
;
1663 parm
= (PUCHAR
)&fnccal
;
1664 rc
= (*(rt
->CurrentHandlers
->Handlers
[RXFNC
]))(RXFNC
, RXFNCCAL
, parm
);
1665 assert( rc
==RXEXIT_HANDLED
|| rc
==RXEXIT_NOT_HANDLED
||
1666 rc
==RXEXIT_RAISE_ERROR
) ;
1667 if (rc
== RXEXIT_HANDLED
)
1669 if (fnccal
.rxfnc_flags
.rxfferr
)
1670 *RCode
= RXFLAG_ERROR
;
1671 else if (fnccal
.rxfnc_flags
.rxffnfnd
)
1672 *RCode
= RXFLAG_FAILURE
;
1676 *Retstr
= fnccal
.rxfnc_retc
;
1681 return (RXEXIT_NOT_HANDLED
);
1685 /* The caller of IfcExecFunc should call this function with fresh copies of
1686 * Name, Length and Strings to be bullet-proof. The called function MAY
1687 * change the values although this is illegal.
1688 * RetLength and RetString should point to {0,NULL}. They will be filled with
1689 * freshly allocated values if there are some.
1691 int IfcExecFunc( const tsd_t
*TSD
, PFN Func
, char *Name
, int Params
,
1692 int *Lengths
, char **Strings
,
1693 int *RetLength
, char **RetString
,
1694 int *RC
, char exitonly
, char called
)
1696 struct funcbox2
*fptr
=NULL
;
1697 int i
=0, length
=0, rc
=0, RCode
=0 ;
1698 RXSTRING
*params
, retstr
;
1700 char execfunc_result
[ILLEGAL_USE_SIZE
+RXAUTOBUFLEN
] ;
1704 assert( Params
>= 0 ) ;
1706 params
= MallocTSD( sizeof(RXSTRING
)*Params
) ;
1707 for (i
=0; i
<Params
; i
++)
1709 length
= Lengths
[i
] ;
1710 if (length
==RX_NO_STRING
)
1712 params
[i
].strptr
= NULL
;
1713 params
[i
].strlength
= 0 ;
1717 params
[i
].strptr
= Strings
[i
] ;
1718 params
[i
].strlength
= length
;
1722 memset( execfunc_result
, 0, sizeof( execfunc_result
) ) ;
1723 retstr
.strptr
= execfunc_result
+ ILLEGAL_USE_SIZE
;
1724 retstr
.strlength
= RXAUTOBUFLEN
; /* MH 26-12-95 */
1726 rc
= IfcFunctionExit( TSD
, Name
, Params
, params
, "default",
1727 &retstr
, &RCode
, called
);
1730 case RXEXIT_NOT_HANDLED
:
1733 *RC
= ERR_ROUTINE_NOT_FOUND
;
1737 /* Func or fptr->entry will inherit a possible return value in
1738 * retstr. This might be a problem, expect suspicious results
1739 * if the called functions are not error free.
1743 if ((fptr
=findfunc( TSD
, Name
)) == NULL
)
1746 return RX_CODE_NOSUCH
;
1748 rc
= (*(fptr
->entry
))( Name
, Params
, params
, "default", &retstr
) ;
1751 rc
= (*(Func
))( Name
, Params
, params
, "default", &retstr
) ;
1754 *RC
= ERR_INCORRECT_CALL
;
1759 case RXEXIT_HANDLED
:
1760 if (RCode
== RXFLAG_ERROR
)
1761 *RC
= ERR_INCORRECT_CALL
;
1762 else if (RCode
== RXFLAG_FAILURE
)
1763 *RC
= ERR_ROUTINE_NOT_FOUND
;
1767 case RXEXIT_RAISE_ERROR
:
1768 *RC
= ERR_SYSTEM_FAILURE
;
1774 if (!(*RC
) && retstr
.strptr
)
1776 *RetString
= MallocTSD( (retstr
.strlength
< 1) ? 1 : retstr
.strlength
) ;
1777 memcpy( *RetString
, retstr
.strptr
, retstr
.strlength
) ;
1778 *RetLength
= retstr
.strlength
;
1781 *RetLength
= RX_NO_STRING
;
1783 if (retstr
.strptr
&& retstr
.strptr
!= execfunc_result
+ ILLEGAL_USE_SIZE
)
1784 IfcFreeMemory( retstr
.strptr
) ;
1789 int IfcHaveFunctionExit(const tsd_t
*TSD
)
1794 if ( rt
->CurrentHandlers
&& rt
->CurrentHandlers
->Handlers
[RXFNC
] )
1800 /* ============================================================= */
1801 /* Asynchronous Rexx API interface */
1803 EXPORT_C APIRET APIENTRY
RexxSetHalt(LONG dummyProcess
,
1808 TSD
= GLOBAL_ENTRY_POINT();
1809 StartupInterface(TSD
);
1811 * Perform sanity check on the parameters; is process id me ?
1817 /* ============================================================= */
1818 /* Named queue interface */
1820 EXPORT_C APIRET APIENTRY
RexxCreateQueue( PSZ Buffer
,
1828 TSD
= GLOBAL_ENTRY_POINT();
1829 StartupInterface(TSD
);
1831 TSD
->called_from_saa
= 1;
1832 code
= IfcCreateQueue( TSD
, RequestedName
, (RequestedName
) ? strlen( RequestedName
): 0, Buffer
, DupFlag
, BuffLen
);
1833 TSD
->called_from_saa
= 0;
1837 EXPORT_C APIRET APIENTRY
RexxDeleteQueue( PSZ QueueName
)
1842 TSD
= GLOBAL_ENTRY_POINT();
1843 StartupInterface(TSD
);
1845 TSD
->called_from_saa
= 1;
1846 if (!QueueName
|| !strlen(QueueName
))
1847 code
= RXQUEUE_BADQNAME
;
1849 code
= IfcDeleteQueue( TSD
, QueueName
, strlen( QueueName
) );
1850 TSD
->called_from_saa
= 0;
1854 EXPORT_C APIRET APIENTRY
RexxQueryQueue( PSZ QueueName
,
1860 TSD
= GLOBAL_ENTRY_POINT();
1861 StartupInterface(TSD
);
1863 TSD
->called_from_saa
= 1;
1864 if (!QueueName
|| !strlen(QueueName
))
1865 code
= RXQUEUE_BADQNAME
;
1867 code
= IfcQueryQueue( TSD
, QueueName
, strlen( QueueName
), Count
);
1868 TSD
->called_from_saa
= 0;
1872 EXPORT_C APIRET APIENTRY
RexxAddQueue( PSZ QueueName
,
1873 PRXSTRING EntryData
,
1879 TSD
= GLOBAL_ENTRY_POINT();
1880 StartupInterface(TSD
);
1882 TSD
->called_from_saa
= 1;
1883 if (!QueueName
|| !strlen(QueueName
))
1884 code
= RXQUEUE_BADQNAME
;
1886 code
= IfcAddQueue( TSD
, QueueName
, strlen( QueueName
), EntryData
->strptr
, EntryData
->strlength
, AddFlag
==RXQUEUE_LIFO
);
1887 TSD
->called_from_saa
= 0;
1891 EXPORT_C APIRET APIENTRY
RexxPullQueue( PSZ QueueName
,
1893 PDATETIME TimeStamp
,
1901 TSD
= GLOBAL_ENTRY_POINT();
1902 StartupInterface(TSD
);
1904 if ( WaitFlag
!= RXQUEUE_WAIT
&& WaitFlag
!= RXQUEUE_NOWAIT
)
1905 return RXQUEUE_BADWAITFLAG
;
1908 TSD
->called_from_saa
= 1;
1909 if (!QueueName
|| !strlen(QueueName
))
1910 code
= RXQUEUE_BADQNAME
;
1913 code
= IfcPullQueue( TSD
, QueueName
, strlen( QueueName
), &buf
, &buflen
, WaitFlag
==RXQUEUE_WAIT
);
1921 code
= RXQUEUE_EMPTY
;
1925 DataBuf
->strlength
= buflen
;
1926 DataBuf
->strptr
=(char *)IfcAllocateMemory(buflen
+1);
1927 if ( DataBuf
->strptr
)
1929 memcpy(DataBuf
->strptr
,(void *) buf
,buflen
);
1930 *(DataBuf
->strptr
+(buflen
)) = '\0';
1933 code
= RXQUEUE_MEMFAIL
;
1937 TSD
->called_from_saa
= 0;
1941 /* ============================================================= */
1942 /* MacroSpace Rexx API interface */
1944 EXPORT_C APIRET APIENTRY
RexxAddMacro( PSZ FuncName
,
1951 EXPORT_C APIRET APIENTRY
RexxDropMacro( PSZ FuncName
)
1956 EXPORT_C APIRET APIENTRY
RexxSaveMacroSpace( ULONG FuncCount
,
1963 EXPORT_C APIRET APIENTRY
RexxLoadMacroSpace( ULONG FuncCount
,
1970 EXPORT_C APIRET APIENTRY
RexxQueryMacro( PSZ FuncName
,
1976 EXPORT_C APIRET APIENTRY
RexxReorderMacro( PSZ FuncName
,
1982 EXPORT_C APIRET APIENTRY
RexxClearMacroSpace( VOID
)
1987 /* ============================================================= */
1988 /* Regina extensions */
1989 /* see rexxsaa.h for a description */
1990 EXPORT_C APIRET APIENTRY
ReginaVersion( PRXSTRING VersionString
)
1996 TSD
= GLOBAL_ENTRY_POINT();
1997 StartupInterface(TSD
);
2002 if (VersionString
->strlength
== 0)
2004 if ((VersionString
->strptr
=
2005 IfcAllocateMemory(sizeof(PARSE_VERSION_STRING
))) == NULL
)
2007 VersionString
->strlength
= sizeof(PARSE_VERSION_STRING
);
2010 if ((len
= VersionString
->strlength
) > sizeof(PARSE_VERSION_STRING
))
2011 len
= sizeof(PARSE_VERSION_STRING
);
2012 memcpy(VersionString
->strptr
,PARSE_VERSION_STRING
,len
);
2014 /* sizeof includes the terminating 0. Subtract it if we should. */
2015 if (len
> sizeof(PARSE_VERSION_STRING
) - 1)
2016 len
= sizeof(PARSE_VERSION_STRING
) - 1;
2017 VersionString
->strlength
= len
;
2020 low
[0] = REGINA_VERSION_MINOR
[0];
2021 if (low
[0] == '0') /* atoi may have problems with leading zeros (octal) */
2023 low
[0] = REGINA_VERSION_MINOR
[1];
2027 low
[1] = REGINA_VERSION_MINOR
[1];
2029 return( (atoi(REGINA_VERSION_MAJOR
) << 8) | atoi(low
) ) ;