* Renamed main.c into libelk.c.
* Added a new main.c that uses libelk. Can be built this way: gcc main.c -o scheme -L. -lelk git-svn-id: svn://svn.zoy.org/elk/trunk@18 55e467fa-43c5-0310-a8a2-de718669efc6
This commit is contained in:
parent
f66cc0d573
commit
166aa29795
35
src/build
35
src/build
|
@ -61,7 +61,7 @@ C= autoload.c\\
|
|||
io.c\\
|
||||
list.c\\
|
||||
load.c\\
|
||||
main.c\\
|
||||
libelk.c\\
|
||||
malloc.c\\
|
||||
math.c\\
|
||||
onfork.c\\
|
||||
|
@ -112,15 +112,18 @@ OCOMMON=\\
|
|||
type.o\\
|
||||
vector.o
|
||||
|
||||
O1= \$(OCOMMON) main.o stab.o
|
||||
O2= \$(OCOMMON) main2.o stab2.o
|
||||
O3= \$(OCOMMON) main3.o stab2.o
|
||||
O1= \$(OCOMMON) libelk.o stab.o
|
||||
O2= \$(OCOMMON) libelk2.o stab2.o
|
||||
O3= \$(OCOMMON) libelk3.o stab2.o
|
||||
|
||||
all: scheme standalone.a module.a
|
||||
all: scheme libelk.so standalone.a module.a
|
||||
|
||||
scheme: \$(O1)
|
||||
\$(CC) -o \$@ \$(CFLAGS) \$(O1) \$(LDFLAGS)
|
||||
|
||||
libelk.so: \$(O3)
|
||||
gcc -shared -o \$@ \$(O3) \$(LDFLAGS)
|
||||
|
||||
standalone.a: \$(O2)
|
||||
ar cru \$@ \$(O2)
|
||||
|
||||
|
@ -154,7 +157,7 @@ heap.o: \$(H) heap.c heap-sc.c heap-gen.c
|
|||
io.o: \$(H) io.c
|
||||
list.o: \$(H) list.c
|
||||
load.o: \$(H) load.c $load
|
||||
main.o: \$(H) main.c
|
||||
libelk.o: \$(H) libelk.c
|
||||
malloc.o: \$(H) malloc.c
|
||||
math.o: \$(H) math.c
|
||||
onfork.o: \$(H) onfork.c
|
||||
|
@ -172,20 +175,20 @@ terminate.o: \$(H) terminate.c
|
|||
type.o: \$(H) type.c
|
||||
vector.o: \$(H) vector.c
|
||||
|
||||
main2.o: \$(H) main.c
|
||||
rm -f main2.c; ln main.c main2.c
|
||||
\$(CC) -DINIT_OBJECTS \$(CFLAGS) -I\$(INC) -c main2.c
|
||||
rm main2.c
|
||||
libelk2.o: \$(H) libelk.c
|
||||
rm -f libelk2.c; ln libelk.c libelk2.c
|
||||
\$(CC) -DINIT_OBJECTS \$(CFLAGS) -I\$(INC) -c libelk2.c
|
||||
rm libelk2.c
|
||||
|
||||
stab2.o: \$(H) stab.c $stab
|
||||
rm -f stab2.c; ln stab.c stab2.c
|
||||
\$(CC) -DINIT_OBJECTS \$(CFLAGS) -I\$(INC) -c stab2.c
|
||||
rm stab2.c
|
||||
|
||||
main3.o: \$(H) main.c
|
||||
rm -f main3.c; ln main.c main3.c
|
||||
\$(CC) -DINIT_OBJECTS -DNOMAIN \$(CFLAGS) -I\$(INC) -c main3.c
|
||||
rm main3.c
|
||||
libelk3.o: \$(H) libelk.c
|
||||
rm -f libelk3.c; ln libelk.c libelk3.c
|
||||
\$(CC) -DINIT_OBJECTS -DNOMAIN \$(CFLAGS) -I\$(INC) -c libelk3.c
|
||||
rm libelk3.c
|
||||
|
||||
install: scheme standalone.a module.a
|
||||
-@if [ ! -d $install_dir/bin ]; then \\
|
||||
|
@ -208,8 +211,8 @@ lint:
|
|||
lint \$(LINTFLAGS) -I\$(INC) \$(C)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a core main2.c stab2.c main3.c
|
||||
rm -f *.o *.a core libelk2.c stab2.c libelk3.c
|
||||
|
||||
distclean:
|
||||
rm -f *.o *.a core main2.c stab2.c main3.c lint.out scheme Makefile.local
|
||||
rm -f *.o *.a core libelk2.c stab2.c libelk3.c lint.out scheme Makefile.local
|
||||
EOT
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
#include "kernel.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef MAX_STACK_SIZE
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
# ifdef INCLUDE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# include <sys/file.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern void Call_Initializers (SYMTAB *, char *, int);
|
||||
extern void Load_Source (Object);
|
||||
extern void Call_Finalizers ();
|
||||
extern void Finit_Load ();
|
||||
extern void Generational_GC_Reinitialize ();
|
||||
extern int Check_Stack_Grows_Down ();
|
||||
extern void Make_Heap (int);
|
||||
extern void Free_Heap ();
|
||||
extern void Init_Auto (void);
|
||||
extern void Init_Cstring();
|
||||
extern void Init_Dump ();
|
||||
extern void Init_Env ();
|
||||
extern void Init_Error ();
|
||||
extern void Init_Exception ();
|
||||
extern void Init_Features ();
|
||||
extern void Init_Heap ();
|
||||
extern void Init_Io ();
|
||||
extern void Init_Load ();
|
||||
extern void Init_Loadpath (char *);
|
||||
extern void Init_Math ();
|
||||
extern void Init_Prim ();
|
||||
extern void Init_Print ();
|
||||
extern void Init_Proc ();
|
||||
extern void Init_Read ();
|
||||
extern void Init_Special ();
|
||||
extern void Init_String ();
|
||||
extern void Init_Symbol ();
|
||||
extern void Init_Terminate ();
|
||||
extern void Init_Type();
|
||||
|
||||
extern char *getenv();
|
||||
|
||||
void Get_Stack_Limit ();
|
||||
void Usage ();
|
||||
void Init_Everything ();
|
||||
|
||||
char *stkbase;
|
||||
int Stack_Grows_Down;
|
||||
unsigned int Max_Stack;
|
||||
int Interpreter_Initialized;
|
||||
int GC_Debug = 0;
|
||||
int Case_Insensitive;
|
||||
int Verb_Load = 0, Verb_Init = 0;
|
||||
|
||||
char **Argv;
|
||||
int Argc, First_Arg;
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
char *A_Out_Name;
|
||||
char *Find_Executable();
|
||||
#endif
|
||||
|
||||
#if defined(CAN_LOAD_OBJ) || defined(INIT_OBJECTS)
|
||||
SYMTAB *The_Symbols;
|
||||
#endif
|
||||
|
||||
void Exit_Handler () {
|
||||
#if defined(CAN_LOAD_OBJ) || defined(INIT_OBJECTS)
|
||||
Call_Finalizers ();
|
||||
#endif
|
||||
#ifdef CAN_LOAD_OBJ
|
||||
Finit_Load ();
|
||||
#endif
|
||||
Free_Heap ();
|
||||
}
|
||||
|
||||
#ifndef ATEXIT
|
||||
/* Hack: __GNUC_MINOR__ was introduced together with __attribute__ */
|
||||
#ifdef __GNUC_MINOR__
|
||||
extern void _exit() __attribute__ ((noreturn));
|
||||
#endif
|
||||
#ifndef PROFILING
|
||||
void exit (n) {
|
||||
Exit_Handler ();
|
||||
_cleanup ();
|
||||
_exit (n);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CAN_DUMP
|
||||
int Was_Dumped;
|
||||
char *Brk_On_Dump;
|
||||
#endif
|
||||
|
||||
|
||||
/* dump currently does not work for applications using Elk_Init().
|
||||
* The reason is that in this case the INITIAL_STK_OFFSET which
|
||||
* compensates for differences in argv[] in the original/dumped a.out
|
||||
* is not in effect (see comment below).
|
||||
* This cannot be fixed without changing Elk_Init() and its use in
|
||||
* an incompatible way.
|
||||
*/
|
||||
void Check_If_Dump_Works () {
|
||||
#ifdef NOMAIN
|
||||
Primitive_Error ("not yet supported for standalone applications");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOMAIN
|
||||
|
||||
void Elk_Init (int ac, char **av, int init_objects, char *toplevel) {
|
||||
|
||||
#else
|
||||
|
||||
int main (int ac, char **av) {
|
||||
|
||||
#endif
|
||||
|
||||
/* To avoid that the stack copying code overwrites argv if a dumped
|
||||
* copy of the interpreter is invoked with more arguments than the
|
||||
* original a.out, move the stack base INITIAL_STK_OFFSET bytes down.
|
||||
* The call to memset() is there to prevent the optimizer from removing
|
||||
* the array.
|
||||
*/
|
||||
#ifdef CAN_DUMP
|
||||
char unused[INITIAL_STK_OFFSET];
|
||||
#endif
|
||||
char *initfile, *loadfile = 0, *loadpath = 0;
|
||||
int debug = 0, heap = HEAP_SIZE;
|
||||
Object file;
|
||||
struct stat st;
|
||||
extern int errno;
|
||||
#ifdef CAN_DUMP
|
||||
#ifdef NOMAIN
|
||||
# define foo (av[0][0])
|
||||
#else
|
||||
char foo;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CAN_DUMP
|
||||
memset (unused, 0, 1); /* see comment above */
|
||||
#endif
|
||||
if (ac == 0) {
|
||||
av[0] = "Elk"; ac = 1;
|
||||
}
|
||||
Get_Stack_Limit ();
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
A_Out_Name = Find_Executable (av[0]);
|
||||
#endif
|
||||
|
||||
Argc = ac; Argv = av;
|
||||
First_Arg = 1;
|
||||
#ifdef CAN_DUMP
|
||||
if (Was_Dumped) {
|
||||
/* Check if beginning of stack has moved by a large amount.
|
||||
* This is the case, for instance, on a Sun-4m when the
|
||||
* interpreter was dumped on a Sun-4c and vice versa.
|
||||
*/
|
||||
if (abs (stkbase - &foo) > INITIAL_STK_OFFSET) {
|
||||
fprintf (stderr,
|
||||
"Can't restart dumped interpreter from a different machine architecture\n");
|
||||
fprintf (stderr,
|
||||
" (Stack delta = %lld bytes).\n", (long long int)(ptrdiff_t)(stkbase - &foo));
|
||||
exit (1);
|
||||
}
|
||||
/* Check if program break must be reset.
|
||||
*/
|
||||
if ((ptrdiff_t)Brk_On_Dump && (ptrdiff_t)brk (Brk_On_Dump)
|
||||
== (ptrdiff_t)-1) {
|
||||
perror ("brk"); exit (1);
|
||||
}
|
||||
#if defined(HP9K) && defined(CAN_DUMP) && defined(HPSHLIB)
|
||||
Restore_Shared_Data ();
|
||||
#endif
|
||||
#ifdef GENERATIONAL_GC
|
||||
Generational_GC_Reinitialize ();
|
||||
#endif
|
||||
Loader_Input = 0;
|
||||
Install_Intr_Handler ();
|
||||
(void)Funcall_Control_Point (Dump_Control_Point, Arg_True, 0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( ; First_Arg < ac; First_Arg++) {
|
||||
if (strcmp (av[First_Arg], "-g") == 0) {
|
||||
debug = 1;
|
||||
} else if (strcmp (av[First_Arg], "-i") == 0) {
|
||||
Case_Insensitive = 1;
|
||||
} else if (strcmp (av[First_Arg], "-v") == 0) {
|
||||
if (++First_Arg == ac)
|
||||
Usage ();
|
||||
if (strcmp (av[First_Arg], "load") == 0)
|
||||
Verb_Load = 1;
|
||||
else if (strcmp (av[First_Arg], "init") == 0)
|
||||
Verb_Init = 1;
|
||||
else Usage ();
|
||||
} else if (strcmp (av[First_Arg], "-h") == 0) {
|
||||
if (++First_Arg == ac)
|
||||
Usage ();
|
||||
if ((heap = atoi (av[First_Arg])) <= 0) {
|
||||
fprintf (stderr, "Heap size must be a positive number.\n");
|
||||
exit (1);
|
||||
}
|
||||
} else if (strcmp (av[First_Arg], "-l") == 0) {
|
||||
if (++First_Arg == ac || loadfile)
|
||||
Usage ();
|
||||
loadfile = av[First_Arg];
|
||||
} else if (strcmp (av[First_Arg], "-p") == 0) {
|
||||
if (++First_Arg == ac || loadpath)
|
||||
Usage ();
|
||||
loadpath = av[First_Arg];
|
||||
} else if (strcmp (av[First_Arg], "--") == 0) {
|
||||
First_Arg++;
|
||||
break;
|
||||
} else if (av[First_Arg][0] == '-') {
|
||||
Usage ();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stkbase = &foo;
|
||||
Stack_Grows_Down = Check_Stack_Grows_Down ();
|
||||
ALIGN(stkbase);
|
||||
Make_Heap (heap);
|
||||
Init_Everything ();
|
||||
#ifdef ATEXIT
|
||||
if (atexit (Exit_Handler) != 0)
|
||||
Fatal_Error ("atexit returned non-zero value");
|
||||
#endif
|
||||
#ifdef INIT_OBJECTS
|
||||
#ifdef NOMAIN
|
||||
if (init_objects) {
|
||||
Set_Error_Tag ("init-objects");
|
||||
The_Symbols = Open_File_And_Snarf_Symbols (A_Out_Name);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_EXTENSION);
|
||||
}
|
||||
#else
|
||||
Set_Error_Tag ("init-objects");
|
||||
The_Symbols = Open_File_And_Snarf_Symbols (A_Out_Name);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_CONSTRUCTOR);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_EXTENSION);
|
||||
#endif
|
||||
#endif
|
||||
if (loadpath || (loadpath = getenv (LOADPATH_ENV)))
|
||||
Init_Loadpath (loadpath);
|
||||
|
||||
/* The following code is sort of a hack. initscheme.scm should not
|
||||
* be resolved against load-path. However, the .scm-files may not
|
||||
* have been installed yet (note that the interpreter is already
|
||||
* used in the "make" process).
|
||||
* Solution: if initscheme.scm hasn't been installed yet, do search
|
||||
* the load-path, so that -p can be used.
|
||||
*/
|
||||
Set_Error_Tag ("scheme-init");
|
||||
initfile = Safe_Malloc (strlen (SCM_DIR) + 1 + sizeof (INITFILE) + 1);
|
||||
sprintf (initfile, "%s/%s", SCM_DIR, INITFILE);
|
||||
if (stat (initfile, &st) == -1 && errno == ENOENT)
|
||||
file = Make_String (INITFILE, sizeof(INITFILE)-1);
|
||||
else
|
||||
file = Make_String (initfile, strlen (initfile));
|
||||
free (initfile);
|
||||
(void)General_Load (file, The_Environment);
|
||||
|
||||
Install_Intr_Handler ();
|
||||
|
||||
Set_Error_Tag ("top-level");
|
||||
#ifdef NOMAIN
|
||||
if (toplevel == 0) {
|
||||
Interpreter_Initialized = 1;
|
||||
GC_Debug = debug;
|
||||
return;
|
||||
}
|
||||
/* Special case: if toplevel is "", act as if run from main() */
|
||||
if (loadfile == 0 && toplevel[0] != '\0')
|
||||
loadfile = toplevel;
|
||||
#endif
|
||||
if (loadfile == 0)
|
||||
loadfile = "toplevel.scm";
|
||||
file = Make_String (loadfile, strlen (loadfile));
|
||||
Interpreter_Initialized = 1;
|
||||
GC_Debug = debug;
|
||||
if (loadfile[0] == '-' && loadfile[1] == '\0')
|
||||
Load_Source_Port (Standard_Input_Port);
|
||||
else
|
||||
(void)General_Load (file, The_Environment);
|
||||
#ifndef NOMAIN
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *Usage_Msg[] = {
|
||||
"Options:",
|
||||
" [-l filename] Load file instead of standard toplevel",
|
||||
" [-l -] Load from standard input",
|
||||
" [-h heapsize] Heap size in KBytes",
|
||||
" [-p loadpath] Initialize load-path (colon-list of directories)",
|
||||
" [-g] Enable GC-debugging",
|
||||
" [-i] Case-insensitive symbols",
|
||||
" [-v type] Be verbose. \"type\" controls what to print:",
|
||||
" load linker command when loading object file",
|
||||
" init names of extension [f]init functions when \
|
||||
called",
|
||||
" [--] End options and begin arguments",
|
||||
0 };
|
||||
|
||||
void Usage () {
|
||||
char **p;
|
||||
|
||||
fprintf (stderr, "Usage: %s [options] [arguments]\n", Argv[0]);
|
||||
for (p = Usage_Msg; *p; p++)
|
||||
fprintf (stderr, "%s\n", *p);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void Init_Everything () {
|
||||
Init_Type ();
|
||||
Init_Cstring ();
|
||||
Init_String ();
|
||||
Init_Symbol ();
|
||||
Init_Env ();
|
||||
Init_Error ();
|
||||
Init_Exception ();
|
||||
Init_Io ();
|
||||
Init_Prim ();
|
||||
Init_Math ();
|
||||
Init_Print ();
|
||||
Init_Auto ();
|
||||
Init_Heap ();
|
||||
Init_Load ();
|
||||
Init_Proc ();
|
||||
Init_Special ();
|
||||
Init_Read ();
|
||||
Init_Features ();
|
||||
Init_Terminate ();
|
||||
#ifdef CAN_DUMP
|
||||
Init_Dump ();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Get_Stack_Limit () {
|
||||
#ifdef MAX_STACK_SIZE
|
||||
Max_Stack = MAX_STACK_SIZE;
|
||||
#else
|
||||
struct rlimit rl;
|
||||
|
||||
if (getrlimit (RLIMIT_STACK, &rl) == -1) {
|
||||
perror ("getrlimit");
|
||||
exit (1);
|
||||
}
|
||||
Max_Stack = rl.rlim_cur;
|
||||
#endif
|
||||
Max_Stack -= STACK_MARGIN;
|
||||
}
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
int Executable (char *fn) {
|
||||
struct stat s;
|
||||
|
||||
return stat (fn, &s) != -1 && (s.st_mode & S_IFMT) == S_IFREG
|
||||
&& access (fn, X_OK) != -1;
|
||||
}
|
||||
|
||||
char *Find_Executable (char *fn) {
|
||||
char *path, *dir, *getenv();
|
||||
static char buf[1025]; /* Can't use Path_Max or Safe_Malloc here */
|
||||
register char *p;
|
||||
|
||||
for (p = fn; *p; p++) {
|
||||
if (*p == '/') {
|
||||
if (Executable (fn))
|
||||
return fn;
|
||||
else
|
||||
Fatal_Error ("%s is not executable", fn);
|
||||
}
|
||||
}
|
||||
if ((path = getenv ("PATH")) == 0)
|
||||
path = ":/usr/ucb:/bin:/usr/bin";
|
||||
dir = path;
|
||||
do {
|
||||
p = buf;
|
||||
while (*dir && *dir != ':')
|
||||
*p++ = *dir++;
|
||||
if (*dir)
|
||||
++dir;
|
||||
if (p > buf)
|
||||
*p++ = '/';
|
||||
strcpy (p, fn);
|
||||
if (Executable (buf))
|
||||
return buf;
|
||||
} while (*dir);
|
||||
if (dir > path && dir[-1] == ':' && Executable (fn))
|
||||
return fn;
|
||||
Fatal_Error ("cannot find pathname of %s", fn);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
||||
|
||||
Object P_Command_Line_Args () {
|
||||
Object ret, tail;
|
||||
register int i;
|
||||
GC_Node2;
|
||||
|
||||
ret = tail = P_Make_List (Make_Integer (Argc-First_Arg), Null);
|
||||
GC_Link2 (ret, tail);
|
||||
for (i = First_Arg; i < Argc; i++, tail = Cdr (tail)) {
|
||||
Object a;
|
||||
|
||||
a = Make_String (Argv[i], strlen (Argv[i]));
|
||||
Car (tail) = a;
|
||||
}
|
||||
GC_Unlink;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object P_Exit (int argc, Object *argv) {
|
||||
exit (argc == 0 ? 0 : Get_Unsigned (argv[0]));
|
||||
/*NOTREACHED*/
|
||||
}
|
436
src/main.c
436
src/main.c
|
@ -1,437 +1,7 @@
|
|||
#include "kernel.h"
|
||||
#include <elk/scheme.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef MAX_STACK_SIZE
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
# ifdef INCLUDE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# else
|
||||
# include <sys/file.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern void Call_Initializers (SYMTAB *, char *, int);
|
||||
extern void Load_Source (Object);
|
||||
extern void Call_Finalizers ();
|
||||
extern void Finit_Load ();
|
||||
extern void Generational_GC_Reinitialize ();
|
||||
extern int Check_Stack_Grows_Down ();
|
||||
extern void Make_Heap (int);
|
||||
extern void Free_Heap ();
|
||||
extern void Init_Auto (void);
|
||||
extern void Init_Cstring();
|
||||
extern void Init_Dump ();
|
||||
extern void Init_Env ();
|
||||
extern void Init_Error ();
|
||||
extern void Init_Exception ();
|
||||
extern void Init_Features ();
|
||||
extern void Init_Heap ();
|
||||
extern void Init_Io ();
|
||||
extern void Init_Load ();
|
||||
extern void Init_Loadpath (char *);
|
||||
extern void Init_Math ();
|
||||
extern void Init_Prim ();
|
||||
extern void Init_Print ();
|
||||
extern void Init_Proc ();
|
||||
extern void Init_Read ();
|
||||
extern void Init_Special ();
|
||||
extern void Init_String ();
|
||||
extern void Init_Symbol ();
|
||||
extern void Init_Terminate ();
|
||||
extern void Init_Type();
|
||||
|
||||
extern char *getenv();
|
||||
|
||||
void Get_Stack_Limit ();
|
||||
void Usage ();
|
||||
void Init_Everything ();
|
||||
|
||||
char *stkbase;
|
||||
int Stack_Grows_Down;
|
||||
unsigned int Max_Stack;
|
||||
int Interpreter_Initialized;
|
||||
int GC_Debug = 0;
|
||||
int Case_Insensitive;
|
||||
int Verb_Load = 0, Verb_Init = 0;
|
||||
|
||||
char **Argv;
|
||||
int Argc, First_Arg;
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
char *A_Out_Name;
|
||||
char *Find_Executable();
|
||||
#endif
|
||||
|
||||
#if defined(CAN_LOAD_OBJ) || defined(INIT_OBJECTS)
|
||||
SYMTAB *The_Symbols;
|
||||
#endif
|
||||
|
||||
void Exit_Handler () {
|
||||
#if defined(CAN_LOAD_OBJ) || defined(INIT_OBJECTS)
|
||||
Call_Finalizers ();
|
||||
#endif
|
||||
#ifdef CAN_LOAD_OBJ
|
||||
Finit_Load ();
|
||||
#endif
|
||||
Free_Heap ();
|
||||
}
|
||||
|
||||
#ifndef ATEXIT
|
||||
/* Hack: __GNUC_MINOR__ was introduced together with __attribute__ */
|
||||
#ifdef __GNUC_MINOR__
|
||||
extern void _exit() __attribute__ ((noreturn));
|
||||
#endif
|
||||
#ifndef PROFILING
|
||||
void exit (n) {
|
||||
Exit_Handler ();
|
||||
_cleanup ();
|
||||
_exit (n);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CAN_DUMP
|
||||
int Was_Dumped;
|
||||
char *Brk_On_Dump;
|
||||
#endif
|
||||
|
||||
|
||||
/* dump currently does not work for applications using Elk_Init().
|
||||
* The reason is that in this case the INITIAL_STK_OFFSET which
|
||||
* compensates for differences in argv[] in the original/dumped a.out
|
||||
* is not in effect (see comment below).
|
||||
* This cannot be fixed without changing Elk_Init() and its use in
|
||||
* an incompatible way.
|
||||
*/
|
||||
void Check_If_Dump_Works () {
|
||||
#ifdef NOMAIN
|
||||
Primitive_Error ("not yet supported for standalone applications");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOMAIN
|
||||
|
||||
void Elk_Init (int ac, char **av, int init_objects, char *toplevel) {
|
||||
|
||||
#else
|
||||
|
||||
int main (int ac, char **av) {
|
||||
|
||||
#endif
|
||||
|
||||
/* To avoid that the stack copying code overwrites argv if a dumped
|
||||
* copy of the interpreter is invoked with more arguments than the
|
||||
* original a.out, move the stack base INITIAL_STK_OFFSET bytes down.
|
||||
* The call to memset() is there to prevent the optimizer from removing
|
||||
* the array.
|
||||
*/
|
||||
#ifdef CAN_DUMP
|
||||
char unused[INITIAL_STK_OFFSET];
|
||||
#endif
|
||||
char *initfile, *loadfile = 0, *loadpath = 0;
|
||||
int debug = 0, heap = HEAP_SIZE;
|
||||
Object file;
|
||||
struct stat st;
|
||||
extern int errno;
|
||||
#ifdef CAN_DUMP
|
||||
#ifdef NOMAIN
|
||||
# define foo (av[0][0])
|
||||
#else
|
||||
char foo;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CAN_DUMP
|
||||
memset (unused, 0, 1); /* see comment above */
|
||||
#endif
|
||||
if (ac == 0) {
|
||||
av[0] = "Elk"; ac = 1;
|
||||
}
|
||||
Get_Stack_Limit ();
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
A_Out_Name = Find_Executable (av[0]);
|
||||
#endif
|
||||
|
||||
Argc = ac; Argv = av;
|
||||
First_Arg = 1;
|
||||
#ifdef CAN_DUMP
|
||||
if (Was_Dumped) {
|
||||
/* Check if beginning of stack has moved by a large amount.
|
||||
* This is the case, for instance, on a Sun-4m when the
|
||||
* interpreter was dumped on a Sun-4c and vice versa.
|
||||
*/
|
||||
if (abs (stkbase - &foo) > INITIAL_STK_OFFSET) {
|
||||
fprintf (stderr,
|
||||
"Can't restart dumped interpreter from a different machine architecture\n");
|
||||
fprintf (stderr,
|
||||
" (Stack delta = %lld bytes).\n", (long long int)(ptrdiff_t)(stkbase - &foo));
|
||||
exit (1);
|
||||
}
|
||||
/* Check if program break must be reset.
|
||||
*/
|
||||
if ((ptrdiff_t)Brk_On_Dump && (ptrdiff_t)brk (Brk_On_Dump)
|
||||
== (ptrdiff_t)-1) {
|
||||
perror ("brk"); exit (1);
|
||||
}
|
||||
#if defined(HP9K) && defined(CAN_DUMP) && defined(HPSHLIB)
|
||||
Restore_Shared_Data ();
|
||||
#endif
|
||||
#ifdef GENERATIONAL_GC
|
||||
Generational_GC_Reinitialize ();
|
||||
#endif
|
||||
Loader_Input = 0;
|
||||
Install_Intr_Handler ();
|
||||
(void)Funcall_Control_Point (Dump_Control_Point, Arg_True, 0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( ; First_Arg < ac; First_Arg++) {
|
||||
if (strcmp (av[First_Arg], "-g") == 0) {
|
||||
debug = 1;
|
||||
} else if (strcmp (av[First_Arg], "-i") == 0) {
|
||||
Case_Insensitive = 1;
|
||||
} else if (strcmp (av[First_Arg], "-v") == 0) {
|
||||
if (++First_Arg == ac)
|
||||
Usage ();
|
||||
if (strcmp (av[First_Arg], "load") == 0)
|
||||
Verb_Load = 1;
|
||||
else if (strcmp (av[First_Arg], "init") == 0)
|
||||
Verb_Init = 1;
|
||||
else Usage ();
|
||||
} else if (strcmp (av[First_Arg], "-h") == 0) {
|
||||
if (++First_Arg == ac)
|
||||
Usage ();
|
||||
if ((heap = atoi (av[First_Arg])) <= 0) {
|
||||
fprintf (stderr, "Heap size must be a positive number.\n");
|
||||
exit (1);
|
||||
}
|
||||
} else if (strcmp (av[First_Arg], "-l") == 0) {
|
||||
if (++First_Arg == ac || loadfile)
|
||||
Usage ();
|
||||
loadfile = av[First_Arg];
|
||||
} else if (strcmp (av[First_Arg], "-p") == 0) {
|
||||
if (++First_Arg == ac || loadpath)
|
||||
Usage ();
|
||||
loadpath = av[First_Arg];
|
||||
} else if (strcmp (av[First_Arg], "--") == 0) {
|
||||
First_Arg++;
|
||||
break;
|
||||
} else if (av[First_Arg][0] == '-') {
|
||||
Usage ();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stkbase = &foo;
|
||||
Stack_Grows_Down = Check_Stack_Grows_Down ();
|
||||
ALIGN(stkbase);
|
||||
Make_Heap (heap);
|
||||
Init_Everything ();
|
||||
#ifdef ATEXIT
|
||||
if (atexit (Exit_Handler) != 0)
|
||||
Fatal_Error ("atexit returned non-zero value");
|
||||
#endif
|
||||
#ifdef INIT_OBJECTS
|
||||
#ifdef NOMAIN
|
||||
if (init_objects) {
|
||||
Set_Error_Tag ("init-objects");
|
||||
The_Symbols = Open_File_And_Snarf_Symbols (A_Out_Name);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_EXTENSION);
|
||||
}
|
||||
#else
|
||||
Set_Error_Tag ("init-objects");
|
||||
The_Symbols = Open_File_And_Snarf_Symbols (A_Out_Name);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_CONSTRUCTOR);
|
||||
Call_Initializers (The_Symbols, (char *)0, PR_EXTENSION);
|
||||
#endif
|
||||
#endif
|
||||
if (loadpath || (loadpath = getenv (LOADPATH_ENV)))
|
||||
Init_Loadpath (loadpath);
|
||||
|
||||
/* The following code is sort of a hack. initscheme.scm should not
|
||||
* be resolved against load-path. However, the .scm-files may not
|
||||
* have been installed yet (note that the interpreter is already
|
||||
* used in the "make" process).
|
||||
* Solution: if initscheme.scm hasn't been installed yet, do search
|
||||
* the load-path, so that -p can be used.
|
||||
*/
|
||||
Set_Error_Tag ("scheme-init");
|
||||
initfile = Safe_Malloc (strlen (SCM_DIR) + 1 + sizeof (INITFILE) + 1);
|
||||
sprintf (initfile, "%s/%s", SCM_DIR, INITFILE);
|
||||
if (stat (initfile, &st) == -1 && errno == ENOENT)
|
||||
file = Make_String (INITFILE, sizeof(INITFILE)-1);
|
||||
else
|
||||
file = Make_String (initfile, strlen (initfile));
|
||||
free (initfile);
|
||||
(void)General_Load (file, The_Environment);
|
||||
|
||||
Install_Intr_Handler ();
|
||||
|
||||
Set_Error_Tag ("top-level");
|
||||
#ifdef NOMAIN
|
||||
if (toplevel == 0) {
|
||||
Interpreter_Initialized = 1;
|
||||
GC_Debug = debug;
|
||||
return;
|
||||
}
|
||||
/* Special case: if toplevel is "", act as if run from main() */
|
||||
if (loadfile == 0 && toplevel[0] != '\0')
|
||||
loadfile = toplevel;
|
||||
#endif
|
||||
if (loadfile == 0)
|
||||
loadfile = "toplevel.scm";
|
||||
file = Make_String (loadfile, strlen (loadfile));
|
||||
Interpreter_Initialized = 1;
|
||||
GC_Debug = debug;
|
||||
if (loadfile[0] == '-' && loadfile[1] == '\0')
|
||||
Load_Source_Port (Standard_Input_Port);
|
||||
else
|
||||
(void)General_Load (file, The_Environment);
|
||||
#ifndef NOMAIN
|
||||
int main(int ac, char **av) {
|
||||
Elk_Init(ac, av, 1, "");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *Usage_Msg[] = {
|
||||
"Options:",
|
||||
" [-l filename] Load file instead of standard toplevel",
|
||||
" [-l -] Load from standard input",
|
||||
" [-h heapsize] Heap size in KBytes",
|
||||
" [-p loadpath] Initialize load-path (colon-list of directories)",
|
||||
" [-g] Enable GC-debugging",
|
||||
" [-i] Case-insensitive symbols",
|
||||
" [-v type] Be verbose. \"type\" controls what to print:",
|
||||
" load linker command when loading object file",
|
||||
" init names of extension [f]init functions when \
|
||||
called",
|
||||
" [--] End options and begin arguments",
|
||||
0 };
|
||||
|
||||
void Usage () {
|
||||
char **p;
|
||||
|
||||
fprintf (stderr, "Usage: %s [options] [arguments]\n", Argv[0]);
|
||||
for (p = Usage_Msg; *p; p++)
|
||||
fprintf (stderr, "%s\n", *p);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void Init_Everything () {
|
||||
Init_Type ();
|
||||
Init_Cstring ();
|
||||
Init_String ();
|
||||
Init_Symbol ();
|
||||
Init_Env ();
|
||||
Init_Error ();
|
||||
Init_Exception ();
|
||||
Init_Io ();
|
||||
Init_Prim ();
|
||||
Init_Math ();
|
||||
Init_Print ();
|
||||
Init_Auto ();
|
||||
Init_Heap ();
|
||||
Init_Load ();
|
||||
Init_Proc ();
|
||||
Init_Special ();
|
||||
Init_Read ();
|
||||
Init_Features ();
|
||||
Init_Terminate ();
|
||||
#ifdef CAN_DUMP
|
||||
Init_Dump ();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Get_Stack_Limit () {
|
||||
#ifdef MAX_STACK_SIZE
|
||||
Max_Stack = MAX_STACK_SIZE;
|
||||
#else
|
||||
struct rlimit rl;
|
||||
|
||||
if (getrlimit (RLIMIT_STACK, &rl) == -1) {
|
||||
perror ("getrlimit");
|
||||
exit (1);
|
||||
}
|
||||
Max_Stack = rl.rlim_cur;
|
||||
#endif
|
||||
Max_Stack -= STACK_MARGIN;
|
||||
}
|
||||
|
||||
#ifdef FIND_AOUT
|
||||
int Executable (char *fn) {
|
||||
struct stat s;
|
||||
|
||||
return stat (fn, &s) != -1 && (s.st_mode & S_IFMT) == S_IFREG
|
||||
&& access (fn, X_OK) != -1;
|
||||
}
|
||||
|
||||
char *Find_Executable (char *fn) {
|
||||
char *path, *dir, *getenv();
|
||||
static char buf[1025]; /* Can't use Path_Max or Safe_Malloc here */
|
||||
register char *p;
|
||||
|
||||
for (p = fn; *p; p++) {
|
||||
if (*p == '/') {
|
||||
if (Executable (fn))
|
||||
return fn;
|
||||
else
|
||||
Fatal_Error ("%s is not executable", fn);
|
||||
}
|
||||
}
|
||||
if ((path = getenv ("PATH")) == 0)
|
||||
path = ":/usr/ucb:/bin:/usr/bin";
|
||||
dir = path;
|
||||
do {
|
||||
p = buf;
|
||||
while (*dir && *dir != ':')
|
||||
*p++ = *dir++;
|
||||
if (*dir)
|
||||
++dir;
|
||||
if (p > buf)
|
||||
*p++ = '/';
|
||||
strcpy (p, fn);
|
||||
if (Executable (buf))
|
||||
return buf;
|
||||
} while (*dir);
|
||||
if (dir > path && dir[-1] == ':' && Executable (fn))
|
||||
return fn;
|
||||
Fatal_Error ("cannot find pathname of %s", fn);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif
|
||||
|
||||
Object P_Command_Line_Args () {
|
||||
Object ret, tail;
|
||||
register int i;
|
||||
GC_Node2;
|
||||
|
||||
ret = tail = P_Make_List (Make_Integer (Argc-First_Arg), Null);
|
||||
GC_Link2 (ret, tail);
|
||||
for (i = First_Arg; i < Argc; i++, tail = Cdr (tail)) {
|
||||
Object a;
|
||||
|
||||
a = Make_String (Argv[i], strlen (Argv[i]));
|
||||
Car (tail) = a;
|
||||
}
|
||||
GC_Unlink;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object P_Exit (int argc, Object *argv) {
|
||||
exit (argc == 0 ? 0 : Get_Unsigned (argv[0]));
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue