home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * Crtinit: C run-time initialization code.
- * Written by Eric R. Smith, and placed in the public domain.
- * Use at your own risk.
- *
- * 01/03/89 ++jrb
- * The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
- *
- * _stksize meaning
- * -1L keep all of memory (except MINFREE at top) and do
- * mallocs from own heap, with heap grown upwards towards
- * stack, and the stack growing down towards heap,
- * with a minimum slush between them so that they
- * dont meet (only checked while malloc'ing). With
- * this model, further spawning is not possible, but it is
- * well suited for programs such as gcc-cc1 etc.
- * Thanks to Piet van Oostrum & Atze Dijkstra for this idea
- *
- * 0L keep minimum amount of memory. this is also the
- * case when _stksize is undefined by the user.
- * 1L keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
- * 2L keep 2/4 (1/2), free rest
- * 3L keep 3/4, free 1/4
- * other keep that many bytes
- * -other keep |other| bytes, use the heap for mallocs
- *
- * 02/14/90 ++jrb (thanks edgar)
- * auto acc detect
- * undump friendly
- *
- * NOTE: dumping applications should use _initial_stack instead: if
- * !=0, then _stksize is initialized from _initial_stack, and
- * mallocs are always from internal heap. (TeX works much better now),
- * thanks edgar!
- *
- * Acc convention:
- * user sets _heapbase to bottom of stack + heap area
- * sets _stksize to the size of this area
- * at startup, sp will be set to top of this area
- * (_heapbase + _stksize ) and malloc()'s will happen from heap.
- * (note malloc() and *not* Malloc())
- *
- * 02/16/90 ++jrb
- * - bug fix: dont get screwed by desktop launch when fast bit is set
- * convert env string to format usable
- * (atari get your act together!!)
- */
-
- #include <basepage.h>
- #include <osbind.h>
-
- #define isspace(c) ((c) == ' '||(c) == '\t')
- #define BUFSIZ ((unsigned long)1024) /* this must track the value */
- /* in stdio.h */
- #define MINFREE (8L * 1024L) /* free at least this much mem */
- /* on top */
- #define MINKEEP (8L * 1024L) /* keep at least this much mem */
-
- BASEPAGE *_base;
- char **environ;
- static long argc;
- static char **argv;
-
- /*
- * initial stack is used primarily by dumping application,
- * if it is, malloc is always from heap, and _stksize is init
- * from initial_stack (to preserve the value in the undumped run)
- */
- long _initial_stack; /* .comm __initial_size, 4 */
- extern long _stksize; /* picked up from user or from stksiz.c */
-
- /* set to heap base addr when _stksize == -1L || _initial_stack || When DA */
- void *_heapbase;
-
- /* default sizeof stdio buffers */
- unsigned long __DEFAULT_BUFSIZ__; /* .comm */
-
- /* are we an app? */
- short _app;
-
- static long parseargs();
- static void setup_handlers __PROTO((void));
- __EXTERN void _main __PROTO((long, char **, char **));
- __EXTERN void _init_signal __PROTO((void));
- __EXTERN void monstartup __PROTO((void *lowpc, void *highpc));
- __EXTERN void _mcleanup __PROTO((void));
- __EXTERN void moncontrol __PROTO((long));
-
-
- /*
- * accessories start here:
- */
-
- static char *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
-
- void _acc_main()
- {
- _app = 0; /* this is an accessory */
- _main(1L, acc_argv, acc_argv);
- /*NOTREACHED*/
- }
-
- /* functions in crt0.s or gcrt0.s */
- extern void _setstack(), _monstartup(), _moncontrol(), __mcleanup();
-
- void _crtinit()
- {
- register BASEPAGE *bp;
- register long m;
- register long freemem;
-
- _app = 1; /* its an application */
- if(!__DEFAULT_BUFSIZ__)
- __DEFAULT_BUFSIZ__ = BUFSIZ;
-
- bp = _base;
- m = parseargs(bp); /* m = # bytes used by environment + args */
-
- /* make m the total number of bytes required by program sans stack/heap */
- m += (bp->p_tlen + bp->p_dlen + bp->p_blen);
- m = (m + 3L) & (~3L);
- /* freemem the amount of free mem accounting for MINFREE at top */
- if((freemem = (long)bp->p_hitpa - (long)bp->p_tbase - MINFREE - m) <= 0L)
- goto notenough;
-
- if(_initial_stack)
- {
- /* the primary use of _initial_stack will be in dumping */
- /* applications where only a heap for malloc makes sense */
- _heapbase = (void *) ((long)bp->p_tbase + m);
- _stksize = _initial_stack;
- }
-
- switch(_stksize)
- {
- case -1L: /* keep all but MINFREE, and malloc from own heap */
- _stksize = freemem;
- _heapbase = (void *) ((long)bp->p_tbase + m);
- break;
-
- case 0L: /* free all but MINKEEP */
- _stksize = MINKEEP;
- break;
-
- case 1L: /* keep 1/4, free 3/4 */
- _stksize = freemem >> 2;
- break;
-
- case 2L: /* keep 1/2, free 1/2 */
- _stksize = freemem >> 1;
- break;
-
- case 3L: /* keep 3/4, free 1/4 */
- _stksize = freemem - (freemem >> 2);
- break;
-
- default:
- if(_stksize < 0) { /* keep |_stksize|, use heap for mallocs */
- _stksize = -_stksize;
- _heapbase = (void *)((long)bp->p_tbase + m);
- }
- }
-
- /* make m the total number of bytes including stack */
- _stksize = _stksize & (~3L);
- m += _stksize;
-
- /* make sure there's enough room for the stack */
- if ((((long)bp->p_tbase) + m) > ((long)bp->p_hitpa - MINFREE))
- goto notenough;
-
- /* set up the new stack to bp->p_tbase + m */
- _setstack(bp->p_tbase + m);
-
- /* shrink the TPA */
- /* this is right only if bp == bp->p_tbase - sizeof(BASEPAGE) */
- (void)Mshrink(bp, m + sizeof(BASEPAGE));
-
- /* establish handlers, call the main routine */
- setup_handlers();
-
- /* start profiling, if we were linked with crt0.o */
- _monstartup((void *)(bp->p_tbase),
- (void *)((long)bp->p_tbase + bp->p_tlen));
-
- _main(argc, argv, environ);
- /* not reached normally */
-
- notenough:
- Cconws("Fatal error: insufficient memory\r\n");
- Pterm(-1);
- }
-
-
- /*
- * parseargs(bp): parse the environment and arguments pointed to by the
- * basepage. Return the number of bytes of environment and arguments
- * that have been appended to the bss area (the environ and argv arrays
- * are put here, as is a temporary buffer for the command line, if
- * necessary).
- *
- * The MWC extended argument passing scheme is assumed.
- *
- */
-
- static long parseargs(bp)
- BASEPAGE *bp;
- {
- long count = 4; /* compensate for aligning */
- long i;
- char *from, *cmdln, *to;
- char **envp, **arg;
- /* flag to indicate desktop-style arg. passing */
- long desktoparg = 0;
-
- /* handle the environment first */
-
- environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
- from = bp->p_env;
- while (*from) {
-
- /* if we find MWC arguments, tie off environment here */
- if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
- *(from+3) == 'V' && *(from+4) == '=') {
- *envp++ = (char *) 0; count += 4;
- *from++ = 0;
- #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
- if (bp->p_cmdlin[0] != 127)
- goto old_cmdlin;
- #endif
- while (*from++) ; /* skip ARGV= string */
- argv = arg = envp++;
- *arg++ = from; count+= 4;
- while (*from++) ; /* skip argv[0] */
- goto do_argc;
- }
- *envp++ = from;
- count += 4;
- desktoparg = 1;
- while (*from) {
- if (*from == '=') {
- desktoparg = 0;
- }
- from++;
- }
- from++; /* skip 0 */
-
- /* the desktop (and some shells) use the environment in the wrong
- way, putting in "PATH=\0C:\0" instead of "PATH=C:". so if we
- find an "environment variable" without an '=' in it, we
- see if the last environment variable ended with '=\0', and
- if so we append this one to the last one
- */
- if(desktoparg && envp > &environ[1])
- {
- /* launched from desktop -- fix up env */
- char *p, *q;
-
- q = envp[-2]; /* current one is envp[-1] */
- while (*q) q++;
- if (q[-1] == '=') {
- p = *--envp;
- while(*p)
- *q++ = *p++;
- *q = '\0';
- }
- }
- }
- *envp++ = (char *)0;
- count += 4;
-
- /* old_cmdlin: */
- /* Allocate some room for the command line to be parsed */
- cmdln = bp->p_cmdlin;
- i = *cmdln++;
- from = to = (char *) envp;
- if (i > 0) {
- count += (i&(~3));
- envp = (char **) ( ((long) envp) + (i&(~3)) );
- }
- envp += 2; count += 8;
-
- /* Now parse the command line and put argv after the environment */
-
- argv = arg = envp;
- *arg++ = ""; /* argv[0] not available */
- count += 4;
- while(i > 0 && isspace(*cmdln) )
- cmdln++,--i;
-
- while (i > 0) {
- if (isspace(*cmdln)) {
- --i; cmdln++;
- while (i > 0 && isspace(*cmdln))
- --i,cmdln++;
- *to++ = 0;
- }
- else {
- if (!(*to++ = *cmdln++)) break;
- --i;
- }
- }
- *to++ = '\0';
- *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
- /* the loop below expects \0\0 at end to terminate! */
- /* the byte @ cmdln[i+2] != 0 when fast bit is set */
- do_argc:
- argc = 1; /* at this point argv[0] is done */
- while (*from) {
- *arg++ = from;
- argc++;
- count += 4;
- while(*from++) ;
- }
- *arg++ = (char *) 0;
- return count+4;
- }
-
- static void setup_handlers()
- {
- _init_signal();
- }
-
- /*
- * _exit: does the actual exiting. Note that _moncontrol and __mcleanup are
- * dummies in crt0.s, but do something in gcrt0.s
- */
-
- void _exit(status)
- int status;
- {
- _moncontrol(0L);
- __mcleanup();
- Pterm(status);
- }
-