2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-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 * Sigh, let's live dangerously. We need to remove the definition of
22 * _POSIX_SOURCE, in order to get defined some extenstions to POSIX,
23 * since dynamic loading is not a part of POSIX.
28 #define DONT_TYPEDEF_PFN
40 * Starting after 3.3RC1 we process both the Rexx???Exe as the Rexx???Dll
41 * stuff here and only here. An Exe element is an element with a library of
45 #define EP_COUNT 133 /* should be a prime for distribution */
51 typedef struct { /* lib_tsd: static variables of this module (thread-safe) */
52 struct library
* first_library
;
53 struct library
* orphaned
;
54 struct entry_point
*ep
[3][EP_COUNT
]; /* FUNCS, EXITS, SUBCOMS */
56 } lib_tsd_t
; /* thread-specific but only needed by this module. see
61 * init_library initializes the module.
62 * Currently, we set up the thread specific data.
63 * The function returns 1 on success, 0 if memory is short.
65 int init_library( tsd_t
*TSD
)
69 if ( TSD
->lib_tsd
!= NULL
)
72 if ( ( TSD
->lib_tsd
= MallocTSD( sizeof( lib_tsd_t
) ) ) == NULL
)
74 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
75 memset( lt
, 0, sizeof( lib_tsd_t
) ); /* correct for all values */
81 * insert_library inserts the passed library in the linked list of used
82 * libraries unconditionally.
84 static void insert_library( const tsd_t
*TSD
, struct library
*ptr
)
88 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
90 ptr
->next
= lt
->first_library
;
91 lt
->first_library
= ptr
;
92 if ( ptr
->next
!= NULL
)
93 ptr
->next
->prev
= ptr
;
97 * unlink_orphaned_libs attempts to remove the address space from unused
98 * DLLs aka shared libraries.
100 * We must be extremely careful. Scenario:
101 * Load a function package, e.g. w32funcs. This lets several functions
102 * (e.g. win32func???) and win32load and win32unload been registered.
103 * When the call of win32unload happens, each function name gets unload and
104 * on the last call the entire library gets released. But this happens just
105 * when RexxDeregisterFunction(win32unload) happens! The address space doesn't
106 * exist any longer and the call does a return to unmapped memory. Crash!
108 * Therefore the freeing of the library moves the unused lib to the list of
109 * orphaned libs which are removed when it's safe to do so.
111 * Alternatively we have to maintain a list of used external entry points
112 * which lock the associated libraries only (move to orphaned), others are
113 * freed immediately. The disadvantage is the maintainance problem with
116 * If the flag force is set we assume a clean state which should be set only
117 * on reforking or terminating.
119 static void unlink_orphaned_libs( const tsd_t
*TSD
, lib_tsd_t
*lt
, int force
)
129 * The system is ready to remove every lib if TSD->systeminfo->previous
130 * is empty AND TSD->systeminfo->input_name is empty.
131 * Otherwise we don't catch the plain main() calls or other calls I can
132 * imagine that use the first systeminfo directly.
134 if ( TSD
->systeminfo
)
136 if ( TSD
->systeminfo
->previous
|| TSD
->systeminfo
->input_file
)
141 while ( ( ptr
= lt
->orphaned
) != NULL
)
143 lt
->orphaned
= ptr
->next
;
145 lt
->orphaned
->prev
= NULL
;
147 assert( ptr
->used
== 0 );
149 wrapper_unload( TSD
, ptr
->handle
);
151 Free_stringTSD( ptr
->name
);
157 * remove_library removes the passed library from the linked list of used
158 * libraries unconditionally.
159 * The library will be unloaded and the name and the passed structure will be
160 * freed later when it's safe to do so.
161 * See unlink_orphaned_libs.
163 static void remove_library( const tsd_t
*TSD
, struct library
*ptr
)
167 assert( ptr
->used
== 0 );
169 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
171 ptr
->next
->prev
= ptr
->prev
;
174 ptr
->prev
->next
= ptr
->next
;
176 lt
->first_library
= ptr
->next
;
178 ptr
->next
= lt
->orphaned
;
180 lt
->orphaned
->prev
= ptr
;
185 * Now try to remove it really.
187 unlink_orphaned_libs( TSD
, lt
, 0 );
192 * remove_entry removes the passed library entry from the linked list of used
193 * library entries unconditionally.
194 * The slot must be either FUNCS, EXITS, or SUBCOMS.
195 * Used memory will be freed and the holding library will be removed if this
196 * entry was the last entry used of the library.
198 static void remove_entry( tsd_t
*TSD
, struct entry_point
*fptr
, int slot
)
202 assert( slot
>= FUNCS
&& slot
<= SUBCOMS
);
204 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
206 Free_stringTSD( fptr
->name
);
207 #if defined(HAVE_GCI) && defined(DYNAMIC)
208 if ( ( fptr
->special
.gci_info
!= NULL
) && ( slot
== FUNCS
) )
209 GCI_remove_structure( TSD
, (GCI_treeinfo
*)fptr
->special
.gci_info
);
212 fptr
->next
->prev
= fptr
->prev
;
214 fptr
->prev
->next
= fptr
->next
;
216 lt
->ep
[slot
][fptr
->hash
% EP_COUNT
] = fptr
->next
;
219 if ( fptr
->lib
!= NULL
)
221 assert( fptr
->lib
->used
> 0 );
222 if ( --fptr
->lib
->used
== 0 )
223 remove_library( TSD
, fptr
->lib
);
231 * free_orphaned_libs disconnect from unused DLLs, see unlink_orphaned_libs.
233 void free_orphaned_libs( tsd_t
*TSD
)
236 lib_tsd_t
*lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
238 unlink_orphaned_libs( TSD
, lt
, 0 );
245 * purge_library frees all used memory used by every entry point that is
246 * registered and unloads every library.
247 * This routine is a little bit slow.
249 void purge_library( tsd_t
*TSD
)
251 struct entry_point
*ep
, *save_ep
;
255 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
256 if ( lt
->first_library
!= NULL
)
258 for ( i
= FUNCS
; i
<= SUBCOMS
; i
++ )
260 for ( j
= 0; j
< EP_COUNT
; j
++ )
262 if ( ( ep
= lt
->ep
[i
][j
] ) != NULL
)
266 remove_entry( TSD
, ep
, i
);
267 if ( ( ep
= lt
->ep
[i
][j
] ) == save_ep
)
269 } while ( ep
!= NULL
);
270 if ( lt
->first_library
== NULL
)
277 assert( lt
->first_library
== NULL
);
278 lt
->first_library
= NULL
;
280 unlink_orphaned_libs( TSD
, lt
, 1 );
282 assert( lt
->orphaned
== NULL
);
284 memset( lt
->ep
, 0, sizeof( lt
->ep
) );
289 * find_library returns the internal structure associated with the passed
290 * library name or NULL if such a library doesn't exist.
292 struct library
*find_library( const tsd_t
*TSD
, const streng
*name
)
294 struct library
*lptr
;
297 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
298 lptr
= lt
->first_library
;
299 for ( ; lptr
; lptr
= lptr
->next
)
301 if ( !Str_cmp( name
, lptr
->name
) )
310 * add_entry creates a new library entry from the passed data and inserts it
311 * in the linked list of used entries unconditionally.
312 * The slot must be either FUNCS, EXITS, or SUBCOMS.
313 * rxname is the name that can be used by a REXX script.
314 * addr is the entry point of the function/exit hook/subcom hook.
315 * lptr is a loaded library or NULL for a call of RexxRegister???Exe.
316 * Either gci_info or user_area may be set depending on the kind of the entry.
318 * The internal counter of the library isn't incremented.
320 static void add_entry( const tsd_t
*TSD
, int slot
, const streng
*rxname
,
322 struct library
*lptr
, void *gci_info
,
327 struct entry_point
*fptr
;
329 assert( slot
>= FUNCS
&& slot
<= SUBCOMS
);
330 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
332 fptr
= (struct entry_point
*)MallocTSD( sizeof( struct entry_point
) );
333 fptr
->name
= Str_upper( Str_dupstrTSD( rxname
) );
334 fptr
->hash
= hashvalue( rxname
->value
, rxname
->len
);
337 memset( &fptr
->special
, 0, sizeof( fptr
->special
) );
339 fptr
->special
.gci_info
= gci_info
;
342 if ( user_area
!= NULL
)
343 memcpy( fptr
->special
.user_area
, user_area
,
344 sizeof ( fptr
->special
.user_area
) );
347 hash0
= fptr
->hash
% EP_COUNT
;
348 fptr
->next
= lt
->ep
[slot
][hash0
];
349 lt
->ep
[slot
][hash0
] = fptr
;
352 fptr
->next
->prev
= fptr
;
356 * find_entry_point returns NULL if no entry is found. Returns the exact entry
357 * if both the name and the library match. Returns any entry with a fitting
358 * name if the library doesn't match but the name exists.
359 * library may be NULL for entries registered by RexxRegister???Exe.
360 * The slot must be either FUNCS, EXITS, or SUBCOMS.
362 static struct entry_point
*find_entry_point( const tsd_t
*TSD
,
367 struct entry_point
*lptr
;
368 unsigned hash
, hash0
;
370 struct entry_point
*retval
= NULL
;
372 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
373 hash
= hashvalue( name
->value
, name
->len
);
374 hash0
= hash
% EP_COUNT
;
375 for ( lptr
= lt
->ep
[slot
][hash0
]; lptr
; lptr
= lptr
->next
)
377 if ( hash
== lptr
->hash
)
378 if ( Str_cmp( name
, lptr
->name
) == 0 )
380 if ( lptr
->lib
== library
)
391 * find_first_entry_point returns NULL if no entry is found and returns the
392 * most recent hook otherwise.
393 * The slot must be either FUNCS, EXITS, or SUBCOMS.
395 static struct entry_point
*find_first_entry_point( const tsd_t
*TSD
,
399 struct entry_point
*lptr
;
400 unsigned hash
, hash0
;
403 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
404 hash
= hashvalue( name
->value
, name
->len
);
405 hash0
= hash
% EP_COUNT
;
406 for ( lptr
= lt
->ep
[slot
][hash0
]; lptr
; lptr
= lptr
->next
)
408 if ( hash
== lptr
->hash
)
409 if ( Str_cmp( name
, lptr
->name
) == 0 )
417 * find_all_entries returns 0 if no entry is found. Otherwise it returns the
418 * number of all matching entries with the given name, different in the module
420 * The slot must be either FUNCS, EXITS, or SUBCOMS.
421 * *list will be set to a list of all available entries.
423 * This function is slow.
425 static int find_all_entries( const tsd_t
*TSD
, const streng
*name
, int slot
,
426 struct entry_point
***list
)
428 struct entry_point
*lptr
, **array
;
429 unsigned hash
, hash0
;
433 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
434 hash
= hashvalue( name
->value
, name
->len
);
435 hash0
= hash
% EP_COUNT
;
436 for ( cnt
= 0, lptr
= lt
->ep
[slot
][hash0
]; lptr
; lptr
= lptr
->next
)
438 if ( hash
== lptr
->hash
)
439 if ( Str_cmp( name
, lptr
->name
) == 0 )
449 array
= (struct entry_point
**)MallocTSD( cnt
* sizeof( struct entry_point
* ) );
452 for ( cnt
= 0, lptr
= lt
->ep
[slot
][hash0
]; lptr
; lptr
= lptr
->next
)
454 if ( hash
== lptr
->hash
)
455 if ( Str_cmp( name
, lptr
->name
) == 0 )
463 * set_err_message replaces the current error message by a new one that will
464 * be assembled as the concatenation of the two passed messages.
465 * The created string will be returned by RxFuncErrMsg().
467 void set_err_message( const tsd_t
*TSD
, const char *message1
,
468 const char *message2
)
473 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
474 if ( lt
->err_message
)
475 Free_stringTSD( lt
->err_message
);
477 size
= strlen( message1
) + strlen( message2
);
478 lt
->err_message
= Str_makeTSD( size
+ 1 );
479 if ( lt
->err_message
)
481 strcpy( lt
->err_message
->value
, message1
);
482 strcat( lt
->err_message
->value
, message2
);
483 lt
->err_message
->len
= size
;
488 * load_entry creates a new library entry from the passed data and inserts it
489 * in the linked list of used entries.
490 * lptr is a loaded library or NULL for a call of RexxRegister???Exe.
491 * rxname is the name that can be used by a REXX script.
492 * objnam will be used if lptr != NULL only and is the name of the hook
493 * or function that is exported by the library.
494 * entry will be used if lptr == NULL only and is the entry point of the hook
496 * The slot must be either FUNCS, EXITS, or SUBCOMS.
497 * Either gci_info or user_area may be set depending on the kind of the entry.
501 * 1 if the function is defined already.
502 * 1 if the hook is defined already and bound to the same library. The new
504 * 2 if the hook is defined already and bound to another library. The new
506 * 3 if objnam isn't exported by lptr.
507 * 4 if external libraries are not supported.
509 static int load_entry( const tsd_t
*TSD
, struct library
*lptr
,
510 const streng
*rxname
, const streng
*objnam
,
512 int slot
, void *gci_info
, void *user_area
)
515 struct entry_point
*fptr
;
517 assert( ( lptr
!= NULL
) ^ ( entry
!= NULL
) );
518 assert( rxname
!= NULL
);
519 assert( slot
>= FUNCS
&& slot
<= SUBCOMS
);
521 * Check the exceptions first.
523 if ( ( fptr
= find_entry_point( TSD
, rxname
, lptr
, slot
) ) != NULL
)
526 * EXITS and SUBCOMS may have the same callable name bound to different
529 if ( ( slot
== FUNCS
) || ( fptr
->lib
== lptr
) )
532 * must be a hook with the same name in a different module.
539 assert( objnam
!= NULL
);
541 if ( ( entry
= wrapper_get_addr( TSD
, lptr
, objnam
) ) == NULL
)
549 add_entry( TSD
, slot
, rxname
, entry
, lptr
, gci_info
, user_area
);
554 * unload_entry removes a known library entry from the linked list of known
557 * rxname is the name that can be used by a REXX script.
558 * module is the name of the library and may be NULL for a generic request
559 * or is a RexxRegister???Exe registered funcion/hook shall be unloaded.
560 * The slot must be either FUNCS, EXITS, or SUBCOMS.
564 * 1 if the function/hook is not defined or a hook with this name is bound
565 * to different modules and the module name is not given.
567 static int unload_entry( tsd_t
*TSD
, const streng
*rxname
,
568 const streng
*module
, int slot
)
570 struct entry_point
*fptr
, **list
;
575 if ( module
== NULL
)
579 if ( ( lib
= find_library( TSD
, module
) ) == NULL
)
583 if ( module
!= NULL
)
588 fptr
= find_entry_point( TSD
, rxname
, lib
, slot
);
592 if ( fptr
->lib
== lib
)
594 remove_entry( TSD
, fptr
, slot
);
599 * Not a properly matching function. Check for the "wildcard" library.
605 * We need it the hard way. Check if more than one entry is registered.
607 cnt
= find_all_entries( TSD
, rxname
, slot
, &list
);
614 remove_entry( TSD
, *list
, slot
);
620 * loadrxfunc adds a new function to the set of registered entry points.
622 * lptr is a loaded library or NULL for a call of RexxRegisterFunctionExe.
623 * rxname is the name that can be used by a REXX script.
624 * objnam will be used if lptr != NULL only and is the name of the function
625 * that is exported by the library.
626 * entry will be used if lptr == NULL only and is the entry point of the
628 * gci_info may be set depending on whether RxFuncDefine is used.
630 * Returns a return code suitable for RexxRegisterFunction???.
632 static int loadrxfunc( const tsd_t
*TSD
, struct library
*lptr
,
633 const streng
*rxname
, const streng
*objnam
,
639 rc
= load_entry( TSD
, lptr
, rxname
, objnam
, entry
, FUNCS
, gci_info
, NULL
);
642 case 0: return 0; /* RXFUNC_OK */
643 case 1: return 10; /* RXFUNC_DEFINED */
644 case 3: return 50; /* RXFUNC_ENTNOTFND */
645 case 4: return 60; /* RXFUNC_NOTINIT */
648 return 10000 + rc
; /* something not recognisable */
652 * loadrxhook adds a new exit/subcom hook to the set of registered entry
655 * lptr is a loaded library or NULL for a call of RexxRegister???Exe.
656 * rxname is the name that can be used in a hook list.
657 * objnam will be used if lptr != NULL only and is the name of the hook that
658 * that is exported by the library.
659 * entry will be used if lptr == NULL only and is the entry point of the hook.
660 * user_area is the passed parameter called UserArea of the Registration.
661 * The slot must be either EXITS or SUBCOMS.
663 * Returns a return code suitable for RexxRegister???.
665 static int loadrxhook( const tsd_t
*TSD
, struct library
*lptr
,
666 const streng
*rxname
, const streng
*objnam
,
668 void *user_area
, int slot
)
672 rc
= load_entry( TSD
, lptr
, rxname
, objnam
, entry
, slot
, NULL
, user_area
);
675 case 0: return 0; /* RX???_OK */
676 case 1: return 30; /* RX???_NOTREG */
677 case 2: return 10; /* RX???_DUP */
678 case 3: return 50; /* RX???_LOADERR */
679 case 4: return 1004; /* RX???_NOTINIT */
682 return 10000 + rc
; /* something not recognisable */
686 * unloadrxhook removes a registered function entry point.
688 * rxname is the name that can be used by a REXX script.
690 * Returns a return code suitable for RexxDeregisterFunction.
692 static int unloadrxfunc( tsd_t
*TSD
, const streng
*rxname
)
694 assert( rxname
!= NULL
);
696 if ( unload_entry( TSD
, rxname
, NULL
, FUNCS
) == 0 )
698 return 30; /* RXFUNC_NOTREG */
702 * unloadrxhook removes a registered exit/subcom hook entry point.
704 * rxname is the name that can be used in a hook list.
705 * module is the name of the module that contains the hook or NULL if either
706 * the generic hook should be removed or if a RexxRegister???Exe-hook should
707 * be removed. The later one has precedence.
708 * The slot must be either EXITS or SUBCOMS.
710 * Returns a return code suitable for RexxDeregister???.
712 static int unloadrxhook( tsd_t
*TSD
, const streng
*rxname
,
713 const streng
*module
, int slot
)
715 assert( rxname
!= NULL
);
717 if ( unload_entry( TSD
, rxname
, module
, slot
) == 0 )
719 return 30; /* RX???_NOTREG */
723 * rex_funcadd processes a RexxRegisterFunctionDll() or
724 * RexxRegisterFunctionExe() request.
726 * rxname is the name that can be used by a REXX script.
727 * module is the name of the library and may be NULL only a
728 * RexxRegisterFunctionExe is processed.
729 * objnam will be used if module != NULL only and is the name of the function
730 * that is exported by the library.
731 * entry will be used if module == NULL only and is the entry point of the
733 * gci_info may be set depending on whether RxFuncDefine is used.
735 * Returns a return code suitable for RexxRegisterFunction???.
737 static int rex_funcadd( const tsd_t
*TSD
, const streng
*rxname
,
738 const streng
*module
, const streng
*objnam
,
742 struct library
*lptr
=NULL
;
748 streng
*regutil
=Str_crestr( "regutil" );
749 streng
*rexxutil
=Str_crestr( "rexxutil" );
751 assert( rxname
!= NULL
);
753 if ( module
!= NULL
)
755 assert( entry
== NULL
);
757 if ( Str_ccmp( module
, rexxutil
) == 0 )
759 if ( ( lptr
= find_library( TSD
, regutil
) ) == NULL
)
762 handle
= wrapper_load( TSD
, regutil
) ;
765 lptr
= (struct library
*)MallocTSD( sizeof( struct library
)) ;
766 lptr
->name
= Str_dupstrTSD( regutil
) ;
767 lptr
->handle
= handle
;
772 Free_stringTSD( regutil
);
773 Free_stringTSD( rexxutil
);
774 return 40; /* RXFUNC_MODNOTFND */
776 insert_library( TSD
, lptr
) ;
781 if ( ( lptr
= find_library( TSD
, module
) ) == NULL
)
784 handle
= wrapper_load( TSD
, module
) ;
787 lptr
= (struct library
*)MallocTSD( sizeof( struct library
)) ;
788 lptr
->name
= Str_dupstrTSD( module
) ;
789 lptr
->handle
= handle
;
794 Free_stringTSD( regutil
);
795 Free_stringTSD( rexxutil
);
796 return 40; /* RXFUNC_MODNOTFND */
798 insert_library( TSD
, lptr
) ;
802 Free_stringTSD( regutil
);
803 Free_stringTSD( rexxutil
);
804 return 60; /* RXFUNC_NOTINIT */
809 assert( entry
!= NULL
);
811 if ( ( rc
= loadrxfunc( TSD
, lptr
, rxname
, objnam
, entry
, gci_info
) ) != 0 )
815 remove_library( TSD
, lptr
);
818 Free_stringTSD( regutil
);
819 Free_stringTSD( rexxutil
);
824 * rex_hookadd processes a RexxRegisterExitDll(), RexxRegisterExitExe(),
825 * RexxRegisterSubcomDll(), or RexxRegisterSubcomExe() request.
827 * rxname is the name that can be used in a hook list.
828 * module is the name of the library and may be NULL only a RexxRegister???Exe
830 * objnam will be used if module != NULL only and is the name of the hook
831 * that is exported by the library.
832 * entry will be used if module == NULL only and is the entry point of the
834 * user_area is the passed parameter called UserArea of the Registration.
835 * The slot must be either EXITS or SUBCOMS.
837 * Returns a return code suitable for RexxRegister???.
839 static int rex_hookadd( const tsd_t
*TSD
, const streng
*rxname
,
840 const streng
*module
, const streng
*objnam
,
842 void *user_area
, int slot
)
844 struct library
*lptr
=NULL
;
851 assert( rxname
!= NULL
);
853 if ( module
!= NULL
)
855 assert( entry
== NULL
);
857 if ( ( lptr
= find_library( TSD
, module
) ) == NULL
)
860 handle
= wrapper_load( TSD
, module
) ;
863 lptr
= (struct library
*)MallocTSD( sizeof( struct library
)) ;
864 lptr
->name
= Str_dupstrTSD( module
) ;
865 lptr
->handle
= handle
;
870 return 50; /* RX???_LOADERR */
872 insert_library( TSD
, lptr
) ;
875 return 1004; /* RX???_NOTINIT */
880 assert( entry
!= NULL
);
882 rc
= loadrxhook( TSD
, lptr
, rxname
, objnam
, entry
, user_area
, slot
);
883 if ( ( rc
!= 0 ) && ( rc
!= 10 ) )
887 remove_library( TSD
, lptr
);
894 * rex_rxfuncerrmsg implements the BIF RxFuncErrMsg.
896 streng
*rex_rxfuncerrmsg( tsd_t
*TSD
, cparamboxptr parms
)
902 checkparam( parms
, 0, 0, "RXFUNCERRMSG" );
905 lt
= (lib_tsd_t
*)TSD
->lib_tsd
;
906 if ( lt
->err_message
)
907 return Str_dupTSD( lt
->err_message
);
909 return nullstringptr();
911 return Str_creTSD( "Module doesn't support dynamic linking; are you running the \"regina\" executable?" );
916 * rex_rxfuncquery implements the BIF RxFuncQuery.
918 streng
*rex_rxfuncquery( tsd_t
*TSD
, cparamboxptr parms
)
922 struct entry_point
*fptr
;
925 checkparam( parms
, 1, 1, "RXFUNCQUERY" );
928 name
= Str_upper( Str_dupTSD( parms
->value
) );
929 fptr
= find_entry_point( TSD
, name
, NULL
, FUNCS
);
930 Free_stringTSD( name
);
933 return int_to_streng( TSD
, 0 );
934 return int_to_streng( TSD
, 1 );
936 return int_to_streng( TSD
, 1 );
942 * rex_rxfuncadd implements the BIF RxFuncAdd.
943 * The returned value is suitable for RexxRegisterFunctionDll.
946 * 1) name of the function to be added (in Rexx)
947 * 2) name of object file to link in
948 * 3) name of the function to be added (in the object file)
950 streng
*rex_rxfuncadd( tsd_t
*TSD
, cparamboxptr parms
)
954 streng
*module
, *objnam
;
958 if ( TSD
->restricted
)
959 exiterror( ERR_RESTRICTED
, 1, "RXFUNCADD" );
961 checkparam( parms
, 2, 3, "RXFUNCADD" );
964 rxname
= Str_upper( Str_dupTSD( parms
->value
) );
965 objnam
= parms
->value
;
966 module
= ( parms
= parms
->next
)->value
;
967 if ( ( parms
->next
!= NULL
) && ( parms
->next
->value
!= NULL
) )
968 objnam
= parms
->next
->value
;
970 rc
= rex_funcadd( TSD
, rxname
, module
, objnam
, NULL
, NULL
);
971 Free_stringTSD( rxname
);
972 return int_to_streng( TSD
, rc
);
974 return int_to_streng( TSD
, 60 ); /* RXFUNC_NOTINIT */
980 * rex_rxfuncdefine implements the BIF RxFuncDefine.
983 * 1) name of the function to be added (in Rexx)
984 * 2) name of object file to link in
985 * 3) name of the function to be added (in the object file)
986 * 4) name of a stem containing the definition of the function
988 streng
*rex_rxfuncdefine( tsd_t
*TSD
, cparamboxptr parms
)
991 streng
*rxname
,*module
,*objnam
,*def_stem
;
996 if ( TSD
->restricted
)
997 exiterror( ERR_RESTRICTED
, 1, "RXFUNCDEFINE" );
999 checkparam( parms
, 4, 4, "RXFUNCDEFINE" );
1002 rxname
= Str_upper( Str_dupTSD( parms
->value
) );
1003 objnam
= parms
->value
;
1004 module
= ( parms
= parms
->next
)->value
;
1005 parms
= parms
->next
;
1006 if ( parms
->value
!= NULL
)
1007 objnam
= parms
->value
;
1008 def_stem
= parms
->next
->value
;
1010 if ( ( rc
= GCI_checkDefinition( TSD
, def_stem
, &gci_info
) ) != 0 )
1012 Free_stringTSD( rxname
);
1013 return int_to_streng( TSD
, 1 );
1016 rc
= rex_funcadd( TSD
, rxname
, module
, objnam
, NULL
, gci_info
);
1017 Free_stringTSD( rxname
);
1019 GCI_remove_structure( TSD
, (GCI_treeinfo
*)gci_info
);
1020 return int_to_streng( TSD
, rc
);
1022 return int_to_streng( TSD
, 60 ); /* RXFUNC_NOTINIT */
1027 * rex_gciprefixchar implements the BIF GciPrefixChar.
1030 * 1) new prefix character
1032 streng
*rex_gciprefixchar( tsd_t
*TSD
, cparamboxptr parms
)
1034 static const char valid
[] = " !?_#$@"; /* last 3 are Regina specific */
1035 char oldval
[2], newval
[2];
1038 checkparam( parms
, 0, 1, "GCIPREFIXCHAR" );
1040 oldval
[0] = TSD
->gci_prefix
[0];
1041 oldval
[1] = TSD
->gci_prefix
[1];
1044 value
= parms
->value
;
1047 if ( Str_len( value
) == 0 )
1051 else if ( Str_len( value
) > 1 )
1053 exiterror( ERR_INCORRECT_CALL
, 23, "GCIPREFIXCHAR", 1, tmpstr_of( TSD
, value
) );
1057 newval
[0] = Str_val( value
)[0];
1060 if ( strchr( valid
, (int) newval
[0] ) == NULL
)
1062 exiterror( ERR_INCORRECT_CALL
, 28, "GCIPREFIXCHAR", 1, valid
, newval
);
1065 if ( newval
[0] == ' ' )
1073 newval
[0] = oldval
[0];
1076 TSD
->gci_prefix
[0] = newval
[0];
1077 TSD
->gci_prefix
[1] = newval
[1];
1079 return Str_creTSD( oldval
);
1084 * rex_rxfuncdrop implements the BIF RxFuncDrop.
1085 * The returned value is suitable for RexxDeregisterFunction.
1087 streng
*rex_rxfuncdrop( tsd_t
*TSD
, cparamboxptr parms
)
1091 checkparam( parms
, 1, 1, "RXFUNCDROP" );
1092 name
= Str_upper( parms
->value
);
1094 return int_to_streng( TSD
, unloadrxfunc( TSD
, name
) );
1098 * IfcRegFunc is the interface function for RexxRegisterFunctionExe and
1099 * RexxRegisterFunctionDll.
1100 * Either entry or module and objnam must be set.
1102 int IfcRegFunc( const tsd_t
*TSD
, const char *rxname
, const char *module
,
1111 ext
= Str_upper( Str_creTSD( rxname
) );
1112 if ( module
&& objnam
)
1114 intr
= Str_creTSD( objnam
);
1115 lib
= Str_creTSD( module
);
1118 rc
= rex_funcadd( TSD
, ext
, lib
, intr
, entry
, NULL
);
1120 Free_stringTSD( ext
);
1123 Free_stringTSD( intr
);
1124 Free_stringTSD( lib
);
1131 * IfcRegHook is the interface function for RexxRegisterExitExe,
1132 * RexxRegisterExitDll, RexxRegisterSubcomExe, RexxRegisterSubcomtDll.
1133 * Either entry or module and objnam must be set.
1135 static int IfcRegHook( const tsd_t
*TSD
, const char *rxname
,
1136 const char *module
, const char *objnam
,
1138 void *user_area
, int slot
)
1145 ext
= Str_upper( Str_creTSD( rxname
) );
1146 if ( module
&& objnam
)
1148 intr
= Str_creTSD( objnam
);
1149 lib
= Str_creTSD( module
);
1152 rc
= rex_hookadd( TSD
, ext
, lib
, intr
, entry
, user_area
, slot
);
1154 Free_stringTSD( ext
);
1157 Free_stringTSD( intr
);
1158 Free_stringTSD( lib
);
1165 * IfcRegExit is the interface function for RexxRegisterExitExe or
1166 * RexxRegisterExitDll.
1167 * Either entry or module and objnam must be set.
1169 int IfcRegExit( const tsd_t
*TSD
, const char *rxname
, const char *module
,
1174 return IfcRegHook( TSD
, rxname
, module
, objnam
, entry
, user_area
, EXITS
);
1178 * IfcRegSubcom is the interface function for RexxRegisterSubcomExe or
1179 * RexxRegisterSubcomDll.
1180 * Either entry or module and objnam must be set.
1182 int IfcRegSubcom( const tsd_t
*TSD
, const char *rxname
, const char *module
,
1188 env
= Str_creTSD( rxname
);
1189 set_subcomed_envir( TSD
, env
, 1 );
1190 Free_stringTSD( env
);
1191 return IfcRegHook( TSD
, rxname
, module
, objnam
, entry
, user_area
, SUBCOMS
);
1195 * IfcDelFunc is the interface function for RexxDeregisterFunction.
1197 int IfcDelFunc( tsd_t
*TSD
, const char *rxname
)
1202 ext
= Str_upper( Str_creTSD( rxname
) );
1203 rc
= unloadrxfunc( TSD
, ext
);
1204 Free_stringTSD( ext
);
1210 * IfcDelHook is the interface function for RexxDeregisterExit or
1211 * RexxDeregisterSubcom.
1213 static int IfcDelHook( tsd_t
*TSD
, const char *rxname
, const char *module
,
1219 ext
= Str_upper( Str_creTSD( rxname
) );
1220 if ( module
!= NULL
)
1221 mod
= Str_creTSD( module
);
1224 rc
= unloadrxhook( TSD
, ext
, mod
, slot
);
1225 Free_stringTSD( ext
);
1227 Free_stringTSD( mod
);
1233 * IfcDelExit is the interface function for RexxDeregisterExit.
1235 int IfcDelExit( tsd_t
*TSD
, const char *rxname
, const char *module
)
1237 return IfcDelHook( TSD
, rxname
, module
, EXITS
);
1241 * IfcDelSubcom is the interface function for RexxDeregisterSubcom.
1243 int IfcDelSubcom( tsd_t
*TSD
, const char *rxname
, const char *module
)
1246 env
= Str_creTSD( rxname
);
1247 set_subcomed_envir( TSD
, env
, 0 );
1248 Free_stringTSD( env
);
1249 return IfcDelHook( TSD
, rxname
, module
, SUBCOMS
);
1253 * IfcQueryFunc is the interface function for RexxQueryFunction.
1255 int IfcQueryFunc( const tsd_t
*TSD
, const char *rxname
)
1260 ext
= Str_upper( Str_creTSD( rxname
) );
1261 rc
= ( find_entry_point( TSD
, ext
, NULL
, FUNCS
) != NULL
) ? 0 : 30;
1262 Free_stringTSD( ext
);
1268 * IfcQueryHook is the interface function for RexxQueryExit or RexxQuerySubcom.
1270 static int IfcQueryHook( const tsd_t
*TSD
, const char *rxname
,
1271 const char *module
, int slot
, void *user_area
)
1274 struct entry_point
*fptr
,**list
;
1275 struct library
*lib
;
1281 ext
= Str_upper( Str_creTSD( rxname
) );
1282 if ( module
!= NULL
)
1285 mod
= Str_creTSD( module
);
1286 lib
= find_library( TSD
, mod
);
1287 Free_stringTSD( mod
);
1290 Free_stringTSD( ext
);
1291 return 30; /* RX???_NOTREG */
1294 return 1004; /* RX???_NOTINIT */
1300 fptr
= find_entry_point( TSD
, ext
, lib
, slot
);
1304 Free_stringTSD( ext
);
1305 return 30; /* RX???_NOTREG */
1308 if ( fptr
->lib
!= lib
)
1311 * Found via wildcard mechanism, check if more than one element exists
1312 * and if a wildcard is allowed.
1316 Free_stringTSD( ext
);
1317 return 30; /* RX???_NOTREG */
1320 cnt
= find_all_entries( TSD
, ext
, slot
, &list
);
1322 Free_stringTSD( ext
);
1325 return 30; /* RX???_NOTREG */
1328 Free_stringTSD( ext
);
1330 if ( user_area
!= NULL
)
1331 memcpy( user_area
, fptr
->special
.user_area
,
1332 sizeof ( fptr
->special
.user_area
) );
1337 * IfcQueryExit is the interface function for RexxQueryExit.
1339 int IfcQueryExit( const tsd_t
*TSD
, const char *rxname
, const char *module
,
1342 return IfcQueryHook( TSD
, rxname
, module
, EXITS
, user_area
);
1346 * IfcQuerySubcom is the interface function for RexxQuerySubcom.
1348 int IfcQuerySubcom( const tsd_t
*TSD
, const char *rxname
, const char *module
,
1351 return IfcQueryHook( TSD
, rxname
, module
, SUBCOMS
, user_area
);
1354 struct entry_point
*loaded_lib_func( const tsd_t
*TSD
, const streng
*name
)
1356 struct entry_point
*box
;
1359 upp
= Str_upper( Str_dupTSD( name
) );
1360 box
= find_first_entry_point( TSD
, upp
, FUNCS
);
1361 Free_stringTSD( upp
);
1367 * exit_hook returns the most recent exit handler of the given name.
1368 * The value may be NULL if no hook is registered.
1370 struct entry_point
*exit_hook( const tsd_t
*TSD
, const char *env
, int len
)
1373 struct entry_point
*ret
;
1375 name
= Str_upper( Str_ncreTSD( env
, len
) );
1376 ret
= find_first_entry_point( TSD
, name
, EXITS
);
1377 Free_stringTSD( name
);
1383 * subcom_hook returns the most recent subcom handler of the given name.
1384 * The value may be NULL if no hook is registered.
1386 struct entry_point
*subcom_hook( const tsd_t
*TSD
, const char *com
, int len
)
1389 struct entry_point
*ret
;
1391 name
= Str_upper( Str_ncreTSD( com
, len
) );
1392 ret
= find_first_entry_point( TSD
, name
, SUBCOMS
);
1393 Free_stringTSD( name
);