1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1989-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23#ifndef _WIN32
24
25/*
26 * SEPIA C SOURCE MODULE
27 *
28 * VERSION	$Id: main.c,v 1.6 2011/04/10 14:11:38 jschimpf Exp $
29 */
30
31/*
32 *
33 * SEPIA main() procedure.
34 *
35 * It initialises the system, interprets the command line options,
36 *  allocates heap and stacks, and eventually
37 * calls the Prolog emulator with an appropriate goal.
38 */
39
40#include 	"config.h"
41#include	"os_support.h"
42
43#include        "sepia.h"
44#include 	"types.h"
45#include	"embed.h"
46#include 	"error.h"
47#include 	"mem.h"
48#include 	"dict.h"
49#include	"emu_export.h"
50#include	"module.h"
51#include	"property.h"
52
53#include <stdio.h>
54#include <errno.h>
55
56#ifdef STDC_HEADERS
57#include <stdlib.h>
58#endif
59
60#ifdef HAVE_STRING_H
61#include <string.h>
62#else
63extern char *	strcpy();
64extern char *	strcat();
65#endif
66
67#ifndef ACCESS_IN_UNISTD
68#include <sys/file.h>
69#endif
70
71#if defined(BARRELFISH)
72#include <vfs/vfs.h>
73#endif
74
75#ifdef STRTOL_UNDEF
76extern long strtol(const char *, char **, int);
77#endif
78
79#define KB		1024
80#define MIN_LOCAL	100*KB
81#define MIN_GLOBAL	210*KB
82#define MIN_PRIVATE	210*KB
83#define MIN_SHARED	210*KB
84
85#define MAX_MEMORY	(SIGN_BIT/8*15)	/* 15/16 of the address space */
86
87#define BOOTFILES		20
88
89
90/*
91 * EXTERN declarations
92 */
93
94extern int	eclipse_global_init(int init_flags);
95extern int	eclipse_boot(char *initfile);
96extern void	msg_trigger();
97extern int	it_emulc(value v_sig, type t_sig);
98
99/*
100 * LOCAL declarations
101 */
102
103static void	main_panic(const char *what, const char *where),
104		usage(char *opt);
105
106
107/*
108 * GLOBAL variable definitions
109 */
110
111/*
112 * To avoid infinite loops when the memory is corrupted, this flag
113 * is set when SEPIA did not manage it to print the prompt and start user query
114 * after a reset. 0 means ok, 1 is after a reset and before a query.
115 */
116static int	memory_corrupted = 0;
117
118jmp_buf         reset;
119
120static uword
121sizearg(char *arg)
122{
123    int last = strlen(arg) -1;
124    uword multiple = 0;
125    uword size;
126
127    switch(arg[last])
128    {
129    case 'k':
130    case 'K':
131	multiple = KB;
132	arg[last] = '\000';
133	break;
134    case 'm':
135    case 'M':
136	multiple = KB * KB;
137	arg[last] = '\000';
138	break;
139    case 'g':
140    case 'G':
141	multiple = KB * KB * KB;
142	arg[last] = '\000';
143	break;
144    case '0': case '1': case '2': case '3': case '4':
145    case '5': case '6': case '7': case '8': case '9':
146	multiple = KB;
147	break;
148    default:
149    	usage(arg);
150    }
151    size = (uword) atol(arg);
152    return (size > MAX_MEMORY/multiple) ? 0 : size * multiple;
153}
154
155int
156main(int argc, char **argv)
157{
158    char	bootfile_buf[MAX_PATH_LEN];
159    char *	initfile = (char *) 0;
160    char *	eclipsedir = (char *) 0;
161    int		c, new_argc;
162    pword	goal, module;
163    int		err;
164    int		init_flags = INIT_SHARED|INIT_PRIVATE|INIT_ENGINE|INIT_PROCESS;
165    unsigned	startup_delay = 0;
166    int		vm_options = 0;
167    char *	session, * nsrv_hostname;
168    unsigned    nsrv_port_number;
169
170#if defined(BARRELFISH)
171    vfs_init();
172#endif
173
174#ifdef PROFILE
175    moncontrol(0);	/* disable profiling by default */
176#endif
177
178    /*
179     * collect information from the command line
180     * remove some internally used arguments from the command line
181     */
182    for (c = new_argc = 1; c < argc; )
183    {
184	if (argv[c][0] == '-' && argv[c][2] == 0)	/* single char opt */
185	{
186	    switch (argv[c][1])
187	    {
188	    case 'a':			/* -a <worker> <session>
189                                              <nsrv_hostname> <nsrv_port_no> */
190		if (++c + 4 > argc) usage(argv[c-1]);
191		ec_options.parallel_worker = atoi(argv[c++]);
192		session = argv[c++];
193		nsrv_hostname = argv[c++];
194		nsrv_port_number = atoi(argv[c++]);
195		break;
196
197	    case 'c':				/* -c <shared_map_file> */
198		if (++c + 1 > argc) usage(argv[c-1]);
199		ec_options.mapfile = argv[c++];
200		ec_options.allocation = ALLOC_FIXED;
201		init_flags &= ~INIT_SHARED;
202		break;
203
204	    case 'm':				/* -m <shared_map_file> */
205		if (++c + 1 > argc) usage(argv[c-1]);
206		ec_options.mapfile = argv[c++];
207		ec_options.allocation = ALLOC_FIXED;
208		break;
209
210	    case 'g':				/* -g <size> */
211		argv[new_argc++] = argv[c];		/* shift */
212		if (++c + 1 > argc) usage(argv[c-1]);
213		argv[new_argc++] = argv[c];		/* shift */
214		ec_options.globalsize = sizearg(argv[c++]);
215		if (ec_options.globalsize < MIN_GLOBAL) {
216		    ec_bad_exit("ECLiPSe: Global stack size out of range.");
217		}
218		break;
219
220	    case 'd':				/* -d <n> */
221		/* delay worker startup by <n> seconds */
222		if (++c + 1 > argc) usage(argv[c-1]);
223		startup_delay = atoi(argv[c++]);
224		if (startup_delay == 0)
225		    ec_options.io_option = OWN_IO;	/* every worker has its own i/o */
226		else
227		    sleep(startup_delay);
228		break;
229
230	    case 'D':				/* -D <eclipsedir> */
231		if (++c + 1 > argc) usage(argv[c-1]);
232		eclipsedir = argv[c++];
233		break;
234
235	    case 'l':				/* -l <size> */
236		argv[new_argc++] = argv[c];		/* shift */
237		if (++c + 1 > argc) usage(argv[c-1]);
238		argv[new_argc++] = argv[c];		/* shift */
239		ec_options.localsize = sizearg(argv[c++]);
240		if (ec_options.localsize < MIN_LOCAL) {
241		    ec_bad_exit("ECLiPSe: local stack size out of range.");
242		}
243		break;
244
245	    case 'h':				/* -h <size> */
246		argv[new_argc++] = argv[c];		/* shift */
247		if (++c + 1 > argc) usage(argv[c-1]);
248		argv[new_argc++] = argv[c];		/* shift */
249		ec_options.privatesize = sizearg(argv[c++]);
250		if (ec_options.privatesize < MIN_PRIVATE) {
251		    ec_bad_exit("ECLiPSe: Private heap size out of range.");
252		}
253		break;
254
255	    case 's':				/* -s <size> */
256		argv[new_argc++] = argv[c];		/* shift */
257		if (++c + 1 > argc) usage(argv[c-1]);
258		argv[new_argc++] = argv[c];		/* shift */
259		ec_options.sharedsize = sizearg(argv[c++]);
260		if (ec_options.sharedsize < MIN_SHARED) {
261		    ec_bad_exit("ECLiPSe: Shared heap size out of range.");
262		}
263		break;
264
265	    case 'o':				/* enable oracles */
266		c += 1;
267		vm_options = ORACLES_ENABLED;
268		break;
269
270	    case 'p':
271		argv[new_argc++] = argv[c];		/* shift */
272		if (++c + 1 > argc) usage(argv[c-2]);
273		argv[new_argc++] = argv[c];		/* shift */
274		ec_options.option_p = atoi(argv[c++]);
275		break;
276
277                /* Options processed by Prolog-level code */
278	    case 'b':				/* -b <bootfile> */
279	    case 'f':				/* -f <file> */
280	    case 'e':				/* -e <goal> */
281	    case 'L':				/* -L <language> */
282	    case 't':				/* -t <module> */
283		argv[new_argc++] = argv[c];		/* shift */
284		if (++c + 1 > argc) usage(argv[c-1]);
285		argv[new_argc++] = argv[c++];		/* shift */
286		break;
287
288	    case '-':				/* -- give the rest to Prolog */
289		for (; c < argc;)
290		    argv[new_argc++] = argv[c++];
291		break;
292
293	    default:				/* unknown: error */
294		usage(argv[c]);
295		break;
296	    }
297	}
298	else if (!strcmp(argv[c], "-debug_level"))
299	{
300	    if (++c + 1 > argc) usage(argv[c-1]);
301	    ec_options.debug_level = atoi(argv[c++]);
302	}
303	else if (!strcmp(argv[c], "-layout"))
304	{
305	    int	lflags = 0;
306	    char	*from = 0;
307	    char	*to = 0;
308	    long	increment = 0;
309
310	    if (++c + 1 <= argc)
311		lflags = (int) strtol(argv[c++], (char **) 0, 16);
312	    if (c + 1 <= argc)
313		increment = strtol(argv[c++], (char **) 0, 16);
314	    if (c + 1 <= argc)
315		from = (char *) strtol(argv[c++], (char **) 0, 16);
316	    if (c + 1 <= argc)
317		to = (char *) strtol(argv[c++], (char **) 0, 16);
318
319	    if (ec_options.allocation == ALLOC_FIXED)
320		    mem_layout();
321#ifdef HAVE_MMAP
322	    ec_layout(lflags, from, to, increment);
323#else
324	    ec_bad_exit("ECLiPSe: The -layout scan is not supported without\nmemory mapping.");
325#endif
326	}
327	else if (!strcmp(argv[c], "-norl"))
328	{
329	    argv[new_argc++] = argv[c++];		/* shift */
330	    ec_options.rl = 0;
331	}
332	else /* raise error unless preceeded by a -- option */
333	{
334	    usage(argv[c]);
335	}
336    }
337
338    /*----------------------------------------------------------------
339     * Initialize private heap as early as possible
340     * (must be before setup_mps())
341     *----------------------------------------------------------------*/
342    malloc_init();
343    irq_lock_init(delayed_break);
344
345    /*----------------------------------------------------------------
346     * Init message passing system
347     *----------------------------------------------------------------*/
348    if (ec_options.parallel_worker)
349    {
350	setup_mps(ec_options.parallel_worker, session, nsrv_hostname,
351			nsrv_port_number, init_flags & INIT_SHARED);
352    }
353
354    /*----------------------------------------------------------------
355     * Make the connection to the shared heap, if any.
356     * Because of mmap problems on some machines this should
357     * happen AFTER initializing the message passing system.
358     *----------------------------------------------------------------*/
359    mem_init(init_flags);	/* depends on -c and -m options */
360
361
362    /*----------------------------------------------------------------
363     * Init parallel scheduler etc.
364     *----------------------------------------------------------------*/
365    if (ec_options.parallel_worker)
366    {
367	parallel_init(init_flags);
368    }
369
370    /*----------------------------------------------------------------
371     * Init the low-level I/O stuff, ie the part which should
372     * really not be done by eclipse itself...
373     *----------------------------------------------------------------*/
374    /* char_io_init();  does not yet exist */
375
376
377    /*----------------------------------------------------------------
378     * Entry point after longjmp(reset)
379     *----------------------------------------------------------------*/
380
381    switch (setjmp(reset))
382    {
383    case 0:		/* raw boot or -r from above */
384	break;
385    case 3:		/* restore program state */
386    case 2:
387	init_flags = REINIT_SHARED|INIT_ENGINE|INIT_PRIVATE;
388	break;
389    case 4:		/* restore execution state */
390	init_flags = REINIT_SHARED|INIT_PRIVATE;
391	break;
392    case 1:		/* reset after fatal error */
393    default:
394	if (!(GlobalFlags & HEAP_READY) || ec_options.parallel_worker)
395	  {
396	    (void) ec_cleanup();
397	    exit(-1);
398	  }
399	init_flags = INIT_ENGINE;
400	switch (memory_corrupted++)
401	{
402	    case 0:
403		break;
404
405	    case 1:
406		/* try to print a message */
407		memory_corrupted = 2;
408		ec_bad_exit("ECLiPSe: Fatal error, memory corrupted.");
409		/* fall to */
410	    case 2:
411		/* we couldn't even print the message */
412		exit(-1);
413	}
414	break;
415    }
416
417
418    /*
419     * set up our own panic function which longjumps back to reset
420     * To access command line through global variabes
421     */
422    ec_options.user_panic = main_panic;
423    ec_options.Argc = new_argc;
424    ec_options.Argv = argv;
425    ec_options.eclipse_home = (char *) 0;
426    ec_options.init_flags = init_flags;
427    if (eclipsedir)
428	ec_options.eclipse_home = eclipsedir;
429
430
431    /*
432     * Init the global (shared) eclipse structures, dictionary, code...
433     * Maybe load a saved state.
434     * Note that we don't have an engine yet!
435     */
436
437    eclipse_global_init(init_flags);
438
439
440    /*----------------------------------------------------------------
441     * Setup the Prolog engine
442     *----------------------------------------------------------------*/
443
444    /*
445     * If we have a PROG_AND_DATA saved state (execution state saved)
446     * we are finished and enter the emulator.
447     */
448    if (!(init_flags & INIT_ENGINE))
449    {
450	err = restart_emulc();
451	(void) ec_cleanup();
452	exit(err);
453    }
454
455    /*
456     * Initialize the Prolog engine
457     */
458    emu_init(init_flags, vm_options);
459
460    /*
461     * If we are not running an already booted eclipse,
462     * compile $ECLIPSEDIR/lib/kernel.eco
463     */
464    if (init_flags & INIT_SHARED)
465    {
466	char msg[1024];
467
468	initfile = strcat(strcpy(bootfile_buf, ec_eclipse_home), "/lib/kernel.eco");
469	if (ec_access(initfile, R_OK) < 0)
470	{
471	    sprintf(msg,
472		"ECLiPSe: Can't find boot file %s!\nPlease check the setting of your ECLIPSEDIR environment variable\nor use the -D <dir> command line option.",
473		initfile);
474	    ec_bad_exit(msg);
475	}
476
477	err = eclipse_boot(initfile);
478	if (err != PSUCCEED)
479	{
480	    (void) ec_cleanup();
481	    exit(err);
482	}
483    }
484
485    if (init_flags & (INIT_SHARED|REINIT_SHARED))
486	GlobalFlags |= HEAP_READY;	/* for the other workers */
487
488    goal = ec_term(ec_did("main",1), ec_long(init_flags & INIT_SHARED ? 0 : 1));
489    module.val.did = d_.kernel_sepia;
490    module.tag.kernel = ModuleTag(d_.kernel_sepia);
491
492    if (ec_options.parallel_worker <= 1)	/* only or first worker */
493    {
494	err = main_emulc_noexit(goal.val, goal.tag, module.val, module.tag);
495	if (err == PYIELD)
496	{
497	    memory_corrupted = 0;	/* assume it's ok */
498	    ec_post_goal(ec_term(ec_did(":",2), ec_atom(ec_did("sepia_kernel",0)),
499		    ec_atom(ec_did("standalone_toplevel",0))));
500	    do {
501		err = ec_resume();
502	    } while (err == PYIELD);
503	}
504    }
505    else
506    {
507	err = slave_emulc();
508    }
509    ec_cleanup();
510    exit(err);
511    /*NOTREACHED*/
512}
513
514
515/*
516 * Print the warning about wrong usage and bad_exit.
517 * The argument is the bad option string.
518 */
519/*ARGSUSED*/
520static void
521usage(char *opt)
522{
523    ec_bad_exit(
524"Usage:\n\
525    -b <file>       compile or load a file on startup (deprecated, same as -f)\n\
526    -f <file>       compile or load a file on startup (.ecl or .eco)\n\
527    -e <goal>       goal to execute (in Prolog syntax)\n\
528    -g <kbytes>     global+trail stack size\n\
529    -l <kbytes>     local+control stack size\n\
530    -L <language>   default language dialect\n\
531    -h <kbytes>     private heap size\n\
532    -s <kbytes>     shared heap size\n\
533    -t <module>     name of initial toplevel module\n\
534    -d <seconds>    delayed startup\n\
535    -D <dir>        installation directory\n\
536    --              end of ECLiPSe options\n\
537Parallel system only:\n\
538    -w <num>        number of parallel workers\n\
539    -wmi            popup worker manager interface\n\
540    -wv             verbose worker startup\n\
541    -wx <exec>      use specified worker executable\n\
542Reserved:\n\
543    -a <><><><>\n\
544    -c <>\n\
545    -m <>\n\
546    -o \n\
547    -r <>\n"
548    );
549}
550
551static void
552main_panic(const char *what, const char *where)
553{
554    fprintf(stderr, "\n*** ECLiPSe fatal error: %s",what);
555
556    if (where)
557        fprintf(stderr, " in %s",where);
558
559    fprintf(stderr, "\n");
560    fflush(stderr);
561
562    longjmp(reset, 1);
563}
564
565
566#else /* _WIN32 */
567
568/*
569 * ECLiPSe C SOURCE MODULE
570 *
571 *
572 * Simplified standalone main() for Windows
573 *
574 */
575
576#include	<windows.h>
577#include 	"eclipse.h"
578#include	"os_support.h"
579
580
581#include <stdio.h>
582#include <errno.h>
583#include <setjmp.h>
584
585#ifdef STDC_HEADERS
586#include <stdlib.h>
587#include <string.h>
588#endif
589
590#ifndef ACCESS_IN_UNISTD
591#include <sys/file.h>
592#endif
593
594#ifdef STRTOL_UNDEF
595extern long strtol();
596#endif
597
598#define KB			1024
599#define MIN_LOCAL		100*KB
600#define MIN_GLOBAL		210*KB
601#define MIN_PRIVATE		210*KB
602#define MIN_SHARED		210*KB
603
604#define MAX_MEMORY	(SIGN_BIT/8*15)	/* 15/16 of the address space */
605
606/*
607 * LOCAL declarations
608 */
609
610static void main_panic(char *, char *);
611static void usage(char *);
612
613
614/*
615 * GLOBAL variable definitions
616 */
617
618/*
619 * To avoid infinite loops when the memory is corrupted, this flag
620 * is set when SEPIA did not manage it to print the prompt and start user query
621 * after a reset. 0 means ok, 1 is after a reset and before a query.
622 */
623static int	memory_corrupted = 0;
624
625jmp_buf         reset;
626
627static uword
628sizearg(char *arg)
629{
630    int last = strlen(arg) -1;
631    uword multiple = 0;
632    uword size;
633
634    switch(arg[last])
635    {
636    case 'k':
637    case 'K':
638	multiple = KB;
639	arg[last] = '\000';
640	break;
641    case 'm':
642    case 'M':
643	multiple = KB * KB;
644	arg[last] = '\000';
645	break;
646    case 'g':
647    case 'G':
648	multiple = KB * KB * KB;
649	arg[last] = '\000';
650	break;
651    case '0': case '1': case '2': case '3': case '4':
652    case '5': case '6': case '7': case '8': case '9':
653	multiple = KB;
654	break;
655    default:
656    	usage(arg);
657    }
658    size = (uword) atol(arg);
659    return (size > MAX_MEMORY/multiple) ? 0 : size * multiple;
660}
661
662main(int argc, char **argv)
663{
664    char *	eclipsedir = (char *) 0;
665    int		c, new_argc, err;
666    int		init_flags = INIT_SHARED|INIT_PRIVATE|INIT_ENGINE|INIT_PROCESS;
667    char *	session, * nsrv_hostname;
668    unsigned    nsrv_port_number;
669    uword	size;
670
671    /*
672     * If stdio is not a tty, get rid of the console window. This is not ideal
673     * since the window flashes up briefly, but no better solution yet.
674     * (The correct way would be not to build eclipse.exe as a "console
675     * application" and have a WinMain() instead of main(). But then we have
676     * to do all the setup of stdin/out/err, argc/argv, environment etc
677     * ourselves)
678     */
679    if (!isatty(_fileno(stdin))
680     && !isatty(_fileno(stdout))
681     && !isatty(_fileno(stderr)))
682    {
683	FreeConsole();
684    }
685
686    /*
687     * collect information from the command line
688     * remove some internally used arguments from the command line
689     */
690    for (c = new_argc = 1; c < argc; )
691    {
692	if (argv[c][0] == '-' && argv[c][2] == 0)	/* single char opt */
693	{
694	    switch (argv[c][1])
695	    {
696	    case 'a':			/* -a <worker> <session>
697                                              <nsrv_hostname> <nsrv_port_no> */
698		if (++c + 4 > argc) usage(argv[c-1]);
699		ec_set_option_int(EC_OPTION_PARALLEL_WORKER, atoi(argv[c++]));
700		session = argv[c++];
701		nsrv_hostname = argv[c++];
702		nsrv_port_number = atoi(argv[c++]);
703		break;
704
705	    case 'c':				/* -c <shared_map_file> */
706		if (++c + 1 > argc) usage(argv[c-1]);
707		ec_set_option_ptr(EC_OPTION_MAPFILE, argv[c++]);
708		ec_set_option_int(EC_OPTION_ALLOCATION, ALLOC_FIXED);
709		init_flags &= ~INIT_SHARED;
710		break;
711
712	    case 'm':				/* -m <shared_map_file> */
713		if (++c + 1 > argc) usage(argv[c-1]);
714		ec_set_option_ptr(EC_OPTION_MAPFILE, argv[c++]);
715		ec_set_option_int(EC_OPTION_ALLOCATION, ALLOC_FIXED);
716		break;
717
718	    case 'g':				/* -g <size> */
719		argv[new_argc++] = argv[c];		/* shift */
720		if (++c + 1 > argc) usage(argv[c-1]);
721		argv[new_argc++] = argv[c];		/* shift */
722		size = sizearg(argv[c++]);
723		ec_set_option_long(EC_OPTION_GLOBALSIZE, size);
724		if (size < MIN_GLOBAL) {
725		    fprintf(stderr,"Global stack size out of range\n");
726		    exit(-1);
727		}
728		break;
729
730	    case 'd':				/* -d <n> */
731		/* delay worker startup by <n> seconds */
732		if (++c + 1 > argc) usage(argv[c-1]);
733		Sleep(1000 * atoi(argv[c++]));
734		break;
735
736	    case 'D':				/* -D <eclipsedir> */
737		if (++c + 1 > argc) usage(argv[c-1]);
738		eclipsedir = argv[c++];
739		break;
740
741	    case 'l':				/* -l <size> */
742		argv[new_argc++] = argv[c];		/* shift */
743		if (++c + 1 > argc) usage(argv[c-1]);
744		argv[new_argc++] = argv[c];		/* shift */
745		size = sizearg(argv[c++]);
746		ec_set_option_long(EC_OPTION_LOCALSIZE, size);
747		if (size < MIN_LOCAL) {
748		    fprintf(stderr,"Local stack size out of range\n");
749		    exit(-1);
750		}
751		break;
752
753	    case 'h':				/* -h <size> */
754		argv[new_argc++] = argv[c];		/* shift */
755		if (++c + 1 > argc) usage(argv[c-1]);
756		argv[new_argc++] = argv[c];		/* shift */
757		size = sizearg(argv[c++]);
758		ec_set_option_long(EC_OPTION_PRIVATESIZE, size);
759		if (size < MIN_PRIVATE) {
760		    fprintf(stderr,"Private heap size out of range\n");
761		    exit(-1);
762		}
763		break;
764
765	    case 's':				/* -s <size> */
766		argv[new_argc++] = argv[c];		/* shift */
767		if (++c + 1 > argc) usage(argv[c-1]);
768		argv[new_argc++] = argv[c];		/* shift */
769		size = sizearg(argv[c++]);
770		ec_set_option_long(EC_OPTION_SHAREDSIZE, size);
771		if (size < MIN_SHARED) {
772		    fprintf(stderr,"Shared heap size out of range\n");
773		    exit(-1);
774		}
775		break;
776
777	    case 'o':				/* enable oracles */
778		c += 1;
779		/* vm_options = ORACLES_ENABLED; */
780		break;
781
782                /* Options processed by Prolog-level code */
783	    case 'b':				/* -b <bootfile> */
784	    case 'f':				/* -f <file> */
785	    case 'e':				/* -e <goal> */
786	    case 'L':				/* -L <language> */
787	    case 't':				/* -t <module> */
788		argv[new_argc++] = argv[c];		/* shift */
789		if (++c + 1 > argc) usage(argv[c-1]);
790		argv[new_argc++] = argv[c++];		/* shift */
791		break;
792
793	    case '-':				/* -- give the rest to Prolog */
794		for (; c < argc; )
795		    argv[new_argc++] = argv[c++];
796		break;
797
798	    default:				/* unknown: error */
799		usage(argv[c]);
800		break;
801	    }
802	}
803	else if (!strcmp(argv[c], "-debug_level"))
804	{
805	    if (++c + 1 > argc) usage(argv[c-1]);
806	    ec_set_option_int(EC_OPTION_DEBUG_LEVEL, atoi(argv[c++]));
807	}
808	else /* raise error unless preceeded by a -- option */
809	{
810	    usage(argv[c]);
811	}
812    }
813
814    /*----------------------------------------------------------------
815     * Entry point after longjmp(reset)
816     *----------------------------------------------------------------*/
817
818    switch (setjmp(reset))
819    {
820    case 0:		/* raw boot or -r from above */
821	break;
822    case 3:		/* restore program state */
823    case 2:
824	init_flags = REINIT_SHARED|INIT_ENGINE|INIT_PRIVATE;
825	break;
826    case 4:		/* restore execution state */
827	init_flags = REINIT_SHARED|INIT_PRIVATE;
828	break;
829    case 1:		/* reset after fatal error */
830    default:
831	init_flags = INIT_ENGINE;
832	switch (memory_corrupted++)
833	{
834	    case 0:
835		break;
836
837	    case 1:
838		/* try to print a message */
839		memory_corrupted = 2;
840		fprintf(stderr,"\n*** SEPIA Fatal error: memory corrupted\n");
841		/* fall to */
842	    case 2:
843		/* we couldn't even print the message */
844		exit(-1);
845	}
846	break;
847    }
848
849    /*
850     * set up our own panic function which longjumps back to reset
851     */
852    ec_set_option_ptr(EC_OPTION_PANIC, main_panic);
853
854    ec_set_option_int(EC_OPTION_INIT, init_flags);
855    ec_set_option_int(EC_OPTION_ARGC, new_argc);
856    ec_set_option_ptr(EC_OPTION_ARGV, argv);
857    if (eclipsedir)
858	ec_set_option_ptr(EC_OPTION_ECLIPSEDIR, eclipsedir);
859
860    ec_init();
861    ec_post_goal(ec_term(ec_did(":",2), ec_atom(ec_did("sepia_kernel",0)),
862	    ec_atom(ec_did("standalone_toplevel",0))));
863    do {
864	err = ec_resume();
865    } while (err == PYIELD);
866    ec_cleanup();
867    return err;
868}
869
870
871/*
872 * Print the warning about wrong usage and bad_exit.
873 * The argument is the bad option string.
874 */
875/*ARGSUSED*/
876static void
877usage(char *opt)
878{
879    fprintf(stderr,"Bad option: %s\n",opt);
880    fprintf(stderr,"Usage:\n");
881    fprintf(stderr,"-b <file>       compile or load file on startup (deprecated, same as -f)\n");
882    fprintf(stderr,"-f <file>       compile or load file on startup (.ecl or .eco)\n");
883    fprintf(stderr,"-e <goal>       goal to execute (in Prolog syntax)\n");
884    fprintf(stderr,"-g <kbytes>     global+trail stack size\n");
885    fprintf(stderr,"-l <kbytes>     local+control stack size\n");
886    fprintf(stderr,"-L <language>   default language dialect\n");
887    fprintf(stderr,"-h <kbytes>     private heap size\n");
888    fprintf(stderr,"-s <kbytes>     shared heap size\n");
889    fprintf(stderr,"-t <module>     name of initial toplevel module\n");
890    fprintf(stderr,"-d <seconds>    delayed startup\n");
891    fprintf(stderr,"-D <dir>        installation directory\n");
892    fprintf(stderr,"--              end of ECLiPSe options\n");
893    fprintf(stderr,"Parallel system only:\n");
894    fprintf(stderr,"-w <num>        number of parallel workers\n");
895    fprintf(stderr,"-wmi            popup worker manager interface\n");
896    fprintf(stderr,"-wv             verbose worker startup\n");
897    fprintf(stderr,"-wx <exec>      use specified worker executable\n");
898    fprintf(stderr,"Reserved:\n");
899    fprintf(stderr,"-a <><><><>\n");
900    fprintf(stderr,"-c <>\n");
901    fprintf(stderr,"-m <>\n");
902    fprintf(stderr,"-o \n");
903    fprintf(stderr,"-r <>\n");
904    exit(-1);
905}
906
907static void
908main_panic(char *what, char *where)
909{
910    fprintf(stderr, "\n*** ECLiPSe fatal error: %s",what);
911
912    if (where)
913        fprintf(stderr, " in %s",where);
914
915    fprintf(stderr, "\n");
916    fflush(stderr);
917
918    longjmp(reset, 1);
919}
920
921#endif
922