/* from Dale Schumacher's dLibs */ /* heavily modified by ers and jrb */ #include #include #include #include #include #include #include #include #include #include int errno; int __mint; /* 0 for TOS, MiNT version number otherwise */ char _rootdir; /* user's preferred root directory */ clock_t _starttime; /* 200 HZ tick when we started the program */ clock_t _childtime; /* time consumed so far by our children */ FILE _iob[_NFILE]; /* stream buffers initialized below */ /* functions registered by user for calling at exit */ #ifdef __STDC__ typedef void (*ExitFn)(void); #else typedef void (*ExitFn)(); #endif static ExitFn *_at_exit; static int num_at_exit; /* number of functions registered - 1 */ /* * get MiNT version number. Since this has to be done in supervisor mode, * we might as well set the start-up time of the system here, too. */ static void getMiNT() { long *cookie; /* get the system time in 200HZ ticks from the BIOS _hz_200 variable */ _starttime = *((unsigned long *) 0x4ba); _childtime = 0; cookie = *((long **) 0x5a0); if (!cookie) __mint = 0; else { while (*cookie) { if (*cookie == 0x4d694e54L) { /* MiNT */ __mint = cookie[1]; return; } cookie += 2; } } __mint = 0; } /* supplied by the user */ __EXTERN int main __PROTO((int, char **, char **)); /* in getbuf.c */ __EXTERN void _getbuf __PROTO((FILE *)); void _main(_argc, _argv, _envp) long _argc; char **_argv, **_envp; { register FILE *f; register int i; char *s, *t, *new; extern int __default_mode__; /* in binmode.c or defined by user */ extern short _app; /* tells if we're an application or acc */ num_at_exit = 0; errno = 0; /* * check for MiNT */ (void)Supexec(getMiNT); if (__mint && _app) (void)Pdomain(1); /* set MiNT domain */ /* * initialize UNIXMODE stuff. Note that this library supports only * a few of the UNIXMODE variables, namely "b" (binary mode default) * and "r" (default root directory). */ if ((s = getenv("UNIXMODE")) != 0) { while (*s) { if (*s == 'b') __default_mode__ = _IOBIN; else if (*s == 'r' && s[1]) _rootdir = *++s; s++; } } if (_rootdir >= 'A' && _rootdir <= 'Z') _rootdir = _rootdir - 'A' + 'a'; /* * if we're running under MiNT, and the current drive is U:, then this * must be our preferred drive */ if (!_rootdir && __mint >= 9) { if (Dgetdrv() == 'U'-'A') _rootdir = 'u'; } /* if stderr is not re-directed to a file, force 2 to console * (UNLESS we've been run from a shell we trust, i.e. one that supports * the official ARGV scheme, in which case we leave stderr be). */ if(!*_argv[0] && isatty(2)) (void)Fforce(2, -1); stdin->_flag = _IOREAD|_IOFBF|__default_mode__; stdout->_flag = _IOWRT|_IOLBF|__default_mode__; stderr->_flag = _IORW|_IONBF|__default_mode__; /* some brain-dead people read from stderr */ for(i = 0, f = _iob; i < 3; ++i, ++f) { /* flag device streams */ if(isatty(f->_file = i)) f->_flag |= _IODEV; else if(f == stdout) { /* stderr is NEVER buffered */ /* if stdout re-directed, make it full buffered */ f->_flag &= ~(_IOLBF | _IONBF); f->_flag |= _IOFBF; } _getbuf(f); /* get a buffer */ } for(i = 3; i < _NFILE; i++, f++) { f->_flag = 0; /* clear flags, if this is a dumped program */ } /* Fix up environment, if necessary. At present, the only variable * affected is PATH; the "standard" path separators for PATH are * ',' and ';' in the Atari world, but POSIX mandates ':'. This * conflicts with the use of ':' as a drive separator, so we * also convert names like A:\foo to /dev/A/foo * NOTE: this conversion must be undone in spawn.c so that * old fashioned programs will understand us! */ for (i = 0; s = _envp[i]; i++) { /* '=', NOT '==' */ if (s[0] == 'P' && s[1] == 'A' && s[2] == 'T' && s[3] == 'H' && s[4] == '=') { new = alloca(4*strlen(s)); strncpy(new, s, 5); t = new+5; s += 5; while (*s) { if (s[1] == ':') { /* drive letter */ *t++ = '/'; *t++ = 'd'; *t++ = 'e'; *t++ = 'v'; *t++ = '/'; *t++ = *s++; s++; } else if (*s == ';' || *s == ',') { *t++ = ':'; s++; } else if (*s == '\\') { *t++ = '/'; s++; } else { *t++ = *s++; } } *t++ = 0; _envp[i] = strdup(new); break; } } /* ANSI-Draft: A return from the initial call to the main * function is equivalent to calling the exit function with * the value returned by the main function as its argument. If * the main function executes a return that specifies no * value, the termination status returned to the host * environment is undefined. [section 2.1.2.2] */ exit(main((int) _argc, _argv, _envp)); } __EXITING exit(status) int status; { register int i, f; for(i = num_at_exit - 1; i >= 0; --i) (*_at_exit[i])(); for(i=0; i<_NFILE; ++i) { f = _iob[i]._flag; if(f & (_IORW | _IOREAD | _IOWRT)) if (_iob[i]._file <= 2) /* only flush std. streams */ fflush(&_iob[i]); else fclose(&_iob[i]); } _exit(status); } /* register a function for execution on termination */ /* Ansi requires atleast 32 entries, we make it dynamic and hope it meets the ansi requirement */ int atexit(func) ExitFn func; { ExitFn *new_at_exit = _at_exit; if (num_at_exit == 0) new_at_exit = (ExitFn *)malloc((size_t)sizeof(ExitFn)); else new_at_exit = (ExitFn *)realloc(new_at_exit, (size_t)((num_at_exit + 1) * sizeof(ExitFn))); if(new_at_exit == (ExitFn *)NULL) return -1; /* failure */ _at_exit = new_at_exit; _at_exit[num_at_exit++] = func; return 0; /* success */ }