Same fix as r45172 for classes/iconimage:
[AROS-Contrib.git] / regina / client.c
blob5efc0abca02ad0786a6051b8e8320f7c5fb587a2
1 /*
2 * The Regina Rexx Interpreter
3 * Copyright (C) 1993-1994 Anders Christensen <anders@pvv.unit.no>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* JH 20-10-99 */ /* To make Direct setting of stems Direct and not Symbolic. */
21 #include "regina_c.h"
23 #if defined(WIN32) && defined(__IBMC__)
24 # include <windows.h>
25 # pragma warning(default: 4115 4201 4214)
26 #else
27 # if defined(WIN32) && (defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__))
28 # undef APIENTRY
29 # include <windows.h>
30 # else
31 # if defined(__EMX__) && defined(OS2)
32 # define DONT_TYPEDEF_PFN
33 # undef APIENTRY
34 # include <os2emx.h>
35 # else
36 # if defined(__WATCOMC__) && defined(OS2)
37 # undef APIENTRY
38 # define DONT_TYPEDEF_PFN
39 # include <os2.h>
40 # else
41 # if defined(_MSC_VER) && !defined(__WINS__)
42 # undef APIENTRY
43 # if _MSC_VER >= 1100
44 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
45 # pragma warning(disable: 4115 4201 4214 4514)
46 # endif
47 # include <windows.h>
48 # if _MSC_VER >= 1100
49 # pragma warning(default: 4115 4201 4214)
50 # endif
51 # else
52 # define APIENTRY
53 # endif
54 # endif
55 # endif
56 # endif
57 #endif
59 #ifndef RXLIB /* need __regina_faked_main which is known with RXLIB only */
60 # define RXLIB
61 #endif
62 #include "rexx.h"
64 #ifdef HAVE_UNISTD_H
65 # include <unistd.h>
66 #endif
68 #include "rxiface.h"
69 #include <stdio.h>
70 #include <string.h>
72 #ifdef HAVE_ERRNO_H
73 #include <errno.h>
74 #endif
76 #ifdef HAVE_ASSERT_H
77 # include <assert.h>
78 #endif
80 #ifdef HAVE_STDARG_H
81 #include <stdarg.h>
82 #endif
84 #ifndef min
85 # define min(a,b) (((a) < (b)) ? (a) : (b))
86 #endif
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
94 * errors.
96 char * ExternalName ;
97 int StringsCount ;
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
101 * init_client
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 )
110 cli_tsd_t *ct;
112 if ( TSD->cli_tsd != NULL )
113 return(1);
115 if ( ( TSD->cli_tsd = MallocTSD( sizeof(cli_tsd_t) ) ) == NULL )
116 return(0);
117 ct = (cli_tsd_t *)TSD->cli_tsd;
118 memset( ct, 0, sizeof(cli_tsd_t) );
119 ct->StringsCount = -1;
120 return(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 ;
138 else
139 result = NULL ;
141 return result ;
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 ;
151 else
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 ;
162 int count=0, i=0 ;
164 count = ArgCount ;
165 for (i=0; count--; i++ )
167 if (parms)
169 parms->next = (paramboxptr)MallocTSD( sizeof(parambox)) ;
170 parms = parms->next ;
172 else
173 parms = root = (paramboxptr)MallocTSD( sizeof(parambox )) ;
175 parms->value = wrapstring( TSD, ParStrings[i], ParLengths[i] ) ;
178 if (parms)
179 parms->next = NULL ;
181 return root ;
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
190 * become NULL.
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,
200 char **targetbuf )
202 int len;
205 * Check for an invalid source first.
207 if ( ( src == NULL ) || ( Str_val( src ) == NULL ) )
209 *targetlen = 0;
210 *targetbuf = NULL;
211 return;
213 len = Str_len( src );
214 if ( *targetlen < len + 1 )
216 if ( ( *targetbuf = (char *)IfcAllocateMemory( len + 1 ) ) == NULL )
219 * Better idea?
221 *targetlen = 0;
222 return;
225 memcpy( *targetbuf, Str_val( src ), len );
226 (*targetbuf)[len] = '\0';
227 *targetlen = len;
231 * ScriptSetup does the setup step of IfcExecScript.
232 * This function is part of the technique to bypass problems with
233 * setjmp/longjmp.
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,
241 int restricted,
242 int *hooks, int ExitFlags,
243 streng **environment, int EnvLen, const char *EnvName )
245 int i;
246 char c;
247 streng *h;
249 *instore_buf = NULL;
250 *instore_length = 0;
251 *command = wrapstring( TSD, Name, NameLen );
252 TSD->systeminfo->input_file = *command;
253 assert( *command );
254 *params = parametrize( TSD, ArgCount, ParLengths, ParStrings );
256 *ctype = map_type( CallType );
258 TSD->restricted = restricted;
260 *hooks = 0;
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-- )
278 c = Str_val( h )[i];
279 if ( c == '.' )
281 i++;
282 break;
284 else if ( strchr( FILE_SEPARATORS, c ) != NULL )
286 i = -1;
287 break;
291 * i == -1: no suffix
292 * i otherwise: position after dot (may lead to empty string, too)
294 if ( i == -1 )
295 i = Str_len( h );
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 );
311 else
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
325 * setjmp/longjmp.
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 );
338 if ( result )
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;
357 jmp_buf exit_addr;
358 streng * command;
359 paramboxptr params;
360 int ctype,hooks,type;
361 unsigned InterpreterStatus[IPRT_BUFSIZE];
364 * NOTE:
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
372 * values.
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.
376 * Florian
378 saved_TSD = TSD;
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.
390 * FGC
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 ) )
398 TSD = saved_TSD;
399 result = TSD->systeminfo->result;
400 TSD->systeminfo->result = NULL;
401 if ( !RetCode )
403 if ( result )
404 RetCode = atoi( result->value );
405 else
406 RetCode = -1;
408 result = NULL; /* result was a static buffer provided by exiterror */
409 jumped++;
412 if ( !jumped )
414 ScriptSetup( TSD,
415 instore_buf, instore_length,
416 &command, Name, NameLen,
417 &params, ArgCount, ParLengths, ParStrings,
418 &ctype, CallType,
419 restricted,
420 &hooks, ExitFlags,
421 (streng **) &environment, EnvLen, EnvName );
423 type = SourceCode ;
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 )
445 && ArgCount
446 && ( *ParStrings != NULL )
447 && ( *ParLengths == 3 )
448 && ( memcmp( "//T", *ParStrings, 3 ) == 0 ) )
449 ; /* request for tokenisation only, don't execute */
450 else
452 ipt.kill = SrcStr;
453 result = do_instore( TSD, command, params, environment,
454 (int *) &RetCode, hooks, NULL,0, NULL,0, &ipt,
455 ctype);
456 /* do_instore already has deleted the internal structure */
459 else
461 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" );
462 return 0;
466 ScriptCleanup( TSD, old_exit_addr, environment, result, RetLen, RetString,
467 InterpreterStatus );
469 return RetCode;
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 )
476 nodeptr node;
477 paramboxptr args;
478 streng *result;
479 streng *name;
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 )
487 FreeTSD( name );
488 return RX_CODE_NOSUCH;
490 FreeTSD( name );
491 if ( node->u.trace_only )
493 FreeTSD( name );
494 return RX_CODE_NOSUCH;
498 * Fixes bug 772199
500 args = initargs( TSD, ArgCount, ParLengths, ParStrings );
501 result = CallInternalFunction( TSD, node, TSD->currentnode, args );
503 IfcPrepareReturnString( result, RetLen, RetString );
505 if ( result )
506 Free_stringTSD( result );
508 return 0;
512 static int handle_source( const tsd_t *TSD, int *Length, char **String,
513 int *allocated )
515 int infile=0, total=0, invoked=0 ;
516 const char *stype=NULL ;
517 char *ctmp=NULL ;
518 int sleng=0 ;
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 ) ;
530 *allocated = 1;
531 return RX_CODE_OK ;
534 static int handle_param( tsd_t *TSD, int *Length, char **String )
536 paramboxptr ptr=NULL ;
537 streng *value=NULL ;
538 int number=0 ;
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 ) ;
546 if (value)
548 *(Length+1) = value->len ;
549 *(String+1) = value->value ;
551 else
552 *(Length+1) = RX_NO_STRING ;
554 return RX_CODE_OK ;
557 static int handle_no_of_params( const tsd_t *TSD, int *Length, char **String )
559 paramboxptr ptr=NULL ;
560 int count=0 ;
561 cli_tsd_t *ct;
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) ;
571 return RX_CODE_OK ;
576 static int get_next_var( tsd_t *TSD, int *Lengths, char **Strings,
577 int *allocated )
579 variableptr value=NULL, rval=NULL, rrval=NULL ;
580 int l;
582 *allocated = 0;
583 if (TSD->var_indicator==0)
585 get_next_variable( TSD, 1 ) ;
586 TSD->var_indicator = 1 ;
589 for (;;)
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 ) ;
601 break ;
604 if (!rval->stem)
605 continue ;
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 ) ;
616 break ;
618 else
619 continue ;
622 break ;
625 if (rval)
627 if (rval->stem)
629 *allocated |= 1;
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 ) ;
636 else
638 Lengths[0] = rval->name->len ;
639 Strings[0] = rval->name->value ;
642 if (rval->value)
644 Lengths[1] = rval->value->len ;
645 Strings[1] = rval->value->value ;
647 else
649 *allocated |= 2;
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 ) ;
658 return 2 ;
660 else
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 ;
667 return 0 ;
672 static int MapHook( const tsd_t *TSD, int RexxHook )
674 switch ( 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 ;
691 default:
692 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" );
695 return 0 ;
699 static int ReMapHook( const tsd_t *TSD, int NetHook )
701 switch ( 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 ;
719 default:
720 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" );
723 return 0 ;
728 int hookup( tsd_t *TSD, int hook )
730 int rcode=0, code=0;
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)
738 rcode = HOOK_GO_ON ;
739 else if (rcode==RX_HOOK_NOPE)
740 rcode = HOOK_NOPE ;
741 else
742 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
743 return rcode ;
746 int hookup_output( tsd_t *TSD, int hook, const streng *outdata )
748 int rcode=0, code=0 ;
749 char *str;
750 int len = 0;
752 code = MapHook( TSD, hook );
753 /* assert (code == RX_EXIT_STDOUT || code == RX_EXIT_STDERR ); */
754 if (outdata)
756 str = str_of( TSD, outdata ) ;
757 len = outdata->len ;
759 else
761 str = (char *)MallocTSD( 1 ) ;
762 str[0] = '\0' ;
763 len = 0 ;
766 rcode = IfcDoExit( TSD, code, len, str, 0, NULL, NULL, NULL) ;
767 FreeTSD( str ) ;
768 if (rcode==RX_HOOK_ERROR)
769 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
770 else if (rcode==RX_HOOK_GO_ON)
771 rcode = HOOK_GO_ON ;
772 else if (rcode==RX_HOOK_NOPE)
773 rcode = HOOK_NOPE ;
774 else
775 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
777 return rcode ;
780 int hookup_output2( tsd_t *TSD, int hook, const streng *outdata1, const streng *outdata2 )
782 int rcode=0, code=0 ;
783 char *str1, *str2;
784 int len1 = 0, len2 = 0;
786 code = MapHook( TSD, hook );
787 /* assert (code == RX_EXIT_SETENV ); */
788 if (outdata1)
790 str1 = str_of( TSD, outdata1 ) ;
791 len1 = outdata1->len ;
793 else
795 str1 = (char *)MallocTSD( 1 ) ;
796 str1[0] = '\0' ;
797 len1 = 0 ;
799 if (outdata2)
801 str2 = str_of( TSD, outdata2 ) ;
802 len2 = outdata2->len ;
804 else
806 str2 = (char *)MallocTSD( 1 ) ;
807 str2[0] = '\0' ;
808 len2 = 0 ;
811 rcode = IfcDoExit( TSD, code, len1, str1, len2, str2, NULL, NULL) ;
812 FreeTSD( str1 ) ;
813 FreeTSD( str2 ) ;
814 if (rcode==RX_HOOK_ERROR)
815 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
816 else if (rcode==RX_HOOK_GO_ON)
817 rcode = HOOK_GO_ON ;
818 else if (rcode==RX_HOOK_NOPE)
819 rcode = HOOK_NOPE ;
820 else
821 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
823 return rcode ;
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] ;
834 int retlen=256 ;
835 char *retstr=RetBuf;
837 code = MapHook( TSD, hook );
838 /* assert (code == RX_EXIT_PULL || code == RX_EXIT_TRCIN ); */
840 strcpy(RetBuf,"");
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)
848 rcode = HOOK_GO_ON ;
849 else if (rcode==RX_HOOK_NOPE)
850 rcode = HOOK_NOPE ;
851 else
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
857 return rcode ;
860 int hookup_input_output( tsd_t *TSD, int hook, const streng *outdata, streng **indata )
862 char *str;
863 int len = 0;
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] ;
870 int retlen=256 ;
871 char *retstr=RetBuf;
873 code = MapHook( TSD, hook );
874 /* assert (code == RX_EXIT_GETENV );*/
876 if (outdata)
878 str = str_of( TSD, outdata ) ;
879 len = outdata->len ;
881 else
883 str = (char *)MallocTSD( 1 ) ;
884 str[0] = '\0' ;
885 len = 0 ;
888 strcpy(RetBuf,"");
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 ) ;
893 FreeTSD( str ) ;
894 if (rcode==RX_HOOK_ERROR)
895 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
896 else if (rcode==RX_HOOK_GO_ON)
897 rcode = HOOK_GO_ON ;
898 else if (rcode==RX_HOOK_NOPE)
899 rcode = HOOK_NOPE ;
900 else
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
906 return rcode ;
911 streng *SubCom( tsd_t *TSD, const streng *command, const streng *envir, int *rc )
913 int tmplen ;
914 char *tmpptr ;
915 streng *retval ;
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 ) ;
923 FreeTSD( tmpptr ) ;
924 return retval ;
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
935 * (respectively).
936 * - if direct call getdirvalue()
938 * BUG031
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[],
945 int *allocated)
947 const streng *value;
948 streng *varbl;
949 char *retval;
950 int i,len,state;
952 varbl = wrapstring( TSD, Strings[0], Lengths[0] );
954 if ( !varbl )
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 );
970 else
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;
982 *allocated = 0;
983 Free_stringTSD( varbl );
984 return RX_CODE_OK;
987 Lengths[1] = len = value->len;
988 Strings[1] = retval = (char *)MallocTSD( len );
989 memcpy( retval, value->value, len );
990 *allocated = 2;
991 Free_stringTSD( varbl );
993 if ( Code == RX_GETSVAR )
995 mem_upper( retval, len );
997 else
999 /* JH 13-12-99 If this is a direct variable, only uppercase the
1000 * stem name.
1003 * Bypass the dot test for the first character to allow reserved
1004 * variables.
1006 if ( len )
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
1021 * (respectively).
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()
1026 * BUG031
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;
1033 int rcode,i,state;
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 ) );
1047 else
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
1060 * variables.
1061 * This bypass is not relevant anymore. See comment above.
1063 if ( varname->len )
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 */
1083 if ( value )
1085 if ( Code == RX_SETSVAR )
1086 setvalue( TSD, varname, value, -1 );
1087 else
1088 setdirvalue( TSD, varname, value );
1090 else
1092 if ( Code == RX_SETSVAR )
1093 drop_var( TSD, varname );
1094 else
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 );
1103 return rcode;
1106 static int handle_version( int *Length, char **String )
1108 *Length = strlen(PARSE_VERSION_STRING) ;
1109 *String = PARSE_VERSION_STRING ;
1110 return RX_CODE_OK ;
1114 static int handle_queue( const tsd_t *TSD, int *Length, char **String )
1116 fill_queue_name( TSD, Length, String );
1117 return RX_CODE_OK ;
1121 /****************************************************************************
1123 * JH 13/12/1999
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[],
1133 int *allocated )
1135 int rc=0 ;
1137 *allocated = 0;
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 ) ;
1154 else
1155 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1157 return rc ;
1160 /* Removes ct->Strings and ct->Lengths AND ct->ExternalName. */
1161 static void RemoveParams(const tsd_t *TSD)
1163 int i;
1164 cli_tsd_t *ct;
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] );
1178 if ( ct->Lengths )
1179 FreeTSD( ct->Lengths ) ;
1180 if ( ct->Strings )
1181 FreeTSD( ct->Strings ) ;
1182 if ( ct->ExternalName )
1183 FreeTSD( ct->ExternalName ) ;
1185 ct->StringsCount = -1;
1186 ct->Strings = NULL;
1187 ct->Lengths = NULL;
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)
1196 int i;
1197 cparamboxptr p=NULL ;
1198 cli_tsd_t *ct;
1200 ct = (cli_tsd_t *)TSD->cli_tsd;
1202 /* Cleanup the old parameters before we set StringsCount */
1203 RemoveParams(TSD);
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++)
1209 if (p->value)
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++)
1219 if (p->value)
1221 ct->Lengths[i] = Str_len( p->value ) ;
1222 ct->Strings[i] = str_of( TSD, p->value );
1224 else
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,
1242 cparamboxptr parms,
1243 char exitonly,
1244 char called )
1246 int RetLength=0 ;
1247 char *RetString=NULL ;
1248 streng *retval ;
1249 streng *queue;
1250 int rc ;
1251 int RC ;
1252 PFN Func;
1253 cli_tsd_t *ct;
1254 void *gci_info;
1255 volatile char *tmpExternalName; /* used to save ct->ExternalName */
1256 /* when erroring */
1258 ct = (cli_tsd_t *)TSD->cli_tsd;
1260 MakeParams( TSD, parms ) ;
1261 if (ExeName)
1263 ct->ExternalName = str_of( TSD, ExeName );
1264 tmpExternalName = tmpstr_of( TSD, ExeName );
1265 Func = NULL;
1266 gci_info = NULL;
1268 else
1270 ct->ExternalName = str_of( TSD, box->name );
1271 tmpExternalName = tmpstr_of( TSD, box->name );
1272 Func = box->addr;
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 ) ;
1287 if (RC)
1289 switch( RC )
1291 case ERR_ROUTINE_NOT_FOUND:
1292 exiterror( ERR_ROUTINE_NOT_FOUND, 1, tmpExternalName );
1293 break;
1294 default:
1295 exiterror( RC, 0) ;
1296 break;
1298 retval = NULL ;
1300 else if ( RetLength == RX_NO_STRING )
1303 * ERR_NO_DATA_RETURNED is detected later in expr.c.
1305 retval = NULL;
1307 else
1309 retval = Str_makeTSD( RetLength ) ;
1310 memcpy( retval->value, RetString, RetLength ) ;
1311 FreeTSD( RetString );
1312 retval->len = RetLength ;
1314 return retval ;
1318 streng *call_unknown_external( tsd_t *TSD, const streng *name, cparamboxptr parms, char called )
1320 assert(name);
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 )
1327 assert(vbox);
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;
1335 int rc;
1337 if ( qname )
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
1356 if ( queuename
1357 && rc == 1 )
1358 *dupflag = 1;
1359 else
1360 *dupflag = 0;
1361 FreeTSD( strdata );
1362 rc = 0;
1364 if ( queuename) Free_stringTSD( queuename );
1365 return rc;
1368 int IfcDeleteQueue( tsd_t *TSD, const char *qname, const int qlen )
1370 streng *queuename;
1371 int rc;
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 );
1378 return rc;
1381 int IfcQueryQueue( tsd_t *TSD, const char *qname, const int qlen, unsigned long *count )
1383 streng *queuename;
1384 int rc;
1386 queuename = Str_makeTSD( qlen ) ;
1387 memcpy( queuename->value, qname, qlen ) ;
1388 queuename->len = qlen;
1389 rc = lines_in_stack( TSD, queuename );
1390 if ( rc < 0 )
1391 rc = -rc;
1392 else
1394 *count = rc;
1395 rc = 0;
1397 Free_stringTSD( queuename );
1398 return rc;
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;
1404 int rc;
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;
1414 if ( addlifo )
1415 rc = stack_lifo( TSD, strdata, queuename );
1416 else
1417 rc = stack_fifo( TSD, strdata, queuename );
1418 Free_stringTSD( queuename );
1419 return rc;
1422 int IfcPullQueue( tsd_t *TSD, const char *qname, const int qlen, char **data, unsigned long *datalen, unsigned long waitforline )
1424 streng *queuename,*strdata;
1425 int rc, len;
1426 char *p;
1428 queuename = Str_makeTSD( qlen ) ;
1429 memcpy( queuename->value, qname, qlen ) ;
1430 queuename->len = qlen;
1432 strdata = popline( TSD, queuename, &rc, waitforline );
1434 if ( rc == 0 )
1436 if ( strdata == NULL )
1439 * Queue is empty
1441 rc = 8; /* RXQUEUE_EMPTY */
1443 else
1445 len = strdata->len;
1447 if ( ( *data == NULL ) || ( *datalen <= (unsigned long) len ) )
1448 p = (char *)IfcAllocateMemory( len + 1 );
1449 else
1450 p = *data;
1451 if ( p == NULL )
1452 rc = 12; /* RXQUEUE_MEMFAIL */
1453 else
1456 * Using the temporary p inhibits use of *data until it's sure
1457 * that we return 0.
1459 *data = p;
1460 memcpy( *data, strdata->value, len );
1461 (*data)[len] = '\0';
1462 *datalen = len;
1464 Free_stringTSD( strdata );
1467 Free_stringTSD( queuename );
1468 return rc;