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.
19 /* JH 20-10-99 */ /* To make Direct setting of stems Direct and not Symbolic. */
23 #if defined(WIN32) && defined(__IBMC__)
25 # pragma warning(default: 4115 4201 4214)
27 # if defined(WIN32) && (defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__))
31 # if defined(__EMX__) && defined(OS2)
32 # define DONT_TYPEDEF_PFN
36 # if defined(__WATCOMC__) && defined(OS2)
38 # define DONT_TYPEDEF_PFN
41 # if defined(_MSC_VER) && !defined(__WINS__)
44 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
45 # pragma warning(disable: 4115 4201 4214 4514)
49 # pragma warning(default: 4115 4201 4214)
59 #ifndef RXLIB /* need __regina_faked_main which is known with RXLIB only */
85 # define min(a,b) (((a) < (b)) ? (a) : (b))
88 static int ReMapHook( const tsd_t
*TSD
, int NetHook
) ;
90 typedef struct { /* cli_tsd: static variables of this module (thread-safe) */
91 char count_params_buf
[32]; /* handle_no_of_params() */
93 /* Buffering of external parameters allows a delayed deletion in case of
98 int * Lengths
; /* StringsCount + 1 elements */
99 char ** Strings
; /* StringsCount + 1 elements */
100 } cli_tsd_t
; /* thread-specific but only needed by this module. see
104 /* init_client initializes the module.
105 * Currently, we set up the thread specific data.
106 * The function returns 1 on success, 0 if memory is short.
108 int init_client( tsd_t
*TSD
)
112 if ( TSD
->cli_tsd
!= NULL
)
115 if ( ( TSD
->cli_tsd
= MallocTSD( sizeof(cli_tsd_t
) ) ) == NULL
)
117 ct
= (cli_tsd_t
*)TSD
->cli_tsd
;
118 memset( ct
, 0, sizeof(cli_tsd_t
) );
119 ct
->StringsCount
= -1;
124 /* wrapstring makes a streng from external (application) data. If you get
125 * an exception you may have a wild pointer in your application.
126 * Returns NULL if string==NULL or length<0.
128 static streng
*wrapstring( const tsd_t
*TSD
, const char *string
, int length
)
130 streng
*result
=NULL
;
132 if (length
>=0 && string
)
134 result
= Str_makeTSD( length
) ;
135 memcpy( result
->value
, string
, length
) ;
136 result
->len
= length
;
145 static int map_type( int in
)
147 if (in
==RX_TYPE_COMMAND
)
148 return INVO_COMMAND
;
149 else if (in
==RX_TYPE_FUNCTION
)
150 return INVO_FUNCTION
;
153 assert( in
== RX_TYPE_SUBROUTINE
) ;
154 return INVO_SUBROUTINE
;
159 static paramboxptr
parametrize( const tsd_t
*TSD
, int ArgCount
, const int *ParLengths
, const char **ParStrings
)
161 paramboxptr parms
=NULL
, root
=NULL
;
165 for (i
=0; count
--; i
++ )
169 parms
->next
= (paramboxptr
)MallocTSD( sizeof(parambox
)) ;
170 parms
= parms
->next
;
173 parms
= root
= (paramboxptr
)MallocTSD( sizeof(parambox
)) ;
175 parms
->value
= wrapstring( TSD
, ParStrings
[i
], ParLengths
[i
] ) ;
185 * IfcPrepareReturnString will copy the content of src to the buffer described
186 * by the pair (*targetlen, *targetbuf). The target is not checked, but a
187 * value of RX_NO_STRING for *targetlen will be accepted.
189 * If src is a NULL pointer the targetlen will become 0 and targetbuf will
191 * Otherwise the length of the target is checked if it can hold the entire
192 * source string PLUS one string termination character. The terminator won't
193 * be honoured in *targetlen.
194 * A new buffer will be allocated using IfcAllocateString on insufficient size,
195 * but the old one is not freed.
197 * This function is intended to be the opposite of wrapstring.
199 static void IfcPrepareReturnString( const streng
*src
, int *targetlen
,
205 * Check for an invalid source first.
207 if ( ( src
== NULL
) || ( Str_val( src
) == NULL
) )
213 len
= Str_len( src
);
214 if ( *targetlen
< len
+ 1 )
216 if ( ( *targetbuf
= (char *)IfcAllocateMemory( len
+ 1 ) ) == NULL
)
225 memcpy( *targetbuf
, Str_val( src
), len
);
226 (*targetbuf
)[len
] = '\0';
231 * ScriptSetup does the setup step of IfcExecScript.
232 * This function is part of the technique to bypass problems with
235 static void ScriptSetup( tsd_t
*TSD
,
236 void **instore_buf
, unsigned long *instore_length
,
237 streng
**command
, const char *Name
, int NameLen
,
238 paramboxptr
*params
, int ArgCount
,
239 const int *ParLengths
, const char **ParStrings
,
240 int *ctype
, int CallType
,
242 int *hooks
, int ExitFlags
,
243 streng
**environment
, int EnvLen
, const char *EnvName
)
251 *command
= wrapstring( TSD
, Name
, NameLen
);
252 TSD
->systeminfo
->input_file
= *command
;
254 *params
= parametrize( TSD
, ArgCount
, ParLengths
, ParStrings
);
256 *ctype
= map_type( CallType
);
258 TSD
->restricted
= restricted
;
261 for( i
= 0; i
< 30; i
++ )
263 if ( ExitFlags
& ( 1 << i
) )
264 *hooks
|= 1 << ReMapHook( TSD
, i
);
267 *environment
= wrapstring( TSD
, EnvName
, EnvLen
);
268 if ( *environment
== NULL
)
271 * We have to use the extension of the file. That is what the REXX API
272 * documentations says and we have been called by the API in this case!
274 h
= TSD
->systeminfo
->input_file
;
276 for ( i
= Str_len( h
) - 1; i
>= 0; i
-- )
284 else if ( strchr( FILE_SEPARATORS
, c
) != NULL
)
292 * i otherwise: position after dot (may lead to empty string, too)
297 *environment
= Str_nodupTSD( h
, i
, Str_len( h
) - i
);
301 * When executing a script, check if the environment we are running under exists
302 * and has been "redirected" by a call to RexxRegisterSubcom???()
304 if ( envir_exists( TSD
, *environment
) )
306 if ( get_subcomed_envir( TSD
, *environment
) )
308 add_envir( TSD
, Str_dupTSD( *environment
), ENVIR_PIPE
, 0 );
313 add_envir( TSD
, Str_dupTSD( *environment
), ENVIR_PIPE
, 0 );
318 * ScriptCleanup does the cleanup step of IfcExecScript.
319 * 1) script_exit becomes the new old value for a jumped exit.
320 * 2) environment is deregistered and freed.
321 * 3) A fresh Ifc-allocated copy of result is put into RetLen/RetString,
322 * and result is freed. *RetString is either used or replaced.
323 * 4) InterpreterStatus is reset to the given value.
324 * This function is part of the technique to bypass problems with
327 static void ScriptCleanup(tsd_t
*TSD
, jmp_buf *script_exit
, streng
*environment
,
328 streng
*result
, int *RetLen
, char **RetString
,
329 unsigned *InterpreterStatus
)
331 TSD
->systeminfo
->script_exit
= script_exit
;
332 del_envir( TSD
, environment
);
333 Free_stringTSD( environment
);
334 RestoreInterpreterStatus( TSD
, InterpreterStatus
);
336 IfcPrepareReturnString( result
, RetLen
, RetString
);
339 Free_stringTSD( result
);
342 int IfcExecScript( tsd_t
* volatile TSD
, int NameLen
, const char *Name
,
343 int ArgCount
, const int *ParLengths
, const char **ParStrings
,
344 int CallType
, int ExitFlags
, int EnvLen
, const char *EnvName
,
345 int SourceCode
, int restricted
,
346 const char *SourceString
, unsigned long SourceStringLen
,
347 const void *TinnedTree
, unsigned long TinnedTreeLen
,
348 int *RetLen
, char **RetString
, void **instore_buf
,
349 unsigned long *instore_length
)
351 streng
* volatile result
=NULL
;
352 tsd_t
* volatile saved_TSD
;
353 jmp_buf * volatile old_exit_addr
;
354 int volatile RetCode
=0;
355 streng
* volatile environment
=NULL
;
356 volatile int jumped
=0;
360 int ctype
,hooks
,type
;
361 unsigned InterpreterStatus
[IPRT_BUFSIZE
];
365 * setjmp and longjmp will clobber all variables not explicitely marked
366 * as volatile. The reason is the unexpected jump from anywhere to the
367 * code following the setjmp() call. Every assumption of the compiler
368 * about valid register variables are wrong. We have to remove all
369 * register variables set by the optimizer. This can be done either by
370 * using volatile, or by not using variables before the setjmp() INCLUDING
371 * initialization or by using non-inline functions for manipulating
373 * We use a combination here.
374 * If you ever need to change ANY line before the setjmp() code,
375 * double-check the compiler's chance to cache some variables in registers.
379 SaveInterpreterStatus( TSD
, InterpreterStatus
);
381 /* It may be that TSD->systeminfo->script_exit is not set. This may lead to
382 * an exit() call, e.g. at Rexx "EXIT". We set TSD->systeminfo->script_exit
383 * if it is not set. If a problem occurs we will be informed by a longjmp
384 * and we will not completely been killed by an exit(). Remember: This
385 * function is typically called if a program uses "us" as a subroutine.
386 * Exiting is very harmful in this case.
387 * Note: The memory allocated within called subsoutines will NOT be
388 * freed. We must change many things to do this. Maybe, it's a good
389 * idea to traverse all called subroutine trees and free the leaves.
392 if ( ( old_exit_addr
= TSD
->systeminfo
->script_exit
) == NULL
)
394 TSD
->systeminfo
->script_exit
= &exit_addr
;
395 assert( !TSD
->in_protected
);
396 if ( setjmp( *TSD
->systeminfo
->script_exit
) )
399 result
= TSD
->systeminfo
->result
;
400 TSD
->systeminfo
->result
= NULL
;
404 RetCode
= atoi( result
->value
);
408 result
= NULL
; /* result was a static buffer provided by exiterror */
415 instore_buf
, instore_length
,
416 &command
, Name
, NameLen
,
417 ¶ms
, ArgCount
, ParLengths
, ParStrings
,
421 (streng
**) &environment
, EnvLen
, EnvName
);
424 if ( type
== RX_TYPE_EXTERNAL
)
426 result
= execute_external( TSD
, command
, params
, environment
,
427 (int *) &RetCode
, hooks
, ctype
);
429 else if ( type
== RX_TYPE_INSTORE
)
431 result
= do_instore( TSD
, command
, params
, environment
,
432 (int *) &RetCode
, hooks
,
433 TinnedTree
, TinnedTreeLen
,
434 SourceString
, SourceStringLen
, NULL
, ctype
);
436 else if ( type
== RX_TYPE_MACRO
)
437 result
= nullstringptr();
438 else if ( type
== RX_TYPE_SOURCE
)
440 streng
*SrcStr
= wrapstring( TSD
, SourceString
, SourceStringLen
);
441 internal_parser_type ipt
;
443 ipt
= enter_macro( TSD
, SrcStr
, instore_buf
, instore_length
) ;
444 if ( ( CallType
== RX_TYPE_COMMAND
)
446 && ( *ParStrings
!= NULL
)
447 && ( *ParLengths
== 3 )
448 && ( memcmp( "//T", *ParStrings
, 3 ) == 0 ) )
449 ; /* request for tokenisation only, don't execute */
453 result
= do_instore( TSD
, command
, params
, environment
,
454 (int *) &RetCode
, hooks
, NULL
,0, NULL
,0, &ipt
,
456 /* do_instore already has deleted the internal structure */
461 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" );
466 ScriptCleanup( TSD
, old_exit_addr
, environment
, result
, RetLen
, RetString
,
472 int IfcExecCallBack( tsd_t
* volatile TSD
, int NameLen
, const char *Name
,
473 int ArgCount
, const int *ParLengths
, const char **ParStrings
,
474 int *RetLen
, char **RetString
)
482 * If we can't find the label, no point in continuing.
484 name
= Str_ncreTSD( Name
, NameLen
);
485 if ( ( node
= getlabel( TSD
, name
) ) == NULL
)
488 return RX_CODE_NOSUCH
;
491 if ( node
->u
.trace_only
)
494 return RX_CODE_NOSUCH
;
500 args
= initargs( TSD
, ArgCount
, ParLengths
, ParStrings
);
501 result
= CallInternalFunction( TSD
, node
, TSD
->currentnode
, args
);
503 IfcPrepareReturnString( result
, RetLen
, RetString
);
506 Free_stringTSD( result
);
512 static int handle_source( const tsd_t
*TSD
, int *Length
, char **String
,
515 int infile
=0, total
=0, invoked
=0 ;
516 const char *stype
=NULL
;
520 stype
= system_type() ;
521 sleng
= strlen( stype
) ;
522 infile
= TSD
->systeminfo
->input_file
->len
;
523 invoked
= strlen(invo_strings
[TSD
->systeminfo
->invoked
]) ;
524 total
= sleng
+ 1 + invoked
+ 1 + infile
;
526 ctmp
= *String
= (char *)MallocTSD( (*Length
=total
)+2 ) ;
527 sprintf( ctmp
, "%s %s ", stype
, invo_strings
[TSD
->systeminfo
->invoked
]) ;
528 strncat( ctmp
, TSD
->systeminfo
->input_file
->value
, infile
) ;
534 static int handle_param( tsd_t
*TSD
, int *Length
, char **String
)
536 paramboxptr ptr
=NULL
;
540 ptr
= TSD
->systeminfo
->currlevel0
->args
;
541 value
= wrapstring( TSD
, *String
, *Length
) ;
542 number
= atopos( TSD
, value
, "internal", 1 ) ;
543 Free_stringTSD( value
) ;
544 value
= get_parameter( ptr
, number
) ;
548 *(Length
+1) = value
->len
;
549 *(String
+1) = value
->value
;
552 *(Length
+1) = RX_NO_STRING
;
557 static int handle_no_of_params( const tsd_t
*TSD
, int *Length
, char **String
)
559 paramboxptr ptr
=NULL
;
563 ct
= (cli_tsd_t
*)TSD
->cli_tsd
;
564 ptr
= TSD
->systeminfo
->currlevel0
->args
;
565 count
= count_params( ptr
, PARAM_TYPE_HARD
) ;
567 sprintf( ct
->count_params_buf
, "%d", count
) ;
568 *String
= ct
->count_params_buf
;
569 *Length
= strlen(*String
) ;
576 static int get_next_var( tsd_t
*TSD
, int *Lengths
, char **Strings
,
579 variableptr value
=NULL
, rval
=NULL
, rrval
=NULL
;
583 if (TSD
->var_indicator
==0)
585 get_next_variable( TSD
, 1 ) ;
586 TSD
->var_indicator
= 1 ;
591 value
= get_next_variable( TSD
, 0 ) ;
592 for (rval
=value
; rval
&& rval
->realbox
; rval
=rval
->realbox
)
596 if (rval
&& !(rval
->flag
& VFLAG_STR
))
598 if (rval
->flag
& VFLAG_NUM
)
600 expand_to_str( TSD
, rval
) ;
607 for (rrval
=rval
->stem
; rrval
&& rrval
->realbox
; rrval
=rrval
->realbox
)
611 if (rrval
&& !(rrval
->flag
& VFLAG_STR
))
613 if (rval
->flag
& VFLAG_NUM
)
615 expand_to_str( TSD
, rval
) ;
630 l
= Lengths
[0] = rval
->stem
->name
->len
+ rval
->name
->len
;
631 Strings
[0] = (char *)MallocTSD( (l
< 1) ? 1 : l
) ;
632 memcpy(Strings
[0], rval
->stem
->name
->value
, rval
->stem
->name
->len
);
633 memcpy(Strings
[0]+rval
->stem
->name
->len
,
634 rval
->name
->value
, rval
->name
->len
) ;
638 Lengths
[0] = rval
->name
->len
;
639 Strings
[0] = rval
->name
->value
;
644 Lengths
[1] = rval
->value
->len
;
645 Strings
[1] = rval
->value
->value
;
650 assert( rval
->stem
&& rrval
->value
) ;
651 l
= Lengths
[1] = rval
->stem
->name
->len
+ rval
->name
->len
;
652 Strings
[1] = (char *)MallocTSD( (l
< 1) ? 1 : l
) ;
653 memcpy( Strings
[1], rval
->stem
->name
->value
, value
->stem
->name
->len
);
654 memcpy( Strings
[1]+value
->stem
->name
->len
,
655 rval
->name
->value
, rval
->name
->len
) ;
663 * Once we have reached the end of all variables, reset var_indicator
664 * so next time we can start from the beginning again.
666 TSD
->var_indicator
= 0 ;
672 static int MapHook( const tsd_t
*TSD
, int RexxHook
)
676 case HOOK_STDOUT
: return RX_EXIT_STDOUT
;
677 case HOOK_STDERR
: return RX_EXIT_STDERR
;
678 case HOOK_TRCIN
: return RX_EXIT_TRCIN
;
679 case HOOK_PULL
: return RX_EXIT_PULL
;
681 case HOOK_INIT
: return RX_EXIT_INIT
;
682 case HOOK_TERMIN
: return RX_EXIT_TERMIN
;
683 case HOOK_SUBCOM
: return RX_EXIT_SUBCOM
;
685 case HOOK_GETENV
: return RX_EXIT_GETENV
;
686 case HOOK_SETENV
: return RX_EXIT_SETENV
;
688 case HOOK_GETCWD
: return RX_EXIT_GETCWD
;
689 case HOOK_SETCWD
: return RX_EXIT_SETCWD
;
692 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" );
699 static int ReMapHook( const tsd_t
*TSD
, int NetHook
)
703 case RX_EXIT_STDOUT
: return HOOK_STDOUT
;
704 case RX_EXIT_STDERR
: return HOOK_STDERR
;
705 case RX_EXIT_TRCIN
: return HOOK_TRCIN
;
706 case RX_EXIT_PULL
: return HOOK_PULL
;
708 case RX_EXIT_TERMIN
: return HOOK_TERMIN
;
709 case RX_EXIT_INIT
: return HOOK_INIT
;
710 case RX_EXIT_SUBCOM
: return HOOK_SUBCOM
;
711 case RX_EXIT_FUNC
: return HOOK_FUNC
;
713 case RX_EXIT_GETENV
: return HOOK_GETENV
;
714 case RX_EXIT_SETENV
: return HOOK_SETENV
;
716 case RX_EXIT_GETCWD
: return HOOK_GETCWD
;
717 case RX_EXIT_SETCWD
: return HOOK_SETCWD
;
720 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" );
728 int hookup( tsd_t
*TSD
, int hook
)
732 code
= MapHook ( TSD
, hook
);
733 assert (code
== RX_EXIT_INIT
|| code
== RX_EXIT_TERMIN
);
734 rcode
= IfcDoExit( TSD
, code
, 0, NULL
, 0, NULL
, NULL
, NULL
) ;
735 if (rcode
==RX_HOOK_ERROR
)
736 exiterror( ERR_SYSTEM_FAILURE
, 0 ) ;
737 else if (rcode
==RX_HOOK_GO_ON
)
739 else if (rcode
==RX_HOOK_NOPE
)
742 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
746 int hookup_output( tsd_t
*TSD
, int hook
, const streng
*outdata
)
748 int rcode
=0, code
=0 ;
752 code
= MapHook( TSD
, hook
);
753 /* assert (code == RX_EXIT_STDOUT || code == RX_EXIT_STDERR ); */
756 str
= str_of( TSD
, outdata
) ;
761 str
= (char *)MallocTSD( 1 ) ;
766 rcode
= IfcDoExit( TSD
, code
, len
, str
, 0, NULL
, NULL
, NULL
) ;
768 if (rcode
==RX_HOOK_ERROR
)
769 exiterror( ERR_SYSTEM_FAILURE
, 0 ) ;
770 else if (rcode
==RX_HOOK_GO_ON
)
772 else if (rcode
==RX_HOOK_NOPE
)
775 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
780 int hookup_output2( tsd_t
*TSD
, int hook
, const streng
*outdata1
, const streng
*outdata2
)
782 int rcode
=0, code
=0 ;
784 int len1
= 0, len2
= 0;
786 code
= MapHook( TSD
, hook
);
787 /* assert (code == RX_EXIT_SETENV ); */
790 str1
= str_of( TSD
, outdata1
) ;
791 len1
= outdata1
->len
;
795 str1
= (char *)MallocTSD( 1 ) ;
801 str2
= str_of( TSD
, outdata2
) ;
802 len2
= outdata2
->len
;
806 str2
= (char *)MallocTSD( 1 ) ;
811 rcode
= IfcDoExit( TSD
, code
, len1
, str1
, len2
, str2
, NULL
, NULL
) ;
814 if (rcode
==RX_HOOK_ERROR
)
815 exiterror( ERR_SYSTEM_FAILURE
, 0 ) ;
816 else if (rcode
==RX_HOOK_GO_ON
)
818 else if (rcode
==RX_HOOK_NOPE
)
821 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
826 int hookup_input( tsd_t
*TSD
, int hook
, streng
**indata
)
828 int rcode
=0, code
=0 ;
829 /* The following value allows called programs to call "free" to the return
830 * parameters without destroying our stack.
832 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
833 char RetBuf
[ILLEGAL_USE_SIZE
+ 256] ;
837 code
= MapHook( TSD
, hook
);
838 /* assert (code == RX_EXIT_PULL || code == RX_EXIT_TRCIN ); */
841 /* FIXME, FGC: The documentation says that the input of a PULL or TRCIN is
842 * undefined. Why do we provide a buffer?
844 rcode
= IfcDoExit( TSD
, code
, 0, NULL
, 0, NULL
, &retlen
, &retstr
) ;
845 if (rcode
==RX_HOOK_ERROR
)
846 exiterror( ERR_SYSTEM_FAILURE
, 0 ) ;
847 else if (rcode
==RX_HOOK_GO_ON
)
849 else if (rcode
==RX_HOOK_NOPE
)
852 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
854 *indata
= wrapstring( TSD
, retstr
, retlen
) ;
855 FreeTSD( retstr
) ; /* retstr was always newly allocated */
856 #undef ILLEGAL_USE_SIZE
860 int hookup_input_output( tsd_t
*TSD
, int hook
, const streng
*outdata
, streng
**indata
)
864 int rcode
=0, code
=0 ;
865 /* The following value allows called programs to call "free" to the return
866 * parameters without destroying our stack.
868 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
869 char RetBuf
[ILLEGAL_USE_SIZE
+ 256] ;
873 code
= MapHook( TSD
, hook
);
874 /* assert (code == RX_EXIT_GETENV );*/
878 str
= str_of( TSD
, outdata
) ;
883 str
= (char *)MallocTSD( 1 ) ;
889 /* FIXME, FGC: The documentation says that the input of a PULL or TRCIN is
890 * undefined. Why do we provide a buffer?
892 rcode
= IfcDoExit( TSD
, code
, len
, str
, 0, NULL
, &retlen
, &retstr
) ;
894 if (rcode
==RX_HOOK_ERROR
)
895 exiterror( ERR_SYSTEM_FAILURE
, 0 ) ;
896 else if (rcode
==RX_HOOK_GO_ON
)
898 else if (rcode
==RX_HOOK_NOPE
)
901 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
903 *indata
= wrapstring( TSD
, retstr
, retlen
) ;
904 FreeTSD( retstr
) ; /* retstr was always newly allocated */
905 #undef ILLEGAL_USE_SIZE
911 streng
*SubCom( tsd_t
*TSD
, const streng
*command
, const streng
*envir
, int *rc
)
917 *rc
= IfcSubCmd( TSD
,
918 envir
? envir
->len
: RX_NO_STRING
,
919 envir
? envir
->value
: NULL
,
920 command
->len
, command
->value
, &tmplen
, &tmpptr
) ;
922 retval
= wrapstring( TSD
, tmpptr
, tmplen
) ;
928 /****************************************************************************
930 * JH 13/12/1999 Trying to satisfy both BUG031 and BUG022.
932 * BUG022 To make Direct setting of stems Direct and not Symbolic.
933 * - Added new parameter, "Code". Assumed values are RX_GETSVAR, and
934 * RX_GETVAR. They denote that the actiion is symbolic, or direct
936 * - if direct call getdirvalue()
939 * - if default value is being returned, uppercase the whole name for
940 * symbolics, and only the stem for directs. This should be a moot
941 * issue, as there is code in variable.c to return default values.
943 ****************************************************************************/
944 static int GetVariable( tsd_t
*TSD
, int Code
, int *Lengths
, char *Strings
[],
952 varbl
= wrapstring( TSD
, Strings
[0], Lengths
[0] );
956 Lengths
[1] = RX_NO_STRING
;
957 return RX_CODE_INVNAME
;
960 if ( !valid_var_symbol( varbl
) )
962 Free_stringTSD( varbl
);
963 Lengths
[1] = RX_NO_STRING
;
964 return RX_CODE_INVNAME
;
967 state
= variables_per_SAA( TSD
);
968 if ( Code
== RX_GETSVAR
)
969 value
= getvalue( TSD
, varbl
, -1 );
971 value
= getdirvalue( TSD
, varbl
);
972 restore_variable_state( TSD
, state
);
975 * getvalue returns varbl or a temporary value on NOVALUE, don't free varbl
976 * until the final use of value and varbl.
978 if ( var_was_found( TSD
) )
980 Lengths
[1] = value
->len
;
981 Strings
[1] = (char *) value
->value
;
983 Free_stringTSD( varbl
);
987 Lengths
[1] = len
= value
->len
;
988 Strings
[1] = retval
= (char *)MallocTSD( len
);
989 memcpy( retval
, value
->value
, len
);
991 Free_stringTSD( varbl
);
993 if ( Code
== RX_GETSVAR
)
995 mem_upper( retval
, len
);
999 /* JH 13-12-99 If this is a direct variable, only uppercase the
1003 * Bypass the dot test for the first character to allow reserved
1007 retval
[0] = (unsigned char) rx_toupper( retval
[0] );
1008 for( i
= 1; ( i
< len
) && ( '.' != retval
[i
] ); i
++ )
1009 retval
[i
] = (unsigned char) rx_toupper( retval
[i
] );
1011 return RX_CODE_NOVALUE
;
1014 /****************************************************************************
1016 * JH 13/12/1999 Trying to satisfy both BUG031 and BUG022.
1018 * BUG022 To make Direct setting of stems Direct and not Symbolic.
1019 * - Added new parameter, "Code". Assumed values are RX_SETSVAR, and
1020 * RX_SETVAR. They denote that the actiion is symbolic, or direct
1022 * Until this point setting and dropping variables have been treated as
1023 * the same. If there is a value, then it is a set, otherwise drop it.
1024 * - if direct call setdirvalue()
1025 * - if direct call drop_dirvar()
1027 * - uppercase the whole name for symbolics, and only the stem for directs.
1029 ****************************************************************************/
1030 static int SetVariable( tsd_t
*TSD
, int Code
, int *Lengths
, char *Strings
[] )
1032 streng
*varbl
,*varname
,*value
;
1035 varbl
= wrapstring( TSD
, Strings
[0], Lengths
[0] );
1037 if ( varbl
== NULL
)
1040 * If the variable name is empty, return an error
1042 return RX_CODE_INVNAME
;
1045 if ( Code
== RX_SETSVAR
)
1046 varname
= Str_upper( Str_dupTSD( varbl
) );
1050 * Setting reserved variables is not allowed :-(
1052 if ( varbl
->len
&& varbl
->value
[0] == '.' )
1054 Free_stringTSD( varbl
) ;
1055 return RX_CODE_INVNAME
;
1057 varname
= Str_dupTSD( varbl
);
1059 * Bypass the dot test for the first character to allow reserved
1061 * This bypass is not relevant anymore. See comment above.
1064 varname
->value
[0] = (unsigned char) rx_toupper( varname
->value
[0] );
1065 for( i
= 1; ( i
< varname
->len
) && ( '.' != varname
->value
[i
] ); i
++ )
1067 varname
->value
[i
] = (unsigned char) rx_toupper( varname
->value
[i
] );
1070 Free_stringTSD( varbl
) ;
1071 varbl
= NULL
; /* For debugging purpose only */
1073 if ( !valid_var_symbol( varname
) )
1075 Free_stringTSD( varname
);
1076 return RX_CODE_INVNAME
;
1079 value
= wrapstring( TSD
, Strings
[1], Lengths
[1] );
1081 state
= variables_per_SAA( TSD
);
1082 rcode
= RX_CODE_OK
; /* default value */
1085 if ( Code
== RX_SETSVAR
)
1086 setvalue( TSD
, varname
, value
, -1 );
1088 setdirvalue( TSD
, varname
, value
);
1092 if ( Code
== RX_SETSVAR
)
1093 drop_var( TSD
, varname
);
1095 drop_dirvar( TSD
, varname
);
1097 restore_variable_state( TSD
, state
);
1099 if ( !var_was_found( TSD
) )
1100 rcode
= RX_CODE_NOVALUE
;
1102 Free_stringTSD( varname
);
1106 static int handle_version( int *Length
, char **String
)
1108 *Length
= strlen(PARSE_VERSION_STRING
) ;
1109 *String
= PARSE_VERSION_STRING
;
1114 static int handle_queue( const tsd_t
*TSD
, int *Length
, char **String
)
1116 fill_queue_name( TSD
, Length
, String
);
1121 /****************************************************************************
1125 * BUG022 To make Direct setting of stems Direct and not Symbolic.
1126 * - Added checks for the direct variable functions RX_GETVAR and RX_SETVAR.
1128 * *allocated will be set, if the returned value(s) is/are allocated and
1129 * should be freed after the use.
1131 ****************************************************************************/
1132 int IfcVarPool( tsd_t
*TSD
, int Code
, int *Lengths
, char *Strings
[],
1138 if (Code
==RX_GETSVAR
||Code
==RX_GETVAR
)
1139 rc
= GetVariable( TSD
, Code
, Lengths
, Strings
, allocated
) ;
1140 else if (Code
==RX_SETSVAR
||Code
==RX_SETVAR
)
1141 rc
= SetVariable( TSD
, Code
, Lengths
, Strings
) ;
1142 else if (Code
==RX_NEXTVAR
)
1143 rc
= get_next_var( TSD
, Lengths
, Strings
, allocated
) ;
1144 else if (Code
==RX_CODE_VERSION
)
1145 rc
= handle_version( Lengths
, Strings
) ;
1146 else if (Code
==RX_CODE_SOURCE
)
1147 rc
= handle_source( TSD
, Lengths
, Strings
, allocated
) ;
1148 else if (Code
==RX_CODE_QUEUE
)
1149 rc
= handle_queue( TSD
, Lengths
, Strings
);
1150 else if (Code
==RX_CODE_PARAMS
)
1151 rc
= handle_no_of_params( TSD
, Lengths
, Strings
) ;
1152 else if (Code
==RX_CODE_PARAM
)
1153 rc
= handle_param( TSD
, Lengths
, Strings
) ;
1155 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1160 /* Removes ct->Strings and ct->Lengths AND ct->ExternalName. */
1161 static void RemoveParams(const tsd_t
*TSD
)
1166 ct
= (cli_tsd_t
*)TSD
->cli_tsd
;
1168 if ( ct
->Strings
&& ct
->Lengths
)
1170 for (i
= 0;i
< ct
->StringsCount
;i
++) /* The last one is always NULL */
1172 if ((ct
->Lengths
[i
] != RX_NO_STRING
) &&
1173 (ct
->Strings
[i
] != NULL
))
1174 FreeTSD( ct
->Strings
[i
] );
1179 FreeTSD( ct
->Lengths
) ;
1181 FreeTSD( ct
->Strings
) ;
1182 if ( ct
->ExternalName
)
1183 FreeTSD( ct
->ExternalName
) ;
1185 ct
->StringsCount
= -1;
1188 ct
->ExternalName
= NULL
;
1191 /* Creates (possibly after a removal of old values) ct->Strings and ct->Lengths
1192 * from the given parms. One hidden NULL string is appended.
1194 static void MakeParams(const tsd_t
*TSD
, cparamboxptr parms
)
1197 cparamboxptr p
=NULL
;
1200 ct
= (cli_tsd_t
*)TSD
->cli_tsd
;
1202 /* Cleanup the old parameters before we set StringsCount */
1205 ct
->StringsCount
= 0; /* This is the default in case of unused parameters */
1206 /* Detect the index of the last valid parameter */
1207 for (i
=0,p
=parms
; p
; p
=p
->next
,i
++)
1210 ct
->StringsCount
=i
+1 ;
1213 /* add one NULL string at the end */
1214 ct
->Lengths
= (int *)MallocTSD( sizeof(int) * (ct
->StringsCount
+1) ) ;
1215 ct
->Strings
= (char **)MallocTSD( sizeof(char*) * (ct
->StringsCount
+1) ) ;
1217 for (i
=0,p
=parms
; i
< ct
->StringsCount
; p
=p
->next
,i
++)
1221 ct
->Lengths
[i
] = Str_len( p
->value
) ;
1222 ct
->Strings
[i
] = str_of( TSD
, p
->value
);
1226 ct
->Lengths
[i
] = RX_NO_STRING
;
1227 ct
->Strings
[i
] = NULL
;
1231 /* Provide a hidden NULL string at the end */
1232 ct
->Lengths
[ct
->StringsCount
] = RX_NO_STRING
;
1233 ct
->Strings
[ct
->StringsCount
] = NULL
;
1236 /* do_an_external calls IfcExecFunc with the appropriate parameters. Basically
1237 * it wraps the parameters. Either ExeName or box must be NULL.
1239 static streng
*do_an_external( tsd_t
*TSD
,
1240 const streng
*ExeName
,
1241 const struct entry_point
*box
,
1247 char *RetString
=NULL
;
1255 volatile char *tmpExternalName
; /* used to save ct->ExternalName */
1258 ct
= (cli_tsd_t
*)TSD
->cli_tsd
;
1260 MakeParams( TSD
, parms
) ;
1263 ct
->ExternalName
= str_of( TSD
, ExeName
);
1264 tmpExternalName
= tmpstr_of( TSD
, ExeName
);
1270 ct
->ExternalName
= str_of( TSD
, box
->name
);
1271 tmpExternalName
= tmpstr_of( TSD
, box
->name
);
1273 gci_info
= box
->special
.gci_info
;
1276 queue
= get_queue( TSD
);
1278 rc
= IfcExecFunc( TSD
, Func
, ct
->ExternalName
,
1279 ct
->StringsCount
, ct
->Lengths
, ct
->Strings
,
1280 Str_len( queue
), Str_val( queue
),
1281 &RetLength
, &RetString
, &RC
, called
, gci_info
);
1282 (void)rc
; // FIXME: Should 'rc' be tested for success?
1284 Free_stringTSD( queue
);
1285 RemoveParams( TSD
) ;
1291 case ERR_ROUTINE_NOT_FOUND
:
1292 exiterror( ERR_ROUTINE_NOT_FOUND
, 1, tmpExternalName
);
1300 else if ( RetLength
== RX_NO_STRING
)
1303 * ERR_NO_DATA_RETURNED is detected later in expr.c.
1309 retval
= Str_makeTSD( RetLength
) ;
1310 memcpy( retval
->value
, RetString
, RetLength
) ;
1311 FreeTSD( RetString
);
1312 retval
->len
= RetLength
;
1318 streng
*call_unknown_external( tsd_t
*TSD
, const streng
*name
, cparamboxptr parms
, char called
)
1322 return( do_an_external( TSD
, name
, NULL
, parms
, 1, called
) ) ;
1325 streng
*call_known_external( tsd_t
*TSD
, const struct entry_point
*vbox
, cparamboxptr parms
, char called
)
1329 return( do_an_external( TSD
, NULL
, vbox
, parms
, 0, called
) ) ;
1332 int IfcCreateQueue( tsd_t
*TSD
, const char *qname
, const int qlen
, char *data
, unsigned long *dupflag
, unsigned long buflen
)
1334 streng
*queuename
=NULL
,*strdata
;
1339 queuename
= Str_makeTSD( qlen
) ;
1340 memcpy( queuename
->value
, qname
, qlen
) ;
1341 queuename
->len
= qlen
;
1343 rc
= create_queue( TSD
, queuename
, &strdata
);
1345 if ( rc
== 0 || rc
== 1 )
1348 * Return the new queue name
1350 memcpy( data
, strdata
->value
, min( strdata
->len
, (int) buflen
- 1 ) );
1351 data
[min( strdata
->len
, (int) buflen
- 1)] = '\0';
1353 * If the returned queue name is different to
1354 * the one we requested, set the dupflag
1364 if ( queuename
) Free_stringTSD( queuename
);
1368 int IfcDeleteQueue( tsd_t
*TSD
, const char *qname
, const int qlen
)
1373 queuename
= Str_makeTSD( qlen
) ;
1374 memcpy( queuename
->value
, qname
, qlen
) ;
1375 queuename
->len
= qlen
;
1376 rc
= delete_queue( TSD
, queuename
);
1377 Free_stringTSD( queuename
);
1381 int IfcQueryQueue( tsd_t
*TSD
, const char *qname
, const int qlen
, unsigned long *count
)
1386 queuename
= Str_makeTSD( qlen
) ;
1387 memcpy( queuename
->value
, qname
, qlen
) ;
1388 queuename
->len
= qlen
;
1389 rc
= lines_in_stack( TSD
, queuename
);
1397 Free_stringTSD( queuename
);
1401 int IfcAddQueue( tsd_t
*TSD
, const char *qname
, const int qlen
, const char *data
, const int datalen
, unsigned long addlifo
)
1403 streng
*queuename
,*strdata
;
1406 queuename
= Str_makeTSD( qlen
) ;
1407 memcpy( queuename
->value
, qname
, qlen
) ;
1408 queuename
->len
= qlen
;
1410 strdata
= Str_makeTSD( datalen
) ;
1411 memcpy( strdata
->value
, data
, datalen
) ;
1412 strdata
->len
= datalen
;
1415 rc
= stack_lifo( TSD
, strdata
, queuename
);
1417 rc
= stack_fifo( TSD
, strdata
, queuename
);
1418 Free_stringTSD( queuename
);
1422 int IfcPullQueue( tsd_t
*TSD
, const char *qname
, const int qlen
, char **data
, unsigned long *datalen
, unsigned long waitforline
)
1424 streng
*queuename
,*strdata
;
1428 queuename
= Str_makeTSD( qlen
) ;
1429 memcpy( queuename
->value
, qname
, qlen
) ;
1430 queuename
->len
= qlen
;
1432 strdata
= popline( TSD
, queuename
, &rc
, waitforline
);
1436 if ( strdata
== NULL
)
1441 rc
= 8; /* RXQUEUE_EMPTY */
1447 if ( ( *data
== NULL
) || ( *datalen
<= (unsigned long) len
) )
1448 p
= (char *)IfcAllocateMemory( len
+ 1 );
1452 rc
= 12; /* RXQUEUE_MEMFAIL */
1456 * Using the temporary p inhibits use of *data until it's sure
1460 memcpy( *data
, strdata
->value
, len
);
1461 (*data
)[len
] = '\0';
1464 Free_stringTSD( strdata
);
1467 Free_stringTSD( queuename
);