mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-11 22:31:12 +02:00
* init.c (scm_start_stack): Don't initialize scm_progargs here.
(scm_boot_guile): Call scm_set_program_arguments here, later than the old initialization. * init.c: (scm_boot_guile, scm_boot_guile_1): New, simplified initialization procedure. - Delete in, out, err arguments; there are other perfectly good ways to override these when desired. - Delete result argument; this function shouldn't ever return. - Rename init_func argument to main_func, for less confusion. - Delete boot_cmd argument; main_func is more general. -Add 'closure' argument, to help people pass data to main_func without resorting to global variables. - Abort if reentered; don't bother returning an error code. - Call scm_init_standard_ports to set up the default/current standard ports; no need to pass them to scm_start_stack. - Remove code to evaluate the boot_cmd, and start the repl; let the user do something like that in main_func if they want. - Remove code to package up a return value; main_func can do any of that as needed. - Call exit (0), instead of returning. (scm_start_stack): Don't initialize the I/O ports here; that's weird. Delete in, out, err arguments. Move guts to scm_init_standard_ports, scm_stdio_to_port. (scm_init_standard_ports): New function, to set up current and default standard ports. (scm_start_stack, scm_restart_stack): Make these static. * init.h (scm_boot_guile): Adjust declaration. (scm_start_stack, scm_restart_stack): Remove externally visible declarations for these. (enum scm_boot_status): Removed; now scm_boot_guile never returns.
This commit is contained in:
parent
a089567e22
commit
1cdaaafb73
1 changed files with 98 additions and 222 deletions
320
libguile/init.c
320
libguile/init.c
|
@ -119,77 +119,19 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void
|
static void scm_start_stack SCM_P ((void *base));
|
||||||
scm_start_stack (base, in, out, err)
|
static void scm_restart_stack SCM_P ((void * base));
|
||||||
|
|
||||||
|
static void
|
||||||
|
scm_start_stack (base)
|
||||||
void * base;
|
void * base;
|
||||||
FILE * in;
|
|
||||||
FILE * out;
|
|
||||||
FILE * err;
|
|
||||||
{
|
{
|
||||||
SCM root;
|
SCM root;
|
||||||
struct scm_port_table * pt;
|
|
||||||
|
|
||||||
root = scm_permanent_object (scm_make_root (SCM_UNDEFINED));
|
root = scm_permanent_object (scm_make_root (SCM_UNDEFINED));
|
||||||
scm_set_root (SCM_ROOT_STATE (root));
|
scm_set_root (SCM_ROOT_STATE (root));
|
||||||
|
|
||||||
scm_stack_base = base;
|
scm_stack_base = base;
|
||||||
|
|
||||||
/* Create standard ports from stdio files, if requested to do so.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!in)
|
|
||||||
{
|
|
||||||
scm_def_inp = SCM_BOOL_F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SCM_NEWCELL (scm_def_inp);
|
|
||||||
pt = scm_add_to_port_table (scm_def_inp);
|
|
||||||
SCM_SETCAR (scm_def_inp, (scm_tc16_fport | SCM_OPN | SCM_RDNG));
|
|
||||||
SCM_SETPTAB_ENTRY (scm_def_inp, pt);
|
|
||||||
SCM_SETSTREAM (scm_def_inp, (SCM)in);
|
|
||||||
if (isatty (fileno (in)))
|
|
||||||
{
|
|
||||||
scm_setbuf0 (scm_def_inp); /* turn off stdin buffering */
|
|
||||||
SCM_SETOR_CAR (scm_def_inp, SCM_BUF0);
|
|
||||||
}
|
|
||||||
scm_set_port_revealed_x (scm_def_inp, SCM_MAKINUM (1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!out)
|
|
||||||
{
|
|
||||||
scm_def_outp = SCM_BOOL_F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SCM_NEWCELL (scm_def_outp);
|
|
||||||
pt = scm_add_to_port_table (scm_def_outp);
|
|
||||||
SCM_SETCAR (scm_def_outp, (scm_tc16_fport | SCM_OPN | SCM_WRTNG));
|
|
||||||
SCM_SETPTAB_ENTRY (scm_def_outp, pt);
|
|
||||||
SCM_SETSTREAM (scm_def_outp, (SCM)out);
|
|
||||||
scm_set_port_revealed_x (scm_def_outp, SCM_MAKINUM (1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!err)
|
|
||||||
{
|
|
||||||
scm_def_errp = SCM_BOOL_F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SCM_NEWCELL (scm_def_errp);
|
|
||||||
pt = scm_add_to_port_table (scm_def_errp);
|
|
||||||
SCM_SETCAR (scm_def_errp, (scm_tc16_fport | SCM_OPN | SCM_WRTNG));
|
|
||||||
SCM_SETPTAB_ENTRY (scm_def_errp, pt);
|
|
||||||
SCM_SETSTREAM (scm_def_errp, (SCM)err);
|
|
||||||
scm_set_port_revealed_x (scm_def_errp, SCM_MAKINUM (1));
|
|
||||||
}
|
|
||||||
|
|
||||||
scm_cur_inp = scm_def_inp;
|
|
||||||
scm_cur_outp = scm_def_outp;
|
|
||||||
scm_cur_errp = scm_def_errp;
|
|
||||||
|
|
||||||
|
|
||||||
scm_progargs = SCM_BOOL_F; /* vestigial */
|
|
||||||
scm_exitval = SCM_BOOL_F; /* vestigial */
|
scm_exitval = SCM_BOOL_F; /* vestigial */
|
||||||
|
|
||||||
scm_top_level_lookup_thunk_var = SCM_BOOL_F;
|
scm_top_level_lookup_thunk_var = SCM_BOOL_F;
|
||||||
|
@ -198,7 +140,8 @@ scm_start_stack (base, in, out, err)
|
||||||
/* Create an object to hold the root continuation.
|
/* Create an object to hold the root continuation.
|
||||||
*/
|
*/
|
||||||
SCM_NEWCELL (scm_rootcont);
|
SCM_NEWCELL (scm_rootcont);
|
||||||
SCM_SETJMPBUF (scm_rootcont, scm_must_malloc ((long) sizeof (scm_contregs), "continuation"));
|
SCM_SETJMPBUF (scm_rootcont, scm_must_malloc ((long) sizeof (scm_contregs),
|
||||||
|
"continuation"));
|
||||||
SCM_SETCAR (scm_rootcont, scm_tc7_contin);
|
SCM_SETCAR (scm_rootcont, scm_tc7_contin);
|
||||||
SCM_SEQ (scm_rootcont) = 0;
|
SCM_SEQ (scm_rootcont) = 0;
|
||||||
/* The root continuation if further initialized by scm_restart_stack. */
|
/* The root continuation if further initialized by scm_restart_stack. */
|
||||||
|
@ -206,17 +149,18 @@ scm_start_stack (base, in, out, err)
|
||||||
/* Create the look-aside stack for variables that are shared between
|
/* Create the look-aside stack for variables that are shared between
|
||||||
* captured continuations.
|
* captured continuations.
|
||||||
*/
|
*/
|
||||||
scm_continuation_stack = scm_make_vector (SCM_MAKINUM (512), SCM_UNDEFINED, SCM_UNDEFINED);
|
scm_continuation_stack = scm_make_vector (SCM_MAKINUM (512),
|
||||||
|
SCM_UNDEFINED, SCM_UNDEFINED);
|
||||||
/* The continuation stack is further initialized by scm_restart_stack. */
|
/* The continuation stack is further initialized by scm_restart_stack. */
|
||||||
|
|
||||||
/* The remainder of stack initialization is factored out to another function so that
|
/* The remainder of stack initialization is factored out to another
|
||||||
* if this stack is ever exitted, it can be re-entered using scm_restart_stack.
|
* function so that if this stack is ever exitted, it can be
|
||||||
*/
|
* re-entered using scm_restart_stack. */
|
||||||
scm_restart_stack (base);
|
scm_restart_stack (base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
scm_restart_stack (base)
|
scm_restart_stack (base)
|
||||||
void * base;
|
void * base;
|
||||||
{
|
{
|
||||||
|
@ -288,6 +232,27 @@ check_config ()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* initializing standard and current I/O ports */
|
||||||
|
|
||||||
|
/* Create standard ports from stdio stdin, stdout, and stderr. */
|
||||||
|
static void
|
||||||
|
scm_init_standard_ports ()
|
||||||
|
{
|
||||||
|
/* I'm not sure why this should be unbuffered when coming from a
|
||||||
|
tty; isn't line buffering more common? */
|
||||||
|
scm_def_inp = scm_stdio_to_port (stdin,
|
||||||
|
(isatty (fileno (stdin)) ? "r0" : "r"),
|
||||||
|
"standard input");
|
||||||
|
scm_def_outp = scm_stdio_to_port (stdout, "w", "standard output");
|
||||||
|
scm_def_errp = scm_stdio_to_port (stderr, "w", "standard error");
|
||||||
|
|
||||||
|
scm_cur_inp = scm_def_inp;
|
||||||
|
scm_cur_outp = scm_def_outp;
|
||||||
|
scm_cur_errp = scm_def_errp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _UNICOS
|
#ifdef _UNICOS
|
||||||
typedef int setjmp_type;
|
typedef int setjmp_type;
|
||||||
|
@ -295,73 +260,67 @@ typedef int setjmp_type;
|
||||||
typedef long setjmp_type;
|
typedef long setjmp_type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Fire up Scheme.
|
static void scm_boot_guile_1 SCM_P ((SCM_STACKITEM *base,
|
||||||
*
|
int argc, char **argv,
|
||||||
* argc and argv are made the return values of program-arguments.
|
void (*main_func) (void *closure,
|
||||||
*
|
int argc,
|
||||||
* in, out, and err, if not NULL, become the standard ports.
|
char **argv),
|
||||||
* If NULL is passed, your "initfunc" should set up the
|
void *closure));
|
||||||
* standard ports.
|
|
||||||
*
|
|
||||||
* boot_cmd is a string containing a Scheme expression to evaluate
|
|
||||||
* to get things rolling.
|
|
||||||
*
|
|
||||||
* result is returned a string containing a printed result of evaluating
|
|
||||||
* the boot command.
|
|
||||||
*
|
|
||||||
* the return value is:
|
|
||||||
* scm_boot_ok - evaluation concluded normally
|
|
||||||
* scm_boot_error - evaluation concluded with a Scheme error
|
|
||||||
* scm_boot_emem - allocation error mallocing *result
|
|
||||||
* scm_boot_ereenter - scm_boot_guile was called re-entrantly, which is
|
|
||||||
* prohibited.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int scm_boot_guile_1 SCM_P ((SCM_STACKITEM *base,
|
|
||||||
char **result,
|
|
||||||
int argc, char **argv,
|
|
||||||
FILE *in, FILE *out, FILE *err,
|
|
||||||
void (*init_func) (),
|
|
||||||
char *boot_cmd));
|
|
||||||
|
|
||||||
int
|
/* Fire up the Guile Scheme interpreter.
|
||||||
scm_boot_guile (result, argc, argv, in, out, err, init_func, boot_cmd)
|
|
||||||
char ** result;
|
Call MAIN_FUNC, passing it CLOSURE, ARGC, and ARGV. MAIN_FUNC
|
||||||
|
should do all the work of the program (initializing other packages,
|
||||||
|
reading user input, etc.) before returning. When MAIN_FUNC
|
||||||
|
returns, call exit (0); this function never returns. If you want
|
||||||
|
some other exit value, MAIN_FUNC may call exit itself.
|
||||||
|
|
||||||
|
scm_boot_guile arranges for program-arguments to return the strings
|
||||||
|
given by ARGC and ARGV. If MAIN_FUNC modifies ARGC/ARGV, should
|
||||||
|
call scm_set_program_arguments with the final list, so Scheme code
|
||||||
|
will know which arguments have been processed.
|
||||||
|
|
||||||
|
Why must the caller do all the real work from MAIN_FUNC? The
|
||||||
|
garbage collector assumes that all local variables of type SCM will
|
||||||
|
be above scm_boot_guile's stack frame on the stack. If you try to
|
||||||
|
manipulate SCM values after this function returns, it's the luck of
|
||||||
|
the draw whether the GC will be able to find the objects you
|
||||||
|
allocate. So, scm_boot_guile function exits, rather than
|
||||||
|
returning, to discourage people from making that mistake. */
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_boot_guile (argc, argv, main_func, closure)
|
||||||
int argc;
|
int argc;
|
||||||
char ** argv;
|
char ** argv;
|
||||||
FILE * in;
|
void (*main_func) ();
|
||||||
FILE * out;
|
void *closure;
|
||||||
FILE * err;
|
|
||||||
void (*init_func) ();
|
|
||||||
char * boot_cmd;
|
|
||||||
{
|
{
|
||||||
|
/* The garbage collector uses the address of this variable as one
|
||||||
|
end of the stack, and the address of one of its own local
|
||||||
|
variables as the other end. */
|
||||||
SCM_STACKITEM dummy;
|
SCM_STACKITEM dummy;
|
||||||
|
|
||||||
return scm_boot_guile_1 (&dummy, result, argc, argv, in, out, err,
|
return scm_boot_guile_1 (&dummy, argc, argv, main_func, closure);
|
||||||
init_func, boot_cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
scm_boot_guile_1 (base, result, argc, argv, in, out, err, init_func, boot_cmd)
|
static void
|
||||||
|
scm_boot_guile_1 (base, argc, argv, main_func, closure)
|
||||||
SCM_STACKITEM *base;
|
SCM_STACKITEM *base;
|
||||||
char ** result;
|
|
||||||
int argc;
|
int argc;
|
||||||
char ** argv;
|
char **argv;
|
||||||
FILE * in;
|
void (*main_func) ();
|
||||||
FILE * out;
|
void *closure;
|
||||||
FILE * err;
|
|
||||||
void (*init_func) ();
|
|
||||||
char * boot_cmd;
|
|
||||||
{
|
{
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
static int live = 0;
|
static int live = 0;
|
||||||
setjmp_type setjmp_val;
|
setjmp_type setjmp_val;
|
||||||
int stat;
|
|
||||||
|
|
||||||
if (live) /* This function is not re-entrant. */
|
/* This function is not re-entrant. */
|
||||||
{
|
if (live)
|
||||||
return scm_boot_ereenter;
|
abort ();
|
||||||
}
|
|
||||||
|
|
||||||
live = 1;
|
live = 1;
|
||||||
|
|
||||||
|
@ -382,7 +341,7 @@ scm_boot_guile_1 (base, result, argc, argv, in, out, err, init_func, boot_cmd)
|
||||||
#ifdef USE_THREADS
|
#ifdef USE_THREADS
|
||||||
scm_init_threads (base);
|
scm_init_threads (base);
|
||||||
#endif
|
#endif
|
||||||
scm_start_stack (base, in, out, err);
|
scm_start_stack (base);
|
||||||
scm_init_gsubr ();
|
scm_init_gsubr ();
|
||||||
scm_init_feature ();
|
scm_init_feature ();
|
||||||
scm_init_alist ();
|
scm_init_alist ();
|
||||||
|
@ -452,119 +411,36 @@ scm_boot_guile_1 (base, result, argc, argv, in, out, err, init_func, boot_cmd)
|
||||||
scm_init_ramap ();
|
scm_init_ramap ();
|
||||||
scm_init_unif ();
|
scm_init_unif ();
|
||||||
scm_init_simpos ();
|
scm_init_simpos ();
|
||||||
scm_progargs = scm_makfromstrs (argc, argv);
|
|
||||||
scm_init_load_path ();
|
scm_init_load_path ();
|
||||||
|
scm_init_standard_ports ();
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
scm_block_gc = 0; /* permit the gc to run */
|
scm_block_gc = 0; /* permit the gc to run */
|
||||||
/* ints still disabled */
|
/* ints still disabled */
|
||||||
|
|
||||||
{
|
|
||||||
SCM command;
|
|
||||||
|
|
||||||
command = scm_makfrom0str (boot_cmd);
|
|
||||||
|
|
||||||
setjmp_val = setjmp (SCM_JMPBUF (scm_rootcont));
|
|
||||||
|
|
||||||
#ifdef STACK_CHECKING
|
#ifdef STACK_CHECKING
|
||||||
scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
|
scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
|
||||||
#endif
|
#endif
|
||||||
if (!setjmp_val)
|
|
||||||
{
|
|
||||||
SCM last = SCM_UNDEFINED;
|
|
||||||
scm_init_signals ();
|
|
||||||
|
|
||||||
/* Call the initialization function passed in by the user, if
|
setjmp_val = setjmp (SCM_JMPBUF (scm_rootcont));
|
||||||
present. */
|
if (!setjmp_val)
|
||||||
if (init_func) (*init_func) ();
|
{
|
||||||
|
scm_init_signals ();
|
||||||
|
|
||||||
/* Evaluate boot_cmd string. */
|
scm_set_program_arguments (argc, argv);
|
||||||
{
|
(*main_func) (closure, argc, argv);
|
||||||
SCM p;
|
}
|
||||||
SCM form;
|
|
||||||
|
|
||||||
p = scm_mkstrport (SCM_MAKINUM (0),
|
scm_restore_signals ();
|
||||||
command,
|
|
||||||
SCM_OPN | SCM_RDNG,
|
|
||||||
"boot_guile");
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
form = scm_read (p, SCM_BOOL_F, SCM_BOOL_F);
|
|
||||||
if (SCM_EOF_VAL == form)
|
|
||||||
break;
|
|
||||||
last = scm_eval_x (form);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
/* This tick gives any pending
|
||||||
|
* asyncs a chance to run. This must be done after
|
||||||
|
* the call to scm_restore_signals.
|
||||||
|
*/
|
||||||
|
SCM_ASYNC_TICK;
|
||||||
|
|
||||||
scm_restore_signals ();
|
/* If the caller doesn't want this, they should return from
|
||||||
/* This tick gives any pending
|
main_func themselves. */
|
||||||
* asyncs a chance to run. This must be done after
|
exit (0);
|
||||||
* the call to scm_restore_signals.
|
|
||||||
*/
|
|
||||||
SCM_ASYNC_TICK;
|
|
||||||
|
|
||||||
scm_ints_disabled = 1; /* Hopefully redundant but just to be sure. */
|
|
||||||
|
|
||||||
{
|
|
||||||
SCM str_answer;
|
|
||||||
|
|
||||||
str_answer = scm_strprint_obj (last);
|
|
||||||
*result = (char *)malloc (1 + SCM_LENGTH (str_answer));
|
|
||||||
if (!*result)
|
|
||||||
stat = scm_boot_emem;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (*result, SCM_CHARS (str_answer), SCM_LENGTH (str_answer));
|
|
||||||
(*result)[SCM_LENGTH (str_answer)] = 0;
|
|
||||||
stat = scm_boot_ok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This is reached if an unhandled throw terminated Scheme.
|
|
||||||
* Such an occurence should be extremely unlikely -- it indicates
|
|
||||||
* a programming error in the boot code.
|
|
||||||
*
|
|
||||||
* Details of the bogus exception are stored in scm_exitval even
|
|
||||||
* though that isn't currently reflected in the return value.
|
|
||||||
* !!!
|
|
||||||
*/
|
|
||||||
|
|
||||||
scm_restore_signals ();
|
|
||||||
/* This tick gives any pending
|
|
||||||
* asyncs a chance to run. This must be done after
|
|
||||||
* the call to scm_restore_signals.
|
|
||||||
*
|
|
||||||
* Note that an unhandled exception during signal handling
|
|
||||||
* will put as back at the call to scm_restore_signals immediately
|
|
||||||
* preceeding. A sufficiently bogus signal handler could
|
|
||||||
* conceivably cause an infinite loop here.
|
|
||||||
*/
|
|
||||||
SCM_ASYNC_TICK;
|
|
||||||
|
|
||||||
scm_ints_disabled = 1; /* Hopefully redundant but just to be sure. */
|
|
||||||
|
|
||||||
{
|
|
||||||
SCM str_answer;
|
|
||||||
|
|
||||||
str_answer = scm_strprint_obj (scm_exitval);
|
|
||||||
*result = (char *)malloc (1 + SCM_LENGTH (str_answer));
|
|
||||||
if (!*result)
|
|
||||||
stat = scm_boot_emem;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (*result, SCM_CHARS (str_answer), SCM_LENGTH (str_answer));
|
|
||||||
(*result)[SCM_LENGTH (str_answer)] = 0;
|
|
||||||
stat = scm_boot_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scm_block_gc = 1;
|
|
||||||
live = 0;
|
|
||||||
return stat;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue