home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib32.zoo / crtinit.c < prev    next >
C/C++ Source or Header  |  1993-05-23  |  13KB  |  505 lines

  1. /*
  2.  *
  3.  * Crtinit: C run-time initialization code.
  4.  * Written by Eric R. Smith, and placed in the public domain.
  5.  * Use at your own risk.
  6.  *
  7.  * 01/03/89 ++jrb
  8.  *    The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
  9.  *
  10.  *    _stksize            meaning
  11.  *      -1L        keep all of memory (except MINFREE at top) and do
  12.  *            mallocs from own heap, with heap grown upwards towards
  13.  *            stack, and the stack growing down towards heap,
  14.  *            with a minimum slush between them so that they
  15.  *            dont meet (only checked while malloc'ing). With
  16.  *            this model, further spawning is not possible, but it is
  17.  *            well suited for programs such as gcc-cc1 etc.
  18.  *            Thanks to Piet van Oostrum & Atze Dijkstra for this idea
  19.  *
  20.  *    0L        keep minimum amount of memory. this is also the
  21.  *            case when _stksize is undefined by the user.
  22.  *    1L        keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
  23.  *    2L        keep 2/4 (1/2), free rest
  24.  *    3L        keep 3/4, free 1/4
  25.  *    other        keep that many bytes
  26.  *    -other        keep |other| bytes, use the heap for mallocs
  27.  *
  28.  * 02/14/90 ++jrb (thanks edgar)
  29.  *    auto acc detect
  30.  *    undump friendly
  31.  *
  32.  * NOTE: dumping applications should use _initial_stack instead: if
  33.  *     !=0, then _stksize is initialized from _initial_stack, and
  34.  *     mallocs are always from internal heap. (TeX works much better now),
  35.  *     thanks edgar!
  36.  *
  37.  * Acc convention:
  38.  *      Preferred: user sets _stksize, then _heapbase is set to Malloc(_stksize)
  39.  *      sp to _heapbase + _stksize and all mallocs happen from heap
  40.  *
  41.  *      Old way:
  42.  *    user sets _heapbase to bottom of stack + heap area
  43.  *         sets _stksize to the size of this area
  44.  *         at startup, sp will be set to top of this area
  45.  *         (_heapbase  + _stksize ) and malloc()'s will happen from heap.
  46.  *        (note malloc() and *not* Malloc())
  47.  *
  48.  * 02/16/90 ++jrb
  49.  *  - bug fix: dont get screwed by desktop launch when fast bit is set
  50.  *             convert env string to format usable
  51.  *        (atari get your act together!!)
  52.  *
  53.  * 09-20-92 hyc
  54.  *    Support base relative addressing, for shared-text execution.
  55.  *    Also merged in some stuff from ++jrb's crt0.c.
  56.  *
  57.  * Turbo / Pure C version 21-6-92 um
  58.  *   the Turbo / Pure linker reserves stack space in the BSS and sets
  59.  *   the symbol _StkSize to its size. If _StkSize is set to 0, we use
  60.  *   _stksize etc. as usual
  61.  *
  62.  * 19 Jan 93 hohmuth
  63.  *    new variable _PgmSize, holds size of program area
  64.  *    (useful when doing Ptermres)
  65.  *
  66.  * 08 Apr 93 hohmuth
  67.  *    added support for ARGV standard extension allowing empty arguments
  68.  *
  69.  */
  70.  
  71. /* define this symbol to get ARGV argument passing that's strictly
  72.  * compatible with the Atari standard. If it's not defined, then
  73.  * the startup code won't validate the ARGV= variable by checking
  74.  * the command byte for 0x127. Note that there are still some
  75.  * applications (gulam is a notable example) that implement only
  76.  * part of the standard and don't set the command byte to 0x127.
  77.  */
  78.  
  79. #if 0
  80. #define STRICTLY_COMPATIBLE_WITH_STANDARD
  81. #endif
  82.  
  83. #include <basepage.h>
  84. #include <osbind.h>
  85. #include "lib.h"
  86.  
  87. #define isspace(c) ((c) == ' '||(c) == '\t')
  88. #define isdigit(c) ((c) >= '0' && (c) <= '9')
  89.  
  90. #define MINFREE    (8L * 1024L)        /* free at least this much mem */
  91.                     /* on top */
  92. #define MINKEEP (8L * 1024L)        /* keep at least this much mem */
  93.  
  94. BASEPAGE *_base;
  95. char **environ;
  96. static long argc;
  97. static char **argv;
  98.  
  99. /* size to be allocated for the stack */
  100. extern long _stksize;        /* picked up from user or from stksiz.c */
  101.  
  102. /* set to heap base addr when _stksize < 0 || _initial_stack || When DA
  103.  * note that we allow the user to provide a _heapbase of their own, since
  104.  * that used to be necessary for acc's; but that is no longer needed
  105.  * (or encouraged) since the acc startup code now Mallocs a heap
  106.  * automatically
  107.  */
  108. extern void *_heapbase;        /* picked up from user or from heapbase.c */
  109.  
  110. /*
  111.  * initial stack is used primarily by dumping application,
  112.  * if it is, malloc is always from heap, and _stksize is init
  113.  * from initial_stack (to preserve the value in the undumped run)
  114.  */
  115. extern long _initial_stack;    /* picked up from user or from inistack.c */
  116.  
  117. unsigned long _PgmSize;        /* total size of program area */
  118.  
  119. #ifdef __TURBOC__
  120. char *_StkLim;    /* for Turbo / Pure C stack checking */
  121. extern _StkSize; /* set by linker */
  122. #endif
  123.  
  124. /* default sizeof stdio buffers */
  125. size_t __DEFAULT_BUFSIZ__;    /* .comm             */
  126.  
  127. /* are we an app? */
  128. short _app;
  129.  
  130. /* are we on a split addr mem ST */
  131. short _split_mem = 0;
  132.  
  133. static long parseargs    __PROTO((BASEPAGE *));
  134. static void setup_handlers    __PROTO((void));
  135. __EXTERN void _main    __PROTO((long, char **, char **));
  136. __EXTERN void _init_signal    __PROTO((void));
  137. __EXTERN void _monstartup __PROTO((void *lowpc, void *highpc));
  138. __EXTERN void __mcleanup __PROTO((void));
  139. __EXTERN void _moncontrol __PROTO((long));
  140. __EXTERN void _setstack __PROTO((char *));
  141.  
  142. /*
  143.  * accessories start here:
  144.  */
  145.  
  146. static char    *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
  147.  
  148. void _acc_main()
  149. {
  150. #ifdef __TURBOC__
  151.     if (&_StkSize == 0)
  152.     {
  153. #endif
  154.  
  155.     if (_stksize == 0 || _stksize == -1L)
  156.         _stksize = MINKEEP;
  157.  
  158.     if (_stksize < 0)
  159.         _stksize = -_stksize;
  160.     _stksize &= 0xfffffffeL;    /* stack on word boundary */
  161.  
  162. #ifdef __TURBOC__
  163.     }
  164.     else
  165.     {
  166.         /* This compound statement is executed if the Pure linker
  167.         has reserved space for the stack in the BSS */
  168.         _stksize = (long) &_StkSize;
  169.         _heapbase = _base->p_bbase + _base->p_blen - _stksize;
  170.     }
  171.     _StkLim = (char *) _heapbase + 256;     /* for stack checking */
  172. #endif
  173.   
  174.     if (_heapbase == 0) {
  175.         _heapbase = (void *)Malloc(_stksize);
  176.     }
  177.     _setstack((char *) _heapbase + _stksize);
  178.     _app = 0;                /* this is an accessory */
  179.  
  180.     _main(1L, acc_argv, acc_argv);
  181.     /*NOTREACHED*/
  182. }
  183.  
  184. void _crtinit()
  185. {
  186.     register BASEPAGE *bp;
  187.     register long m;
  188.     register long freemem;
  189. #ifdef __GNUC__
  190.     extern void etext();    /* a "function" to fake out pc-rel addressing */
  191. #endif
  192.     _app = 1;    /* its an application */
  193.     if(!__DEFAULT_BUFSIZ__)
  194.         __DEFAULT_BUFSIZ__ = BUFSIZ;
  195.  
  196.     bp = _base;
  197.  
  198.     m = parseargs(bp);    /* m = # bytes used by environment + args */
  199.  
  200. /* make m the total number of bytes required by program sans stack/heap */
  201.     m += (bp->p_tlen + bp->p_dlen + bp->p_blen + sizeof(BASEPAGE));
  202.     m = (m + 3L) & (~3L);
  203.  
  204. #ifdef __TURBOC__
  205.     if (&_StkSize == 0)
  206.     {
  207. #endif
  208.  
  209. /* freemem the amount of free mem accounting for MINFREE at top */
  210.     if((freemem = (long)bp->p_hitpa - (long)bp - MINFREE - m) <= 0L)
  211.         goto notenough;
  212.     
  213.     if(_initial_stack)
  214.     {
  215.         /* the primary use of _initial_stack will be in dumping */
  216.         /* applications where only a heap for malloc makes sense */
  217.         _heapbase = (void *) ((long)bp + m);
  218.         _stksize = _initial_stack;
  219.     } else {
  220.         if (_stksize >= -1L)
  221.         _split_mem = 1; /* malloc from Malloc first, then from own heap */
  222.     }
  223.  
  224.     if (_stksize == -1L) {
  225.         _stksize = freemem;
  226.         _heapbase = (void *) ((long)bp + m);
  227.     } else if (_stksize == 0L) {    /* free all but MINKEEP */
  228.         _stksize = MINKEEP;
  229.     } else if (_stksize == 1L) {     /* keep 1/4, free 3/4 */
  230.         _stksize = freemem >> 2;
  231.     } else if (_stksize ==  2L) {    /* keep 1/2, free 1/2 */
  232.         _stksize = freemem >> 1;
  233.     } else if (_stksize == 3L) {    /* keep 3/4, free 1/4 */
  234.         _stksize = freemem - (freemem >> 2); 
  235.     } else {
  236.         if(_stksize < -1L) { /* keep |_stksize|, use heap for mallocs */
  237.         _stksize = -_stksize;
  238.         _heapbase = (void *)((long)bp + m);
  239.         }
  240.     }
  241.     
  242. /* make m the total number of bytes including stack */
  243.     _stksize = _stksize & (~3L);
  244.     m += _stksize;
  245.  
  246. /* make sure there's enough room for the stack */
  247.     if (((long)bp + m) > ((long)bp->p_hitpa - MINFREE))
  248.         goto notenough;
  249.  
  250. /* set up the new stack to bp + m  */
  251.  
  252. #ifdef __TURBOC__
  253.     {
  254.         char *tmp;
  255.         tmp = (char *) bp + m;
  256.         _setstack(tmp);
  257.         _StkLim = tmp - _stksize + 256; /* for stack checking */
  258.     }
  259. #else
  260.     _setstack((char *)bp + m);
  261. #endif
  262.  
  263. #ifdef __TURBOC__
  264.     } /* if (&_StkSize == 0) */
  265.     else
  266.     {
  267.         /* This compound statement is executed if the Pure linker
  268.         has reserved space for the stack in the BSS */
  269.         _stksize = (long) &_StkSize;
  270.         _stksize = _stksize & (~3L);
  271.         
  272.         {
  273.             char *tmp;
  274.             tmp = (char *) bp->p_bbase + bp->p_blen;
  275.             _setstack(tmp);
  276.             _StkLim = tmp - _stksize + 256; /* for stack checking */
  277.             _heapbase = NULL; /* no mallocs from heap */
  278.         }
  279.     }
  280. #endif /* __TURBOC__ */
  281.  
  282. /* shrink the TPA */
  283.     (void)Mshrink(bp, m);
  284.  
  285. /* keep length of program area */
  286.     _PgmSize = m;
  287.  
  288. /* establish handlers,  call the main routine */
  289.     setup_handlers();
  290.  
  291. /* start profiling, if we were linked with gcrt0.o */
  292. #ifdef __GNUC__
  293.     _monstartup((void *)bp->p_tbase, (void *)((long)etext - 1));
  294. #else
  295.     _monstartup((void *)(bp->p_tbase), 
  296.            (void *)((long)bp->p_tbase +  bp->p_tlen));
  297. #endif
  298.  
  299.     _main(argc, argv, environ);
  300.     /* not reached normally */
  301.  
  302. notenough:
  303.     Cconws("Fatal error: insufficient memory\r\n");
  304.         Pterm(-1);
  305. }
  306.  
  307.  
  308. /*
  309.  * parseargs(bp): parse the environment and arguments pointed to by the
  310.  * basepage. Return the number of bytes of environment and arguments
  311.  * that have been appended to the bss area (the environ and argv arrays
  312.  * are put here, as is a temporary buffer for the command line, if
  313.  * necessary).
  314.  *
  315.  * The MWC extended argument passing scheme is assumed.
  316.  *
  317.  */
  318.  
  319. static long parseargs(bp)
  320.     BASEPAGE *bp;
  321. {
  322.     long count = 4;        /* compensate for aligning */
  323.     long  i;
  324.     char *from, *cmdln, *to;
  325.     char **envp, **arg;
  326.     char *null_list = 0;
  327. /* flag to indicate desktop-style arg. passing */
  328.     long desktoparg = 0;
  329.  
  330. /* handle the environment first */
  331.  
  332.     environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
  333.     from = bp->p_env;
  334.     while (*from) {
  335.  
  336. /* if we find MWC arguments, tie off environment here */
  337.         if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
  338.             *(from+3) == 'V' && *(from+4) == '=')
  339.         {
  340.             *envp++ = (char *) 0; count += 4;
  341.             *from = 0;
  342. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  343.             if (bp->p_cmdlin[0] != 127)
  344.                 goto old_cmdlin;
  345. #endif
  346.             from += 5;        /* skip ARGV= string */
  347.  
  348.             /* find list of empty params
  349.              */
  350.             if (*from == 'N' && *(from+1) == 'U'
  351.                 && *(from+2) == 'L' && *(from+3) == 'L' 
  352.                 && *(from+4) == ':')
  353.             {
  354.                 null_list = from + 5;
  355.             }
  356.                 
  357.             while (*from++) ; /* skip ARGV= value */
  358.             argv = arg = envp++;
  359.             *arg++ = from; count+= 4;
  360.             while (*from++) ; /* skip argv[0] */
  361.             goto do_argc;
  362.         }
  363.         *envp++ = from;
  364.         count += 4;
  365.         desktoparg = 1;
  366.         while (*from) {
  367.             if (*from == '=') {
  368.                 desktoparg = 0;
  369.             }
  370.             from++;
  371.         }
  372.         from++;        /* skip 0 */
  373.  
  374. /* the desktop (and some shells) use the environment in the wrong
  375.    way, putting in "PATH=\0C:\0" instead of "PATH=C:". so if we
  376.    find an "environment variable" without an '=' in it, we
  377.    see if the last environment variable ended with '=\0', and
  378.    if so we append this one to the last one
  379.  */
  380.         if(desktoparg && envp > &environ[1]) 
  381.         {
  382.         /* launched from desktop -- fix up env */
  383.             char *p, *q;
  384.  
  385.             q = envp[-2];    /* current one is envp[-1] */
  386.             while (*q) q++;
  387.             if (q[-1] == '=') {
  388.             p = *--envp;
  389.             while(*p)
  390.                *q++ = *p++;
  391.                 *q = '\0';
  392.            }
  393.         }
  394.     }
  395.     *envp++ = (char *)0;
  396.     count += 4;
  397.  
  398. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  399. old_cmdlin:
  400. #endif
  401. /* Allocate some room for the command line to be parsed */
  402.     cmdln = bp->p_cmdlin;
  403.     i = *cmdln++;
  404.     from = to = (char *) envp;
  405.     if (i > 0) {
  406.         count += (i&(~3));
  407.         envp = (char **) ( ((long) envp)  + (i&(~3)) );
  408.     }
  409.     envp += 2; count += 8;
  410.  
  411. /* Now parse the command line and put argv after the environment */
  412.  
  413.     argv = arg = envp;
  414.     *arg++ = "";        /* argv[0] not available */
  415.     count += 4;
  416.     while(i > 0 && isspace(*cmdln) )
  417.         cmdln++,--i;
  418.  
  419.     while (i > 0) {
  420.         if (isspace(*cmdln)) {
  421.             --i; cmdln++;
  422.             while (i > 0 && isspace(*cmdln))
  423.                 --i,cmdln++;
  424.             *to++ = 0;
  425.         }
  426.         else {
  427.             if ((*to++ = *cmdln++) == 0) break;
  428.             --i;
  429.         }
  430.     }
  431.     *to++ = '\0';
  432.     *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
  433.     /* the loop below expects \0\0 at end to terminate! */
  434.     /* the byte @ cmdln[i+2] != 0 when fast bit is set */
  435. do_argc:
  436.     argc = 1;        /* at this point argv[0] is done */
  437.     while (*from) {
  438.         *arg++ = from;
  439.         argc++;
  440.         count += 4;
  441.         while(*from++) ;
  442.     }
  443.     *arg++ = (char *) 0;
  444.  
  445.     /* zero epmty params
  446.      */
  447.     if (null_list) {
  448.         char *s;
  449.         unsigned long idx;
  450.  
  451.         while (*null_list) {
  452.             s = null_list;
  453.             
  454.             while (* ++null_list) {    /* find ',' or '\0' */
  455.                 if (*null_list == ',') {
  456.                     *null_list++ = 0;
  457.                     break;
  458.                 }
  459.             }
  460.             
  461.             idx = 0;
  462.             for (;;) {
  463.                 if (! isdigit(*s))
  464.                     goto bail_out;
  465.                     
  466.                 /* don't feed this to strtol(),
  467.                  * do the ascii -> long conversion by 
  468.                  * hand for efficency
  469.                  */
  470.                 idx += *s++ - '0';
  471.                 if (*s)
  472.                     idx = (idx << 3) + (idx << 1);
  473.                 else
  474.                     break;
  475.             }
  476.         
  477.             if (idx < argc)
  478.                 *(argv[idx]) = 0;
  479.             else
  480.                 goto bail_out;
  481.         }
  482.     }
  483.  
  484. bail_out:
  485.     return count+4;
  486. }
  487.  
  488. static void setup_handlers()
  489. {
  490.     _init_signal();
  491. }
  492.  
  493. /*
  494.  * _exit: does the actual exiting. Note that _moncontrol and __mcleanup are
  495.  * dummies in crt0.s, but do something in gcrt0.s
  496.  */
  497.  
  498. void _exit(status)
  499.     int status;
  500. {
  501.     _moncontrol(0L);
  502.     __mcleanup();
  503.     Pterm(status);
  504. }
  505.