home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
mint
/
mntlib16.lzh
/
MNTLIB16
/
CRTINIT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
9KB
|
337 lines
/*
*
* 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);
}