2003-08-30 12:47:54 -04:00
|
|
|
/* libelk.c
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
|
|
|
|
* Copyright 2002, 2003 Sam Hocevar <sam@zoy.org>, Paris
|
|
|
|
*
|
|
|
|
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
|
|
|
|
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
|
|
|
|
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
|
|
|
|
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
|
|
|
|
*
|
|
|
|
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
|
|
|
|
* owners or individual owners of copyright in this software, grant to any
|
|
|
|
* person or company a worldwide, royalty free, license to
|
|
|
|
*
|
|
|
|
* i) copy this software,
|
|
|
|
* ii) prepare derivative works based on this software,
|
|
|
|
* iii) distribute copies of this software or derivative works,
|
|
|
|
* iv) perform this software, or
|
|
|
|
* v) display this software,
|
|
|
|
*
|
|
|
|
* provided that this notice is not removed and that neither Oliver Laumann
|
|
|
|
* nor Teles nor Nixdorf are deemed to have made any representations as to
|
|
|
|
* the suitability of this software for any purpose nor are held responsible
|
|
|
|
* for any defects of this software.
|
|
|
|
*
|
|
|
|
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2003-09-06 07:25:29 -04:00
|
|
|
#include "config.h"
|
2003-08-21 05:58:05 -04:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2003-09-06 10:46:24 -04:00
|
|
|
#include <stdlib.h>
|
2003-08-21 05:58:05 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#ifndef MAX_STACK_SIZE
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <sys/resource.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FIND_AOUT
|
2003-08-25 10:17:09 -04:00
|
|
|
# ifdef HAVE_UNISTD_H
|
2003-08-21 05:58:05 -04:00
|
|
|
# include <unistd.h>
|
|
|
|
# else
|
|
|
|
# include <sys/file.h>
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2003-09-06 07:25:29 -04:00
|
|
|
#include "kernel.h"
|
|
|
|
|
2003-08-21 05:58:05 -04:00
|
|
|
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 ();
|
|
|
|
}
|
|
|
|
|
2003-08-25 10:17:09 -04:00
|
|
|
#ifndef HAVE_ATEXIT
|
2003-08-21 05:58:05 -04:00
|
|
|
/* Hack: __GNUC_MINOR__ was introduced together with __attribute__ */
|
|
|
|
#ifdef __GNUC_MINOR__
|
2003-09-06 08:33:55 -04:00
|
|
|
extern void _exit() elk_attribute(__noreturn__);
|
2003-08-21 05:58:05 -04:00
|
|
|
#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;
|
2003-09-06 12:05:13 -04:00
|
|
|
#if defined(CAN_DUMP) && defined(NOMAIN)
|
|
|
|
# define foo (av[0][0])
|
2003-08-21 05:58:05 -04:00
|
|
|
#else
|
|
|
|
char foo;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CAN_DUMP
|
|
|
|
memset (unused, 0, 1); /* see comment above */
|
|
|
|
#endif
|
|
|
|
if (ac == 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
av[0] = "Elk"; ac = 1;
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
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) {
|
2003-09-02 04:12:11 -04:00
|
|
|
/* 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,
|
2003-08-21 05:58:05 -04:00
|
|
|
"Can't restart dumped interpreter from a different machine architecture\n");
|
2003-09-02 04:12:11 -04:00
|
|
|
fprintf (stderr,
|
2003-09-06 11:30:43 -04:00
|
|
|
" (Stack delta = %lld bytes).\n", (long long int)(intptr_t)(stkbase - &foo));
|
2003-09-02 04:12:11 -04:00
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
/* Check if program break must be reset.
|
|
|
|
*/
|
2003-09-06 11:30:43 -04:00
|
|
|
if ((intptr_t)Brk_On_Dump && (intptr_t)brk (Brk_On_Dump)
|
|
|
|
== (intptr_t)-1) {
|
2003-09-02 04:12:11 -04:00
|
|
|
perror ("brk"); exit (1);
|
|
|
|
}
|
2003-08-21 05:58:05 -04:00
|
|
|
#if defined(HP9K) && defined(CAN_DUMP) && defined(HPSHLIB)
|
2003-09-02 04:12:11 -04:00
|
|
|
Restore_Shared_Data ();
|
2003-08-21 05:58:05 -04:00
|
|
|
#endif
|
|
|
|
#ifdef GENERATIONAL_GC
|
2003-09-02 04:12:11 -04:00
|
|
|
Generational_GC_Reinitialize ();
|
2003-08-21 05:58:05 -04:00
|
|
|
#endif
|
2003-09-02 04:12:11 -04:00
|
|
|
Loader_Input = 0;
|
|
|
|
Install_Intr_Handler ();
|
|
|
|
(void)Funcall_Control_Point (Dump_Control_Point, Arg_True, 0);
|
|
|
|
/*NOTREACHED*/
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for ( ; First_Arg < ac; First_Arg++) {
|
2003-09-02 04:12:11 -04:00
|
|
|
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;
|
|
|
|
}
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
stkbase = &foo;
|
|
|
|
Stack_Grows_Down = Check_Stack_Grows_Down ();
|
|
|
|
ALIGN(stkbase);
|
|
|
|
Make_Heap (heap);
|
|
|
|
Init_Everything ();
|
2003-08-25 10:17:09 -04:00
|
|
|
#ifdef HAVE_ATEXIT
|
2003-08-21 05:58:05 -04:00
|
|
|
if (atexit (Exit_Handler) != 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
Fatal_Error ("atexit returned non-zero value");
|
2003-08-21 05:58:05 -04:00
|
|
|
#endif
|
|
|
|
#ifdef INIT_OBJECTS
|
|
|
|
#ifdef NOMAIN
|
|
|
|
if (init_objects) {
|
2003-09-02 04:12:11 -04:00
|
|
|
Set_Error_Tag ("init-objects");
|
|
|
|
The_Symbols = Open_File_And_Snarf_Symbols (A_Out_Name);
|
|
|
|
Call_Initializers (The_Symbols, (char *)0, PR_EXTENSION);
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
#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)))
|
2003-09-02 04:12:11 -04:00
|
|
|
Init_Loadpath (loadpath);
|
2003-08-21 05:58:05 -04:00
|
|
|
|
|
|
|
/* 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)
|
2003-09-02 04:12:11 -04:00
|
|
|
file = Make_String (INITFILE, sizeof(INITFILE)-1);
|
2003-08-21 05:58:05 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
file = Make_String (initfile, strlen (initfile));
|
2003-08-21 05:58:05 -04:00
|
|
|
free (initfile);
|
|
|
|
(void)General_Load (file, The_Environment);
|
|
|
|
|
|
|
|
Install_Intr_Handler ();
|
|
|
|
|
|
|
|
Set_Error_Tag ("top-level");
|
|
|
|
#ifdef NOMAIN
|
|
|
|
if (toplevel == 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
Interpreter_Initialized = 1;
|
|
|
|
GC_Debug = debug;
|
|
|
|
return;
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
/* Special case: if toplevel is "", act as if run from main() */
|
|
|
|
if (loadfile == 0 && toplevel[0] != '\0')
|
2003-09-02 04:12:11 -04:00
|
|
|
loadfile = toplevel;
|
2003-08-21 05:58:05 -04:00
|
|
|
#endif
|
|
|
|
if (loadfile == 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
loadfile = "toplevel.scm";
|
2003-08-21 05:58:05 -04:00
|
|
|
file = Make_String (loadfile, strlen (loadfile));
|
|
|
|
Interpreter_Initialized = 1;
|
|
|
|
GC_Debug = debug;
|
|
|
|
if (loadfile[0] == '-' && loadfile[1] == '\0')
|
2003-09-02 04:12:11 -04:00
|
|
|
Load_Source_Port (Standard_Input_Port);
|
2003-08-21 05:58:05 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
(void)General_Load (file, The_Environment);
|
2003-08-21 05:58:05 -04:00
|
|
|
#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++)
|
2003-09-02 04:12:11 -04:00
|
|
|
fprintf (stderr, "%s\n", *p);
|
2003-08-21 05:58:05 -04:00
|
|
|
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) {
|
2003-09-02 04:12:11 -04:00
|
|
|
perror ("getrlimit");
|
|
|
|
exit (1);
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
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
|
2003-09-02 04:12:11 -04:00
|
|
|
&& access (fn, X_OK) != -1;
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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++) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (*p == '/') {
|
|
|
|
if (Executable (fn))
|
|
|
|
return fn;
|
|
|
|
else
|
|
|
|
Fatal_Error ("%s is not executable", fn);
|
|
|
|
}
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
if ((path = getenv ("PATH")) == 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
path = ":/usr/ucb:/bin:/usr/bin";
|
2003-08-21 05:58:05 -04:00
|
|
|
dir = path;
|
|
|
|
do {
|
2003-09-02 04:12:11 -04:00
|
|
|
p = buf;
|
|
|
|
while (*dir && *dir != ':')
|
|
|
|
*p++ = *dir++;
|
|
|
|
if (*dir)
|
|
|
|
++dir;
|
|
|
|
if (p > buf)
|
|
|
|
*p++ = '/';
|
|
|
|
strcpy (p, fn);
|
|
|
|
if (Executable (buf))
|
|
|
|
return buf;
|
2003-08-21 05:58:05 -04:00
|
|
|
} while (*dir);
|
|
|
|
if (dir > path && dir[-1] == ':' && Executable (fn))
|
2003-09-02 04:12:11 -04:00
|
|
|
return fn;
|
2003-08-21 05:58:05 -04:00
|
|
|
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)) {
|
2003-09-02 04:12:11 -04:00
|
|
|
Object a;
|
2003-08-21 05:58:05 -04:00
|
|
|
|
2003-09-02 04:12:11 -04:00
|
|
|
a = Make_String (Argv[i], strlen (Argv[i]));
|
|
|
|
Car (tail) = a;
|
2003-08-21 05:58:05 -04:00
|
|
|
}
|
|
|
|
GC_Unlink;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object P_Exit (int argc, Object *argv) {
|
|
|
|
exit (argc == 0 ? 0 : Get_Unsigned (argv[0]));
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|