bringing SDL 1.2.14 from vendor into the main branch
[AROS-Contrib.git] / regina / client.c
blob66f9d7846092b01a02ad0b066de94fb4265ee284
1 #ifndef lint
2 static char *RCSid = "$Id$";
3 #endif
5 /*
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1993-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* JH 20-10-99 */ /* To make Direct setting of stems Direct and not Symbolic. */
24 #if defined(WIN32) && defined(__IBMC__)
25 # include <windows.h>
26 # pragma warning(default: 4115 4201 4214)
27 #else
28 # if defined(WIN32) && (defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__MINGW32__))
29 # undef APIENTRY
30 # include <windows.h>
31 # else
32 # if defined(__EMX__) && defined(OS2)
33 # define DONT_TYPEDEF_PFN
34 # undef APIENTRY
35 # include <os2emx.h>
36 # else
37 # if defined(__WATCOMC__) && defined(OS2)
38 # undef APIENTRY
39 # define DONT_TYPEDEF_PFN
40 # include <os2.h>
41 # else
42 # if defined(_MSC_VER) && !defined(__WINS__)
43 # undef APIENTRY
44 # if _MSC_VER >= 1100
45 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
46 # pragma warning(disable: 4115 4201 4214)
47 # endif
48 # include <windows.h>
49 # if _MSC_VER >= 1100
50 # pragma warning(default: 4115 4201 4214)
51 # endif
52 # else
53 # define APIENTRY
54 # endif
55 # endif
56 # endif
57 # endif
58 #endif
60 #ifndef RXLIB /* need __regina_faked_main which is known with RXLIB only */
61 # define RXLIB
62 #endif
63 #include "rexx.h"
65 #ifdef HAVE_UNISTD_H
66 # include <unistd.h>
67 #endif
69 #include "rxiface.h"
70 #include <stdio.h>
71 #include <string.h>
73 #ifdef HAVE_ERRNO_H
74 #include <errno.h>
75 #endif
77 #ifdef HAVE_ASSERT_H
78 # include <assert.h>
79 #endif
81 #ifdef HAVE_STDARG_H
82 #include <stdarg.h>
83 #endif
85 #ifdef HAVE_CTYPE_H
86 #include <ctype.h>
87 #endif
89 #ifndef max
90 # define max(a,b) (((a) > (b)) ? (a) : (b))
91 #endif
93 static int ReMapHook( const tsd_t *TSD, int NetHook ) ;
95 typedef struct { /* cli_tsd: static variables of this module (thread-safe) */
96 char count_params_buf[32]; /* handle_no_of_params() */
98 /* Buffering of external parameters allows a delayed deletion in case of
99 * errors.
101 char * ExternalName ;
102 int StringsCount ;
103 int * Lengths ; /* StringsCount + 1 elements */
104 char ** Strings ; /* StringsCount + 1 elements */
105 } cli_tsd_t; /* thread-specific but only needed by this module. see
106 * init_client
109 /* init_client initializes the module.
110 * Currently, we set up the thread specific data.
111 * The function returns 1 on success, 0 if memory is short.
113 int init_client( tsd_t *TSD )
115 cli_tsd_t *ct;
117 if (TSD->cli_tsd != NULL)
118 return(1);
120 if ((ct = TSD->cli_tsd = MallocTSD(sizeof(cli_tsd_t))) == NULL)
121 return(0);
122 memset(ct,0,sizeof(cli_tsd_t));
123 ct->StringsCount = -1;
124 return(1);
128 /* wrapstring makes a streng from external (application) data. If you get
129 * an exception you may have a wild pointer in your application.
130 * Returns NULL if string==NULL or length<0.
132 static streng *wrapstring( const tsd_t *TSD, const char *string, int length )
134 streng *result=NULL ;
136 if (length>=0 && string)
138 result = Str_makeTSD( length ) ;
139 memcpy( result->value, string, length ) ;
140 result->len = length ;
142 else
143 result = NULL ;
145 return result ;
149 static int map_type( int in )
151 if (in==RX_TYPE_COMMAND)
152 return INVO_COMMAND ;
153 else if (in==RX_TYPE_FUNCTION)
154 return INVO_FUNCTION ;
155 else
157 assert( in == RX_TYPE_SUBROUTINE ) ;
158 return INVO_SUBROUTINE ;
163 static void closedown( const tsd_t *TSD )
165 CloseOpenFiles( TSD );
166 if (TSD->in_protected)
168 jmp_buf h;
170 memcpy(h,TSD->protect_return,sizeof(jmp_buf));
171 /* cheat about the const, we go away anyway :-) */
172 ((tsd_t *)(TSD))->delayed_error_type = PROTECTED_DelayedExit;
173 ((tsd_t *)(TSD))->expected_exit_error = 0;
174 longjmp( h, 1 ) ;
176 TSD->MTExit( 0 ) ;
179 static paramboxptr parametrize( const tsd_t *TSD, int ArgCount, const int *ParLengths, const char **ParStrings )
181 paramboxptr parms=NULL, root=NULL ;
182 int count=0, i=0 ;
184 count = ArgCount ;
185 for (i=0; count--; i++ )
187 if (parms)
189 parms->next = MallocTSD( sizeof(parambox)) ;
190 parms = parms->next ;
192 else
193 parms = root = MallocTSD( sizeof(parambox )) ;
195 parms->value = wrapstring( TSD, ParStrings[i], ParLengths[i] ) ;
198 if (parms)
199 parms->next = NULL ;
201 return root ;
204 int IfcExecScript( int NameLen, const char *Name,
205 int ArgCount, const int *ParLengths, const char **ParStrings,
206 int CallType, int ExitFlags, int EnvLen, const char *EnvName,
207 int SourceCode, int restricted,
208 const char *SourceString, unsigned long SourceStringLen,
209 const void *TinnedTree, unsigned long TinnedTreeLen,
210 int *RetLen, char **RetString, void **instore_buf,
211 unsigned long *instore_length )
213 streng * volatile command=NULL ;
214 int RetCode=0 ;
215 int num=0 ;
216 int type=0 ;
217 int added=0 ;
218 volatile paramboxptr params=NULL ;
219 jmp_buf panic, *oldpanic ;
220 tsd_t *wTSD;
221 /* We need volatiles here to prevent variable clobbering by longjmp. */
222 volatile int panicked=0;
223 volatile int hooks=0, ctype=0 ;
224 volatile streng * volatile environment=NULL ;
225 volatile streng * volatile result=NULL ;
226 volatile tsd_t *volatile TSD;
227 unsigned InterpreterStatus[IPRT_BUFSIZE];
229 TSD = __regina_get_tsd(); /* The TSD should be fetched directly.
230 * see longjmp and below for more information.
232 wTSD = (tsd_t *) TSD;
234 SaveInterpreterStatus(wTSD,InterpreterStatus);
235 *instore_buf = NULL;
236 *instore_length = 0;
237 command = wrapstring( wTSD, Name, NameLen ) ;
238 assert(command) ;
239 params = parametrize( wTSD, ArgCount, ParLengths, ParStrings ) ;
241 ctype = map_type(CallType) ;
243 TSD->restricted = restricted;
245 for (hooks=num=0; num<30; num++)
247 if ((ExitFlags>>num) & 0x01)
248 hooks |= (1 << (ReMapHook(wTSD, num))) ;
251 environment = wrapstring( wTSD, EnvName, EnvLen ) ;
252 if (!environment)
253 environment = Str_cre_TSD( wTSD, "DEFAULT" ) ;
255 if ( !envir_exists( wTSD, (streng *)environment ) )
257 add_envir( wTSD, Str_dup_TSD(wTSD, (streng *)environment), ENVIR_PIPE, 0 ) ;
258 added = 1 ;
261 /* It may be that TSD->systeminfo->panic is not set. This may lead to
262 * an exit() call, e.g. at Rexx "EXIT". We set TSD->systeminfo->panic if it
263 * is not set. If a problem occurs we will be informed by a longjmp and
264 * we will not completely been killed by an exit(). Remember: This
265 * function is typically called if a program uses "us" as a subroutine.
266 * Exiting is very harmful in this case.
267 * Note: The memory allocated within called subsoutines will NOT be
268 * freed. We must change many things to do this. Maybe, it's a good
269 * idea to traverse all called subroutine trees and free the leaves.
270 * FGC
272 if ( ( oldpanic = TSD->systeminfo->panic ) == NULL )
274 TSD->systeminfo->panic = &panic;
275 assert(!TSD->in_protected);
276 if ( setjmp( *TSD->systeminfo->panic ) )
278 wTSD = (tsd_t *) TSD; /* Values in(!!) TSD may have changes due longjmp */
279 if (result == NULL)
280 result = Str_make_TSD(wTSD, 0);
281 if (!RetCode)
282 RetCode = -1 ;
283 panicked++ ;
286 wTSD = (tsd_t *) TSD; /* Values in(!!) TSD may have changes due longjmp */
287 if ( !panicked )
289 type = SourceCode ;
290 if (type==RX_TYPE_EXTERNAL)
292 result=execute_external(wTSD,command,params,(streng *) environment,
293 &RetCode,hooks,ctype);
294 Free_string_TSD( wTSD, command );
296 else if (type==RX_TYPE_INSTORE)
298 result=do_instore(wTSD,command,params,(streng *) environment,&RetCode,
299 hooks,
300 TinnedTree,TinnedTreeLen,
301 SourceString,SourceStringLen,
302 NULL,
303 ctype);
305 else if (type==RX_TYPE_MACRO)
306 result = Str_make_TSD(wTSD, 0);
307 else if (type==RX_TYPE_SOURCE)
309 streng *SrcStr = wrapstring( wTSD, SourceString, SourceStringLen ) ;
310 internal_parser_type ipt;
311 ipt = enter_macro( wTSD, SrcStr, command, instore_buf, instore_length ) ;
312 if ( CallType == RX_TYPE_COMMAND
313 && ArgCount
314 && *ParLengths
315 && *ParLengths == 3
316 && memcmp( "//T", *ParStrings, 3 ) == 0 )
317 ; /* request for tokenisation only, don't execute */
318 else
320 ipt.kill = SrcStr ;
321 result=do_instore(wTSD,command,params,(streng *) environment,&RetCode,
322 hooks,
323 NULL,0,
324 NULL,0,
325 &ipt,
326 ctype);
327 /* do_instore already has deleted the internal structure */
330 else
332 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
333 return 0 ;
337 TSD->systeminfo->panic = oldpanic;
338 if (added)
339 del_envir( wTSD, (streng *) environment ) ;
340 Free_string_TSD( wTSD, (streng *) environment ) ;
341 RestoreInterpreterStatus(wTSD,InterpreterStatus);
343 if (result && result->len)
345 *RetLen = result->len ;
346 *RetString=(char *)IfcAllocateMemory(result->len+1);
347 if ( *RetString )
349 memcpy(*RetString,(void *) result->value,result->len);
350 *(*RetString+(result->len)) = '\0';
352 else
353 *RetLen = RX_NO_STRING ;
355 else
356 *RetLen = RX_NO_STRING ;
357 if (result)
358 Free_TSD(wTSD, (void *) result);
360 return RetCode ;
364 static int handle_source( const tsd_t *TSD, int *Length, char **String )
366 int infile=0, total=0, invoked=0 ;
367 const char *stype=NULL ;
368 char *ctmp=NULL ;
369 int sleng=0 ;
371 stype = system_type() ;
372 sleng = strlen( stype ) ;
373 infile = TSD->systeminfo->input_file->len ;
374 invoked = strlen(invo_strings[TSD->systeminfo->invoked]) ;
375 total = sleng + 1 + invoked + 1 + infile ;
377 ctmp = *String = MallocTSD( (*Length=total)+2 ) ;
378 sprintf( ctmp, "%s %s ", stype, invo_strings[TSD->systeminfo->invoked]) ;
379 strncat( ctmp, TSD->systeminfo->input_file->value, infile ) ;
381 return RX_CODE_OK ;
384 static int handle_param( tsd_t *TSD, int *Length, char **String )
386 paramboxptr ptr=NULL ;
387 streng *value=NULL ;
388 int number=0 ;
390 ptr = TSD->currlevel->args ;
391 value = wrapstring( TSD, *String, *Length ) ;
392 number = atopos( TSD, value, "internal", 1 ) ;
393 Free_stringTSD( value ) ;
394 value = get_parameter( ptr, number ) ;
396 if (value)
398 *(Length+1) = value->len ;
399 *(String+1) = value->value ;
401 else
402 *(Length+1) = RX_NO_STRING ;
404 return RX_CODE_OK ;
407 static int handle_no_of_params( const tsd_t *TSD, int *Length, char **String )
409 paramboxptr ptr=NULL ;
410 int count=0 ;
411 cli_tsd_t *ct;
413 ct = TSD->cli_tsd;
414 ptr = TSD->currlevel->args ;
415 count = count_params( ptr, PARAM_TYPE_HARD ) ;
417 sprintf( ct->count_params_buf, "%d", count ) ;
418 *String = ct->count_params_buf;
419 *Length = strlen(*String) ;
421 return RX_CODE_OK ;
426 static int get_next_var( tsd_t *TSD, int *Lengths, char **Strings )
428 variableptr value=NULL, rval=NULL, rrval=NULL ;
429 int l;
431 if (TSD->var_indicator==0)
433 get_next_variable( TSD, 1 ) ;
434 TSD->var_indicator = 1 ;
437 for (;;)
439 value = get_next_variable( TSD, 0 ) ;
440 for (rval=value; rval && rval->realbox; rval=rval->realbox)
444 if (rval && !(rval->flag & VFLAG_STR))
446 if (rval->flag & VFLAG_NUM)
448 #ifdef DEBUG
449 expand_to_str( TSD, rval ) ;
450 #else
451 expand_to_str( TSD, rval ) ;
452 #endif
453 break ;
456 if (!rval->stem)
457 continue ;
459 for (rrval=rval->stem; rrval && rrval->realbox; rrval=rrval->realbox)
463 if (rrval && !(rrval->flag & VFLAG_STR))
465 if (rval->flag & VFLAG_NUM)
467 #ifdef DEBUG
468 expand_to_str( TSD, rval ) ;
469 #else
470 expand_to_str( TSD, rval ) ;
471 #endif
472 break ;
474 else
475 continue ;
478 break ;
481 if (rval)
483 if (rval->stem)
485 l = Lengths[0] = rval->stem->name->len + rval->name->len ;
486 Strings[0] = MallocTSD( (l < 1) ? 1 : l ) ;
487 memcpy(Strings[0], rval->stem->name->value, rval->stem->name->len);
488 memcpy(Strings[0]+rval->stem->name->len,
489 rval->name->value, rval->name->len ) ;
491 else
493 Lengths[0] = rval->name->len ;
494 Strings[0] = rval->name->value ;
497 if (rval->value)
499 Lengths[1] = rval->value->len ;
500 Strings[1] = rval->value->value ;
502 else
504 assert( rval->stem && rrval->value ) ;
505 l = Lengths[1] = rval->stem->name->len + rval->name->len ;
506 Strings[1] = MallocTSD( (l < 1) ? 1 : l ) ;
507 memcpy( Strings[1], rval->stem->name->value, value->stem->name->len );
508 memcpy( Strings[1]+value->stem->name->len,
509 rval->name->value, rval->name->len ) ;
512 return 2 ;
514 else
517 * Once we have reached the end of all variables, reset var_indicator
518 * so next time we can start from the beginning again.
520 TSD->var_indicator = 0 ;
521 return 0 ;
526 static int MapHook( const tsd_t *TSD, int RexxHook )
528 switch ( RexxHook )
530 case HOOK_STDOUT: return RX_EXIT_STDOUT ;
531 case HOOK_STDERR: return RX_EXIT_STDERR ;
532 case HOOK_TRCIN: return RX_EXIT_TRCIN ;
533 case HOOK_PULL: return RX_EXIT_PULL ;
535 case HOOK_INIT: return RX_EXIT_INIT ;
536 case HOOK_TERMIN: return RX_EXIT_TERMIN ;
537 case HOOK_SUBCOM: return RX_EXIT_SUBCOM ;
539 case HOOK_GETENV: return RX_EXIT_GETENV ;
540 case HOOK_SETENV: return RX_EXIT_SETENV ;
542 default:
543 closedown( TSD ) ;
546 return 0 ;
550 static int ReMapHook( const tsd_t *TSD, int NetHook )
552 switch ( NetHook )
554 case RX_EXIT_STDOUT: return HOOK_STDOUT ;
555 case RX_EXIT_STDERR: return HOOK_STDERR ;
556 case RX_EXIT_TRCIN: return HOOK_TRCIN ;
557 case RX_EXIT_PULL: return HOOK_PULL ;
559 case RX_EXIT_TERMIN: return HOOK_TERMIN ;
560 case RX_EXIT_INIT: return HOOK_INIT ;
561 case RX_EXIT_SUBCOM: return HOOK_SUBCOM ;
562 case RX_EXIT_FUNC: return HOOK_FUNC ;
564 case RX_EXIT_GETENV: return HOOK_GETENV ;
565 case RX_EXIT_SETENV: return HOOK_SETENV ;
567 default:
568 closedown( TSD ) ;
571 return 0 ;
576 int hookup( const tsd_t *TSD, int hook )
578 int rcode=0, code=0;
580 code = MapHook ( TSD, hook );
581 assert (code == RX_EXIT_INIT || code == RX_EXIT_TERMIN );
582 rcode = IfcDoExit( TSD, code, 0, NULL, 0, NULL, NULL, NULL ) ;
583 if (rcode==RX_HOOK_ERROR)
584 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
585 else if (rcode==RX_HOOK_GO_ON)
586 rcode = HOOK_GO_ON ;
587 else if (rcode==RX_HOOK_NOPE)
588 rcode = HOOK_NOPE ;
589 else
590 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
591 return rcode ;
594 int hookup_output( const tsd_t *TSD, int hook, const streng *outdata )
596 int rcode=0, code=0 ;
597 char *str;
598 int len = 0;
600 code = MapHook( TSD, hook );
601 assert (code == RX_EXIT_STDOUT || code == RX_EXIT_STDERR );
602 if (outdata)
604 str = str_of( TSD, outdata ) ;
605 len = outdata->len ;
607 else
609 str = MallocTSD( 1 ) ;
610 str[0] = '\0' ;
611 len = 0 ;
614 rcode = IfcDoExit( TSD, code, len, str, 0, NULL, NULL, NULL) ;
615 FreeTSD( str ) ;
616 if (rcode==RX_HOOK_ERROR)
617 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
618 else if (rcode==RX_HOOK_GO_ON)
619 rcode = HOOK_GO_ON ;
620 else if (rcode==RX_HOOK_NOPE)
621 rcode = HOOK_NOPE ;
622 else
623 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
625 return rcode ;
628 int hookup_output2( const tsd_t *TSD, int hook, const streng *outdata1, const streng *outdata2 )
630 int rcode=0, code=0 ;
631 char *str1, *str2;
632 int len1 = 0, len2 = 0;
634 code = MapHook( TSD, hook );
635 assert (code == RX_EXIT_SETENV );
636 if (outdata1)
638 str1 = str_of( TSD, outdata1 ) ;
639 len1 = outdata1->len ;
641 else
643 str1 = MallocTSD( 1 ) ;
644 str1[0] = '\0' ;
645 len1 = 0 ;
647 if (outdata2)
649 str2 = str_of( TSD, outdata2 ) ;
650 len2 = outdata2->len ;
652 else
654 str2 = MallocTSD( 1 ) ;
655 str2[0] = '\0' ;
656 len2 = 0 ;
659 rcode = IfcDoExit( TSD, code, len1, str1, len2, str2, NULL, NULL) ;
660 FreeTSD( str1 ) ;
661 FreeTSD( str2 ) ;
662 if (rcode==RX_HOOK_ERROR)
663 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
664 else if (rcode==RX_HOOK_GO_ON)
665 rcode = HOOK_GO_ON ;
666 else if (rcode==RX_HOOK_NOPE)
667 rcode = HOOK_NOPE ;
668 else
669 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
671 return rcode ;
674 int hookup_input( const tsd_t *TSD, int hook, streng **indata )
676 int rcode=0, code=0 ;
677 /* The following value allows called programs to call "free" to the return
678 * parameters without destroying our stack.
680 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
681 char RetBuf[ILLEGAL_USE_SIZE + 256] ;
682 int retlen=256 ;
683 char *retstr=RetBuf;
685 code = MapHook( TSD, hook );
686 assert (code == RX_EXIT_PULL || code == RX_EXIT_TRCIN );
688 strcpy(RetBuf,"");
689 /* FIXME, FGC: The documentation says that the input of a PULL or TRCIN is
690 * undefined. Why do we provide a buffer?
692 rcode = IfcDoExit( TSD, code, 0, NULL, 0, NULL, &retlen, &retstr ) ;
693 if (rcode==RX_HOOK_ERROR)
694 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
695 else if (rcode==RX_HOOK_GO_ON)
696 rcode = HOOK_GO_ON ;
697 else if (rcode==RX_HOOK_NOPE)
698 rcode = HOOK_NOPE ;
699 else
700 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
702 *indata = wrapstring( TSD, retstr, retlen ) ;
703 FreeTSD( retstr ) ; /* retstr was always newly allocated */
704 #undef ILLEGAL_USE_SIZE
705 return rcode ;
708 int hookup_input_output( const tsd_t *TSD, int hook, const streng *outdata, streng **indata )
710 char *str;
711 int len = 0;
712 int rcode=0, code=0 ;
713 /* The following value allows called programs to call "free" to the return
714 * parameters without destroying our stack.
716 #define ILLEGAL_USE_SIZE (8 * sizeof(void *))
717 char RetBuf[ILLEGAL_USE_SIZE + 256] ;
718 int retlen=256 ;
719 char *retstr=RetBuf;
721 code = MapHook( TSD, hook );
722 assert (code == RX_EXIT_GETENV );
724 if (outdata)
726 str = str_of( TSD, outdata ) ;
727 len = outdata->len ;
729 else
731 str = MallocTSD( 1 ) ;
732 str[0] = '\0' ;
733 len = 0 ;
736 strcpy(RetBuf,"");
737 /* FIXME, FGC: The documentation says that the input of a PULL or TRCIN is
738 * undefined. Why do we provide a buffer?
740 rcode = IfcDoExit( TSD, code, len, str, 0, NULL, &retlen, &retstr ) ;
741 FreeTSD( str ) ;
742 if (rcode==RX_HOOK_ERROR)
743 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
744 else if (rcode==RX_HOOK_GO_ON)
745 rcode = HOOK_GO_ON ;
746 else if (rcode==RX_HOOK_NOPE)
747 rcode = HOOK_NOPE ;
748 else
749 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
751 *indata = wrapstring( TSD, retstr, retlen ) ;
752 FreeTSD( retstr ) ; /* retstr was always newly allocated */
753 #undef ILLEGAL_USE_SIZE
754 return rcode ;
759 streng *SubCom( const tsd_t *TSD, const streng *command, const streng *envir, int *rc )
761 int tmplen ;
762 char *tmpptr ;
763 streng *retval ;
765 *rc = IfcSubCmd( TSD,
766 envir ? envir->len : RX_NO_STRING,
767 envir ? envir->value : NULL,
768 command->len, command->value, &tmplen, &tmpptr ) ;
770 retval = wrapstring( TSD, tmpptr, tmplen ) ;
771 FreeTSD( tmpptr ) ;
772 return retval ;
776 /****************************************************************************
778 * JH 13/12/1999 Trying to satisfy both BUG031 and BUG022.
780 * BUG022 To make Direct setting of stems Direct and not Symbolic.
781 * - Added new parameter, "Code". Assumed values are RX_GETSVAR, and
782 * RX_GETVAR. They denote that the actiion is symbolic, or direct
783 * (respectively).
784 * - if direct call getdirvalue()
786 * BUG031
787 * - if default value is being returned, uppercase the whole name for
788 * symbolics, and only the stem for directs. This should be a moot
789 * issue, as there is code in variable.c to return default values.
791 ****************************************************************************/
792 static int GetVariable( tsd_t *TSD, int Code, int *Lengths, char *Strings[] )
794 const streng *value ;
795 streng *retval, *varbl;
796 int rcode, i ;
798 varbl = wrapstring( TSD, Strings[0], Lengths[0] ) ;
800 assert(varbl); /* FIXME, FGC: Shouldn't this better result in
801 * RX_CODE_INVNAME?
804 if (!valid_var_symbol(varbl))
806 Free_stringTSD( varbl ) ;
807 Lengths[1] = RX_NO_STRING ;
808 return RX_CODE_INVNAME ;
811 rcode = RX_CODE_OK ; /* default value */
812 if (Code == RX_GETSVAR)
813 value = getvalue( TSD, varbl, 1 ) ;
814 else
815 value = getdirvalue( TSD, varbl, 1 ) ;
817 retval = Str_dupTSD(value) ;
818 if (!var_was_found( TSD ))
820 if (Code == RX_GETSVAR)
821 retval = Str_upper(retval) ;
822 else
824 /* JH 13-12-99 If this is a direct variable, only uppercase the
825 * stem name.
827 for(i=0;i<retval->len && '.' != retval->value[i];i++)
828 retval->value[i] = (unsigned char) toupper(retval->value[i]);
830 rcode = RX_CODE_NOVALUE ;
833 Lengths[1] = retval->len ;
834 Strings[1] = IfcAllocateMemory(retval->len + 1);
835 /* Must be accessible by the application. */
837 memcpy(Strings[1],retval->value,retval->len);
838 Strings[1][retval->len] = '\0'; /* termination may help bogus
839 * applications.
842 Free_stringTSD( retval ) ;
843 Free_stringTSD( varbl ) ;
844 return rcode ;
847 /****************************************************************************
849 * JH 13/12/1999 Trying to satisfy both BUG031 and BUG022.
851 * BUG022 To make Direct setting of stems Direct and not Symbolic.
852 * - Added new parameter, "Code". Assumed values are RX_SETSVAR, and
853 * RX_SETVAR. They denote that the actiion is symbolic, or direct
854 * (respectively).
855 * Until this point setting and dropping variables have been treated as
856 * the same. If there is a value, then it is a set, otherwise drop it.
857 * - if direct call setdirvalue()
858 * - if direct call drop_dirvar()
859 * BUG031
860 * - uppercase the whole name for symbolics, and only the stem for directs.
862 ****************************************************************************/
863 static int SetVariable(const tsd_t *TSD, int Code, int *Lengths, char *Strings[] )
865 streng *varbl, *varname, *value ;
866 int rcode, i ;
868 varbl = wrapstring( TSD, Strings[0], Lengths[0] ) ;
870 assert(varbl); /* FIXME, FGC: Shouldn't this better result in
871 * RX_CODE_INVNAME?
874 if (Code == RX_SETSVAR)
875 varname = Str_upper(Str_dupTSD(varbl)) ;
876 else
878 varname = Str_dupTSD(varbl) ;
879 for (i=0;i<varname->len && '.' != varname->value[i];i++)
880 varname->value[i] = (unsigned char) toupper(varname->value[i]);
882 Free_stringTSD( varbl ) ;
883 varbl = NULL; /* For debugging purpose only */
885 if (!valid_var_symbol(varname))
887 Free_stringTSD( varname ) ;
888 return RX_CODE_INVNAME ;
891 value = wrapstring( TSD, Strings[1], Lengths[1] ) ;
893 rcode = RX_CODE_OK ; /* default value */
894 if (value)
896 if (Code == RX_SETSVAR)
897 setvalue( TSD, varname, value ) ;
898 else
899 setdirvalue( TSD, varname, value ) ;
901 else
903 if (Code == RX_SETSVAR)
904 drop_var( TSD, varname ) ;
905 else
906 drop_dirvar( TSD, varname ) ;
908 if (!var_was_found( TSD ))
909 rcode = RX_CODE_NOVALUE ;
911 Free_stringTSD( varname ) ;
912 return rcode ;
915 static int handle_version( int *Length, char **String )
917 *Length = strlen(PARSE_VERSION_STRING) ;
918 *String = PARSE_VERSION_STRING ;
919 return RX_CODE_OK ;
923 static int handle_queue( int *Length, char **String )
925 *Length = 7 ;
926 *String = "default" ;
927 return RX_CODE_OK ;
933 /****************************************************************************
935 * JH 13/12/1999
937 * BUG022 To make Direct setting of stems Direct and not Symbolic.
938 * - Added checks for the direct variable functions RX_GETVAR and RX_SETVAR.
942 ****************************************************************************/
943 int IfcVarPool( tsd_t *TSD, int Code, int *Lengths, char *Strings[] )
945 int rc=0 ;
947 if (Code==RX_GETSVAR ||Code==RX_GETVAR )
948 rc = GetVariable( TSD, Code, Lengths, Strings ) ;
949 else if (Code==RX_SETSVAR ||Code==RX_SETVAR )
950 rc = SetVariable( TSD, Code, Lengths, Strings ) ;
951 else if (Code==RX_NEXTVAR)
952 rc = get_next_var( TSD, Lengths, Strings ) ;
953 else if (Code==RX_CODE_VERSION)
954 rc = handle_version( Lengths, Strings ) ;
955 else if (Code==RX_CODE_SOURCE)
956 rc = handle_source( TSD, Lengths, Strings ) ;
957 else if (Code==RX_CODE_QUEUE)
958 rc = handle_queue( Lengths, Strings ) ;
959 else if (Code==RX_CODE_PARAMS)
960 rc = handle_no_of_params( TSD, Lengths, Strings ) ;
961 else if (Code==RX_CODE_PARAM)
962 rc = handle_param( TSD, Lengths, Strings ) ;
963 else
964 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
966 return rc ;
970 /* FGC, FIXME: IfcRegFunc never returns a code for RXFUNC_DUP! */
971 int IfcRegFunc( tsd_t *TSD, const char *Name )
973 streng *name;
974 int rc;
976 assert( Name ) ;
977 name = Str_upper( Str_creTSD( Name ) );
978 rc = addfunc( TSD, name, 1 ) ;
979 if (rc < 1)
980 Free_stringTSD(name);
982 if (rc == -1)
983 return RX_CODE_NOMEM ;
984 return RX_CODE_OK ;
988 int IfcDelFunc( tsd_t *TSD, const char *Name )
990 streng *name;
991 int retval;
993 assert( Name ) ;
994 name = Str_upper( Str_creTSD( Name ) );
995 retval = rex_rxfuncdlldrop(TSD, name);
996 Free_stringTSD(name);
997 return(retval);
1000 int IfcQueryFunc( tsd_t *TSD, const char *Name )
1002 streng *name;
1003 int retval;
1005 assert( Name ) ;
1006 name = Str_upper( Str_creTSD( Name ) );
1007 retval = rex_rxfuncdllquery(TSD, name);
1008 Free_stringTSD(name);
1009 return(retval);
1012 /* You are not allowed to use TSD or __regina_get_tsd() here! */
1013 void *IfcAllocateMemory( unsigned long size )
1015 void *ret;
1016 #if defined( WIN32 )
1017 /* We now use the Virtual-functions instead of Global... */
1018 ret = VirtualAlloc( NULL, size, MEM_COMMIT, PAGE_READWRITE ) ;
1019 return ret;
1020 #elif defined( __EMX__ ) && !defined(DOS)
1021 if (_osmode == OS2_MODE)
1023 if ( ( BOOL )DosAllocMem( &ret, size, fPERM|PAG_COMMIT ) )
1024 return NULL;
1025 else
1026 return ret;
1028 else /* DOS or something else */
1030 ret = (void *)malloc( size );
1031 return ret;
1033 #elif defined( OS2 )
1034 if ( ( BOOL )DosAllocMem( &ret, size, fPERM|PAG_COMMIT ) )
1035 return NULL;
1036 else
1037 return ret;
1038 #else
1039 ret = (void *)malloc( size );
1040 return ret;
1041 #endif
1044 /* You are not allowed to use TSD or __regina_get_tsd() here! */
1045 unsigned long IfcFreeMemory( void *ptr )
1047 #if defined( WIN32 )
1048 /* In opposite to most(!) of the documentation from Microsoft we shouldn't
1049 * decommit and release together. This won't work at least under NT4SP6a.
1050 * We can first decommit and then release or release at once. FGC.
1052 VirtualFree( ptr, 0, MEM_RELEASE ) ;
1053 #elif defined( __EMX__ ) && !defined(DOS)
1054 if (_osmode == OS2_MODE)
1055 DosFreeMem( ptr );
1056 else /* DOS or something else */
1057 free( ptr );
1058 #elif defined( OS2 )
1059 DosFreeMem( ptr );
1060 #else
1061 free( ptr );
1062 #endif
1063 return 0;
1067 /* Removes ct->Strings and ct->Lengths AND ct->ExternalName. */
1068 static void RemoveParams(const tsd_t *TSD)
1070 int i;
1071 cli_tsd_t *ct;
1073 ct = TSD->cli_tsd;
1075 if ( ct->Strings && ct->Lengths )
1077 for (i = 0;i < ct->StringsCount;i++) /* The last one is always NULL */
1079 if ((ct->Lengths[i] != RX_NO_STRING) &&
1080 (ct->Strings[i] != NULL))
1081 FreeTSD( ct->Strings[i] );
1085 if ( ct->Lengths )
1086 FreeTSD( ct->Lengths ) ;
1087 if ( ct->Strings )
1088 FreeTSD( ct->Strings ) ;
1089 if ( ct->ExternalName )
1090 FreeTSD( ct->ExternalName ) ;
1092 ct->StringsCount = -1;
1093 ct->Strings = NULL;
1094 ct->Lengths = NULL;
1095 ct->ExternalName = NULL;
1098 /* Creates (possibly after a removal of old values) ct->Strings and ct->Lengths
1099 * from the given parms. One hidden NULL string is appended.
1101 static void MakeParams(const tsd_t *TSD, cparamboxptr parms)
1103 int i;
1104 cparamboxptr p=NULL ;
1105 cli_tsd_t *ct;
1107 ct = TSD->cli_tsd;
1109 /* Cleanup the old parameters before we set StringsCount */
1110 RemoveParams(TSD);
1112 ct->StringsCount = 0; /* This is the default in case of unused parameters */
1113 /* Detect the index of the last valid parameter */
1114 for (i=0,p=parms; p; p=p->next,i++)
1116 if (p->value)
1117 ct->StringsCount=i+1 ;
1120 /* add one NULL string at the end */
1121 ct->Lengths = MallocTSD( sizeof(int) * (ct->StringsCount+1) ) ;
1122 ct->Strings = MallocTSD( sizeof(char*) * (ct->StringsCount+1) ) ;
1124 for (i=0,p=parms; i < ct->StringsCount; p=p->next,i++)
1126 if (p->value)
1128 ct->Lengths[i] = Str_len( p->value ) ;
1129 ct->Strings[i] = str_of( TSD, p->value );
1131 else
1133 ct->Lengths[i] = RX_NO_STRING ;
1134 ct->Strings[i] = NULL ;
1138 /* Provide a hidden NULL string at the end */
1139 ct->Lengths[ct->StringsCount] = RX_NO_STRING ;
1140 ct->Strings[ct->StringsCount] = NULL ;
1143 /* do_an_external calls IfcExecFunc with the appropriate parameters. Basically
1144 * it wraps the parameters. Either ExeName or box must be NULL.
1146 static streng *do_an_external( tsd_t *TSD,
1147 const streng *ExeName,
1148 const struct library_func *box,
1149 cparamboxptr parms,
1150 char exitonly,
1151 char called )
1153 int RetLength=0 ;
1154 char *RetString=NULL ;
1155 streng *retval ;
1156 int rc ;
1157 int RC ;
1158 PFN Func;
1159 cli_tsd_t *ct;
1160 volatile char *tmpExternalName; /* used to save ct->ExternalName */
1161 /* when erroring */
1163 ct = TSD->cli_tsd;
1165 MakeParams( TSD, parms ) ;
1166 if (ExeName)
1168 ct->ExternalName = str_of( TSD, ExeName );
1169 tmpExternalName = tmpstr_of( TSD, ExeName );
1170 Func = NULL;
1172 else
1174 ct->ExternalName = str_of( TSD, box->name );
1175 tmpExternalName = tmpstr_of( TSD, box->name );
1176 Func = box->addr;
1179 rc = IfcExecFunc( TSD, Func, ct->ExternalName,
1180 ct->StringsCount, ct->Lengths, ct->Strings,
1181 &RetLength, &RetString, &RC, exitonly, called );
1183 RemoveParams( TSD ) ;
1185 if (RC)
1187 switch( RC )
1189 case ERR_ROUTINE_NOT_FOUND:
1190 exiterror( ERR_ROUTINE_NOT_FOUND, 1, tmpExternalName );
1191 break;
1192 default:
1193 exiterror( RC, 0) ;
1194 break;
1196 retval = NULL ;
1198 else
1200 retval = Str_makeTSD( RetLength ) ;
1201 memcpy( retval->value, RetString, RetLength ) ;
1202 FreeTSD( RetString );
1203 retval->len = RetLength ;
1205 return retval ;
1209 streng *do_an_external_exe( tsd_t *TSD, const streng *name, cparamboxptr parms, char exitonly, char called )
1211 assert(name);
1213 return( do_an_external( TSD, name, NULL, parms, exitonly, called ) ) ;
1216 streng *do_an_external_dll( tsd_t *TSD, const void *vbox, cparamboxptr parms, char called )
1218 assert(vbox);
1220 return( do_an_external( TSD, NULL, vbox, parms, 0, called ) ) ;
1223 int IfcCreateQueue( tsd_t *TSD, const char *qname, const int qlen, char *data, unsigned long *dupflag, unsigned long buflen )
1225 streng *queuename=NULL,*strdata;
1226 int rc;
1228 if ( qname )
1230 queuename = Str_makeTSD( qlen ) ;
1231 memcpy( queuename->value, qname, qlen ) ;
1232 queuename->len = qlen;
1234 rc = create_queue( TSD, queuename, &strdata );
1236 if ( rc == 0 || rc == 1 )
1239 * Return the new queue name
1241 memcpy( data, strdata->value, max( strdata->len, (int) buflen) - 1 );
1242 *(data+(max( strdata->len, (int) buflen) - 1)) = '\0';
1244 * If the returned queue name is different to
1245 * the one we requested, set the dupflag
1247 if ( queuename
1248 && rc == 1 )
1249 *dupflag = 3;
1250 else
1251 *dupflag = 0;
1252 FreeTSD( strdata );
1253 rc = 0;
1255 if ( queuename) FreeTSD( queuename );
1256 return rc;
1259 int IfcDeleteQueue( tsd_t *TSD, const char *qname, const int qlen )
1261 streng *queuename;
1262 int rc;
1264 queuename = Str_makeTSD( qlen ) ;
1265 memcpy( queuename->value, qname, qlen ) ;
1266 queuename->len = qlen;
1267 rc = delete_queue( TSD, queuename );
1268 FreeTSD( queuename );
1269 return rc;
1272 int IfcQueryQueue( tsd_t *TSD, const char *qname, const int qlen, unsigned long *count )
1274 streng *queuename;
1275 int rc;
1277 queuename = Str_makeTSD( qlen ) ;
1278 memcpy( queuename->value, qname, qlen ) ;
1279 queuename->len = qlen;
1280 rc = lines_in_stack( TSD, queuename );
1281 if ( rc < 0 )
1282 rc = -rc;
1283 else
1284 *count = rc;
1285 FreeTSD( queuename );
1286 return rc;
1289 int IfcAddQueue( tsd_t *TSD, const char *qname, const int qlen, const char *data, const int datalen, unsigned long addlifo )
1291 streng *queuename,*strdata;
1292 int rc;
1294 queuename = Str_makeTSD( qlen ) ;
1295 memcpy( queuename->value, qname, qlen ) ;
1296 queuename->len = qlen;
1298 strdata = Str_makeTSD( datalen ) ;
1299 memcpy( strdata->value, data, datalen ) ;
1300 strdata->len = datalen;
1302 if ( addlifo )
1303 rc = stack_lifo( TSD, strdata, queuename );
1304 else
1305 rc = stack_fifo( TSD, strdata, queuename );
1306 FreeTSD( queuename );
1307 FreeTSD( strdata );
1308 return rc;
1311 int IfcPullQueue( tsd_t *TSD, const char *qname, const int qlen, char **data, int *datalen, unsigned long waitforline )
1313 streng *queuename,*strdata;
1314 int rc;
1316 queuename = Str_makeTSD( qlen ) ;
1317 memcpy( queuename->value, qname, qlen ) ;
1318 queuename->len = qlen;
1320 strdata = popline( TSD, queuename, &rc, waitforline );
1322 if ( strdata == NULL )
1325 * Queue is empty
1327 *data = NULL;
1328 *datalen = 0;
1330 else
1332 *data = strdata->value;
1333 *datalen = strdata->len;
1335 FreeTSD( queuename );
1336 return rc;