2 static char *RCSid
= "$Id$";
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.
34 void killsystem( tsd_t
*TSD
, sysinfo systm
)
36 if ( systm
->environment
)
38 Free_stringTSD( systm
->environment
) ;
39 systm
->environment
= NULL
;
42 if ( systm
->called_as
)
44 Free_stringTSD( systm
->called_as
) ;
45 systm
->called_as
= NULL
;
48 if (systm
->input_file
)
50 Free_stringTSD( systm
->input_file
) ;
51 systm
->input_file
= NULL
;
56 fclose( systm
->input_fp
) ;
57 systm
->input_fp
= NULL
;
60 DestroyInternalParsingTree( TSD
, &systm
->tree
) ;
62 if (systm
->currlevel0
)
64 removelevel( TSD
, systm
->currlevel0
) ;
65 systm
->currlevel0
= NULL
;
70 FreeTSD( systm
->panic
) ;
76 Free_stringTSD( systm
->result
) ;
82 FreeTSD( systm
->callstack
) ;
83 systm
->callstack
= NULL
;
89 streng
*do_instore( tsd_t
*TSD
, const streng
*name
, paramboxptr args
,
90 const streng
*envir
, int *RetCode
, int hooks
,
91 const void *instore
, unsigned long instore_length
,
92 const char *instore_source
,
93 unsigned long instore_source_length
,
94 const internal_parser_type
*ipt
,
97 sysinfobox
*newsystem
=NULL
, *tmpsys
=NULL
;
100 unsigned InterpreterStatus
[IPRT_BUFSIZE
];
105 SaveInterpreterStatus(TSD
,InterpreterStatus
);
106 TSD
->instore_is_errorfree
= 0 ;
107 jbuf
= MallocTSD( sizeof(jmp_buf) ) ;
108 assert(!TSD
->in_protected
);
111 ptr
= TSD
->systeminfo
->result
;
112 TSD
->systeminfo
->result
= NULL
;
113 if (!TSD
->instore_is_errorfree
&& RetCode
)
118 nodeptr savecurrentnode
= TSD
->currentnode
; /* pgb */
120 TSD
->currentnode
= NULL
;
122 newsystem
= creat_sysinfo( TSD
, Str_dupTSD(envir
)) ;
123 newsystem
->previous
= TSD
->systeminfo
;
124 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
;
126 TSD
->currlevel
= NULL
;
127 TSD
->systeminfo
= newsystem
;
128 TSD
->systeminfo
->hooks
= hooks
;
129 TSD
->systeminfo
->panic
= jbuf
;
130 TSD
->systeminfo
->invoked
= ctype
;
131 TSD
->systeminfo
->called_as
= Str_dupTSD( name
) ;
132 TSD
->systeminfo
->input_file
= Str_dupstrTSD( name
) ;
133 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
= newlevel( TSD
, NULL
) ;
135 TSD
->systeminfo
->trace_override
= newsystem
->previous
->trace_override
;
137 TSD
->currlevel
->args
= args
;
140 TSD
->systeminfo
->tree
= *ipt
;
141 else if (IsValidTin(instore
, instore_length
))
142 TSD
->systeminfo
->tree
= ExpandTinnedTree(TSD
, instore
, instore_length
,
144 instore_source_length
);
147 memset(&TSD
->systeminfo
->tree
, 0, sizeof(TSD
->systeminfo
->tree
));
149 if (TSD
->systeminfo
->hooks
& HOOK_MASK(HOOK_INIT
))
150 hookup( TSD
, HOOK_INIT
) ;
152 if (TSD
->systeminfo
->tree
.root
)
153 ptr
= interpret( TSD
, TSD
->systeminfo
->tree
.root
) ;
156 TSD
->currentnode
= savecurrentnode
; /* pgb */
159 if (TSD
->systeminfo
->hooks
& HOOK_MASK(HOOK_TERMIN
))
160 hookup( TSD
, HOOK_TERMIN
) ;
162 tmpsys
= TSD
->systeminfo
;
163 TSD
->systeminfo
= TSD
->systeminfo
->previous
;
164 TSD
->currlevel
= TSD
->systeminfo
->currlevel0
;
165 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
167 tmpsys
->currlevel0
->args
= NULL
;
168 killsystem( TSD
, tmpsys
) ;
170 RestoreInterpreterStatus(TSD
,InterpreterStatus
);
171 /* Oops, we really ought to handle function-did-not-return-data */
172 return (ptr
) ? ptr
: nullstringptr() ;
175 streng
*execute_external( tsd_t
*TSD
, const streng
*command
, paramboxptr args
,
176 const streng
*envir
, int *RetCode
, int hooks
, int ctype
)
178 sysinfobox
*newsystem
=NULL
, *tmpsys
=NULL
;
181 const char *cptr
=NULL
, *eptr
=NULL
, *start
=NULL
, *stop
=NULL
;
185 internal_parser_type parsing
;
186 volatile proclevel oldlevel
; /* volatile needed at least for GCC 2.7.2 */
187 unsigned InterpreterStatus
[IPRT_BUFSIZE
];
188 nodeptr savecurrentnode
= TSD
->currentnode
; /* pgb */
193 SaveInterpreterStatus(TSD
,InterpreterStatus
);
195 jbuf
= MallocTSD( sizeof(jmp_buf) ) ;
196 TSD
->instore_is_errorfree
= 0 ;
198 assert(!TSD
->in_protected
);
201 /* if (fptr != stdin)
204 ptr
= TSD
->systeminfo
->result
;
205 TSD
->systeminfo
->result
= NULL
;
206 if (!TSD
->instore_is_errorfree
&& RetCode
)
211 /* FGC: Check length first to avoid */
212 /* access of invalid buffer */
213 if ( ( command
->len
== 7 )
214 && ( memcmp("<stdin>",command
->value
,command
->len
) == 0 ) )
217 strcpy(name
,command
->value
);
221 cptr
= command
->value
;
222 eptr
= cptr
+ command
->len
;
224 for (start
=cptr
; start
<eptr
&& isspace(*start
); start
++) ;
225 for (stop
=eptr
-1;stop
>start
&& isspace(*stop
); stop
--) ;
227 memcpy( path
, start
, (stop
-start
)+1 ) ;
228 *(path
+(stop
-start
)+1) = 0x00 ;
229 get_external_routine( TSD
, "REGINA_MACROS", path
, &fptr
, name
, 1 );
232 get_external_routine( TSD
, "PATH", path
, &fptr
, name
, 1 );
236 if ( get_options_flag( TSD
->currlevel
, EXT_STRICT_ANSI
) )
239 * If we can't find the external routine, we should exiterror()
240 * with 43.1 - as per ANSI
242 exiterror( ERR_ROUTINE_NOT_FOUND
, 1, path
);
247 * The only time this function is called with a non-NULL
248 * RetCode is from client.c, when an external routine
249 * is being executed via the SAA interface. In this case
250 * the error returned is the only thing we should do;
251 * we certainly should NOT be writing anything to stdout
256 *RetCode
= -ERR_PROG_UNREADABLE
;
261 *RetCode
= -ERR_PROG_UNREADABLE
;
262 if ( get_options_flag( TSD
->currlevel
, EXT_STDOUT_FOR_STDERR
) )
264 fprintf(stdout
,"REXX: Error %d: %s: \"%s\"\n",
265 ERR_ROUTINE_NOT_FOUND
,
266 errortext( TSD
, ERR_ROUTINE_NOT_FOUND
, 0, 0, &is_fmt
), path
);
267 /* JH 19991105 the variable name was not set by
268 get_external_routine() when file is not found. */
272 fprintf(stderr
,"REXX: Error %d: %s: \"%s\"\n",
273 ERR_ROUTINE_NOT_FOUND
,
274 errortext( TSD
, ERR_ROUTINE_NOT_FOUND
, 0, 0, &is_fmt
), path
);
275 /* JH 19991105 the variable name was not set by
276 get_external_routine() when file is not found. */
285 newsystem
= creat_sysinfo( TSD
, Str_dupTSD(envir
)) ;
286 newsystem
->previous
= TSD
->systeminfo
;
287 /* FGC: NOTE: I found that currlevel has changed outside between calls
288 * to this function. I really don't know, if this should
289 * happen. A typical change of currlevel is done in interpret.
290 * Maybe, in interpret is an error caused by an illegal
291 * "postrecursed" re-interpret. Somebody with a higher view of
292 * the code as mine should check the code there.
293 * I detected the error in THE using regina while calling
294 * macros in macros called by THE in a macro.
295 * (confusing, hmm? :-( )
297 oldlevel
= TSD
->currlevel
;
299 TSD
->currlevel
= NULL
;
300 TSD
->systeminfo
= newsystem
;
301 TSD
->systeminfo
->hooks
= hooks
;
302 TSD
->systeminfo
->invoked
= ctype
;
303 TSD
->systeminfo
->panic
= jbuf
;
304 TSD
->systeminfo
->called_as
= Str_dupTSD( command
) ;
305 TSD
->systeminfo
->input_file
= Str_crestrTSD( name
) ;
306 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
= newlevel( TSD
, NULL
) ;
308 savecurrentnode
= TSD
->currentnode
; /* pgb */
310 TSD
->currlevel
->args
= args
;
311 TSD
->currentnode
= NULL
;
313 fetch_file( TSD
, fptr
, &parsing
);
316 if (parsing
.result
== 0)
318 TSD
->systeminfo
->tree
= parsing
;
319 treadit( TSD
->systeminfo
->tree
.root
) ;
320 if (TSD
->systeminfo
->hooks
& HOOK_MASK(HOOK_INIT
))
321 hookup( TSD
, HOOK_INIT
) ;
323 ptr
= interpret( TSD
, TSD
->systeminfo
->tree
.root
) ;
324 TSD
->currentnode
= savecurrentnode
; /* pgb */
328 TSD
->currentnode
= savecurrentnode
; /* pgb */
330 exiterror( ERR_YACC_SYNTAX
, 1, parsing
.tline
) ;
333 if (TSD
->systeminfo
->hooks
& HOOK_MASK(HOOK_TERMIN
))
334 hookup( TSD
, HOOK_TERMIN
) ;
340 tmpsys
= TSD
->systeminfo
;
341 TSD
->systeminfo
= TSD
->systeminfo
->previous
;
342 TSD
->currlevel
= oldlevel
;
343 TSD
->trace_stat
= TSD
->currlevel
->tracestat
;
345 tmpsys
->currlevel0
->args
= NULL
;
346 killsystem( TSD
, tmpsys
) ;
348 RestoreInterpreterStatus(TSD
,InterpreterStatus
);
349 /* Oops, we really ought to handle function-did-not-return-data */
350 return (ptr
) ? ptr
: nullstringptr() ;
354 internal_parser_type
enter_macro( tsd_t
*TSD
, const streng
*source
,
355 streng
*name
, void **ept
,
356 unsigned long *extlength
)
358 internal_parser_type parsing
;
360 fetch_string( TSD
, source
, &parsing
);
361 if (parsing
.result
!= 0)
363 exiterror( ERR_YACC_SYNTAX
, 1, parsing
.tline
) ;
366 if (ept
&& extlength
)
367 *ept
= TinTree( TSD
, &parsing
, extlength
) ;
368 name
= name
; /* keep compiler happy */
374 * Takes as input a pointer to a parameter structure, and counts the
375 * number of parameters in it, and return that value. The counting
376 * can be performed in two different manners, either soft or hard.
377 * Soft means that "trailing" ommitted parameters are ignored, hard
378 * means that all parameters are counted. (When counting hard, all
379 * routines stared from Rexx has at least one parameter: the one that
380 * was ommitted. However, when started from C by SAA API, functions
381 * can be started with zero parameters.)
383 int count_params( cparamboxptr ptr
, int soft
)
387 assert( PARAM_TYPE_SOFT
&& !PARAM_TYPE_HARD
) ;
389 for (hcnt
=scnt
=0; ptr
; ptr
=ptr
->next
, hcnt
++)
390 if (soft
&& ptr
->value
)
393 return ((soft
) ? scnt
: hcnt
) ;
399 * Takes a pointer to an argument structure as input, together with an
400 * integer. Returns the parameter numbered by the number, or NULL if
401 * either that parameter is omitted or otherwise non-existing.
403 streng
*get_parameter( paramboxptr ptr
, int number
)
406 for (; ptr
&& (--number
!=0); ptr
=ptr
->next
) ;
408 return ((ptr
&& ptr
->value
) ? ptr
->value
: NULL
) ;