2 static char *RCSid
= "$Id$";
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-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 #if defined(WIN32) && defined(__IBMC__)
25 #pragma warning(default: 4115 4201 4214)
29 # if defined(__WATCOMC__) && defined(__NT__)
33 # if defined(__MINGW32__)
37 # if defined(WIN32) && defined(__BORLANDC__)
42 # if defined(_MSC_VER)
45 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
46 # pragma warning(disable: 4115 4201 4214)
50 # pragma warning(default: 4115 4201 4214)
53 # else /* not RXLIB */
54 # if defined(__WATCOMC__) && defined(__NT__)
57 # if defined(__MINGW32__)
60 # if defined(WIN32) && defined(__BORLANDC__)
64 # if defined(_MSC_VER) && !defined(__WINS__)
66 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
67 # pragma warning(disable: 4115 4201 4214)
71 # pragma warning(default: 4115 4201 4214)
77 #if defined(OS2) || defined(__EMX__)
80 # define DONT_TYPEDEF_PFN
94 # include <sys/stat.h>
97 #if defined(DJGPP) || defined(__EMX__) || defined(_MSC_VER) || (defined(__WATCOMC__) && !defined(__QNX__)) || defined(__EPOC32__)
99 # if !defined(__WINS__) && !defined(__EPOC32__)
109 * Since development of Ultrix has ceased, and they never managed to
110 * fix a few things, we want to define a few things, just in order
111 * to kill a few warnings ...
113 #if defined(FIX_PROTOS) && defined(FIX_ALL_PROTOS) && defined(ultrix)
114 int fstat( int fd
, struct stat
*buf
) ;
115 int stat( char *path
, struct stat
*buf
) ;
119 /* Don't terminate the following lines by a semicolon */
120 GLOBAL_PROTECTION_VAR(regina_globals
)
124 * Note: must match the settings of NUM_FORM_* in flags.h
126 const char *numeric_forms
[] = { "SCIENTIFIC", "ENGINEERING" } ;
129 * Note: these must match the definitions of INVO_* in defs.h
131 const char *invo_strings
[] = { "COMMAND", "FUNCTION", "SUBROUTINE" } ;
133 const char *argv0
= NULL
;
136 void marksubtree( nodeptr ptr
)
141 markmemory(ptr
,TRC_TREENODE
) ;
142 if (ptr
->name
) markmemory(ptr
->name
, TRC_TREENODE
) ;
143 for (i
=0;i
<sizeof(ptr
->p
)/sizeof(ptr
->p
[0]);marksubtree(ptr
->p
[i
++])) ;
144 if (ptr
->next
) marksubtree( ptr
->next
) ;
146 if (ptr
->type
== X_STRING
|| ptr
->type
== X_CON_SYMBOL
)
149 markmemory( ptr
->u
.number
, TRC_TREENODE
) ;
150 markmemory( ptr
->u
.number
->num
, TRC_TREENODE
) ;
153 if (ptr
->type
== X_CEXPRLIST
)
155 markmemory( ptr
->u
.strng
, TRC_TREENODE
) ;
158 #endif /* TRACEMEM */
161 /* FIXME, FGC: This is a useless function! */
162 nodeptr
treadit( cnodeptr tree
)
165 nodeptr left, mid, right ;
187 left->next = treadit( mid ) ;
209 /* GetArgv0 tries to find the fully qualified filename of the current program.
210 * It uses some ugly and system specific tricks and it may return NULL if
211 * it can't find any useful value.
212 * The argument should be argv[0] of main() and it may be returned.
213 * This function must not be called from another as the sole one when starting
216 static const char *GetArgv0(const char *argv0
)
221 if (GetModuleFileName(NULL
, buf
, sizeof(buf
)) != 0)
222 return(strdup(buf
)); /* never freed up */
228 if (_osmode
== OS2_MODE
)
231 if (DosGetInfoBlocks(NULL
, &ppib
) == 0)
232 if (DosQueryModuleName(ppib
->pib_hmte
, sizeof(buf
), buf
) == 0)
239 /* No specific code has found the right file name. Maybe, it's coded
240 * in argv0. Check it, if it is an absolute path. Be absolutely sure
241 * to detect it safely!
246 if (argv0
[0] == '/') /* unix systems and some others */
249 if ((argv0
[0] == '\\') && (argv0
[1] == '\\')) /* MS and OS/2 UNC names */
252 if (isalpha(argv0
[0]) && (argv0
[1] == ':') && (argv0
[2] == '\\'))
253 return(argv0
); /* MS and OS/2 drive letter with path */
255 return(NULL
); /* not a proven argv0 argument */
259 int APIENTRY
__regina_faked_main(int argc
,char *argv
[])
260 #define CALL_MAIN __regina_faked_main
262 int main(int argc
,char *argv
[])
263 #define CALL_MAIN main
267 streng
*string
=NULL
;
268 int i
=0, j
=0, stdinput
=1, state
=0, rcode
=0, oldi
=0, trace_override
=0 ;
269 paramboxptr args
=NULL
, prev
;
274 internal_parser_type parsing
;
281 * For WIN32, set an atexit() function to allow the user to see the output
282 * from the program if run from Explorer or the Start menu.
283 * Only do this if we are running Regina, and not from another process
286 #if defined(WIN32) && !defined(__WINS__) && !defined(__EPOC32__)
291 argv0
= GetArgv0(argv
[0]);
293 TSD
= GLOBAL_ENTRY_POINT();
295 TSD
->stddump
= stderr
;
297 TSD
->systeminfo
= creat_sysinfo( TSD
, Str_creTSD("SYSTEM")) ;
298 TSD
->systeminfo
->called_as
= Str_creTSD( argv
[0] ) ;
300 TSD
->systeminfo
->currlevel0
= TSD
->currlevel
= newlevel( TSD
, NULL
) ;
301 TSD
->systeminfo
->trace_override
= 0;
304 for (i
=1; i
<argc
; i
++)
315 set_trace_char(TSD
, 'A') ;
323 TSD
->isclient
= 1 ; /* Other than the default value of 0 */
324 #if defined(WIN32) && !defined(__WINS__) && !defined(__EPOC32__)
325 dont_pause_at_exit();
335 fprintf( stderr
, "%s\n", PARSE_VERSION_STRING
);
343 case 'r': /* safe-rexx */
344 TSD
->restricted
= 1 ;
348 queue_trace_char(TSD
, (char) (*(arg
+1)? *(++arg
) : 'A')) ;
354 TSD
->listleakedmemory
= 1 ;
358 TSD
->systeminfo
->invoked
= INVO_SUBROUTINE
;
365 get_external_routine( TSD
, "REGINA_MACROS", argv
[i
], &fptr
, name
, 1 );
368 get_external_routine( TSD
, "PATH", argv
[i
], &fptr
, name
, 1 );
371 TSD
->systeminfo
->input_file
= Str_crestrTSD(argv
[i
]) ;
372 exiterror( ERR_PROG_UNREADABLE
, 1, "Program was not found" ) ;
375 TSD
->systeminfo
->input_file
= Str_crestrTSD(name
) ;
376 TSD
->systeminfo
->input_fp
= fptr
;
382 * Under DJGPP setmode screws up Parse Pull and entering code interactively :-(
384 #if defined(__EMX__) || (defined(_MSC_VER) && !defined(__WINS__)) || (defined(__WATCOMC__) && !defined(__QNX__))
385 setmode( fileno( stdin
), O_BINARY
);
386 setmode( fileno( stdout
), O_BINARY
);
387 setmode( fileno( stderr
), O_BINARY
);
392 TSD
->systeminfo
->input_file
= Str_crestrTSD("<stdin>") ;
393 TSD
->systeminfo
->input_fp
= NULL
;
401 if ( TSD
->systeminfo
->invoked
== INVO_SUBROUTINE
)
404 for (i
=oldi
;i
<argc
;i
++)
406 args
= MallocTSD(sizeof(parambox
)) ;
408 TSD
->currlevel
->args
= args
;
411 memset(args
,0,sizeof(parambox
)); /* especially ->value */
412 args
->value
= Str_cre_TSD( TSD
, argv
[i
] ) ;
419 j
+= strlen(argv
[i
]) + 1 ;
421 TSD
->currlevel
->args
= args
= MallocTSD(sizeof(parambox
)) ;
422 memset(args
,0,sizeof(parambox
)); /* especially ->value */
424 args->value = Str_dupTSD(TSD->systeminfo->input_file) ;
425 args = args->next = MallocTSD(sizeof(parambox)) ;
429 args
->value
= string
= NULL
;
432 args
->value
= string
= Str_makeTSD( j
) ;
436 for (i
=oldi
;i
<argc
;i
++)
438 string
= Str_catstrTSD(string
,argv
[i
]) ;
439 string
->value
[string
->len
++] = ' ' ;
441 if (string
&& string
->len
)
445 signal_setup( TSD
) ;
448 __reginadebug
= do_yydebug
; /* 1 == yacc-debugging */
450 fetch_file( TSD
, fptr
? fptr
: stdin
, &parsing
);
452 if (parsing
.result
!= 0)
453 exiterror( ERR_YACC_SYNTAX
, 1, parsing
.tline
) ;
455 TSD
->systeminfo
->tree
= parsing
;
458 TSD
->systeminfo
->trace_override
= 1;
460 TSD
->systeminfo
->trace_override
= 0;
474 * The following line is likely to give a warning when compiled
475 * under Ultrix, this can be safely ignored, since it is just a
476 * result of Digital not defining their include files properly.
478 rcode
= fstat( fileno(stdin
), &buffer
) ;
479 if (rcode
==0 && S_ISCHR(buffer
.st_mode
))
487 #endif /* !__IBMC__ */
488 #endif /* !_MSC_VER */
491 #endif /* !MINIMAL */
494 treadit( TSD
->systeminfo
->tree
.root
) ;
500 translate( TSD
, TSD
->systeminfo
->tree
.root
) ;
505 flush_trace_chars(TSD
) ;
507 nodeptr savecurrentnode
= TSD
->currentnode
; /* pgb */
508 string
= interpret( TSD
, TSD
->systeminfo
->tree
.root
) ;
509 TSD
->currentnode
= savecurrentnode
; /* pgb */
511 rcode
= EXIT_SUCCESS
;
513 && myisinteger( string
) )
514 rcode
= myatol( TSD
, string
) ;
517 #if defined(FLISTS) && defined(NEW_FLISTS)
523 * Remove all external function package functions
524 * and libraries. Only valid for the DYNAMIC library.
526 purge_library( TSD
);
530 if (TSD
->listleakedmemory
)
531 listleaked( TSD
, MEMTRC_LEAKED
) ;
534 killsystem( TSD
, TSD
->systeminfo
);
535 TSD
->systeminfo
= NULL
;
538 * Remove all memory allocated by the flists internal memory manager.
548 /* reexecute_main is possibly called by one of the fork_exec routines.
549 * This functions cleans up some stuff to reexecute without problems.
550 * The most useful thing to be done here is freeing all used memory.
551 * NOTE: usage is always the last thing you should try. Better use
552 * spawn or exec to let a fresh interpreter do the work.
554 int __regina_reexecute_main(int argc
, char **argv
)
558 TSD
= __regina_get_tsd(); /* hopefully not multithreading! */
560 if (TSD
!= NULL
) /* yes! I don't know what happens on forking */
561 { /* and active multi-threading */
563 purge_stacks(TSD
); /* see main above for comments */
564 purge_filetable(TSD
);
569 # if defined(NEW_FLISTS)
576 return(CALL_MAIN(argc
, argv
));
580 void mark_systeminfo( const tsd_t
*TSD
)
583 labelbox
*lptr
=NULL
;
584 lineboxptr llptr
=NULL
;
586 for (sinfo
=TSD
->systeminfo
; sinfo
; sinfo
=sinfo
->previous
)
588 markmemory(sinfo
, TRC_SYSINFO
) ;
589 markmemory(sinfo
->called_as
, TRC_SYSINFO
) ;
590 markmemory(sinfo
->input_file
, TRC_SYSINFO
) ;
591 markmemory(sinfo
->environment
, TRC_SYSINFO
) ;
592 markmemory(sinfo
->callstack
, TRC_SYSINFO
) ;
594 markvariables( TSD
, sinfo
->currlevel0
) ;
595 marksource( sinfo
->tree
.first_source_line
) ;
596 /* FGC, FIXME: rewrite this: marksubtree( sinfo->tree.root ) ; */
598 for (lptr
=sinfo
->tree
.first_label
; lptr
; lptr
=lptr
->next
)
600 markmemory( lptr
, TRC_SYSINFO
) ;
603 for (llptr
=sinfo
->tree
.first_source_line
; llptr
; llptr
=llptr
->next
)
605 markmemory( llptr
, TRC_SYSINFO
) ;
606 markmemory( llptr
->line
, TRC_SYSINFO
) ;
613 sysinfobox
*creat_sysinfo( const tsd_t
*TSD
, streng
*envir
)
615 sysinfobox
*sinfo
=NULL
;
617 sinfo
= MallocTSD( sizeof(sysinfobox
) ) ;
618 sinfo
->environment
= envir
;
619 sinfo
->tracing
= DEFAULT_TRACING
;
620 sinfo
->interactive
= DEFAULT_INT_TRACING
;
621 sinfo
->previous
= NULL
;
622 sinfo
->invoked
= INVO_COMMAND
;
623 sinfo
->called_as
= NULL
;
624 sinfo
->input_file
= NULL
;
625 sinfo
->input_fp
= NULL
;
626 sinfo
->panic
= NULL
;
628 sinfo
->callstack
= MallocTSD(sizeof(nodeptr
)*10) ;
629 sinfo
->result
= NULL
;
630 sinfo
->cstackcnt
= 0 ;
631 sinfo
->cstackmax
= 10 ;
632 sinfo
->trace_override
= 0 ;
633 memset(&sinfo
->tree
, 0, sizeof(sinfo
->tree
));
640 static void NoAPI( void )
642 fprintf (stderr
, "Warning: SAA API not compiled into interpreter\n" ) ;
645 int hookup( const tsd_t
*TSD
, int dummy
)
647 /* This should never happen, if we don't have support for SAA API,
648 * Then we should never get a system exit!
651 dummy
= dummy
; /* keep compiler happy */
652 TSD
= TSD
; /* keep compiler happy */
653 return 1 ; /* to keep compiler happy */
655 int hookup_input( const tsd_t
*TSD
, int dummy1
, streng
**dummy2
)
657 /* This should never happen, if we don't have support for SAA API,
658 * Then we should never get a system exit!
660 TSD
= TSD
; /* keep compiler happy */
661 dummy1
= dummy1
; /* keep compiler happy */
662 dummy2
= dummy2
; /* keep compiler happy */
664 return 1 ; /* to keep compiler happy */
666 int hookup_input_output( const tsd_t
*TSD
, int dummy1
, const streng
*dummy2
, streng
**dummy3
)
668 /* This should never happen, if we don't have support for SAA API,
669 * Then we should never get a system exit!
671 TSD
= TSD
; /* keep compiler happy */
672 dummy1
= dummy1
; /* keep compiler happy */
673 dummy2
= dummy2
; /* keep compiler happy */
674 dummy3
= dummy3
; /* keep compiler happy */
676 return 1 ; /* to keep compiler happy */
678 int hookup_output( const tsd_t
*TSD
, int dummy1
, const streng
*dummy2
)
680 /* This should never happen, if we don't have support for SAA API,
681 * Then we should never get a system exit!
684 dummy1
= dummy1
; /* keep compiler happy */
685 dummy2
= dummy2
; /* keep compiler happy */
686 TSD
= TSD
; /* keep compiler happy */
687 return 1 ; /* to keep compiler happy */
689 int hookup_output2( const tsd_t
*TSD
, int dummy1
, const streng
*dummy2
, const streng
*dummy3
)
691 /* This should never happen, if we don't have support for SAA API,
692 * Then we should never get a system exit!
695 dummy1
= dummy1
; /* keep compiler happy */
696 dummy2
= dummy2
; /* keep compiler happy */
697 dummy3
= dummy3
; /* keep compiler happy */
698 TSD
= TSD
; /* keep compiler happy */
699 return 1 ; /* to keep compiler happy */
702 static void Exit(const tsd_t
*TSD
)
704 if (TSD
->in_protected
)
708 memcpy(h
,TSD
->protect_return
,sizeof(jmp_buf));
709 /* cheat about the const, we go away anyway :-) */
710 ((tsd_t
*)TSD
)->delayed_error_type
= PROTECTED_DelayedExit
;
711 ((tsd_t
*)TSD
)->expected_exit_error
= 1;
717 streng
*do_an_external_exe( tsd_t
*TSD
, const streng
*dummy1
, cparamboxptr dummy2
, char dummy3
, char dummy4
)
720 dummy1
= dummy1
; /* keep compiler happy */
721 dummy2
= dummy2
; /* keep compiler happy */
722 dummy3
= dummy3
; /* keep compiler happy */
723 dummy4
= dummy4
; /* keep compiler happy */
728 streng
*do_an_external_dll( tsd_t
*TSD
, const void *dummy1
, cparamboxptr dummy2
, char dummy3
)
731 dummy1
= dummy1
; /* keep compiler happy */
732 dummy2
= dummy2
; /* keep compiler happy */
733 dummy3
= dummy3
; /* keep compiler happy */
739 streng
*SubCom( const tsd_t
*TSD
, const streng
*dummy1
, const streng
*dummy2
, int *dummy3
)
742 dummy1
= dummy1
; /* keep compiler happy */
743 dummy2
= dummy2
; /* keep compiler happy */
744 dummy3
= dummy3
; /* keep compiler happy */
749 int IfcHaveFunctionExit(const tsd_t
*TSD
)
751 TSD
= TSD
; /* keep compiler happy */