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.
29 void killsystem( tsd_t
*TSD
, sysinfo systm
)
31 if ( systm
->environment
)
33 Free_stringTSD( systm
->environment
) ;
34 systm
->environment
= NULL
;
37 if (systm
->input_file
)
39 Free_stringTSD( systm
->input_file
) ;
40 systm
->input_file
= NULL
;
45 fclose( systm
->input_fp
) ;
46 systm
->input_fp
= NULL
;
49 DestroyInternalParsingTree( TSD
, &systm
->tree
) ;
51 if (systm
->currlevel0
)
53 removelevel( TSD
, systm
->currlevel0
) ;
54 systm
->currlevel0
= NULL
;
57 if ( systm
->script_exit
)
59 FreeTSD( systm
->script_exit
) ;
60 systm
->script_exit
= NULL
;
65 Free_stringTSD( systm
->result
) ;
71 FreeTSD( systm
->callstack
) ;
72 systm
->callstack
= NULL
;
78 streng
*do_instore( tsd_t
* volatile TSD
, const streng
*name
, paramboxptr args
,
79 const streng
*envir
, int * volatile RetCode
, int hooks
,
80 const void *instore
, unsigned long instore_length
,
81 const char *instore_source
,
82 unsigned long instore_source_length
,
83 const internal_parser_type
*ipt
,
86 sysinfobox
*newsystem
, *tmpsys
;
89 unsigned InterpreterStatus
[IPRT_BUFSIZE
];
90 tsd_t
* volatile saved_TSD
;
91 int * volatile saved_RetCode
;
92 volatile proclevel oldlevel
;
93 volatile int doTermHook
=0;
98 SaveInterpreterStatus( TSD
, InterpreterStatus
);
99 jbuf
= (jmp_buf *)MallocTSD( sizeof( jmp_buf ) );
100 assert( !TSD
->in_protected
);
102 saved_TSD
= TSD
; /* vars used until here */
103 saved_RetCode
= RetCode
;
104 if ( setjmp( *jbuf
) )
106 TSD
= saved_TSD
; /* prevents bugs like 592393 */
107 RetCode
= saved_RetCode
;
109 ptr
= TSD
->systeminfo
->result
;
110 TSD
->systeminfo
->result
= NULL
;
111 if ( !TSD
->instore_is_errorfree
)
114 * In case of an error we don't return the error number as the result.
115 * Instead, use the current "result" as the error code. It is set
116 * to a negative value already by errortext().
118 * ==> errortext() uses a static buffer, if you ever need the value
119 * you have to dup it after the restore of the old system or you
120 * risk an endless loop.
123 *RetCode
= atoi( ptr
->value
);
130 nodeptr savecurrentnode
= TSD
->currentnode
; /* pgb fixes bug 595300 */
132 TSD
->currentnode
= NULL
;
134 newsystem
= creat_sysinfo( TSD
, Str_dupTSD( envir
) );
135 newsystem
->previous
= TSD
->systeminfo
;
136 newsystem
->hooks
= hooks
;
137 newsystem
->script_exit
= jbuf
;
138 newsystem
->invoked
= ctype
;
139 newsystem
->input_file
= Str_dupstrTSD( name
);
140 newsystem
->trace_override
= newsystem
->previous
->trace_override
;
141 newsystem
->ctrlcounter
= newsystem
->previous
->ctrlcounter
+
142 newsystem
->previous
->cstackcnt
;
145 * see note in execute_external
148 oldlevel
= TSD
->currlevel
;
150 TSD
->systeminfo
= newsystem
;
151 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
= newlevel( TSD
, NULL
);
152 TSD
->currlevel
->pool
= oldlevel
->pool
+ 1;
154 TSD
->currlevel
->args
= args
;
157 TSD
->systeminfo
->tree
= *ipt
;
158 else if ( IsValidTin( (const external_parser_type
*)instore
, instore_length
) )
159 TSD
->systeminfo
->tree
= ExpandTinnedTree( TSD
, (const external_parser_type
*)instore
, instore_length
,
161 instore_source_length
);
164 memset( &TSD
->systeminfo
->tree
, 0, sizeof( TSD
->systeminfo
->tree
) );
166 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_INIT
) )
167 hookup( TSD
, HOOK_INIT
);
171 if ( TSD
->systeminfo
->tree
.root
)
172 ptr
= interpret( TSD
, TSD
->systeminfo
->tree
.root
);
175 TSD
->currentnode
= savecurrentnode
; /* pgb */
181 * Be sure to try it only once.
184 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_TERMIN
) )
185 hookup( TSD
, HOOK_TERMIN
);
188 tmpsys
= TSD
->systeminfo
;
189 TSD
->systeminfo
= TSD
->systeminfo
->previous
;
190 TSD
->currlevel
= oldlevel
;
191 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
193 tmpsys
->currlevel0
->args
= NULL
;
196 * jbuf will be freed by killsystem.
198 killsystem( TSD
, tmpsys
);
200 RestoreInterpreterStatus( TSD
, InterpreterStatus
);
205 streng
*execute_external( tsd_t
* volatile TSD
, const streng
*command
,
206 paramboxptr args
, const streng
*envir
,
207 int * volatile RetCode
, int hooks
, int ctype
)
209 sysinfobox
*newsystem
, *tmpsys
;
216 internal_parser_type parsing
;
217 volatile proclevel oldlevel
;
218 unsigned InterpreterStatus
[IPRT_BUFSIZE
];
219 nodeptr savecurrentnode
= TSD
->currentnode
;
220 tsd_t
* volatile saved_TSD
;
221 int * volatile saved_RetCode
;
222 volatile int doTermHook
=0;
228 SaveInterpreterStatus( TSD
, InterpreterStatus
);
229 jbuf
= (jmp_buf *)MallocTSD( sizeof( jmp_buf ) );
230 assert( !TSD
->in_protected
);
232 saved_TSD
= TSD
; /* vars used until here */
233 saved_RetCode
= RetCode
;
235 if ( setjmp( *jbuf
) )
237 TSD
= saved_TSD
; /* prevents bugs like 592393 */
238 RetCode
= saved_RetCode
;
240 ptr
= TSD
->systeminfo
->result
;
241 TSD
->systeminfo
->result
= NULL
;
242 if ( !TSD
->instore_is_errorfree
)
245 * In case of an error we don't return the error number as the result.
246 * Instead, use the current "result" as the error code. It is set
247 * to a negative value already by errortext().
249 * ==> errortext() uses a static buffer, if you ever need the value
250 * you have to dup it after the restore of the old system or you
251 * risk an endless loop.
254 *RetCode
= atoi( ptr
->value
);
256 * Defer the exiting with 40.1 until the jmpbuf stuff is done
265 /* FGC: Check length first to avoid */
266 /* access of invalid buffer */
267 if ( ( command
->len
== 7 )
268 && ( memcmp( "<stdin>", command
->value
, command
->len
) == 0 ) )
271 name
= Str_dupstrTSD( command
);
275 path
= (char *) tmpstr_of( TSD
, command
);
276 while ( rx_isspace( *path
) )
278 len
= strlen( path
);
280 if ( !rx_isspace( path
[len
- 1] ) )
286 name
= get_external_routine( TSD
, path
, &fptr
);
290 if ( get_options_flag( TSD
->currlevel
, EXT_STRICT_ANSI
) )
293 * If we can't find the external routine, we should exiterror()
294 * with 43.1 - as per ANSI
296 exiterror( ERR_ROUTINE_NOT_FOUND
, 1, path
);
301 * The only time this function is called with a non-NULL
302 * RetCode is from client.c, when an external routine
303 * is being executed via the SAA interface. In this case
304 * the error returned is the only thing we should do;
305 * we certainly should NOT be writing anything to stdout
310 *RetCode
= -ERR_PROG_UNREADABLE
;
317 newsystem
= creat_sysinfo( TSD
, Str_dupTSD( envir
) );
318 newsystem
->previous
= TSD
->systeminfo
;
319 newsystem
->hooks
= hooks
;
320 newsystem
->invoked
= ctype
;
321 newsystem
->script_exit
= jbuf
;
322 newsystem
->input_file
= name
;
323 newsystem
->trace_override
= newsystem
->previous
->trace_override
;
324 newsystem
->ctrlcounter
= newsystem
->previous
->ctrlcounter
+
325 newsystem
->previous
->cstackcnt
;
327 oldlevel
= TSD
->currlevel
;
329 TSD
->systeminfo
= newsystem
;
330 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
= newlevel( TSD
, NULL
);
331 TSD
->currlevel
->pool
= oldlevel
->pool
+ 1;
333 savecurrentnode
= TSD
->currentnode
; /* pgb fixes bug 595300 */
335 TSD
->currlevel
->args
= args
;
336 TSD
->currentnode
= NULL
;
338 fetch_file( TSD
, fptr
, &parsing
);
341 if ( parsing
.result
== 0 )
343 TSD
->systeminfo
->tree
= parsing
;
345 * Execute any RXINI system exit
347 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_INIT
) )
348 hookup( TSD
, HOOK_INIT
);
352 ptr
= interpret( TSD
, TSD
->systeminfo
->tree
.root
);
353 TSD
->currentnode
= savecurrentnode
; /* pgb */
357 TSD
->currentnode
= savecurrentnode
; /* pgb */
359 exiterror( ERR_YACC_SYNTAX
, 1, parsing
.tline
);
363 * Execute any RXTER system exit
368 * Be sure to try it only once.
371 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_TERMIN
) )
372 hookup( TSD
, HOOK_TERMIN
);
374 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_TERMIN
) )
375 hookup( TSD
, HOOK_TERMIN
);
377 tmpsys
= TSD
->systeminfo
;
378 TSD
->systeminfo
= TSD
->systeminfo
->previous
;
379 TSD
->currlevel
= oldlevel
;
380 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
382 tmpsys
->currlevel0
->args
= NULL
;
385 * jbuf will be freed by killsystem
387 killsystem( TSD
, tmpsys
);
390 * If the called routine failed exit with "external routine failed"
391 * depending on OPTION HALT_ON_EXT_CALL_FAIL or with STRICT_ANSI
395 if ( get_options_flag( TSD
->currlevel
, EXT_HALT_ON_EXT_CALL_FAIL
)
396 || get_options_flag( TSD
->currlevel
, EXT_STRICT_ANSI
) )
398 char *cmd
= (char *) tmpstr_of( TSD
, command
);
399 exiterror( 40, 1, cmd
);
403 RestoreInterpreterStatus( TSD
, InterpreterStatus
);
405 * Oops, we really ought to handle function-did-not-return-data
411 internal_parser_type
enter_macro( tsd_t
*TSD
, const streng
*source
,
412 void **ept
, unsigned long *extlength
)
414 internal_parser_type parsing
;
416 fetch_string( TSD
, source
, &parsing
);
417 if (parsing
.result
!= 0)
419 exiterror( ERR_YACC_SYNTAX
, 1, parsing
.tline
) ;
422 if (ept
&& extlength
)
423 *ept
= TinTree( TSD
, &parsing
, extlength
) ;
429 * Takes as input a pointer to a parameter structure, and counts the
430 * number of parameters in it, and return that value. The counting
431 * can be performed in two different manners, either soft or hard.
432 * Soft means that "trailing" ommitted parameters are ignored, hard
433 * means that all parameters are counted. (When counting hard, all
434 * routines stared from Rexx has at least one parameter: the one that
435 * was ommitted. However, when started from C by SAA API, functions
436 * can be started with zero parameters.)
438 int count_params( cparamboxptr ptr
, int soft
)
442 assert( PARAM_TYPE_SOFT
&& !PARAM_TYPE_HARD
) ;
444 for (hcnt
=scnt
=0; ptr
; ptr
=ptr
->next
, hcnt
++)
445 if (soft
&& ptr
->value
)
448 return ((soft
) ? scnt
: hcnt
) ;
454 * Takes a pointer to an argument structure as input, together with an
455 * integer. Returns the parameter numbered by the number, or NULL if
456 * either that parameter is omitted or otherwise non-existing.
458 streng
*get_parameter( paramboxptr ptr
, int number
)
461 for (; ptr
&& (--number
!=0); ptr
=ptr
->next
) ;
463 return ((ptr
&& ptr
->value
) ? ptr
->value
: NULL
) ;