summaryrefslogtreecommitdiffstats
path: root/private/crt32/startup
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/startup')
-rw-r--r--private/crt32/startup/_setargv.c18
-rw-r--r--private/crt32/startup/alpha/chkstk.s131
-rw-r--r--private/crt32/startup/crt0.c594
-rw-r--r--private/crt32/startup/crt0dat.c794
-rw-r--r--private/crt32/startup/crt0fp.c57
-rw-r--r--private/crt32/startup/crt0init.c69
-rw-r--r--private/crt32/startup/crt0msg.c231
-rw-r--r--private/crt32/startup/dllcrt0.c306
-rw-r--r--private/crt32/startup/dllmain.c42
-rw-r--r--private/crt32/startup/i386/atlssup.asm15
-rw-r--r--private/crt32/startup/i386/chkstk.asm127
-rw-r--r--private/crt32/startup/makefile6
-rw-r--r--private/crt32/startup/makefile.inc3
-rw-r--r--private/crt32/startup/mips/chkstk.s104
-rw-r--r--private/crt32/startup/mlock.c382
-rw-r--r--private/crt32/startup/ppc/chkstk.s190
-rw-r--r--private/crt32/startup/ppc/sources3
-rw-r--r--private/crt32/startup/sources65
-rw-r--r--private/crt32/startup/stdargv.c501
-rw-r--r--private/crt32/startup/stdenvp.c192
-rw-r--r--private/crt32/startup/thread.c254
-rw-r--r--private/crt32/startup/tidprint.c286
-rw-r--r--private/crt32/startup/tidtable.c324
-rw-r--r--private/crt32/startup/tlssup.c52
-rw-r--r--private/crt32/startup/wild.c341
-rw-r--r--private/crt32/startup/wincrt0.c6
26 files changed, 5093 insertions, 0 deletions
diff --git a/private/crt32/startup/_setargv.c b/private/crt32/startup/_setargv.c
new file mode 100644
index 000000000..7b3718401
--- /dev/null
+++ b/private/crt32/startup/_setargv.c
@@ -0,0 +1,18 @@
+/***
+*_setargv.c - Wildcard argv[] expansion
+*
+* Copyright (c) 1991-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* _setargv performs wildcard argv[] expansion
+*
+* NOTE: This stub module scheme is compatible with NT build
+* procedure.
+*
+*Revision History:
+* 09-25-91 JCR Stub module created.
+*
+*******************************************************************************/
+
+#define WILDCARD 1
+#include "stdargv.c"
diff --git a/private/crt32/startup/alpha/chkstk.s b/private/crt32/startup/alpha/chkstk.s
new file mode 100644
index 000000000..104254349
--- /dev/null
+++ b/private/crt32/startup/alpha/chkstk.s
@@ -0,0 +1,131 @@
+// TITLE("Runtime Stack Checking")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+// Copyright (c) 1992 Digital Equipment Corporation
+//
+// Module Name:
+//
+// chkstk.s
+//
+// Abstract:
+//
+// This module implements runtime stack checking.
+//
+// Author:
+//
+// David N. Cutler (davec) 14-Mar-1991
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Thomas Van Baak (tvb) 7-May-1992
+//
+// Adapted for Alpha AXP.
+//
+//--
+
+#include "ksalpha.h"
+
+ SBTTL("Check Stack")
+//++
+//
+// ULONG
+// _RtlCheckStack (
+// IN ULONG Allocation
+// )
+//
+// Routine Description:
+//
+// This function provides runtime stack checking for local allocations
+// that are more than a page and for storage dynamically allocated with
+// the alloca function. Stack checking consists of probing downward in
+// the stack a page at a time. If the current stack commitment is exceeded,
+// then the system will automatically attempts to expand the stack. If the
+// attempt succeeds, then another page is committed. Otherwise, a stack
+// overflow exception is raised. It is the responsibility of the caller to
+// handle this exception.
+//
+// N.B. This routine is called using a non-standard calling sequence since
+// it is typically called from within the prologue. The allocation size
+// argument is in register t12 and it must be preserved. Register t11
+// may contain the callers saved ra and it must be preserved. The choice
+// of these registers is hard-coded into the acc C compiler. Register v0
+// may contain a static link pointer (exception handlers) and so it must
+// be preserved. Since this function is called from within the prolog,
+// the a' registers must be preserved, as well as all the s' registers.
+// Registers t8, t9, and t10 are used by this function and are not
+// preserved.
+//
+// The typical calling sequence from the prologue is:
+//
+// mov ra, t11 // save return address
+// ldil t12, SIZE // set requested stack frame size
+// bsr ra, _RtlCheckStack // check stack page allocation
+// subq sp, t12, sp // allocate stack frame
+// mov t11, ra // restore return address
+//
+// Arguments:
+//
+// Allocation (t12) - Supplies the size of the allocation on the stack.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(_RtlCheckStack)
+
+ subq sp, t12, t8 // compute requested new stack address
+ mov v0, t10 // save v0 since the PALcode uses it
+ bgt sp, 10f // if sp>0, then running on user stack
+
+//
+// Running on kernel stack - compute stack limit from initial kernel stack.
+//
+
+ GET_INITIAL_KERNEL_STACK // (PALcode) result in v0
+
+ lda t9, -KERNEL_STACK_SIZE(v0) // compute low limit of kernel stack
+ br zero, 20f // finish in common code
+
+//
+// Running on user stack - get stack limit from thread environment block.
+//
+
+10: GET_THREAD_ENVIRONMENT_BLOCK // (PALcode) put TEB address in v0
+
+ ldl t9, TeStackLimit(v0) // get low limit of user stack address
+
+//
+// The requested bottom of the stack is in t8.
+// The current low limit of the stack is in t9.
+//
+// If the new stack address is greater than the current stack limit, then the
+// pages have already been allocated, and nothing further needs to be done.
+//
+
+20: mov t10, v0 // restore v0, no further PAL calls
+ cmpult t8, t9, t10 // t8<t9? new stack base within limit?
+ beq t10, 40f // if eq [false], then t8>=t9, so yes
+
+ ldil t10, ~(PAGE_SIZE - 1) // round down new stack address
+ and t8, t10, t8 // to next page boundary
+
+//
+// Go down one page, touch one quadword in it, and repeat until we reach the
+// new stack limit.
+//
+
+30: lda t9, -PAGE_SIZE(t9) // compute next address to check
+ stq zero, 0(t9) // probe stack address with a write
+ cmpeq t8, t9, t10 // t8=t9? at the low limit yet?
+ beq t10, 30b // if eq [false], more pages to probe
+
+40: ret zero, (ra) // return
+
+ .end _RtlCheckStack
diff --git a/private/crt32/startup/crt0.c b/private/crt32/startup/crt0.c
new file mode 100644
index 000000000..bc0e4f75d
--- /dev/null
+++ b/private/crt32/startup/crt0.c
@@ -0,0 +1,594 @@
+/***
+*crt0.c - C runtime initialization routine
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This the main startup routine. It is called upon program
+* startup by a very small assembler stub.
+*
+*Revision History:
+* 06-27-89 PHG Module created, based on asm version
+* 11-02-89 JCR Added DOS32QUERYSYSINFO to get osversion
+* 04-09-90 GJF Added #include <cruntime.h>. Put in explicit calling
+* types (_CALLTYPE1 or _CALLTYPE4) for __crt0(),
+* inherit(), __amsg_exit() and _cintDIV(). Also, fixed
+* the copyright and cleaned up the formatting a bit.
+* 04-10-90 GJF Fixed compiler warnings (-W3).
+* 08-08-90 GJF Added exception handling stuff (needed to support
+* runtime errors and signal()).
+* 08-31-90 GJF Removed 32 from API names.
+* 10-08-90 GJF New-style function declarators.
+* 12-05-90 GJF Fixed off-by-one error in inherit().
+* 12-06-90 GJF Win32 version of inherit().
+* 12-06-90 SRW Added _osfile back for win32. Changed _osfinfo from
+* an array of structures to an array of 32-bit handles
+* (_osfhnd)
+* 01-21-91 GJF ANSI naming.
+* 01-25-91 SRW Changed Win32 Process Startup [_WIN32_]
+* 02-01-91 SRW Removed usage of PPEB type [_WIN32_]
+* 02-05-91 SRW Changed to pass _osfile and _osfhnd arrays as binary
+* data to child process. [_WIN32_]
+* 04-02-91 GJF Need to get version number sooner so it can be used in
+* _heap_init. Prefixed an '_' onto BaseProcessStartup.
+* Version info now stored in _os[version|major|minor] and
+* _base[version|major|minor] (_WIN32_).
+* 04-10-91 PNT Added _MAC_ conditional
+* 04-26-91 SRW Removed level 3 warnings
+* 05-14-91 GJF Turn on exception handling for Dosx32.
+* 05-22-91 GJF Fixed careless errors.
+* 07-12-91 GJF Fixed one more careless error.
+* 08-13-91 GJF Removed definitions of _confh and _coninpfh.
+* 09-13-91 GJF Incorporated Stevewo's startup variations.
+* 11-07-91 GJF Revised try-except, fixed outdated comments on file
+* handle inheritance [_WIN32_].
+* 12-02-91 SRW Fixed WinMain startup code to skip over first token
+* plus delimiters for the lpszCommandLine parameter.
+* 01-17-92 GJF Merge of NT and CRT version. Restored Stevewo's scheme
+* for unhandled exceptions.
+* 02-13-92 GJF For Win32, moved file inheritance stuff to ioinit.c.
+* Call to inherit() is replace by call to _ioinit().
+* 04-16-92 DJM POSIX support
+* 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
+* 08-26-92 GJF Deleted version number(s) fetch from POSIX startup (it
+* involved a Win32 API call).
+* 09-30-92 SRW Call _heap_init before _mtinit
+* 04-26-93 GJF Made lpszCommandLine (unsigned char *) to deal with
+* chars > 127 in the command line.
+* 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
+* _RT_INVALDISP and _RT_NONCONT.
+* 05-11-93 SKS Remove obsolete variable _atopsp
+* Change _mtinit to return failure
+* 05-14-93 GJF Added support for quoted program names.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <dos.h>
+#include <internal.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _POSIX_
+#include <rterr.h>
+#else
+#include <posix/sys/types.h>
+#include <posix/unistd.h>
+#include <posix/signal.h>
+#endif
+#include <oscalls.h>
+
+#ifdef _CRUISER_
+/*
+ * C file info string
+ */
+char _acfinfo[] = "_C_FILE_INFO=";
+#endif /* _CRUISER_ */
+
+/*
+ * command line, environment, and a few other globals
+ */
+char *_acmdln; /* points to command line */
+char *_aenvptr; /* points to environment block */
+
+#ifdef _POSIX_
+char *_cmdlin;
+#endif
+
+void (_CRTAPI1 * _aexit_rtn)(int) = _exit; /* RT message return procedure */
+
+#ifdef _CRUISER_
+static void _CRTAPI3 inherit(void); /* local function */
+#endif /* _CRUISER_ */
+
+#ifndef _MAC_
+
+#ifdef _POSIX_
+
+/***
+*mainCRTStartup(PVOID Peb)
+*
+*Purpose:
+* This routine does the C runtime initialization, calls main(), and
+* then exits. It never returns.
+*
+*Entry:
+* PVOID Peb - pointer to Win32 Process Environment Block (not used)
+*
+*Exit:
+* This function never returns.
+*
+*******************************************************************************/
+
+void
+mainCRTStartup(
+ void
+ )
+{
+ int mainret;
+ char **ppch;
+
+ extern char **environ;
+ extern char * __PdxGetCmdLine(void); /* a hacked API in the Posix SS */
+ extern main(int,char**);
+
+ _cmdlin = __PdxGetCmdLine();
+ ppch = (char **)_cmdlin;
+ __argv = ppch;
+
+ // normalize argv pointers
+
+ __argc = 0;
+ while (NULL != *ppch) {
+ *ppch += (int)_cmdlin;
+ ++__argc;
+ ++ppch;
+ }
+ // normalize environ pointers
+
+ ++ppch;
+ environ = ppch;
+
+ while (NULL != *ppch) {
+ *ppch = *ppch + (int)_cmdlin;
+ ++ppch;
+ }
+
+ /*
+ * If POSIX runtime needs to fetch and store POSIX verion info,
+ * it should be done here.
+ *
+ * Get_and_save_version_info;
+ */
+
+ _heap_init(); /* initialize heap */
+ _cinit(); /* do C data initialize */
+
+ try {
+ mainret = main(__argc, __argv);
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ switch (GetExceptionCode()) {
+ case STATUS_ACCESS_VIOLATION:
+ kill(getpid(), SIGSEGV);
+ break;
+ case STATUS_ILLEGAL_INSTRUCTION:
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ kill(getpid(), SIGILL);
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ case STATUS_FLOAT_INEXACT_RESULT:
+ case STATUS_FLOAT_OVERFLOW:
+ case STATUS_FLOAT_STACK_CHECK:
+ case STATUS_FLOAT_UNDERFLOW:
+ kill(getpid(), SIGFPE);
+ break;
+ default:
+ kill(getpid(), SIGKILL);
+ }
+
+ mainret = -1;
+ }
+ exit(mainret);
+}
+#else /* ndef _POSIX_ */
+
+#ifdef _CRUISER_
+
+/***
+*__crt0(cmdline, envptr)
+*
+*Purpose:
+* This routine does the C runtime initialization, calls main(), and
+* then exits. It never returns.
+*
+*Entry:
+* char *cmdline - pointer to OS/2 command line
+* char *envptr - pointer to OS/2 environment block
+*
+*Exit:
+* This function never returns.
+*
+*******************************************************************************/
+
+void _CRTAPI1 __crt0 (
+ char *cmdline,
+ char *envptr
+ )
+{
+ int mainret;
+
+ /* initialize pointers to command line and environment */
+ _acmdln = cmdline;
+ _aenvptr = envptr;
+
+ /* Get the OS/2 version */
+
+ /* make sure our assumptions are correct */
+
+#if (_QSV_VERSION_MAJOR+1 != _QSV_VERSION_MINOR)
+#error Invalid DosQuerySysInfo parameters
+#endif
+
+ DOSQUERYSYSINFO(_QSV_VERSION_MAJOR, _QSV_VERSION_MINOR,
+ (unsigned char *)&_osmajor, (2*sizeof(int)) );
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+/***
+*BaseProcessStartup(PVOID Peb)
+*
+*Purpose:
+* This routine does the C runtime initialization, calls main(), and
+* then exits. It never returns.
+*
+*Entry:
+* PVOID Peb - pointer to Win32 Process Environment Block (not used)
+*
+*Exit:
+* This function never returns.
+*
+*******************************************************************************/
+
+#ifdef _DOSX32_
+
+void _BaseProcessStartup (
+
+#else
+
+#ifdef _WINMAIN_
+void WinMainCRTStartup(
+#else
+void mainCRTStartup(
+#endif
+
+#endif
+ void
+ )
+
+{
+ int mainret;
+
+#ifdef _WINMAIN_
+ unsigned char *lpszCommandLine;
+ STARTUPINFOA StartupInfo;
+#endif
+ _acmdln = (char *)GetCommandLine();
+ _aenvptr = (char *)GetEnvironmentStrings();
+
+ /*
+ * Get the full Win32 version
+ */
+ _osversion = /* OBSOLETE */
+ _osver = GetVersion();
+
+ _winminor = (_osver >> 8) & 0x00FF ;
+ _winmajor = _osver & 0x00FF ;
+ _winver = (_winmajor << 8) + _winminor;
+ _osver = (_osver >> 16) & 0x00FFFF ;
+
+ /* --------- The following block is OBSOLETE --------- */
+
+ /*
+ * unpack base version info
+ */
+ _baseversion = (_osversion & 0xFFFF0000) >> 16;
+ _baseminor = _baseversion & 0x00FF;
+ _basemajor = (_baseversion & 0xFF00) >> 8;
+
+ /*
+ * unpack top-level version info (Windows version)
+ */
+ _osversion &= 0x0000FFFF;
+ _osmajor = _osversion & 0x00FF;
+ _osminor = (_osversion & 0xFF00) >> 8;
+
+ /* --------- The preceding block is OBSOLETE --------- */
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ _heap_init(); /* initialize heap */
+#ifdef MTHREAD
+ if(!_mtinit()) /* initialize multi-thread */
+ _amsg_exit(_RT_THREAD); /* write message and die */
+#endif
+#ifdef _WIN32_
+ _ioinit(); /* initialize lowio */
+#else /* ndef _WIN32_ */
+#ifdef _CRUISER_
+ inherit(); /* inherit file info */
+#endif /* _CRUISER_ */
+#endif /* _WIN32_ */
+ _setargv(); /* get cmd line info */
+ _setenvp(); /* get environ info */
+
+ _cinit(); /* do C data initialize */
+
+ /* now call the main program, and then exit with the return value
+ we get back */
+
+ /*
+ * NOTE: THERE MUST BE NO PROTOTYPE FOR THE main() FUNCTION IF THIS
+ * IS BUILT FOR THE 386 WITH _stdcall AS THE DEFAULT CALLING TYPE!
+ * OTHERWISE, THE STACK WILL NOT BE PROPERLY RESTORED AFTER THE CALL
+ * BELOW. WE MIGHT GET AWAY WITH THIS, SINCE WE EXIT RIGHT AWAY, BUT
+ * THERE IS NO POINT IN ASKING FOR TROUBLE.
+ */
+
+#ifdef _CRUISER_
+
+ _try {
+ mainret = main(__argc, __argv, _environ);
+ }
+ _except ( _XcptFilter(_exception_code(), _exception_info()) )
+ {
+ switch( _exception_code() ) {
+
+ case _XCPT_UNABLE_TO_GROW_STACK :
+ _amsg_exit(_RT_STACK);
+
+ case _XCPT_INTEGER_DIVIDE_BY_ZERO :
+ /*
+ * NOTE: THIS IS WHERE cintDIV WENT!
+ *
+ * exit via high-level exit function
+ */
+ _aexit_rtn = exit;
+ _amsg_exit(_RT_INTDIV);
+
+ case _XCPT_INVALID_DISPOSITION :
+ /*
+ * this exception should never occur. if it
+ * does, it would have to be a bug in the
+ * runtime support for signal() or SEH.
+ */
+ _amsg_exit(_RT_INVALDISP);
+
+ case _XCPT_NONCONTINUABLE_EXCEPTION :
+ /*
+ * this exception could possibly occur as the
+ * result of a bad user exception filter or
+ * an error in _XcptFilter().
+ */
+ _amsg_exit(_RT_NONCONT);
+
+ case _XCPT_SIGABRT :
+ /*
+ * no message is printed unless abort() was
+ * called in which case, abort() prints out
+ * the termination message before raising the
+ * signal
+ */
+ _exit(3);
+
+ default :
+ /*
+ * no default action, should never get here
+ */
+ ;
+ } /* end of switch */
+
+ } /* end of _try - _except */
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ try {
+#ifdef _WINMAIN_
+ /*
+ * Skip past program name (first token in command line).
+ * Check for and handle quoted program name.
+ */
+ lpszCommandLine = (unsigned char *)_acmdln;
+
+ if ( *lpszCommandLine == '\"' ) {
+ /*
+ * Scan, and skip over, subsequent characters until
+ * another double-quote or a null is encountered.
+ */
+ while ( *++lpszCommandLine && (*lpszCommandLine
+ != '\"') );
+ /*
+ * If we stopped on a double-quote (usual case), skip
+ * over it.
+ */
+ if ( *lpszCommandLine == '\"' )
+ lpszCommandLine++;
+ }
+ else {
+ while (*lpszCommandLine > ' ')
+ lpszCommandLine++;
+ }
+
+ /*
+ * Skip past any white space preceeding the second token.
+ */
+ while (*lpszCommandLine && (*lpszCommandLine <= ' ')) {
+ lpszCommandLine++;
+ }
+
+ StartupInfo.dwFlags = 0;
+ GetStartupInfoA( &StartupInfo );
+
+ mainret = WinMain( GetModuleHandle(NULL),
+ NULL,
+ lpszCommandLine,
+ StartupInfo.dwFlags & STARTF_USESHOWWINDOW
+ ? StartupInfo.wShowWindow
+ : SW_SHOWDEFAULT
+ );
+#else
+ mainret = main(__argc, __argv, _environ);
+#endif
+ exit(mainret);
+ }
+ except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
+ {
+ /*
+ * Should never reach here
+ */
+ _exit( GetExceptionCode() );
+
+ } /* end of try - except */
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+}
+
+#endif /* _POSIX_ */
+
+#endif /* ndef _MAC_ */
+
+
+#ifdef _CRUISER_
+
+/***
+*inherit() - obtain and process info on inherited file handles.
+*
+*Purpose:
+*
+* Locates and interprets the C_FILE_INFO environment variable.
+*
+* The value of the variable is written into the "_osfile" array.
+*
+* Format: _C_FILE_INFO=<AA><BB><CC><DD>...
+*
+* This variable is a environment variable where each pair of
+* successive letters from one byte in _osfile. The letters are
+* in the reange "A" through "P" representing the 0 though 15.
+* The first letter of each pair is the more significant 4 bits
+* of the result.
+*
+*Entry:
+* No parameters: reads the environment.
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static void _CRTAPI3 inherit (
+ void
+ )
+{
+ char *p; /* pointer to environment strings */
+ unsigned char byte; /* byte we build up */
+ int fh; /* handle we're on */
+
+ p = _aenvptr;
+ while (*p != '\0') {
+ if (strncmp(p, _acfinfo, CFI_LENGTH + 1) == 0) {
+ /* found the _C_FILE_INFO string, now parse it */
+ p += CFI_LENGTH + 1; /* point to value */
+ fh = 0;
+ do
+ {
+ byte = (*p++ - 'A') << 4;
+ byte += *p++ - 'A'; /* read byte */
+ _osfile[fh++] = byte;
+ }
+ while(byte);
+
+ break;
+ }
+ else
+ p += strlen(p) + 1; /* advance to next string */
+ }
+}
+
+#endif /* _CRUISER_ */
+
+
+/***
+*_amsg_exit(rterrnum) - Fast exit fatal errors
+*
+*Purpose:
+* Exit the program with error code of 255 and appropriate error
+* message.
+*
+*Entry:
+* int rterrnum - error message number (amsg_exit only).
+*
+*Exit:
+* Calls exit() (for integer divide-by-0) or _exit() indirectly
+* through _aexit_rtn [amsg_exit].
+* For multi-thread: calls _exit() function
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _amsg_exit (
+ int rterrnum
+ )
+{
+ _FF_MSGBANNER(); /* write run-time error banner */
+ _NMSG_WRITE(rterrnum); /* write message */
+
+ _aexit_rtn(255); /* normally _exit(255) */
+}
+
+#ifdef _POSIX_
+
+/***
+*RaiseException() - stub for posix FP routines
+*
+*Purpose:
+* Stub of a Win32 API that posix can't call
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+VOID
+WINAPI
+RaiseException(
+ DWORD dwExceptionCode,
+ DWORD dwExceptionFlags,
+ DWORD nNumberOfArguments,
+ LPDWORD lpArguments
+ )
+{
+}
+
+#endif /* _POSIX_ */
diff --git a/private/crt32/startup/crt0dat.c b/private/crt32/startup/crt0dat.c
new file mode 100644
index 000000000..42b6854bc
--- /dev/null
+++ b/private/crt32/startup/crt0dat.c
@@ -0,0 +1,794 @@
+/***
+*crt0dat.c - 32-bit C run-time initialization/termination routines
+*
+* Copyright (c) 1986-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains the routines _cinit, exit, and _exit
+* for C run-time startup and termination. _cinit and exit
+* are called from the _astart code in crt0.asm.
+* This module also defines several data variables used by the
+* runtime.
+*
+* [NOTE: Lock segment definitions are at end of module.]
+*
+* *** FLOATING POINT INITIALIZATION AND TERMINATION ARE NOT ***
+* *** YET IMPLEMENTED IN THIS FILE ***
+*
+*Revision History:
+* 06-28-89 PHG Module created, based on asm version
+* 04-09-90 GJF Added #include <cruntime.h>. Made calling type
+* explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed
+* the copyright.
+* 04-10-90 GJF Fixed compiler warnings (-W3).
+* 05-21-90 GJF Added #undef _NFILE_ (temporary hack) and fixed the
+* indents.
+* 08-31-90 GJF Removed 32 from API names.
+* 09-25-90 GJF Merged tree version with local (8-31 and 5-21 changes).
+* 10-08-90 GJF New-style function declarators.
+* 10-12-90 GJF Removed divide by 0 stuff.
+* 10-18-90 GJF Added _pipech[] array.
+* 11-05-90 GJF Added _umaskval.
+* 12-04-90 GJF Added _osfinfo[] definition for Win32 target. Note that
+* the Win32 support is still incomplete!
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-04-90 SRW Added _osfile back for win32. Changed _osfinfo from
+* an array of structures to an array of 32-bit handles
+* (_osfhnd)
+* 12-28-90 SRW Added _CRUISER_ conditional around pack pragmas
+* 01-29-91 GJF ANSI naming.
+* 01-29-91 SRW Added call to GetFileType [_WIN32_]
+* 02-18-91 SRW Removed duplicate defintion of _NFILE_ (see os2dll.h)
+* 04-04-91 GJF Added definitions for _base[version|major|minor]
+* (_WIN32_).
+* 04-08-91 GJF Temporary hack for Win32/DOS folks - added HeapDestroy
+* call to doexit to tear down the OS heap used by C
+* heap.
+* 04-09-91 PNT Added _MAC_ conditional
+* 04-26-91 SRW Removed level 3 warnings
+* 07-16-91 GJF Added fp initialization test-and-call [_WIN32_].
+* 07-26-91 GJF Revised initialization and termination stuff. In
+* particular, removed need for win32ini.c [_WIN32_].
+* 08-07-91 GJF Added init. for FORTRAN runtime, if present [_WIN32_].
+* 08-21-91 GJF Test _prmtmp against NULL, not _prmtmp().
+* 08-21-91 JCR Added _exitflag, _endstdio, _cpumode, etc.
+* 09-09-91 GJF Revised _doinitterm for C++ init. support and to make
+* _onexit/atexit compatible with C++ needs.
+* 09-16-91 GJF Must test __onexitend before calling _doinitterm.
+* 10-29-91 GJF Force in floating point initialization for MIPS
+* compiler [_WIN32_].
+* 11-13-91 GJF FORTRAN needs _onexit/atexit init. before call thru
+* _pFFinit.
+* 01-10-92 GJF Merged. Also, added _C_Termination_Done [_WIN32_].
+* 02-13-92 GJF Moved all lowio initialization to ioinit.c for Win32.
+* 03-12-92 SKS Major changes to initialization/termination scheme
+* 04-16-92 DJM POSIX support.
+* 04-17-92 SKS Export _initterm() for CRTDLL model
+* 05-07-92 DJM Removed _exit() from POSIX build.
+* 06-03-92 GJF Temporarily restored call to FORTRAN init.
+* 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
+* 08-28-92 GJF Use unistd.h for POSIX build.
+* 09-02-92 SKS Fix _onexit table traversal to be LIFO.
+* Since table is built forward (my changes 03-12-92)
+* the table must be traversed in reverse order.
+* 10-30-92 TVB Force in floating point initialization for ALPHA
+* compiler as was done for MIPS. [_WIN32_].
+* 11-12-92 SKS Remove hard-coded call to FORTRAN initializer
+* 05-11-93 SKS _C_Termination_Done is now used by DLLs in LIBC/LIBCMT
+* models, not just in CRTDLL.DLL.
+* Remove obsolete variable _child.
+* 07-16-93 SRW ALPHA Merge
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#ifdef _POSIX_
+#include <unistd.h>
+#else
+#include <msdos.h>
+#endif
+#include <dos.h>
+#include <oscalls.h>
+#include <os2dll.h>
+#include <internal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <process.h>
+
+/* define errno */
+#ifndef MTHREAD
+int _VARTYPE1 errno = 0; /* libc error value */
+#ifdef _CRUISER_
+int _VARTYPE1 _doserrno = 0; /* OS system error value */
+#else /* ndef _CRUISER_ */
+#ifdef _WIN32_
+unsigned long _VARTYPE1 _doserrno = 0; /* OS system error value */
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
+#endif /* MTHREAD */
+
+/* define umask */
+int _umaskval = 0;
+
+/* define version info variables */
+
+unsigned int _VARTYPE1 _osver = 0;
+unsigned int _VARTYPE1 _winver = 0;
+unsigned int _VARTYPE1 _winmajor = 0;
+unsigned int _VARTYPE1 _winminor = 0;
+
+/* --------- The following block is OBSOLETE --------- */
+
+unsigned int _VARTYPE1 _osversion = 0;
+unsigned int _VARTYPE1 _osmajor = 0;
+unsigned int _VARTYPE1 _osminor = 0;
+
+#if defined(_WIN32_) || defined(_POSIX_)
+unsigned int _VARTYPE1 _baseversion = 0;
+unsigned int _VARTYPE1 _basemajor = 0;
+unsigned int _VARTYPE1 _baseminor = 0;
+#endif /* _WIN32_ || _POSIX_ */
+
+/* define _osmode/_cpumode */
+
+#ifdef _CRUISER_
+unsigned char _osmode = _OS2_20_MODE;
+#else /* ndef _CRUISER_ */
+#ifdef _DOSX32_
+unsigned char _osmode = _DOSX32_MODE;
+#else /* ndef _DOSX32_ */
+#ifdef _WIN32_
+unsigned char _osmode = _WIN_MODE;
+#else /* ndef _WIN32_ */
+#ifdef _POSIX_
+unsigned char _osmode = _POSIX_MODE_;
+#endif /* _POSIX_ */
+#endif /* _WIN32DOS_ */
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
+
+unsigned char _cpumode = _FLAT_MODE;
+
+/* --------- The preceding block is OBSOLETE --------- */
+
+#ifdef _CRUISER_
+
+/* number of allowable file handles */
+int _nfile = _NFILE_;
+
+/* file handle database -- stdout, stdin, stderr are open */
+char _osfile[_NFILE_] = {FOPEN+FTEXT, FOPEN+FTEXT, FOPEN+FTEXT};
+
+#endif /* _CRUISER_ */
+
+#ifdef _WIN32DOS_
+extern HANDLE _HeapHandle;
+#endif /* _WIN32DOS_ */
+
+#ifdef _CRUISER_
+
+/* peek-ahead buffers for pipes, each initialized to a newline */
+
+char _pipech[_NFILE_] = {
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10
+#ifdef MTHREAD
+ , 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+#endif
+ };
+#endif /* _CRUISER_ */
+
+/* argument vector and environment */
+int __argc = 0;
+char **__argv = NULL;
+#ifdef _POSIX_
+char **environ = NULL;
+#else
+char **_environ = NULL;
+#endif
+char *_pgmptr; /* ptr to program name */
+
+/* callable exit flag */
+char _exitflag = 0;
+
+#if defined(_WIN32_)
+/*
+ * flag indicating if C runtime termination has been done. set if exit,
+ * _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
+ * or user DLL's _CRT_INIT is called with DLL_PROCESS_DETACH.
+ */
+int _C_Termination_Done = FALSE;
+#endif
+
+/*
+ * useful type for initialization and termination declarations
+ */
+typedef void (_CALLTYPE1 *PF)(void);
+
+#ifdef _CRUISER_
+
+PF *__onexittable = NULL; /* ptr to on exit function table */
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+
+/*
+ * NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
+ * OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
+ * A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
+ */
+
+/*
+ * pointers to initialization functions
+ */
+
+PF _FPinit; /* floating point init. */
+
+/*
+ * pointers to initialization sections
+ */
+
+extern PF __xi_a[], __xi_z[]; /* C initializers */
+extern PF __xc_a[], __xc_z[]; /* C++ initializers */
+extern PF __xp_a[], __xp_z[]; /* C pre-terminators */
+extern PF __xt_a[], __xt_z[]; /* C terminators */
+
+#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
+/*
+ * For MIPS or ALPHA compilers, must explicitly force in and call the floating
+ * point initialization (those system always have floating-point hardware).
+ */
+extern void _CALLTYPE1 _fpmath(void);
+#endif
+
+/*
+ * pointers to the start and finish of the _onexit/atexit table
+ */
+PF *__onexitbegin;
+PF *__onexitend;
+
+
+/*
+ * static (internal) function that walks a table of function pointers,
+ * calling each entry between the two pointers, skipping NULL entries
+ *
+ * Needs to be exported for CRT DLL so that C++ initializers in the
+ * client EXE / DLLs can be initialized
+ */
+#ifdef CRTDLL
+void _CALLTYPE1 _initterm(PF *, PF *);
+#else
+static void _CALLTYPE4 _initterm(PF *, PF *);
+#endif
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#error ERROR - ONLY CRUISER, WIN32, OR POSIX TARGET SUPPORTED!
+
+#endif /* _WIN32_ || _POSIX_ */
+
+#endif /* _CRUISER_ */
+
+
+/***
+*_cinit - C initialization
+*
+*Purpose:
+* This routine performs the shared DOS and Windows initialization.
+* The following order of initialization must be preserved -
+*
+ifdef MTHREAD
+* 0. Call OS2 to bump max file count (mthread only)
+endif
+* 1. Check for devices for file handles 0 - 2
+* 2. Integer divide interrupt vector setup
+* 3. General C initializer routines
+*
+*Entry:
+* No parameters: Called from __crtstart and assumes data
+* set up correctly there.
+*
+*Exit:
+* Initializes C runtime data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _cinit (
+ void
+ )
+{
+#ifdef _CRUISER_
+ int fh; /* file handle we're checking */
+ ULONG htype; /* handle type */
+
+#ifdef MTHREAD
+ /* 0. Call OS/2 to bump max file count --
+ even though the IO database supports _NFILE_ (256) files,
+ only bump the count to _NFILE_MAXFH_ (40) */
+
+ DOSSETMAXFH(_NFILE_MAXFH_);
+#else
+ #if 0
+ /* This code is intentionally commented out -- to access more
+ than 20 files re-enable this code */
+ DOSSETMAXFH(_NFILE_);
+ #endif
+#endif
+
+ /* 1. check for devices on file handles 0 - 2 */
+ for (fh = 0; fh <= 2; ++fh) {
+ ULONG devattr; /* device attributes */
+
+ /* default: neither pipe nor device */
+ _osfile[fh] &= ~(FDEV | FPIPE);
+
+ if (DOSQUERYHTYPE(fh, &htype, &devattr) == 0) {
+ /* check returned handle type -- only lo byte */
+ if ((htype & 0xFF) == HANDTYPE_DEVICE)
+ _osfile[fh] |= FDEV;
+ else if ((htype & 0xFF) == HANDTYPE_PIPE)
+ _osfile[fh] |= FPIPE;
+ }
+ }
+
+ /* 2. general C initializer routines */
+
+/******* FLOATING POINT INIT SHOULD GO HERE (before initclock) ******/
+
+ __doinits(); /* execute initializers */
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+ /*
+ * initialize floating point package, if present
+ */
+#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
+ /*
+ * The Mips, Alpha, and PPC compilers don't emit external reference to
+ * _fltused. Therefore, must always force in the floating point
+ * initialization.
+ */
+ _fpmath();
+#else
+ if ( _FPinit != NULL )
+ (*_FPinit)();
+#endif
+
+ /*
+ * do initializations
+ */
+ _initterm( __xi_a, __xi_z );
+
+ /*
+ * do C++ initializations
+ */
+ _initterm( __xc_a, __xc_z );
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
+
+#endif /* _MAC_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+}
+
+
+/***
+*exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
+*
+*Purpose:
+*
+* Entry points:
+*
+* exit(code): Performs all the C termination functions
+* and terminates the process with the return code
+* supplied by the user.
+*
+* _exit(code): Performs a quick exit routine that does not
+* do certain 'high-level' exit processing. The _exit
+* routine terminates the process with the return code
+* supplied by the user.
+*
+* _cexit(): Performs the same C lib termination processing
+* as exit(code) but returns control to the caller
+* when done (i.e., does NOT terminate the process).
+*
+* _c_exit(): Performs the same C lib termination processing
+* as _exit(code) but returns control to the caller
+* when done (i.e., does NOT terminate the process).
+*
+* Termination actions:
+*
+* exit(), _cexit():
+*
+* 1. call user's terminator routines
+* 2. call C runtime preterminators
+*
+* _exit(), _c_exit():
+*
+* 3. call C runtime terminators
+* 4. return to DOS or caller
+*
+* Notes:
+*
+* The termination sequence is complicated due to the multiple entry
+* points sharing the common code body while having different entry/exit
+* sequences.
+*
+* Multi-thread notes:
+*
+* 1. exit() should NEVER be called when mthread locks are held.
+* The exit() routine can make calls that try to get mthread locks.
+*
+* 2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
+* Thus, _exit() can NEVER try to get locks (otherwise, deadlock
+* may occur). _exit() should always 'work' (i.e., the process
+* should always terminate successfully).
+*
+* 3. Only one thread is allowed into the exit code (see _lockexit()
+* and _unlockexit() routines).
+*
+*Entry:
+* exit(), _exit()
+* int status - exit status (0-255)
+*
+* _cexit(), _c_exit()
+* <no input>
+*
+*Exit:
+* exit(), _exit()
+* <EXIT to DOS>
+*
+* _cexit(), _c_exit()
+* Return to caller
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+/* worker routine prototype */
+static void _CALLTYPE4 doexit (int code, int quick, int retcaller);
+
+void _CALLTYPE1 exit (
+ int code
+ )
+{
+ doexit(code, 0, 0); /* full term, kill process */
+}
+
+#ifndef _POSIX_
+
+void _CALLTYPE1 _exit (
+ int code
+ )
+{
+ doexit(code, 1, 0); /* quick term, kill process */
+}
+
+void _CALLTYPE1 _cexit (
+ void
+ )
+{
+ doexit(0, 0, 1); /* full term, return to caller */
+}
+
+void _CALLTYPE1 _c_exit (
+ void
+ )
+{
+ doexit(0, 1, 1); /* quick term, return to caller */
+}
+
+#endif /* _POSIX_ */
+
+
+static void _CALLTYPE4 doexit (
+ int code,
+ int quick,
+ int retcaller
+ )
+{
+#ifdef MTHREAD
+ _lockexit(); /* assure only 1 thread in exit path */
+#endif
+
+#if defined(_WIN32_) && defined(CRTDLL)
+ _C_Termination_Done = TRUE;
+#endif
+
+ /* save callable exit flag (for use by terminators) */
+ _exitflag = (char) retcaller; /* 0 = term, !0 = callable exit */
+
+ if (!quick) {
+
+#ifdef _CRUISER_
+ /*
+ * do _onexit/atexit() terminators
+ */
+ if ( __onexitend != NULL )
+ _doinitterm(__onexitend);
+
+ /* call pre-terminators (flushall, rmtmp) */
+ __dopreterms();
+ }
+
+ /* do C terminators */
+ __doterms();
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+ /*
+ * do _onexit/atexit() terminators
+ * (if there are any)
+ *
+ * These terminators MUST be executed in reverse order (LIFO)!
+ *
+ * NOTE:
+ * This code assumes that __onexitbegin points
+ * to the first valid onexit() entry and that
+ * __onexitend points past the last valid entry.
+ * If __onexitbegin == __onexitend, the table
+ * is empty and there are no routines to call.
+ */
+
+ if (__onexitbegin) {
+ PF * pfend = __onexitend;
+
+ while ( -- pfend >= __onexitbegin )
+ /*
+ * if current table entry is non-NULL,
+ * call thru it.
+ */
+ if ( *pfend != NULL )
+ (**pfend)();
+ }
+
+ /*
+ * do pre-terminators
+ */
+ _initterm(__xp_a, __xp_z);
+ }
+
+ /*
+ * do terminators
+ */
+ _initterm(__xt_a, __xt_z);
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#error ERROR - ONLY CRUISER, WIN32, OR POSIX TARGET SUPPORTED!
+
+#endif /* _WIN32_ || _POSIX_ */
+
+#endif /* _CRUISER_ */
+
+
+#ifdef _WIN32DOS_
+
+/*
+ * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE
+ * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT
+ * VirtualAlloc()!
+ */
+
+ HeapDestroy(_HeapHandle);
+
+#endif /* _WIN32DOS_ */
+
+
+/********** FLOATING POINT TERMINATION SHOULD GO HERE ************/
+
+ /* return to OS/2 or to caller */
+ if (retcaller) {
+#ifdef MTHREAD
+ _unlockexit(); /* unlock the exit code path */
+#endif
+ return;
+ }
+
+#ifdef _CRUISER_
+
+ DOSEXIT(EXIT_PROCESS, code);
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ ExitProcess(code);
+
+#else /* ndef _WIN32_ */
+
+#ifdef _POSIX_
+
+ _exit(code);
+
+#else /* ndef _POSIX_ */
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
+
+#endif /* _POSIX_ */
+
+#endif /* _MAC_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+}
+
+#ifdef MTHREAD
+/***
+* _lockexit - Aquire the exit code lock
+*
+*Purpose:
+* Makes sure only one thread is in the exit code at a time.
+* If a thread is already in the exit code, it must be allowed
+* to continue. All other threads must pend.
+*
+* Notes:
+*
+* (1) It is legal for a thread that already has the lock to
+* try and get it again(!). That is, consider the following
+* sequence:
+*
+* (a) program calls exit()
+* (b) thread locks exit code
+* (c) user onexit() routine calls _exit()
+* (d) same thread tries to lock exit code
+*
+* Since _exit() must ALWAYS be able to work (i.e., can be called
+* from anywhere with no regard for locking), we must make sure the
+* program does not deadlock at step (d) above.
+*
+* (2) If a thread executing exit() or _exit() aquires the exit lock,
+* other threads trying to get the lock will pend forever. That is,
+* since exit() and _exit() terminate the process, there is not need
+* for them to unlock the exit code path.
+*
+* (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
+* to protect mthread access to the onexit table.
+*
+* (4) The _lockexit/_unlockexit routines are very complicated in 286
+* OS/2 since a thread that held a lock could not request the lock again.
+* The 32-bit OS/2 semaphore calls DO allow a single thread to aquire the
+* same lock multiple times* thus, this version is straight forward.
+*
+*Entry: <none>
+*
+*Exit:
+* Calling thread has exit code path locked on return.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _lockexit (
+ void
+ )
+{
+ _mlock(_EXIT_LOCK1);
+}
+
+/***
+* _unlockexit - Release exit code lock
+*
+*Purpose:
+* [See _lockexit() description above.]
+*
+* This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
+* The exit() and _exit() routines never unlock the exit code path since
+* they are terminating the process.
+*
+*Entry:
+* Exit code path is unlocked.
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _unlockexit (
+ void
+ )
+{
+ _munlock(_EXIT_LOCK1);
+}
+
+#endif /* MTHREAD */
+
+
+#if defined(_WIN32_) || defined(_POSIX_)
+
+/***
+* static void _initterm(PF * pfbegin, PF * pfend) - call entries in
+* function pointer table
+*
+*Purpose:
+* Walk a table of function pointers, calling each entry, as follows:
+*
+* 1. walk from beginning to end, pfunctbl is assumed to point
+* to the beginning of the table, which is currently a null entry,
+* as is the end entry.
+* 2. skip NULL entries
+* 3. stop walking when the end of the table is encountered
+*
+*Entry:
+* PF *pfbegin - pointer to the beginning of the table (first valid entry).
+* PF *pfend - pointer to the end of the table (after last valid entry).
+*
+*Exit:
+* No return value
+*
+*Notes:
+* This routine must be exported in the CRT DLL model so that the client
+* EXE and client DLL(s) can call it to initialize their C++ constructors.
+*
+*Exceptions:
+* If either pfbegin or pfend is NULL, or invalid, all bets are off!
+*
+*******************************************************************************/
+
+#ifdef CRTDLL
+void _CALLTYPE1 _initterm (
+#else
+static void _CALLTYPE4 _initterm (
+#endif
+ PF * pfbegin,
+ PF * pfend
+ )
+{
+ /*
+ * walk the table of function pointers from the bottom up, until
+ * the end is encountered. Do not skip the first entry. The initial
+ * value of pfbegin points to the first valid entry. Do not try to
+ * execute what pfend points to. Only entries before pfend are valid.
+ */
+ while ( pfbegin < pfend )
+ {
+ /*
+ * if current table entry is non-NULL, call thru it.
+ */
+ if ( *pfbegin != NULL )
+ (**pfbegin)();
+ ++pfbegin;
+ }
+}
+
+#endif /* _WIN32_ || _POSIX_ */
diff --git a/private/crt32/startup/crt0fp.c b/private/crt32/startup/crt0fp.c
new file mode 100644
index 000000000..ba8a2eb0c
--- /dev/null
+++ b/private/crt32/startup/crt0fp.c
@@ -0,0 +1,57 @@
+/***
+*crt0fp.asm - floating point not loaded trap
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* To trap certain cases where certain necessary floating-point
+* software is not loaded. Two specific cases are when no emulator
+* is linked in but no coprocessor is present, and when floating
+* point i/o conversions are done, but no floating-point variables
+* or expressions are used in the program.
+*
+*Revision History:
+* 06-29-89 PHG module created, based on asm version
+* 04-09-90 GJF Added #include <cruntime.h>. Made calling type
+* _CALLTYPE1. Also, fixed the copyright.
+* 04-10-90 GJF Fixed compiler warnings (-W3).
+* 10-08-90 GJF New-style function declarator.
+* 10-11-90 GJF Changed _amsg_exit() interface.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <internal.h>
+#include <rterr.h>
+
+
+/***
+*_fptrap - trap for missing floating-point software
+*
+*Purpose:
+* Catches these cases of incomplete f.p. software linked into a program.
+*
+* (1) no coprocessor present, and no emulator linked in
+*
+* (2) "%e", "%f", and "%g" i/o conversion formats specified, but
+* not all conversion software has been linked in, because the
+* program did not use any floating-point variables or expressions.
+*
+*Entry:
+* None.
+*
+*Exit:
+* Never returns.
+*
+*Exceptions:
+* Transfers control to _amsg_exit which ...
+* - Writes error message to standard error: "floating point not loaded"
+* - Terminates the program by calling _exit().
+*******************************************************************************/
+
+void _CALLTYPE1 _fptrap(
+ void
+ )
+{
+ _amsg_exit(_RT_FLOAT);
+}
diff --git a/private/crt32/startup/crt0init.c b/private/crt32/startup/crt0init.c
new file mode 100644
index 000000000..cabf03a5d
--- /dev/null
+++ b/private/crt32/startup/crt0init.c
@@ -0,0 +1,69 @@
+/***
+*crt0init.c - Initialization segment declarations.
+*
+* Copyright (c) 1992-1994, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Do initialization segment declarations.
+*
+*Notes:
+* In the 16-bit C world, the X*B and X*E segments were empty except for
+* a label. This will not work with COFF since COFF throws out empty
+* sections. Therefore we must put a zero value in them. (Zero because
+* the routine to traverse the initializers will skip over zero entries.)
+*
+*Revision History:
+* 03-19-92 SKS Module created.
+* 03-24-92 SKS Added MIPS support (NO_UNDERSCORE)
+* 08-06-92 SKS Revised to use new section names and macros
+* 10-19-93 SKS Add .DiRECTiVE section for MIPS, too!
+* 10-28-93 GJF Rewritten in C
+* 10-28-94 SKS Add user32.lib as a default library
+* 02-27-95 CFW Remove user32.lib as a default library
+*
+*******************************************************************************/
+
+#ifdef _MSC_VER
+
+
+#include <stdio.h>
+#include <internal.h>
+
+#pragma data_seg(".CRT$XIA")
+_PVFV __xi_a[] = { NULL };
+
+
+#pragma data_seg(".CRT$XIZ")
+_PVFV __xi_z[] = { NULL };
+
+
+#pragma data_seg(".CRT$XCA")
+_PVFV __xc_a[] = { NULL };
+
+
+#pragma data_seg(".CRT$XCZ")
+_PVFV __xc_z[] = { NULL };
+
+
+#pragma data_seg(".CRT$XPA")
+_PVFV __xp_a[] = { NULL };
+
+
+#pragma data_seg(".CRT$XPZ")
+_PVFV __xp_z[] = { NULL };
+
+
+#pragma data_seg(".CRT$XTA")
+_PVFV __xt_a[] = { NULL };
+
+
+#pragma data_seg(".CRT$XTZ")
+_PVFV __xt_z[] = { NULL };
+
+
+#pragma data_seg(".drectve")
+static char __drectve_win32lib[] =
+ "-merge:.CRT=.rdata -ignore:4078";
+#pragma data_seg() /* reset */
+
+#endif /* _MSC_VER */
diff --git a/private/crt32/startup/crt0msg.c b/private/crt32/startup/crt0msg.c
new file mode 100644
index 000000000..5be8938e9
--- /dev/null
+++ b/private/crt32/startup/crt0msg.c
@@ -0,0 +1,231 @@
+/***
+*crt0msg.c - startup error messages
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Prints out banner for runtime error messages.
+*
+*Revision History:
+* 06-27-89 PHG Module created, based on asm version
+* 04-09-90 GJF Added #include <cruntime.h>. Made calling type
+* _CALLTYPE1. Also, fixed the copyright.
+* 04-10-90 GJF Fixed compiler warnings (-W3).
+* 06-04-90 GJF Revised to be more compatible with old scheme.
+* nmsghdr.c merged in.
+* 10-08-90 GJF New-style function declarators.
+* 10-11-90 GJF Added _RT_ABORT, _RT_FLOAT, _RT_HEAP.
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
+* 02-04-91 SRW Changed to call WriteFile (_WIN32_)
+* 02-25-91 MHL Adapt to ReadFile/WriteFile changes (_WIN32_)
+* 04-10-91 PNT Added _MAC_ conditional
+* 09-09-91 GJF Added _RT_ONEXIT error.
+* 09-18-91 GJF Added 3 math errors, also corrected comments for
+* errors that were changed in rterr.h, cmsgs.h.
+* 03-31-92 DJM POSIX support.
+* 10-23-92 GJF Added _RT_PUREVIRT.
+* 04-29-93 GJF Removed rterrs[] entries for _RT_STACK, _RT_INTDIV,
+* _RT_NONCONT and _RT_INVALDISP.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <internal.h>
+#include <stddef.h>
+#include <string.h>
+#include <rterr.h>
+#include <cmsgs.h>
+#include <oscalls.h>
+
+#ifdef _POSIX_
+#include <posix\sys\types.h>
+#include <posix\unistd.h>
+#endif
+
+/* struct used to lookup and access runtime error messages */
+
+struct rterrmsgs {
+ int rterrno; /* error number */
+ char *rterrtxt; /* text of error message */
+};
+
+/* runtime error messages */
+
+static struct rterrmsgs rterrs[] = {
+
+ /* 0 */
+ /* { _RT_STACK, _RT_STACK_TXT }, */
+
+ /* 2 */
+ { _RT_FLOAT, _RT_FLOAT_TXT },
+
+ /* 3 */
+ /* { _RT_INTDIV, _RT_INTDIV_TXT }, */
+
+ /* 8 */
+ { _RT_SPACEARG, _RT_SPACEARG_TXT },
+
+ /* 9 */
+ { _RT_SPACEENV, _RT_SPACEENV_TXT },
+
+ /* 10 */
+ { _RT_ABORT, _RT_ABORT_TXT },
+
+ /* 16 */
+ { _RT_THREAD, _RT_THREAD_TXT },
+
+ /* 17 */
+ { _RT_LOCK, _RT_LOCK_TXT },
+
+ /* 18 */
+ { _RT_HEAP, _RT_HEAP_TXT },
+
+ /* 19 */
+ { _RT_OPENCON, _RT_OPENCON_TXT },
+
+ /* 22 */
+ /* { _RT_NONCONT, _RT_NONCONT_TXT }, */
+
+ /* 23 */
+ /* { _RT_INVALDISP, _RT_INVALDISP_TXT }, */
+
+#ifdef _WIN32_
+
+ /* 24 */
+ { _RT_ONEXIT, _RT_ONEXIT_TXT },
+
+#endif
+
+ /* 25 */
+ { _RT_PUREVIRT, _RT_PUREVIRT_TXT },
+
+ /* 120 */
+ { _RT_DOMAIN, _RT_DOMAIN_TXT },
+
+ /* 121 */
+ { _RT_SING, _RT_SING_TXT },
+
+ /* 122 */
+ { _RT_TLOSS, _RT_TLOSS_TXT },
+
+ /* 252 */
+ { _RT_CRNL, _RT_CRNL_TXT },
+
+ /* 255 */
+ { _RT_BANNER, _RT_BANNER_TXT }
+
+};
+
+/* number of elements in rterrs[] */
+
+#define _RTERRCNT ( sizeof(rterrs) / sizeof(struct rterrmsgs) )
+
+/* For C, _FF_DBGMSG is inactive, so _adbgmsg is
+ set to null
+ For FORTRAN, _adbgmsg is set to point to
+ _FF_DBGMSG in dbginit initializer in dbgmsg.asm */
+
+void (*_adbgmsg)(void) = NULL;
+
+/***
+*_FF_MSGBANNER - writes out first part of run-time error messages
+*
+*Purpose:
+* This routine writes "\r\nrun-time error " to standard error.
+*
+* For FORTRAN $DEBUG error messages, it also uses the _FF_DBGMSG
+* routine whose address is stored in the _adbgmsg variable to print out
+* file and line number information associated with the run-time error.
+* If the value of _adbgmsg is found to be null, then the _FF_DBGMSG
+* routine won't be called from here (the case for C-only programs).
+*
+*Entry:
+* No arguments.
+*
+*Exit:
+* Nothing returned.
+*
+*Exceptions:
+* None handled.
+*
+*******************************************************************************/
+
+void _CRTAPI1 _FF_MSGBANNER (
+ void
+ )
+{
+ _NMSG_WRITE(_RT_CRNL); /* new line to begin error message */
+ if (_adbgmsg != 0)
+ _adbgmsg(); /* call __FF_DBGMSG for FORTRAN */
+ _NMSG_WRITE(_RT_BANNER); /* run-time error message banner */
+}
+
+
+/***
+*__NMSGWRITE(message) - write a given message to handle 2 (stderr)
+*
+*Purpose:
+* This routine writes the message associated with rterrnum
+* to stderr.
+*
+*Entry:
+* int rterrnum - runtime error number
+*
+*Exit:
+* no return value
+*
+*Exceptions:
+* none
+*
+*******************************************************************************/
+
+void _CRTAPI1 _NMSG_WRITE (
+ int rterrnum
+ )
+{
+ int tblindx;
+#ifndef _POSIX_
+ DWORD bytes_written; /* bytes written */
+#endif
+
+ for ( tblindx = 0 ; tblindx < _RTERRCNT ; tblindx++ )
+ if ( rterrnum == rterrs[tblindx].rterrno )
+ break;
+
+ if ( rterrnum == rterrs[tblindx].rterrno )
+#ifdef _CRUISER_
+
+ DOSWRITE(2, rterrs[tblindx].rterrtxt,
+ strlen(rterrs[tblindx].rterrtxt), &bytes_written);
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ WriteFile((HANDLE)_osfhnd[2], rterrs[tblindx].rterrtxt,
+ strlen(rterrs[tblindx].rterrtxt), &bytes_written, NULL);
+
+#else /* ndef _WIN32_ */
+
+#ifdef _POSIX_
+ write(STDERR_FILENO,rterrs[tblindx].rterrtxt,
+ strlen(rterrs[tblindx].rterrtxt));
+#else
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, POSIX, OR MAC TARGET SUPPORTED!
+
+#endif /* _MAC_ */
+
+#endif /* _POSIX_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+}
diff --git a/private/crt32/startup/dllcrt0.c b/private/crt32/startup/dllcrt0.c
new file mode 100644
index 000000000..9f3b7003a
--- /dev/null
+++ b/private/crt32/startup/dllcrt0.c
@@ -0,0 +1,306 @@
+#ifndef _POSIX_ /* not built for POSIX */
+#ifndef CRTDLL /* not built for CRTDLL */
+
+/***
+*dllcrt0.c - C runtime initialization routine for a DLL with linked-in C R-T
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This the startup routine for a DLL which is linked with its own
+* C run-time code. It is similar to the routine _mainCRTStartup()
+* in the file CRT0.C, except that there is no main() in a DLL.
+*
+*Revision History:
+* 05-04-92 SKS Based on CRT0.C (start-up code for EXE's)
+* 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
+* 09-16-92 SKS This module used to be enabled only in LIBCMT.LIB,
+* but it is now enabled for LIBC.LIB as well!
+* 09-29-92 SKS _CRT_INIT needs to be WINAPI, not cdecl
+* 10-16-92 SKS Call _heap_init before _mtinit (fix copied from CRT0.C)
+* 10-24-92 SKS Call to _mtdeletelocks() must be under #ifdef MTHREAD!
+* 04-16-93 SKS Call _mtterm instead of _mtdeletelocks on
+* PROCESS_DETACH to do all multi-thread cleanup
+* It will call _mtdeletelocks and free up the TLS index.
+* 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
+* _RT_INVALDISP and _RT_NONCONT.
+* 05-11-93 SKS Add _DllMainCRTStartup to co-exist with _CRT_INIT
+* _mtinit now returns 0 or 1, no longer calls _amsg_exit
+* Delete obsolete variable _atopsp
+* 06-03-93 GJF Added __proc_attached flag.
+* 06-08-93 SKS Clean up failure handling in _CRT_INIT
+* 12-13-93 SKS Free up per-thread CRT data on DLL_THREAD_DETACH
+* using a call to _freeptd() in _CRT_INIT()
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <dos.h>
+#include <internal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rterr.h>
+#include <oscalls.h>
+#define _DECL_DLLMAIN /* enable prototypes for DllMain and _CRT_INIT */
+#include <process.h>
+
+
+/*
+ * flag set iff _CRTDLL_INIT was called with DLL_PROCESS_ATTACH
+ */
+static int __proc_attached = 0;
+
+
+/*
+ * command line, environment, and a few other globals
+ */
+char *_acmdln; /* points to command line */
+char *_aenvptr; /* points to environment block */
+
+void (_CALLTYPE1 * _aexit_rtn)(int) = _exit; /* RT message return procedure */
+
+
+/*
+ * User routine DllMain is called on all notifications
+ */
+
+extern BOOL WINAPI DllMain(
+ HANDLE hDllHandle,
+ DWORD dwReason,
+ LPVOID lpreserved
+ ) ;
+
+
+/***
+*BOOL WINAPI _CRT_INIT(hDllHandle, dwReason, lpreserved) - C Run-Time
+* initialization for a DLL linked with a C run-time library.
+*
+*Purpose:
+* This routine does the C run-time initialization.
+* For the multi-threaded run-time library, it also cleans up the
+* multi-threading locks on DLL termination.
+*
+*Entry:
+*
+*Exit:
+*
+*NOTES:
+* This routine should either be the entry-point for the DLL
+* or else be called by the entry-point routine for the DLL.
+*
+*******************************************************************************/
+
+BOOL WINAPI
+_CRT_INIT(
+ HANDLE hDllHandle,
+ DWORD dwReason,
+ LPVOID lpreserved
+ )
+{
+ switch (dwReason) {
+ case DLL_PROCESS_DETACH:
+ /*
+ * make sure there has been prior process attach
+ * notification!
+ */
+ if ( __proc_attached > 0 ) {
+ __proc_attached--;
+
+ if ( _C_Termination_Done == FALSE ) {
+ /* do exit() time clean-up */
+ _cexit();
+ }
+
+#ifdef MTHREAD
+ /* delete MT locks, free TLS index, etc. */
+ _mtterm();
+#endif
+ if (_aenvptr) {
+ FreeEnvironmentStrings(_aenvptr);
+ _aenvptr=NULL;
+ }
+
+ return TRUE;
+
+ } else {
+ /* no prior process attach, just return */
+ return FALSE;
+ }
+
+#ifdef MTHREAD
+ case DLL_THREAD_DETACH:
+ _freeptd(NULL); /* free up per-thread CRT data */
+
+ case DLL_THREAD_ATTACH:
+ return TRUE;
+#endif
+
+ case DLL_PROCESS_ATTACH:
+
+ /*
+ * increment flag to indicate process attach notification has been
+ * received
+ */
+ __proc_attached++;
+
+ _acmdln = (char *)GetCommandLine();
+ _aenvptr = (char *)GetEnvironmentStrings();
+
+ /*
+ * Get the full Win32 version
+ */
+ _osversion = /* OBSOLETE */
+ _osver = GetVersion();
+
+ _winminor = (_osver >> 8) & 0x00FF ;
+ _winmajor = _osver & 0x00FF ;
+ _winver = (_winmajor << 8) + _winminor;
+ _osver = (_osver >> 16) & 0x00FFFF ;
+
+ /* --------- The following block is OBSOLETE --------- */
+
+ /*
+ * unpack base version info
+ */
+ _baseversion = (_osversion & 0xFFFF0000) >> 16;
+ _baseminor = _baseversion & 0x00FF;
+ _basemajor = (_baseversion & 0xFF00) >> 8;
+
+ /*
+ * unpack top-level version info (Windows version)
+ */
+ _osversion &= 0x0000FFFF;
+ _osmajor = _osversion & 0x00FF;
+ _osminor = (_osversion & 0xFF00) >> 8;
+
+ /* --------- The preceding block is OBSOLETE --------- */
+
+ _heap_init(); /* initialize heap */
+
+#ifdef MTHREAD
+ if(!_mtinit()) { /* initialize multi-thread */
+ FreeEnvironmentStrings(_aenvptr);
+ return FALSE; /* fail to load DLL */
+ }
+#endif
+ _ioinit(); /* initialize lowio */
+ _setargv(); /* get cmd line info */
+ _setenvp(); /* get environ info */
+
+ _cinit(); /* do C data initialize */
+
+ return TRUE; /* initialization succeeded */
+ }
+}
+
+
+/***
+*BOOL WINAPI _DllMainCRTStartup(hDllHandle, dwReason, lpreserved) -
+* C Run-Time initialization for a DLL linked with a C run-time library.
+*
+*Purpose:
+* This routine does the C run-time initialization or termination
+* and then calls the user code notification handler "DllMain".
+* For the multi-threaded run-time library, it also cleans up the
+* multi-threading locks on DLL termination.
+*
+*Entry:
+*
+*Exit:
+*
+*NOTES:
+* This routine should be the entry point for the DLL if
+* the user is not supplying one and calling _CRT_INIT.
+*
+*******************************************************************************/
+BOOL WINAPI _DllMainCRTStartup(
+ HANDLE hDllHandle,
+ DWORD dwReason,
+ LPVOID lpreserved
+ )
+{
+ BOOL retcode = TRUE;
+
+ /*
+ * If this is a process attach notification, increment the process
+ * attached flag. If this is a process detach notification, check
+ * that there has been a prior process attach notification.
+ */
+ if ( dwReason == DLL_PROCESS_ATTACH )
+ __proc_attached++;
+ else if ( dwReason == DLL_PROCESS_DETACH ) {
+ if ( __proc_attached > 0 )
+ __proc_attached--;
+ else
+ /*
+ * no prior process attach notification. just return
+ * without doing anything.
+ */
+ return FALSE;
+ }
+
+ if ( dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_THREAD_ATTACH )
+ retcode = _CRT_INIT(hDllHandle, dwReason, lpreserved);
+
+ if ( retcode )
+ retcode = DllMain(hDllHandle, dwReason, lpreserved);
+
+ /*
+ * If _CRT_INIT successfully handles a Process Attach notification
+ * but the user's DllMain routine returns failure, we need to do
+ * clean-up of the C run-time similar to what _CRT_INIT does on a
+ * Process Detach Notification.
+ */
+
+ if ( retcode == FALSE && dwReason == DLL_PROCESS_ATTACH )
+ {
+ /* Failure to attach DLL - must clean up C run-time */
+#ifdef MTHREAD
+ _mtterm();
+#endif
+ if (_aenvptr) {
+ FreeEnvironmentStrings(_aenvptr);
+ _aenvptr=NULL;
+ }
+ }
+
+ if ( dwReason == DLL_PROCESS_DETACH || dwReason == DLL_THREAD_DETACH )
+ {
+ if ( _CRT_INIT(hDllHandle, dwReason, lpreserved) == FALSE )
+ retcode = FALSE ;
+ }
+
+ return retcode ;
+}
+
+
+/***
+*_amsg_exit(rterrnum) - Fast exit fatal errors
+*
+*Purpose:
+* Exit the program with error code of 255 and appropriate error
+* message.
+*
+*Entry:
+* int rterrnum - error message number (amsg_exit only).
+*
+*Exit:
+* Calls exit() (for integer divide-by-0) or _exit() indirectly
+* through _aexit_rtn [amsg_exit].
+* For multi-thread: calls _exit() function
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _amsg_exit (
+ int rterrnum
+ )
+{
+ _FF_MSGBANNER(); /* write run-time error banner */
+ _NMSG_WRITE(rterrnum); /* write message */
+
+ _aexit_rtn(255); /* normally _exit(255) */
+}
+#endif /* CRTDLL */
+#endif /* _POSIX_ */
diff --git a/private/crt32/startup/dllmain.c b/private/crt32/startup/dllmain.c
new file mode 100644
index 000000000..8fd0ea706
--- /dev/null
+++ b/private/crt32/startup/dllmain.c
@@ -0,0 +1,42 @@
+/***
+*dllmain.c - Dummy DllMain for user DLLs that have no notification handler
+*
+* Copyright (c) 1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This object goes into LIBC.LIB and LIBCMT.LIB and MSVCRT.LIB for use
+* when linking a DLL with one of the three models of C run-time library.
+* If the user does not provide a DllMain notification routine, this
+* dummy handler will be linked in. It always returns TRUE (success).
+*
+*Revision History:
+* 04-14-93 SKS Initial version
+*
+******************************************************************************/
+
+#include <oscalls.h>
+
+/***
+*DllMain - dummy version DLLs linked with all 3 C Run-Time Library models
+*
+*Purpose:
+* The routine DllMain is always called by _DllMainCrtStartup. If
+* the user does not provide a routine named DllMain, this one will
+* get linked in so that _DllMainCRTStartup has something to call.
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+******************************************************************************/
+
+BOOL WINAPI DllMain(
+ HANDLE hDllHandle,
+ DWORD dwReason,
+ LPVOID lpreserved
+ )
+{
+ return TRUE ;
+}
diff --git a/private/crt32/startup/i386/atlssup.asm b/private/crt32/startup/i386/atlssup.asm
new file mode 100644
index 000000000..590930817
--- /dev/null
+++ b/private/crt32/startup/i386/atlssup.asm
@@ -0,0 +1,15 @@
+; SCCSID = \%Z\%\%M\%:\%I\%
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+.xlist
+include cruntime.inc
+.list
+
+; This symbol is being defined in the C language model
+; and will have an extra underscore character prepended.
+
+ public _tls_array
+_tls_array equ 2Ch ; TEB.ThreadLocalStoragePointer
+
+end
diff --git a/private/crt32/startup/i386/chkstk.asm b/private/crt32/startup/i386/chkstk.asm
new file mode 100644
index 000000000..bd05942d5
--- /dev/null
+++ b/private/crt32/startup/i386/chkstk.asm
@@ -0,0 +1,127 @@
+ page ,132
+ title chkstk - C stack checking routine
+;***
+;chkstk.asm - C stack checking routine
+;
+; Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Provides support for automatic stack checking in C procedures
+; when stack checking is enabled.
+;
+;Revision History:
+; 04-21-87 SKS Added conditional assembly switch for STKHQQ = 0
+; 07-23-87 MAG [1] Added run-time CS:IP error processing for QC
+; 08-17-87 JLS [2] Remove all references to DGROUP
+; 08-25-87 JLS [3] Shift include files
+; 11-13-87 SKS OS/2 Reentrant version, add thread ID check
+; 11-18-87 SKS Make STKHQQ an array (oops!)
+; 12-14-87 SKS add .286p to allow PUSH immediate value
+; 02-19-88 SKS Change minimum bottom limit to STACKSLOP, not 0
+; 06-01-88 PHG Merge DLL and normal versions
+; 09-21-88 WAJ initial 386 version
+; 10-18-88 JCR Chkstk was trashing bx... not good on 386
+; 06-06-89 JCR 386 mthread support
+; 06-20-89 JCR 386: Removed _LOAD_DGROUP code
+; 04-06-90 GJF Fixed the copyright.
+; 06-21-90 GJF Rewritten to probe pages
+; 10-15-90 GJF Restored _end and STKHQQ.
+; 03-19-91 GJF Revised to preserve all registers except eax. Note
+; this is _rchkstk functionality so there is no longer
+; a separate _rchkstk routine.
+; 08-01-91 GJF Got rid of _end and STKHQQ, except for Cruiser
+; (probably not needed for Cruiser either) [_WIN32_].
+; 09-27-91 JCR Merged Stevewo' changes from NT tree
+;
+;*******************************************************************************
+
+.xlist
+ include cruntime.inc
+ include msdos.inc
+.list
+
+; size of a page of memory
+
+_PAGESIZE_ equ 1000h
+
+
+ifdef _CRUISER_
+
+ .data
+
+extrn pascal _end:dword ; stack bottom
+
+ifndef MTHREAD
+
+public pascal STKHQQ ; used by parasitic heap
+STKHQQ dd dataoffset _end+STACKSLOP ; initial value
+
+endif ;MTHREAD
+
+endif ;_CRUISER_
+
+ CODESEG
+
+page
+;***
+;_chkstk - check stack upon procedure entry
+;
+;Purpose:
+; Provide stack checking on procedure entry. Method is to simply probe
+; each page of memory required for the stack in descending order. This
+; causes the necessary pages of memory to be allocated via the guard
+; page scheme, if possible. In the event of failure, the OS raises the
+; _XCPT_UNABLE_TO_GROW_STACK exception.
+;
+; NOTE: Currently, the (EAX < _PAGESIZE_) code path falls through
+; to the "lastpage" label of the (EAX >= _PAGESIZE_) code path. This
+; is small; a minor speed optimization would be to special case
+; this up top. This would avoid the painful save/restore of
+; ecx and would shorten the code path by 4-6 instructions.
+;
+;Entry:
+; EAX = size of local frame
+;
+;Exit:
+; ESP = new stackframe, if successful
+;
+;Uses:
+; EAX
+;
+;Exceptions:
+; _XCPT_GUARD_PAGE_VIOLATION - May be raised on a page probe. NEVER TRAP
+; THIS!!!! It is used by the OS to grow the
+; stack on demand.
+; _XCPT_UNABLE_TO_GROW_STACK - The stack cannot be grown. More precisely,
+; the attempt by the OS memory manager to
+; allocate another guard page in response
+; to a _XCPT_GUARD_PAGE_VIOLATION has
+; failed.
+;
+;*******************************************************************************
+
+labelP _alloca_probe, PUBLIC
+labelP _chkstk, PUBLIC
+
+ push ecx ; save ecx
+ mov ecx,esp ; compute new stack pointer in ecx
+ add ecx,8 ; correct for return address and saved
+ ; ecx value
+probepages:
+ cmp eax,_PAGESIZE_ ; more than one page requested?
+ jb short lastpage ; no
+ sub ecx,_PAGESIZE_ ; yes, move down a page and...
+ or dword ptr [ecx],0 ; ...probe it
+ sub eax,_PAGESIZE_ ; adjust request
+ jmp probepages
+
+lastpage:
+ sub ecx,eax ; move stack down by eax and do a...
+ or dword ptr [ecx],0 ; ...probe in case a page was crossed
+ mov eax,esp ; save pointer to current tos
+ mov esp,ecx ; set the new stack pointer
+ mov ecx,dword ptr [eax] ; recover ecx
+ mov eax,dword ptr [eax + 4] ; recover return address
+ jmp eax ; return
+
+ end
diff --git a/private/crt32/startup/makefile b/private/crt32/startup/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/crt32/startup/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/crt32/startup/makefile.inc b/private/crt32/startup/makefile.inc
new file mode 100644
index 000000000..3db9c8c1c
--- /dev/null
+++ b/private/crt32/startup/makefile.inc
@@ -0,0 +1,3 @@
+_setargv.c: stdargv.c
+
+wincrt0.c: crt0.c
diff --git a/private/crt32/startup/mips/chkstk.s b/private/crt32/startup/mips/chkstk.s
new file mode 100644
index 000000000..3ba199fea
--- /dev/null
+++ b/private/crt32/startup/mips/chkstk.s
@@ -0,0 +1,104 @@
+// TITLE("Runtime Stack Checking")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// chkstk.s
+//
+// Abstract:
+//
+// This module implements runtime stack checking.
+//
+// Author:
+//
+// David N. Cutler (davec) 14-Mar-1991
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Check Stack")
+//++
+//
+// ULONG
+// _RtlCheckStack (
+// IN ULONG Allocation
+// )
+//
+// Routine Description:
+//
+// This function provides runtime stack checking for local allocations
+// that are more than a page and for storage dynamically allocated with
+// the alloca function. Stack checking consists of probing downward in
+// the stack a page at a time. If the current stack commitment is exceeded,
+// then the system will automatically attempt to expand the stack. If the
+// attempt succeeds, then another page is committed. Otherwise, a stack
+// overflow exception is raised. It is the responsiblity of the caller to
+// handle this exception.
+//
+// N.B. This routine is called using a calling sequence that assumes that
+// all registers are preserved.
+//
+// Arguments:
+//
+// Allocation (t8) - Supplies the size of the allocation on the stack.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ NESTED_ENTRY(_RtlCheckStack, 0, ra)
+
+ sw t7,0(sp) // save temporary register
+ sw t8,4(sp) // save allocation size
+ sw t9,8(sp) // save temporary register
+
+ PROLOGUE_END
+
+ .set noreorder
+ .set noat
+ li t9,UsPcr // get address of user PCR
+ bgez sp,10f // if gez, running on user stack
+ subu t8,sp,t8 // compute new bottom of stack
+
+//
+// Running on kernel stack - compute stack limit from initial kernel stack.
+//
+
+ lw t9,KiPcr + PcInitialStack(zero) // get initial kernel stack
+ b 20f // finish in common code
+ subu t9,t9,KERNEL_STACK_SIZE // compute low limit of kernel stack
+
+//
+// Running on user stack - get stack limit from thread environment block.
+//
+
+10: lw t9,PcTeb(t9) // get address of environment block
+ nop // fill
+ lw t9,TeStackLimit(t9) // get low stack address
+ nop // fill
+20: sltu t7,t8,t9 // new stack address within limits?
+ beq zero,t7,40f // if eq, stack within limits
+ li t7,~(PAGE_SIZE - 1) // set address mask
+ and t8,t8,t7 // round down new stack address
+30: subu t9,t9,PAGE_SIZE // compute next address to check
+ bne t8,t9,30b // if ne, more pages to probe
+ sw zero,0(t9) // check stack address
+40: lw t7,0(sp) // restore temporary register
+ lw t8,4(sp) // restore allocation size
+ j ra // return
+ lw t9,8(sp) // restore temporary register
+ .set at
+ .set reorder
+
+ .end _RtlCheckStack
diff --git a/private/crt32/startup/mlock.c b/private/crt32/startup/mlock.c
new file mode 100644
index 000000000..8c8cf33ea
--- /dev/null
+++ b/private/crt32/startup/mlock.c
@@ -0,0 +1,382 @@
+#ifdef MTHREAD
+
+/***
+*mlock.c - Multi-thread locking routines
+*
+* Copyright (c) 1987-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*
+*Revision History:
+* 05-07-90 JCR Module created.
+* 06-04-90 GJF Changed error message interface.
+* 08-08-90 GJF Removed 32 from API names.
+* 08-08-90 SBM _lockmap no longer 8 times required size
+* 10-08-90 GJF New-style function declarators. Removed questionable
+* return statements from void functions (weren't needed
+* and the compiler was bitching).
+* 10-09-90 GJF Thread ids are unsigned longs.
+* 06-06-91 GJF Adapted for Win32 [_WIN32_].
+* 09-29-91 GJF Fixed infinite recursion problem with DEBUG version
+* of _lock [_WIN32_].
+* 03-06-92 GJF Removed _[un]lock_fh() and _[un]lock_stream for Win32
+* targets.
+* 05-28-92 GJF Added _mtdeletelocks() for Win32 for DLLs with contain
+* the C runtime (e.g., crtdll.dll).
+* 10-06-92 SRW Make _locktable an array of PCRITICAL_SECTION pointers
+* instead of structures. Allocate each critical section
+* as it is needed.
+* 02-25-93 GJF Substantially revised. Restored static critical section
+* structures for some locks. Replaced bit-array scheme
+* of keeping track of locks. Removed Cruiser support and
+* replaced obsolete DEBUG code.
+* 03-03-93 GJF Made CRITICAL_SECTION structure for _HEAP_LOCK static.
+* 03-08-93 SKS Fix ptr use error in DEBUG version of _mtdeletelocks
+* 03-08-93 SKS Fix deletion of the special critical sections,
+* especially the heap lock.
+* 05-05-93 GJF Turned DEBUG code off.
+* 06-03-93 SRW Disable FPO optimizations for this file so it can call
+* CriticalSection routines on a checked build even though
+* the C Runtimes are compiled free.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <oscalls.h>
+#include <internal.h>
+#include <os2dll.h>
+#include <rterr.h>
+#include <stddef.h>
+#include <malloc.h>
+#include <limits.h>
+
+
+/*
+ * Local routines
+ */
+void _CRTAPI3 _lockerr_exit(char *);
+
+
+/*
+ * Global Data
+ */
+
+/*
+ * Statically allocated critical section structures for _LOCKTAB_LOCK,
+ * _EXIT_LOCK1 and _HEAP_LOCK.
+ */
+static CRITICAL_SECTION ltlcritsect;
+static CRITICAL_SECTION xlcritsect;
+static CRITICAL_SECTION hlcritsect;
+
+/*
+ * Lock Table
+ * This table contains a pointer to the critical section management structure
+ * for each lock.
+ */
+PCRITICAL_SECTION _locktable[_TOTAL_LOCKS] = {
+ NULL, /* 0 == no lock defined *** OBSOLETE *** */
+ NULL, /* 1 == _SIGNAL_LOCK */
+ NULL, /* 2 == _IOB_SCAN_LOCK */
+ NULL, /* 3 == _TMPNAM_LOCK */
+ NULL, /* 4 == _INPUT_LOCK */
+ NULL, /* 5 == _OUTPUT_LOCK */
+ NULL, /* 6 == _CSCANF_LOCK */
+ NULL, /* 7 == _CPRINTF_LOCK */
+ NULL, /* 8 == _CONIO_LOCK */
+ &hlcritsect, /* 9 == _HEAP_LOCK */
+ NULL, /* 10 == _BHEAP_LOCK *** OBSOLETE *** */
+ NULL, /* 11 == _TIME_LOCK */
+ NULL, /* 12 == _ENV_LOCK */
+ &xlcritsect, /* 13 == _EXIT_LOCK1 */
+ NULL, /* 14 == _EXIT_LOCK2 *** OBSOLETE *** */
+ NULL, /* 15 == _THREADDATA_LOCK *** OBSOLETE *** */
+ NULL, /* 16 == _POPEN_LOCK */
+ &ltlcritsect, /* 17 == _LOCKTAB_LOCK */
+ NULL, /* 18 == _OSFHND_LOCK */
+ NULL, /* 19 == _SETLOCALE_LOCK */
+ NULL, /* 20 == _LC_COLLATE_LOCK */
+ NULL, /* 21 == _LC_CTYPE_LOCK */
+ NULL, /* 22 == _LC_MONETARY_LOCK */
+ NULL, /* 23 == _LC_NUMERIC_LOCK */
+ NULL, /* 24 == _LC_TIME_LOCK */
+ NULL, /* 25 == _STREAM_LOCKS */
+ NULL /* ... */
+ };
+
+
+#define _FATAL _amsg_exit(_RT_LOCK)
+
+#pragma optimize("y",off)
+
+/***
+*_mtinitlocks() - Initialize multi-thread lock scheme
+*
+*Purpose:
+* Perform whatever initialization is required for the multi-thread
+* locking (synchronization) scheme. This routine should be called
+* exactly once, during startup, and this must be before any requests
+* are made to assert locks.
+*
+* NOTES: In Win32, the multi-thread locks are created individually,
+* each upon its first use. That is when any particular lock is asserted
+* for the first time, the underlying critical section is then allocated,
+* initialized and (finally) entered. This allocation and initialization
+* is protected under _LOCKTAB_LOCK. It is _mtinitlocks' job to set up
+* _LOCKTAB_LOCK. _EXIT_LOCK1 is also set up by _mtinitlock
+*
+*Entry:
+* <none>
+*
+*Exit:
+* returns on success
+* calls _amsg_exit on failure
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _mtinitlocks (
+ void
+ )
+{
+#ifdef DEBUG
+ int i;
+
+ /*
+ * Scan _locktable[] and make sure everything was initialized properly
+ */
+ for ( i = 0 ; i < _TOTAL_LOCKS ; i++ ) {
+ if ( i == _LOCKTAB_LOCK ) {
+ if ( _locktable[i] != &ltlcritsect )
+ _lockerr_exit("fatal error in _mtinitlocks #1\n");
+ }
+ else if ( i == _EXIT_LOCK1 ) {
+ if ( _locktable[i] != &xlcritsect )
+ _lockerr_exit("fatal error in _mtinitlocks #2\n");
+ }
+ else if ( i == _HEAP_LOCK ) {
+ if ( _locktable[i] != &hlcritsect )
+ _lockerr_exit("fatal error in _mtinitlocks #3\n");
+ }
+ else if ( _locktable[i] != NULL )
+ _lockerr_exit("fatal error in _mtinitlocks #3\n");
+ }
+#endif /* DEBUG */
+
+ /*
+ * All we need to do is initialize _LOCKTAB_LOCK and _EXIT_LOCK1.
+ */
+ InitializeCriticalSection( _locktable[_LOCKTAB_LOCK] );
+ InitializeCriticalSection( _locktable[_EXIT_LOCK1] );
+ InitializeCriticalSection( _locktable[_HEAP_LOCK] );
+}
+
+
+/***
+*_mtdeletelocks() - Delete all initialized locks
+*
+*Purpose:
+* Walks _locktable[] and _lockmap, and deletes every 'lock' (i.e.,
+* critical section) which has been initialized.
+*
+* This function is intended for use in DLLs containing the C runtime
+* (i.e., crtdll.dll and user DLLs built using libcmt.lib and the
+* special startup objects). It is to be called from within the DLL's
+* entrypoint function when that function is called with
+* DLL_PROCESS_DETACH.
+*
+*Entry:
+* <none>
+*
+*Exit:
+*
+*Exceptions:
+* behavior undefined/unknown if a lock is being held when this routine
+* is called.
+*
+*******************************************************************************/
+
+void _CRTAPI1 _mtdeletelocks(
+ void
+ )
+{
+ int locknum;
+
+ for ( locknum = 0 ; locknum < _TOTAL_LOCKS ; locknum++ ) {
+
+ /*
+ * If the 'lock' has been created, delete it
+ */
+#ifdef DEBUG
+ /*
+ * See if the lock has already been deleted.
+ */
+ if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
+ _lockerr_exit("fatal error in _mtdeletelocks #1\n");
+
+ /*
+ * Delete the lock if it had been created.
+ */
+ if ( _locktable[locknum] != NULL ) {
+ if ( (locknum != _LOCKTAB_LOCK) && (locknum !=
+ _EXIT_LOCK1) && (locknum != _HEAP_LOCK) )
+ {
+ PCRITICAL_SECTION pcs = _locktable[locknum];
+
+ /* mark as deleted */
+ _locktable[locknum] = (PCRITICAL_SECTION)(-1L);
+
+ /* double check that it wasn't already deleted */
+ if ( pcs == (PCRITICAL_SECTION)(-1L) )
+ _lockerr_exit("fatal error in _mtdeletelocks #2\n");
+
+ DeleteCriticalSection(pcs);
+ free(pcs);
+ }
+ }
+#else /* non DEBUG */
+ /*
+ * Delete the lock if it had been created
+ */
+ if ( _locktable[locknum] != NULL ) {
+ if ( (locknum != _LOCKTAB_LOCK) && (locknum !=
+ _EXIT_LOCK1) && (locknum != _HEAP_LOCK) )
+ {
+ /*
+ * Free the memory for the CritSect after deleting
+ * it. It is okay to call free() if the heap lock
+ * is kept valid until after all calls to the heap.
+ */
+ DeleteCriticalSection(_locktable[locknum]);
+ free(_locktable[locknum]);
+ }
+ }
+#endif /* DEBUG */
+
+ }
+
+ /*
+ * Finally, clean up the special locks
+ */
+ DeleteCriticalSection( _locktable[_HEAP_LOCK] );
+ DeleteCriticalSection( _locktable[_EXIT_LOCK1] );
+ DeleteCriticalSection( _locktable[_LOCKTAB_LOCK] );
+}
+
+
+/***
+* _lock - Acquire a multi-thread lock
+*
+*Purpose:
+* Note that it is legal for a thread to aquire _EXIT_LOCK1
+* multiple times.
+*
+*Entry:
+* locknum = number of the lock to aquire
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _lock (
+ int locknum
+ )
+{
+ PCRITICAL_SECTION pcs;
+
+#ifdef DEBUG
+ if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
+ _lockerr_exit("fatal error in _lock #1\n");
+#endif /* DEBUG */
+
+ /*
+ * Create/open the lock, if necessary
+ */
+ if ( _locktable[locknum] == NULL ) {
+
+ if ( (pcs = malloc(sizeof(CRITICAL_SECTION))) == NULL )
+ _amsg_exit(_RT_LOCK);
+
+ _mlock(_LOCKTAB_LOCK); /*** WARNING: Recursive lock call ***/
+
+ if ( _locktable[locknum] == NULL ) {
+ InitializeCriticalSection(pcs);
+ _locktable[locknum] = pcs;
+ }
+ else {
+#ifdef DEBUG
+ if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
+ _lockerr_exit("fatal error in _lock #2\n");
+#endif /* DEBUG */
+ free(pcs);
+ }
+
+ _munlock(_LOCKTAB_LOCK);
+ }
+
+ /*
+ * Enter the critical section.
+ */
+
+ EnterCriticalSection( _locktable[locknum] );
+}
+
+
+/***
+* _unlock - Release multi-thread lock
+*
+*Purpose:
+* Note that it is legal for a thread to aquire _EXIT_LOCK1
+* multiple times.
+*
+*Entry:
+* locknum = number of the lock to release
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _unlock (
+ int locknum
+ )
+{
+ /*
+ * leave the critical section.
+ */
+ LeaveCriticalSection( _locktable[locknum] );
+}
+
+#pragma optimize("y",)
+
+/***
+*_lockerr_exit() - Write error message and die
+*
+*Purpose:
+* Attempt to write out the unexpected lock error message, then terminate
+* the program by a direct API call. This function is used in place of
+* amsg_exit(_RT_LOCK) when it is judged unsafe to allow further lock
+* or unlock calls.
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI3 _lockerr_exit (
+ char *msg
+ )
+{
+ FatalAppExit(0, msg); /* Die with message box */
+ ExitProcess(255); /* Just die */
+}
+
+
+#endif /* MTHREAD */
diff --git a/private/crt32/startup/ppc/chkstk.s b/private/crt32/startup/ppc/chkstk.s
new file mode 100644
index 000000000..ceec550f7
--- /dev/null
+++ b/private/crt32/startup/ppc/chkstk.s
@@ -0,0 +1,190 @@
+// TITLE("C-Runtime Stack Checking")
+//++
+//
+// Copyright (c) 1993,1994 IBM Corporation
+//
+// Module Name:
+//
+// chkstk.s
+//
+// Abstract:
+//
+// This module implements runtime stack checking.
+//
+// Author:
+//
+// Mark D. Johnson
+//
+// Environment:
+//
+// User/Kernel mode.
+//
+// Revision History:
+//
+//--
+
+#include <ksppc.h>
+
+
+ SBTTL("Check Stack")
+//++
+//
+// VOID _RtlCheckStack(in ULONG n_alloc)
+//
+// Routine Description:
+//
+// This function provides runtime stack checking for local allocations
+// that are more than a page and for storage dynamically allocated with
+// the alloca function. Stack checking consists of probing downward in
+// the stack a page at a time. If the current stack commitment is exceeded,
+// then the system will automatically attempt to expand the stack. If the
+// attempt succeeds, then another page is committed. Otherwise, a stack
+// overflow exception is raised. It is the responsiblity of the caller to
+// handle this exception.
+//
+// Two entry points are supported. The first/standard entry point
+// calls for n_alloc to be passed as single argument (in r.3). In
+// the second case, the single argument is the negative of the amount
+// requested (the amount by which to decrement the stack pointer), and
+// is passed in r.12.
+//
+// Registers r.0 and r.11 are modified.
+//
+// Arguments:
+//
+// n_alloc(r.3/r.12) - Supplies the size of the allocation on the stack.
+// With standard entry, passed in r.3. In alternate
+// entry, passed in r.12. In the latter case (r.12)
+// the value supplied is the quanitity by which to
+// decrement r.sp (a negative value).
+//
+// Return Value:
+//
+// None.
+//
+// Assumptions:
+//
+// The value of Teb_Ptr is provided in r.13.
+//
+// The bottom of stack "bot" (r.11) is multiple of PAGE_SIZE.
+//
+
+//
+// low
+// :
+// | :
+// | |
+// | |
+// |.......|<--- r.sp + r.12 - (PAGE_SIZE-1)
+// | ^ |
+// | |< -|- - - - - - always < PAGE_SIZE
+// | v |
+// +-------+<--- bot - m*PAGE_SIZE
+// | |
+// | : |
+// | |
+// +-------+<--- r.sp + r.12
+// | |
+// | |
+// | |
+// | : |
+// | : |
+// | : |
+// | : |
+// | |
+// | |
+// | |
+// | |
+// +=======+<--- bottom of stack "bot" (r.11)
+// | |
+// | |
+// | |
+// | : |
+// | : |
+// | : |
+// | |
+// | |
+// +-------+<--- r.sp
+// | |
+// | |
+// | : |
+// | :
+// | : high
+// : m is count for add'l pages to commit
+//
+//
+// m:=max(0,{bot-[(r.sp+r.12)-(PAGE_SIZE-1)]}/PAGE_SIZE)
+// =max(0,bot-[r.12-(PAGE_SIZE-1)+r.sp])/PAGE_SIZE
+//
+// Operands in expression [r.12-(PAGE_SIZE-1)+r.sp) are known upon entry
+// to routine. This intermediate quantity is calculated early in r.0,
+// behind user/kernel mode test.
+
+
+ .text
+ .align 5
+
+ // want entry for _RtlCheckStack aligned on a 2**5-1 byte boundary so that
+ // more commonly used (internal) entry _RtlCheckStack.12 is aligned on
+ // 2**5 byte (cache-line) boundary ... and most often used code fits in
+ // single cache-line
+
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+
+ or r.11, r.11, r.11; or r.11, r.11, r.11
+ or r.11, r.11, r.11
+
+ LEAF_ENTRY(_RtlCheckStack)
+
+ neg r.12,r.3
+
+ ALTERNATE_ENTRY(_RtlCheckStack.12)
+
+ cmpwi r.sp,0 // user or kernel mode?
+
+ // partial comp of num pages to commit moved here for performance
+
+ subi r.0,r.12,(PAGE_SIZE-1)
+ add r.0,r.0,r.sp
+
+ bge+ UsrMode // sp >=0 indicates user mode
+
+ // kernel mode, KIPCR is system mode macro to get KiPcr
+
+ KIPCR(r.11)
+ lwz r.11,PcInitialStack(r.11)
+ subi r.11,r.11,KERNEL_STACK_SIZE
+ b CommonCode
+
+UsrMode:
+
+ // r.13 contains the TEB pointer
+
+ lwz r.11,TeStackLimit(r.13) // Get low stack address
+
+CommonCode:
+
+ // r.11 contains computed "bot" of stack
+
+ sub r.0,r.11,r.0
+ srawi. r.0,r.0,PAGE_SHIFT // Number pages to add/commit
+ blelr // if <=0, return
+
+ mtctr r.0
+
+PageLoop:
+
+ // Attempt to commit pages beyond the limit
+
+ lwzu r.0,-PAGE_SIZE(r.11)
+ bdnz PageLoop
+
+
+ LEAF_EXIT(_RtlCheckStack)
diff --git a/private/crt32/startup/ppc/sources b/private/crt32/startup/ppc/sources
new file mode 100644
index 000000000..d82d03db9
--- /dev/null
+++ b/private/crt32/startup/ppc/sources
@@ -0,0 +1,3 @@
+PPC_SOURCES=ppc\chkstk.s
+
+
diff --git a/private/crt32/startup/sources b/private/crt32/startup/sources
new file mode 100644
index 000000000..d9d8e2c6d
--- /dev/null
+++ b/private/crt32/startup/sources
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+ jeffrob 29-sep-1990, use crt32.def
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=crt
+MINORCOMP=startup
+
+TARGETNAME=startup
+TARGETPATH=..\obj
+TARGETTYPE=LIBRARY
+386_STDCALL=0
+
+!INCLUDE ..\crt32.def
+
+!IF "$(CRTLIBTYPE)" == "POSIX"
+C_DEFINES=$(C_DEFINES) -D_KERNEL32_
+!ENDIF
+
+SOURCES=crt0.c \
+ crt0dat.c \
+ crt0init.c \
+ crt0fp.c \
+ crt0msg.c \
+ dllcrt0.c \
+ dllmain.c \
+ mlock.c \
+ stdargv.c \
+ stdenvp.c \
+ _setargv.c \
+ thread.c \
+ tidtable.c \
+ tlssup.c \
+ wild.c \
+ wincrt0.c
+
+i386_SOURCES=i386\chkstk.asm \
+ i386\atlssup.asm
+
+MIPS_SOURCES=mips\chkstk.s
+
+ALPHA_SOURCES=alpha\chkstk.s
+
+NTTARGETFILES=
+
diff --git a/private/crt32/startup/stdargv.c b/private/crt32/startup/stdargv.c
new file mode 100644
index 000000000..e75e98b77
--- /dev/null
+++ b/private/crt32/startup/stdargv.c
@@ -0,0 +1,501 @@
+/***
+*stdargv.c - standard & wildcard _setargv routine
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* processes program command line, with or without wildcard expansion
+*
+*Revision History:
+* 06-27-89 PHG module created, based on asm version
+* 04-09-90 GJF Added #include <cruntime.h>. Made calling types
+* explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed the
+* copyright.
+* 06-04-90 GJF Changed error message interface.
+* 08-31-90 GJF Removed 32 from API names.
+* 09-25-90 GJF Merged tree version with local version (8-31 change
+* with 6-4 change).
+* 10-08-90 GJF New-style function declarators.
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
+* 01-25-91 SRW Include oscalls.h if _WIN32_ OR WILDCARD defined
+* 01-25-91 SRW Changed Win32 Process Startup [_WIN32_]
+* 01-25-91 MHL Fixed bug in Win32 Process Startup [_WIN32_]
+* 01-28-91 GJF Fixed call to DOSFINDFIRST (removed last arg).
+* 01-31-91 MHL Changed to call GetModuleFileName instead of NtCurrentPeb() [_WIN32_]
+* 02-18-91 SRW Fixed command line parsing bug [_WIN32_]
+* 03-11-91 GJF Fixed check of FindFirstFile return [_WIN32_].
+* 03-12-91 SRW Add FindClose call to _find [_WIN32_]
+* 04-16-91 SRW Fixed quote parsing logic for arguments.
+* 03-31-92 DJM POSIX support.
+* 05-12-92 DJM ifndefed for POSIX.
+* 06-02-92 SKS Add #include <dos.h> for CRTDLL definition of _pgmptr
+* 04-19-93 GJF Change test in the do-while loop in parse_cmdline to
+* NOT terminate on chars with high bit set.
+* 05-14-93 GJF Added support for quoted program names.
+* 05-28-93 KRS Added MBCS support under _MBCS switches.
+* 06-04-93 KRS Added more MBCS logic.
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <internal.h>
+#include <rterr.h>
+#include <stdlib.h>
+#if defined(WILDCARD) || defined(_WIN32_)
+#include <dos.h>
+#include <oscalls.h>
+#endif
+#ifdef _MBCS
+#include <mbctype.h>
+#endif
+
+static void _CRTAPI3 parse_cmdline(char *cmdstart, char **argv, char *args,
+ int *numargs, int *numbytes);
+
+/***
+*_setargv, __setargv - set up "argc" and "argv" for C programs
+*
+*Purpose:
+* Read the command line and create the argv array for C
+* programs.
+*
+*Entry:
+* Arguments are retrieved from the program command line,
+* pointed to by _acmdln.
+*
+*Exit:
+* "argv" points to a null-terminated list of pointers to ASCIZ
+* strings, each of which is an argument from the command line.
+* "argc" is the number of arguments. The strings are copied from
+* the environment segment into space allocated on the heap/stack.
+* The list of pointers is also located on the heap or stack.
+* _pgmptr points to the program name.
+*
+*Exceptions:
+* Terminates with out of memory error if no memory to allocate.
+*
+*******************************************************************************/
+
+#ifdef WILDCARD
+void _CRTAPI1 __setargv (
+#else
+void _CRTAPI1 _setargv (
+#endif
+ void
+ )
+{
+ char *p;
+ char *cmdstart; /* start of command line to parse */
+ int numargs, numbytes;
+
+#ifdef _CRUISER_
+
+ /* OS/2 sets up memory like this:
+ <nul><full path of program><nul><prog name as typed><nul><arguments><nul>
+ ^
+ _acmdline
+ */
+
+ /* first we set _pgmptr to point to the full name of program */
+ p = _acmdln - 1;
+ while (*(p-1) != '\0')
+ --p;
+ _pgmptr = p;
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_)
+ static char _pgmname[ MAX_PATH ];
+
+ /* Get the program name pointer from Win32 Base */
+
+ GetModuleFileName( NULL, _pgmname, sizeof( _pgmname ));
+ _pgmptr = _pgmname;
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ /* if there's no command line at all (won't happen from cmd.exe, but
+ possibly another program), then we use _pgmptr as the command line
+ to parse, so that argv[0] is initialized to the program name */
+ cmdstart = (*_acmdln == '\0') ? _pgmptr : _acmdln;
+
+ /* first find out how much space is needed to store args */
+ parse_cmdline(cmdstart, NULL, NULL, &numargs, &numbytes);
+
+ /* allocate space for argv[] vector and strings */
+ p = malloc(numargs * sizeof(char *) + numbytes);
+ if (p == NULL)
+ _amsg_exit(_RT_SPACEARG);
+
+ /* store args and argv ptrs in just allocated block */
+ parse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numbytes);
+
+ /* set argv and argc */
+ __argc = numargs - 1;
+ __argv = (char **)p;
+#ifdef WILDCARD
+ /* call _cwild to expand wildcards in arg vector */
+ if (_cwild())
+ _amsg_exit(_RT_SPACEARG); /* out of space */
+#endif
+}
+
+
+/***
+*static void parse_cmdline(cmdstart, argv, args, numargs, numbytes)
+*
+*Purpose:
+* Parses the command line and sets up the argv[] array.
+* On entry, cmdstart should point to the command line,
+* argv should point to memory for the argv array, args
+* points to memory to place the text of the arguments.
+* If these are NULL, then no storing (only coujting)
+* is done. On exit, *numargs has the number of
+* arguments (plus one for a final NULL argument),
+* and *numbytes has the number of bytes used in the buffer
+* pointed to by args.
+*
+*Entry:
+* char *cmdstart - pointer to command line of the form
+* <progname><nul><args><nul>
+* char **argv - where to build argv array; NULL means don't
+* build array
+* char *args - where to place argument text; NULL means don't
+* store text
+*
+*Exit:
+* no return value
+* int *numargs - returns number of argv entries created
+* int *numbytes - number of bytes used in args buffer
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static void _CRTAPI3 parse_cmdline (
+ char *cmdstart,
+ char **argv,
+ char *args,
+ int *numargs,
+ int *numbytes
+ )
+{
+ char *p;
+ unsigned char c;
+ int inquote; /* 1 = inside quotes */
+ int copychar; /* 1 = copy char to *args */
+ unsigned numslash; /* num of backslashes seen */
+
+ *numbytes = 0;
+ *numargs = 1; /* the program name at least */
+
+ /* first scan the program name, copy it, and count the bytes */
+ p = cmdstart;
+ if (argv)
+ *argv++ = args;
+#ifdef WILDCARD
+ /* To handle later wild card expansion, we prefix each entry by
+ it's first character before quote handling. This is done
+ so _cwild() knows whether to expand an entry or not. */
+ if (args)
+ *args++ = *p;
+ ++*numbytes;
+
+#endif /* WILDCARD */
+ /* A quoted program name is handled here. The handling is much
+ simpler than for other arguments. Basically, whatever lies
+ between the leading double-quote and next one, or a terminal null
+ character is simply accepted. Fancier handling is not required
+ because the program name must be a legal NTFS/HPFS file name.
+ Note that the double-quote characters are not copied, nor do they
+ contribute to numbytes. */
+ if ( *p == '\"' ) {
+ /* scan from just past the first double-quote through the next
+ double-quote, or up to a null, whichever comes first */
+ while ( (*(++p) != '\"') && (*p != '\0') ) {
+
+#ifdef _MBCS
+ if (_ismbblead(*p)) {
+ *numbytes += 2;
+ if ( args ) {
+ *args++ = *p++;
+ *args++ = *p;
+ }
+ }
+ else {
+#endif
+ ++*numbytes;
+ if ( args )
+ *args++ = *p;
+#ifdef _MBCS
+ }
+#endif
+ }
+ /* append the terminating null */
+ ++*numbytes;
+ if ( args )
+ *args++ = '\0';
+
+ /* if we stopped on a double-quote (usual case), skip over it */
+ if ( *p == '\"' )
+ p++;
+ }
+ else {
+ /* Not a quoted program name */
+ do {
+ ++*numbytes;
+ if (args)
+ *args++ = *p;
+#ifdef _CRUISER_
+
+ } while (*p++ != '\0');
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ c = (unsigned char) *p++;
+#ifdef _MBCS
+ if (_ismbblead(c)) {
+ ++*numbytes;
+ if (args)
+ *args++ = *p; /* copy 2nd byte too */
+ p++; /* skip over trail byte */
+ }
+#endif
+
+ } while ( c > ' ' );
+
+ if ( c == '\0' ) {
+ p--;
+ } else {
+ if (args)
+ *(args-1) = '\0';
+ }
+ }
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ inquote = 0;
+
+ /* loop on each argument */
+ for(;;) {
+
+#ifdef _CRUISER_
+ /* skip blanks */
+ while (*p == ' ' || *p == '\t')
+ ++p;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+ if ( *p ) {
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ }
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ if (*p == '\0')
+ break; /* end of args */
+
+ /* scan an argument */
+ if (argv)
+ *argv++ = args; /* store ptr to arg */
+ ++*numargs;
+
+#ifdef WILDCARD
+ /* To handle later wild card expansion, we prefix each entry by
+ it's first character before quote handling. This is done
+ so _cwild() knows whether to expand an entry or not. */
+ if (args)
+ *args++ = *p;
+ ++*numbytes;
+
+#endif /* WILDCARD */
+
+ /* loop through scanning one argument */
+ for (;;) {
+ copychar = 1;
+ /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
+ 2N+1 backslashes + " ==> N backslashes + literal "
+ N backslashes ==> N backslashes */
+ numslash = 0;
+ while (*p == '\\') {
+ /* count number of backslashes for use below */
+ ++p;
+ ++numslash;
+ }
+ if (*p == '\"') {
+ /* if 2N backslashes before, start/end quote, otherwise
+ copy literally */
+ if (numslash % 2 == 0) {
+ if (inquote)
+ if (p[1] == '\"')
+ p++; /* Double quote inside quoted string */
+ else /* skip first quote char and copy second */
+ copychar = 0;
+ else
+ copychar = 0; /* don't copy quote */
+
+ inquote = !inquote;
+ }
+ numslash /= 2; /* divide numslash by two */
+ }
+
+ /* copy slashes */
+ while (numslash--) {
+ if (args)
+ *args++ = '\\';
+ ++*numbytes;
+ }
+
+ /* if at end of arg, break loop */
+ if (*p == '\0' || (!inquote && (*p == ' ' || *p == '\t')))
+ break;
+
+ /* copy character into argument */
+#ifdef _MBCS
+ if (copychar) {
+ if (args) {
+ if (_ismbblead(*p)) {
+ *args++ = *p++;
+ ++*numbytes;
+ }
+ *args++ = *p;
+ } else {
+ if (_ismbblead(*p)) {
+ ++p;
+ ++*numbytes;
+ }
+ }
+ ++*numbytes;
+ }
+ ++p;
+#else
+ if (copychar) {
+ if (args)
+ *args++ = *p;
+ ++*numbytes;
+ }
+ ++p;
+#endif
+ }
+
+ /* null-terminate the argument */
+
+ if (args)
+ *args++ = '\0'; /* terminate string */
+ ++*numbytes;
+ }
+
+ /* We put one last argument in -- a null ptr */
+ if (argv)
+ *argv++ = NULL;
+ ++*numargs;
+}
+
+
+#ifdef WILDCARD
+/***
+*_find(pattern) - find matching filename
+*
+*Purpose:
+* if argument is non-null, do a DOSFINDFIRST on that pattern
+* otherwise do a DOSFINDNEXT call. Return matching filename
+* or NULL if no more matches.
+*
+*Entry:
+* pattern = pointer to pattern or NULL
+* (NULL means find next matching filename)
+*
+*Exit:
+* returns pointer to matching file name
+* or NULL if no more matches.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+char * _CRTAPI1 _find (
+ char *pattern
+ )
+{
+ char *retval;
+
+#ifdef _CRUISER_
+ static FILEFINDBUF findbuf;
+ HDIR findhandle = HDIR_SYSTEM;
+ ULONG findcount = 1;
+ int rc;
+
+ if (pattern)
+ rc = DOSFINDFIRST(pattern, &findhandle, FILE_NORMAL | FILE_DIRECTORY,
+ &findbuf, sizeof(findbuf), &findcount, 1L);
+ else
+ rc = DOSFINDNEXT(findhandle, &findbuf, sizeof(findbuf), &findcount);
+
+ retval = rc ? NULL : findbuf.achName;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ static HANDLE _WildFindHandle;
+ static LPWIN32_FIND_DATA findbuf;
+
+ if (pattern) {
+ if (findbuf == NULL)
+ findbuf = (LPWIN32_FIND_DATA)malloc(MAX_PATH + sizeof(*findbuf));
+
+ if (_WildFindHandle != NULL) {
+ (void)FindClose( _WildFindHandle );
+ _WildFindHandle = NULL;
+ }
+
+ _WildFindHandle = FindFirstFile( (LPSTR)pattern, findbuf );
+ if (_WildFindHandle == (HANDLE)0xffffffff)
+ return NULL;
+ }
+ else
+ if (!FindNextFile( _WildFindHandle, findbuf )) {
+ (void)FindClose( _WildFindHandle );
+ _WildFindHandle = NULL;
+ return NULL;
+ }
+
+ retval = findbuf->cFileName;
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ return retval;
+}
+
+#endif /* WILDCARD */
+
+#endif /* ndef _POSIX_ */
diff --git a/private/crt32/startup/stdenvp.c b/private/crt32/startup/stdenvp.c
new file mode 100644
index 000000000..7ebdfa806
--- /dev/null
+++ b/private/crt32/startup/stdenvp.c
@@ -0,0 +1,192 @@
+/***
+*stdenvp.c - OS/2 standard _setenvp routine
+*
+* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module is called by the C start-up routine to set up "_environ".
+* Its sets up an array of pointers to strings in the environment.
+* The global symbol "_environ" is set to point to this array.
+*
+*Revision History:
+* 11-07-84 GFW initial version
+* 01-08-86 SKS Modified for OS/2
+* 05-21-86 SKS Call _stdalloc to get memory for strings
+* 09-04-86 SKS Added check to skip the "*C_FILE_INFO" string
+* 10-21-86 SKS Improved check for "*C_FILE_INFO"/"_C_FILE_INFO"
+* 02-19-88 SKS Handle case where environment starts with a single null
+* 05-10-88 JCR Modified code to accept far pointer from _stdalloc
+* 06-01-88 PHG Merged DLL and normal versions
+* 07-12-88 JCR Largely re-written: (1) split mem allocation into two
+* seperate malloc() calls to help simplify putenv(),
+* (2) stdalloc() no longer robs from stack, (3) cProc/cEnd
+* sequence, (4) misc cleanup
+* 09-20-88 WAJ Initial 386 version
+* 12-13-88 JCR Use rterr.inc parameters for runtime errors
+* 04-09-90 GJF Added #include <cruntime.h>. Made the calling type
+* _CALLTYPE1. Also, fixed the copyright and cleaned up
+* up the formatting a bit.
+* 06-05-90 GJF Changed error message interface.
+* 10-08-90 GJF New-style function declarator.
+* 10-31-90 GJF Fixed statement appending the final NULL (Stevewo
+* found the bug).
+* 12-11-90 SRW Changed to include <oscalls.h> and setup _environ
+* correctly for Win32
+* 01-21-91 GJF ANSI naming.
+* 02-07-91 SRW Change _WIN32_ specific code to allocate static copy (_WIN32_)
+* 02-18-91 SRW Change _WIN32_ specific code to allocate copy of
+* variable strings as well [_WIN32_]
+* 07-25-91 GJF Changed strupr to _strupr.
+* 03-31-92 DJM POSIX support.
+* 04-20-92 GJF Removed conversion to upper-case code for Win32.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <string.h>
+#include <stdlib.h>
+#include <internal.h>
+#include <rterr.h>
+#include <oscalls.h>
+
+/* C file info string */
+extern char _cfinfo[];
+
+/***
+*_setenvp - set up "envp" for C programs
+*
+*Purpose:
+* Reads the environment and build the envp array for C programs.
+*
+*Entry:
+* The environment strings occur at _aenvptr.
+* The list of environment strings is terminated by an extra null
+* byte. Thus two null bytes in a row indicate the end of the
+* last environment string and the end of the environment, resp.
+*
+*Exit:
+* "environ" points to a null-terminated list of pointers to ASCIZ
+* strings, each of which is of the form "VAR=VALUE". The strings
+* are not copied from the environment area. Instead, the array of
+* pointers will point into the OS environment area. This array of
+* pointers will be malloc'ed
+*
+*Uses:
+* Allocates space on the heap for the environment pointers.
+*
+*Exceptions:
+* If space cannot be allocated, program is terminated.
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _setenvp (
+ void
+ )
+{
+ char *p;
+ char **env; /* _environ ptr traversal pointer */
+ int numstrings; /* number of environment strings */
+
+#ifdef _CRUISER_
+
+ numstrings = 0;
+ p = _aenvptr;
+
+ /* NOTE: starting with single null indicates no environ */
+ /* count the number of strings */
+ while (*p != '\0') {
+ p += strlen(p) + 1;
+ ++numstrings;
+ }
+
+ /* need pointer for each string, plus one null ptr at end */
+ _environ = env = malloc((numstrings+1) * sizeof(char *));
+ if (_environ == NULL)
+ _amsg_exit(_RT_SPACEENV);
+
+ p = _aenvptr;
+ /* copy pointers to strings into env - don't copy _C_FILEINFO string */
+ while (*p != '\0') {
+
+ if (strncmp(p, _acfinfo, CFI_LENGTH) != 0)
+ *env++ = p;
+ p += strlen(p) + 1;
+ }
+
+ /* and a final NULL pointer */
+ *env = NULL;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+ int cb;
+
+ numstrings = 0;
+ p = _aenvptr;
+
+ /* NOTE: starting with single null indicates no environ */
+ /* count the number of strings */
+ while (*p != '\0') {
+ p += strlen(p) + 1;
+ ++numstrings;
+ }
+
+ /* need pointer for each string, plus one null ptr at end */
+ if ( (_environ = env = malloc((numstrings+1) * sizeof(char *)))
+ == NULL )
+ _amsg_exit(_RT_SPACEENV);
+
+ /* copy strings to malloc'd memory and save pointers in _environ */
+ for ( p = _aenvptr ; *p != '\0' ; env++, p += cb ) {
+ cb = strlen(p) + 1;
+ if ( (*env = malloc(cb)) == NULL )
+ _amsg_exit(_RT_SPACEENV);
+ strcpy(*env, p);
+ }
+
+ /* and a final NULL pointer */
+ *env = NULL;
+
+#else /* ndef _WIN32_ */
+
+#ifdef _POSIX_
+
+#if 0 /* it would seem that this code is unnecessary for POSIX */
+ /* since it is never called! */
+
+ numstrings = 0;
+ p = _aenvptr;
+
+ /* NOTE: starting with single null indicates no environ */
+ /* count the number of strings */
+ while (*p != '\0') {
+ p += strlen(p) + 1;
+ ++numstrings;
+ }
+
+ /* need pointer for each string, plus one null ptr at end */
+ _environ = env = malloc((numstrings+1) * sizeof(char *));
+
+ p = _aenvptr;
+ while (*p != '\0') {
+ *env = p++;
+ while (*p++ != '\0')
+ ;
+ env++;
+ }
+
+ /* and a final NULL pointer */
+ *env = NULL;
+
+#endif /* 0 */
+
+#else
+
+#error ERROR - ONLY CRUISER, POSIX, OR WIN32 TARGET SUPPORTED!
+
+#endif /* _POSIX_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+}
diff --git a/private/crt32/startup/thread.c b/private/crt32/startup/thread.c
new file mode 100644
index 000000000..5878eecc7
--- /dev/null
+++ b/private/crt32/startup/thread.c
@@ -0,0 +1,254 @@
+#ifdef MTHREAD
+
+
+/***
+*thread.c - Being and end a thread
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This source contains the _beginthread() and _endthread()
+* routines which are used to start and terminate a thread.
+*
+*Revision History:
+* 05-09-90 JCR Translated from ASM to C
+* 07-25-90 SBM Removed '32' from API names
+* 10-08-90 GJF New-style function declarators.
+* 10-09-90 GJF Thread ids are of type unsigned long.
+* 10-19-90 GJF Added code to set _stkhqq properly in stub().
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
+* 06-03-91 GJF Win32 version [_WIN32_].
+* 07-18-91 GJF Fixed many silly errors [_WIN32_].
+* 08-19-91 GJF Allow for newly created thread terminating before
+* _beginthread returns
+* 09-30-91 GJF Add per-thread initialization and termination calls
+* for floating point.
+* 01-18-92 GJF Revised try - except statement.
+* 02-25-92 GJF Initialize _holdrand field to 1.
+* 09-30-92 SRW Add WINAPI keyword to _threadstart routine
+* 10-30-92 GJF Error ret for CreateThread is 0 (NULL), not -1.
+* 02-13-93 GJF Revised to use TLS API. Also, purged Cruiser support.
+* 03-26-93 GJF Fixed horribly embarrassing bug: ptd->pxcptacttab
+* must be initialized to _XcptActTab!
+* 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
+* _RT_INVALDISP and _RT_NONCONT.
+* 12-14-93 SKS Free up per-thread data using a call to _freeptd()
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <oscalls.h>
+#include <internal.h>
+#include <os2dll.h>
+#include <msdos.h>
+#include <malloc.h>
+#include <process.h>
+#include <rterr.h>
+
+/*
+ * Startup code for new thread.
+ */
+static unsigned long WINAPI _threadstart(void *);
+
+/*
+ * useful type for initialization and termination declarations
+ */
+typedef void (_CRTAPI1 *PF)(void);
+
+/*
+ * declare pointers to per-thread FP initialization and termination routines
+ */
+PF _FPmtinit;
+PF _FPmtterm;
+
+
+/***
+*_beginthread() - Create a child thread
+*
+*Purpose:
+* Create a child thread.
+*
+*Entry:
+* initialcode = pointer to thread's startup code address
+* stacksize = size of stack
+* argument = argument to be passed to new thread
+*
+*Exit:
+* success = handle for new thread if successful
+*
+* failure = (unsigned long) -1L in case of error, errno and _doserrno
+* are set
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+unsigned long _CRTAPI1 _beginthread (
+ void (_CRTAPI1 * initialcode) (void *),
+ unsigned stacksize,
+ void * argument
+ )
+{
+ _ptiddata ptd; /* pointer to per-thread data */
+ unsigned long thdl; /* thread handle */
+
+ /*
+ * Allocate and initialize a per-thread data structure for the to-
+ * be-created thread.
+ */
+ if ( (ptd = calloc(1, sizeof(struct _tiddata))) == NULL )
+ goto error_return;
+
+ ptd->_initaddr = (void *) initialcode;
+ ptd->_initarg = argument;
+ ptd->_holdrand = 1L;
+ ptd->_pxcptacttab = (void *)_XcptActTab;
+
+ /*
+ * Create the new thread. Bring it up in a suspended state so that
+ * the _thandle and _tid fields are filled in before execution
+ * starts.
+ */
+ if ( (ptd->_thandle = thdl = (unsigned long)
+ CreateThread( NULL,
+ stacksize,
+ _threadstart,
+ (LPVOID)ptd,
+ CREATE_SUSPENDED,
+ (LPDWORD)&(ptd->_tid) ))
+ == 0L )
+ goto error_return;
+
+ /*
+ * Start the new thread executing
+ */
+ if ( ResumeThread( (HANDLE)thdl ) == (DWORD)(-1L) )
+ goto error_return;
+
+ /*
+ * Good return
+ */
+ return(thdl);
+
+ /*
+ * Error return
+ */
+error_return:
+ /***
+ *** MAP ERROR CODE!
+ ***/
+ return((unsigned long)-1L);
+}
+
+
+/***
+*_threadstart() - New thread begins here
+*
+*Purpose:
+* The new thread begins execution here. This routine, in turn,
+* passes control to the user's code.
+*
+*Entry:
+* void *ptd = pointer to _tiddata structure for this thread
+*
+*Exit:
+* Never returns - terminates thread!
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static unsigned long WINAPI _threadstart (
+ void * ptd
+ )
+{
+ /*
+ * Stash the pointer to the per-thread data stucture in TLS
+ */
+ if ( !TlsSetValue(__tlsindex, ptd) )
+ _amsg_exit(_RT_THREAD);
+
+ /*
+ * Call fp initialization, if necessary
+ */
+ if ( _FPmtinit != NULL )
+ (*_FPmtinit)();
+
+ /*
+ * Guard call to user code with a _try - _except statement to
+ * implement runtime errors and signal support
+ */
+ try {
+ ( (void(_CRTAPI1 *)(void *))(((_ptiddata)ptd)->_initaddr) )
+ ( ((_ptiddata)ptd)->_initarg );
+
+ _endthread();
+ }
+ except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
+ {
+ /*
+ * Should never reach here
+ */
+ _exit( GetExceptionCode() );
+
+ } /* end of _try - _except */
+
+ /*
+ * Never executed!
+ */
+ return(0L);
+}
+
+
+/***
+*_endthread() - Terminate the calling thread
+*
+*Purpose:
+*
+*Entry:
+* void
+*
+*Exit:
+* Never returns!
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _endthread (
+ void
+ )
+{
+ _ptiddata ptd; /* pointer to thread's _tiddata struct */
+
+ /*
+ * Call fp termination, if necessary
+ */
+ if ( _FPmtterm != NULL )
+ (*_FPmtterm)();
+
+ if ( (ptd = _getptd()) == NULL )
+ _amsg_exit(_RT_THREAD);
+
+ /*
+ * Close the thread handle (if there was one)
+ */
+ if ( ptd->_thandle != (unsigned long)(-1L) )
+ (void) CloseHandle( (HANDLE)(ptd->_thandle) );
+
+ /*
+ * Free up the _tiddata structure & its subordinate buffers
+ * _freeptd() will also clear the value for this thread
+ * of the TLS variable __tlsindex.
+ */
+ _freeptd(ptd);
+
+ /*
+ * Terminate the thread
+ */
+ ExitThread(0);
+
+}
+
+#endif /* MTHREAD */
diff --git a/private/crt32/startup/tidprint.c b/private/crt32/startup/tidprint.c
new file mode 100644
index 000000000..290a6288e
--- /dev/null
+++ b/private/crt32/startup/tidprint.c
@@ -0,0 +1,286 @@
+/***
+*tidprint.c - Dislpay thread data
+*
+* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Display the per thread data table.
+*
+* [NOTE: This module is NOT included in the C runtime libraries but
+* is maintained for debugging analysis.]
+*
+*Revision History:
+* 11-17-88 JCR Module created.
+* 04-03-89 JCR Added _stackalloc to tid table
+* 06-06-89 JCR 386 version
+* 06-09-89 JCR 386: Added values to _tiddata struc (for _beginthread)
+* 04-09-90 GJF Added #include <cruntime.h>. Made the calling type
+* _CALLTYPE1. Also, fixed the copyright.
+* 04-10-90 GJF Removed #include <dos.h>.
+* 08-16-90 SBM Made _terrno and _tdoserrno int, not unsigned
+* 10-08-90 GJF New-style function declarators.
+* 10-09-90 GJF Thread ids are of type unsigned long!
+* 12-18-90 GJF Use real thread id, not thread id - 1.
+* 08-01-91 GJF Adapted for Win32 [_WIN32_].
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdio.h>
+#include <os2dll.h>
+
+#ifdef _CRUISER_
+void _CALLTYPE1 _print_tiddata(unsigned long);
+void _CALLTYPE1 _print_tid(struct _tiddata *, unsigned long);
+
+extern unsigned long _tidtabmax;
+extern struct _tiddata * _threaddata;
+
+/***
+*void _print_tiddata(unsigned long) - Display data for a thread
+*
+*Purpose:
+* This routine displays the per thread data for one (or all)
+* threads in the table.
+*
+*Entry:
+* unsigned long = <n> = Threadid of tid to display
+* = -1 = Display all tids' data
+*
+*Exit:
+* <void>
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _print_tiddata (
+ unsigned long tid
+ )
+{
+ unsigned long maxtid;
+ struct _tiddata * tdata;
+ unsigned long i;
+
+ /* Get and save current maxtid value */
+ maxtid = _tidtabmax;
+
+ /* See if user want's all threads or just a specific one. */
+ if (tid == (unsigned long) -1L) {
+
+ /* Print out all threads */
+
+ printf("\nPER THREAD DATA TABLE (NUMBER OF THREADS = %u)\n"
+ "----------------------------------------------\n", maxtid+1);
+
+ for (i=0; i<=maxtid; i++) {
+ /* Get pointer to tidtable entry */
+ tdata = &_threaddata[i];
+ _print_tid(tdata,i+1); /* print it out */
+ }
+
+ /* Make sure the table didn't change size while we processed it */
+ if (_tidtabmax > maxtid)
+ printf("*** WARNING: Tid data table grew while printing out data. ***\n\n");
+
+ printf("END THREAD TABLE\n"
+ "----------------\n\n");
+
+ }
+
+ else {
+
+ /* Print out the specific thread supplied by the user. */
+
+ if (tid > maxtid) {
+ printf("*** ERROR: Tid value outside thread data table. ***\n");
+ return;
+ }
+
+ /* point to tid data */
+ tdata = &_threaddata[tid-1];
+ _print_tid(tdata,tid); /* print it out */
+ }
+
+}
+
+
+/***
+* void _print_tid() - Print out thread data
+*
+*Purpose:
+* Given the address of a thread data entry, print out that
+* information.
+*
+*Entry:
+* struct _tiddata * = pointer to thread's data area
+* unsigned long = associated threadid (0-based)
+*
+*Exit:
+* <void>
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _print_tid (
+ struct _tiddata * td,
+ unsigned long tid
+ )
+{
+
+ printf("TID %u DATA (%lp):\n", tid, td);
+
+ printf("\t_terrno = %d \t (errno value)\n", td->_terrno);
+ printf("\t_tdoserrno = %d \t (_doserrno value)\n", td->_tdoserrno);
+ printf("\t_stkhqq = %#x\t (stack limit)\n", td->_stkhqq);
+ printf("\t_fpds = %#x \t (Floating Point data segment)\n",
+ td->_fpds);
+ printf("\t_holdrand = %u \t (rand() seed value)\n", td->_holdrand);
+ printf("\t_token = %p\t (ptr to strtok() token)\n", td->_token);
+ printf("\t_errmsg = %p\t (ptr to strerror()/_strerror() buff)\n",
+ td->_errmsg);
+ printf("\t_namebuf = %p\t (ptr to tmpfile() buffer)\n",
+ td->_namebuf);
+ printf("\t_asctimebuf = %p\t (ptr to asctime() buffer)\n",
+ td->_asctimebuf);
+ printf("\t_gmtimebuf = %p\t (ptr to gmtime() structure)\n",
+ td->_gmtimebuf);
+ printf("\t_initaddr = %p\t (initial user thread addr)\n",
+ td->_initaddr);
+ printf("\t_initarg = %p\t (initial user thread arg)\n",
+ td->_initarg);
+ printf("\t_initstksz = %u \t (initial stack size)\n",
+ td->_initstksz);
+ putchar((int)'\n');
+
+}
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+void _CALLTYPE1 _print_tiddata(unsigned long);
+void _CALLTYPE1 _print_tiddata1(_ptiddata);
+
+/***
+*void _print_tiddata(unsigned long) - Display data for a thread
+*
+*Purpose:
+* This routine displays the per thread data for a specific, or all,
+* active threads in the _ptd[] table.
+*
+*Entry:
+* unsigned long = <n> = ID of the thread to display
+* = -1 = Display thread data for all threads
+*
+*Exit:
+* <void>
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _print_tiddata (
+ unsigned long tid
+ )
+{
+ int i; /* loop index */
+ int threadcnt; /* number of active threads */
+
+ /*
+ * lock the _ptd[] table.
+ */
+ _mlock(_THREADDATA_LOCK);
+
+ /*
+ * see if caller want's all threads or just a specific one.
+ */
+ if (tid == (unsigned long) -1L) {
+ /*
+ * caller want's all threads!
+ */
+ for ( i = threadcnt = 0 ; i < 1024 ; i++ )
+ /*
+ * print out the fields of *_ptd[i] for each entry
+ * bound to an active thread (i.e., for each i st
+ * _ptd[i] non-NULL). also, count up the total number
+ * of active threads.
+ */
+ if ( _ptd[i] != NULL ) {
+ threadcnt++;
+ _print_tiddata1(_ptd[i]);
+ }
+
+ printf("\nTHERE ARE %d CURRENTLY ACTIVE THREADS!\n", threadcnt);
+ }
+ else {
+ /*
+ * caller just interested in a particular thread. search
+ * the _ptd[] table inline because a call to _getptd[] would
+ * have unpleasant side effects if tid is not (or no longer)
+ * valid.
+ */
+ for ( i = 0 ; (i < 1024) && ((_ptd[i] == NULL) ||
+ (_ptd[i] == (_ptiddata)1L) || (_ptd[i]->_tid != tid)) ;
+ i++ ) ;
+
+ if ( i < 1024 )
+ _print_tiddata1(_ptd[i]);
+ else
+ printf("\nTID INVALID OR THREAD HAS TERMINATED!\n");
+ }
+
+ /*
+ * unlock the _ptd[] table.
+ */
+ _munlock(_THREADDATA_LOCK);
+
+}
+
+
+/***
+* void _print_tiddata1(_ptiddata ptd) - print out _tiddata structure
+*
+*Purpose:
+* Given a pointer to a thread data structure, print out its contents
+*
+*Entry:
+* ptd = pointer to thread's data area
+*
+*Exit:
+* <void>
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _print_tiddata1 (
+ _ptiddata ptd
+ )
+{
+ printf("\t_tid = %lu\n", ptd->_tid );
+ printf("\t_thandle = %lu\n", ptd->_thandle );
+ printf("\t_terrno = %d\n", ptd->_terrno);
+ printf("\t_tdoserrno = %d\n", ptd->_tdoserrno);
+ printf("\t_fpds = %#x\n", ptd->_fpds);
+ printf("\t_holdrand = %u\n", ptd->_holdrand);
+ printf("\t_token = %p\n", ptd->_token);
+ printf("\t_errmsg = %p\n", ptd->_errmsg);
+ printf("\t_namebuf = %p\n", ptd->_namebuf);
+ printf("\t_asctimebuf = %p\n", ptd->_asctimebuf);
+ printf("\t_gmtimebuf = %p\n", ptd->_gmtimebuf);
+ printf("\t_initaddr = %p\n", ptd->_initaddr);
+ printf("\t_initarg = %p\n", ptd->_initarg);
+ printf("\t_pxcptacttab = %p\n", ptd->_pxcptacttab);
+ printf("\t_tpxcptinfoptrs = %p\n", ptd->_tpxcptinfoptrs);
+ printf("\t_tfpecode = %p\n\n", ptd->_tfpecode);
+
+}
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
diff --git a/private/crt32/startup/tidtable.c b/private/crt32/startup/tidtable.c
new file mode 100644
index 000000000..077f42334
--- /dev/null
+++ b/private/crt32/startup/tidtable.c
@@ -0,0 +1,324 @@
+#ifdef MTHREAD
+
+
+/***
+*tidtable.c - Access thread data table
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains the following routines for multi-thread
+* data support:
+*
+* _mtinit = Initialize the mthread data
+* _getptd = get the pointer to the per-thread data structure for
+* the current thread
+* _freeptd = free up a per-thread data structure and its
+* subordinate structures
+* __threadid = return thread ID for the current thread
+* __threadhandle = return pseudo-handle for the current thread
+*
+*Revision History:
+* 05-04-90 JCR Translated from ASM to C for portable 32-bit OS/2
+* 06-04-90 GJF Changed error message interface.
+* 07-02-90 GJF Changed __threadid() for DCR 1024/2012.
+* 08-08-90 GJF Removed 32 from API names.
+* 10-08-90 GJF New-style function declarators.
+* 10-09-90 GJF Thread ids are of type unsigned long! Also, fixed a
+* bug in __threadid().
+* 10-22-90 GJF Another bug in __threadid().
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
+* 05-31-91 GJF Win32 version [_WIN32_].
+* 07-18-91 GJF Fixed many silly errors [_WIN32_].
+* 09-29-91 GJF Conditionally added _getptd_lk/_getptd1_lk so that
+* DEBUG version of mlock doesn't infinitely recurse
+* the first time _THREADDATA_LOCK is asserted [_WIN32_].
+* 01-30-92 GJF Must init. _pxcptacttab field to _XcptActTab.
+* 02-25-92 GJF Initialize _holdrand field to 1.
+* 02-13-93 GJF Revised to use TLS API. Also, purged Cruiser support.
+* 03-26-93 GJF Initialize ptd->_holdrand to 1L (see thread.c).
+* 04-16-93 SKS Add _mtterm to do multi-thread termination
+* Set freed __tlsindex to -1 again to prevent mis-use
+* 12-13-93 SKS Add _freeptd(), which frees up the per-thread data
+* maintained by the C run-time library.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <oscalls.h>
+#include <internal.h>
+#include <os2dll.h>
+#include <memory.h>
+#include <msdos.h>
+#include <rterr.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+unsigned long __tlsindex = 0xffffffff;
+
+/*** TEMP ****/
+/*** MOVE TO OS2DLL.H??? ***/
+extern near * _CRTVAR1 end; /* Link symbol for end of BSS */
+/*** TEMP ****/
+
+
+/****
+*_mtinit() - Init multi-thread data bases
+*
+*Purpose:
+* (1) Call _mtinitlocks to create/open all lock semaphores.
+* (2) Allocate a TLS index to hold pointers to per-thread data
+* structure.
+*
+* NOTES:
+* (1) Only to be called ONCE at startup
+* (2) Must be called BEFORE any mthread requests are made
+*
+*Entry:
+* <NONE>
+*Exit:
+* returns TRUE on success
+* returns FALSE on failure
+* user code should call _amsg_exit if failure is returned
+*
+*Uses:
+* <any registers may be modified at init time>
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 _mtinit (
+ void
+ )
+{
+
+ _ptiddata ptd;
+
+ /*
+ * Initialize the mthread lock data base
+ */
+
+ _mtinitlocks();
+
+ /*
+ * Allocate a TLS index to maintain pointers to per-thread data
+ */
+ if ( (__tlsindex = TlsAlloc()) == 0xffffffff )
+ return FALSE; /* fail to load DLL */
+
+ /*
+ * Create a per-thread data structure for this (i.e., the startup)
+ * thread.
+ */
+ if ( ((ptd = calloc(1, sizeof(struct _tiddata))) == NULL) ||
+ !TlsSetValue(__tlsindex, (LPVOID)ptd) )
+ return FALSE; /* fail to load DLL */
+
+ ptd->_tid = GetCurrentThreadId();
+ ptd->_thandle = (unsigned long)(-1L);
+ ptd->_pxcptacttab = (void *)_XcptActTab;
+ ptd->_holdrand = 1L;
+
+ return TRUE;
+}
+
+
+/****
+*_mtterm() - Clean-up multi-thread data bases
+*
+*Purpose:
+* (1) Call _mtdeletelocks to free up all lock semaphores.
+* (2) Free up the TLS index used to hold pointers to
+* per-thread data structure.
+*
+* NOTES:
+* (1) Only to be called ONCE at termination
+* (2) Must be called AFTER all mthread requests are made
+*
+*Entry:
+* <NONE>
+*Exit:
+* returns
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _mtterm (
+ void
+ )
+{
+ /*
+ * Clean up the mthread lock data base
+ */
+
+ _mtdeletelocks();
+
+ /*
+ * Free up the TLS index
+ *
+ * (Also set the variable __tlsindex back to the unused state = -1L.)
+ */
+
+ if ( __tlsindex != 0xffffffff )
+ {
+ TlsFree(__tlsindex);
+ __tlsindex = 0xffffffff;
+ }
+}
+
+
+
+/***
+*_ptiddata _getptd(void) - get per-thread data structure for the current thread
+*
+*Purpose:
+*
+*Entry:
+* unsigned long tid
+*
+*Exit:
+* success = pointer to _tiddata structure for the thread
+* failure = fatal runtime exit
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_ptiddata _CRTAPI1 _getptd (
+ void
+ )
+{
+ _ptiddata ptd;
+
+ if ( (ptd = TlsGetValue(__tlsindex)) == NULL ) {
+ /*
+ * no per-thread data structure for this thread. try to create
+ * one.
+ */
+ if ( ((ptd = calloc(1, sizeof(struct _tiddata))) != NULL) &&
+ TlsSetValue(__tlsindex, (LPVOID)ptd) ) {
+ ptd->_tid = GetCurrentThreadId();
+ ptd->_thandle = (unsigned long)(-1L);
+ ptd->_holdrand = 1L;
+ ptd->_pxcptacttab = (void *)_XcptActTab;
+ }
+ else
+ _amsg_exit(_RT_THREAD); /* write message and die */
+ }
+
+ return(ptd);
+}
+
+
+/***
+*void _freeptd(_ptiddata) - free up a per-thread data structure
+*
+*Purpose:
+* Called from _endthread and from a DLL thread detach handler,
+* this routine frees up the per-thread buffer associated with a
+* thread that is going away. The tiddata structure itself is
+* freed, but not until its subordinate buffers are freed.
+*
+*Entry:
+* pointer to a per-thread data block (malloc-ed memory)
+* If NULL, the pointer for the current thread is fetched.
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _freeptd (
+ _ptiddata ptd
+ )
+{
+ /*
+ * Do nothing unless per-thread data has been allocated for this module!
+ */
+
+ if ( __tlsindex != 0xFFFFFFFF )
+ {
+ /*
+ * if parameter "ptd" is NULL, get the per-thread data pointer
+ * Must NOT call _getptd because it will allocate one if none exists!
+ */
+
+ if ( ! ptd )
+ ptd = TlsGetValue(__tlsindex );
+
+ /*
+ * Free up the _tiddata structure & its malloc-ed buffers.
+ */
+
+ if ( ptd )
+ {
+ if(ptd->_errmsg)
+ free((void *)ptd->_errmsg);
+
+ if(ptd->_namebuf0)
+ free((void *)ptd->_namebuf0);
+
+ if(ptd->_namebuf1)
+ free((void *)ptd->_namebuf1);
+
+ if(ptd->_asctimebuf)
+ free((void *)ptd->_asctimebuf);
+
+ if(ptd->_gmtimebuf)
+ free((void *)ptd->_gmtimebuf);
+
+ if(ptd->_cvtbuf)
+ free((void *)ptd->_cvtbuf);
+
+ free((void *)ptd);
+ }
+
+ /*
+ * Zero out the one pointer to the per-thread data block
+ */
+
+ TlsSetValue(__tlsindex, (LPVOID)0);
+ }
+}
+
+
+/***
+*__threadid() - Returns current thread ID
+*__threadhandle() - Returns "pseudo-handle" for current thread
+*
+*Purpose:
+* The two function are simply do-nothing wrappers for the corresponding
+* Win32 APIs (GetCurrentThreadId and GetCurrentThread, respectively).
+*
+*Entry:
+* void
+*
+*Exit:
+* thread ID value
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+unsigned long _CRTAPI1 __threadid (
+ void
+ )
+{
+ return( GetCurrentThreadId() );
+}
+
+unsigned long _CRTAPI1 __threadhandle(
+ void
+ )
+{
+ return( (unsigned long)GetCurrentThread() );
+}
+
+
+#endif
diff --git a/private/crt32/startup/tlssup.c b/private/crt32/startup/tlssup.c
new file mode 100644
index 000000000..783ef0d3a
--- /dev/null
+++ b/private/crt32/startup/tlssup.c
@@ -0,0 +1,52 @@
+#ifdef _MSC_VER
+
+
+/* tlssup.c - Thread Local Storage runtime support module */
+
+#include <nt.h>
+
+/* Thread Local Storage index for this .EXE or .DLL */
+
+ULONG _tls_index = 0;
+
+/* Special symbols to mark start and end of Thread Local Storage area.
+ * By convention, we initialize each with a pointer to it's own address.
+ */
+
+#pragma data_seg(".tls")
+
+PVOID _tls_start = &_tls_start;
+
+#pragma data_seg(".tls$ZZZ")
+
+PVOID _tls_end = &_tls_end;
+
+/* Start and end sections for Threadl Local Storage CallBack Array.
+ * Actual array is constructed using .CRT$XLA, .CRT$XLC, .CRT$XLL,
+ * .CRT$XLU, .CRT$XLZ similar to the way global
+ * static initializers are done for C++.
+ */
+
+#pragma data_seg(".CRT$XLA")
+
+PIMAGE_TLS_CALLBACK __xl_a = 0;
+
+#pragma data_seg(".CRT$XLZ")
+
+PIMAGE_TLS_CALLBACK __xl_z = 0;
+
+
+#pragma data_seg(".rdata$T")
+
+IMAGE_TLS_DIRECTORY _tls_used =
+{
+ (ULONG) &_tls_start, // start of tls data
+ (ULONG) &_tls_end, // end of tls data
+ &_tls_index, // address of tls_index
+ &__xl_a, // pointer to call back array
+ (ULONG) 0, // size of tls zero fill
+ (ULONG) 0 // characteristics
+};
+
+
+#endif /* _MSC_VER */
diff --git a/private/crt32/startup/wild.c b/private/crt32/startup/wild.c
new file mode 100644
index 000000000..a13c62d4e
--- /dev/null
+++ b/private/crt32/startup/wild.c
@@ -0,0 +1,341 @@
+/***
+*wild.c - wildcard expander
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* expands wildcards in argv
+*
+* handles '*' (none or more of any char) and '?' (exactly one char)
+*
+*Revision History:
+* 05-21-84 RN initial version
+* 06-07-85 TDC since dos accepts forward slash, added
+* code to accept forward slash in a manner consistent
+* with reverse slash.
+* 09-20-86 SKS Modified for OS/2
+* All argument strings to this function have a
+* leading flag character. If the flag is a quote,
+* that argument string was quoted on the command
+* line and should have not wildcard expansion. In all
+* cases the leading flag character is removed from
+* the string.
+* 11-11-86 JMB Added Kanji support under KANJI switch.
+* 09-21-88 WAJ initial 386 version
+* 04-09-90 GJF Added #include <cruntime.h> and removed #include
+* <register.h>. Made calling types explicit (_CALLTYPE1
+* or _CALLTYPE4). Also, fixed the copyright.
+* 04-10-90 GJF Added #include <internal.h> and fixed compiler warnings
+* (-W3).
+* 07-03-90 SBM Compiles cleanly with -W3 under KANJI, removed
+* redundant includes, removed #include <internal.h>
+* to keep wild.c free of private stuff, should we
+* decide to release it
+* 09-07-90 SBM put #include <internal.h> back in, reason for
+* removing it discovered to be horribly bogus
+* 10-08-90 GJF New-style function declarators.
+* 01-18-91 GJF ANSI naming.
+* 06-09-93 KRS Update _MBCS support.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <msdos.h>
+#include <internal.h>
+
+#ifdef _MBCS
+#include <mbdata.h>
+#include <mbstring.h>
+#define STRPBRK _mbspbrk
+#define STRCMP _mbscmp
+#define STRICMP _mbsicmp
+#else
+#define STRPBRK strpbrk
+#define STRCMP strcmp
+#define STRICMP _stricmp
+#endif
+
+/*
+** these are the data structures
+**
+** __argv
+** ------- ------
+** | |---->| |---->"arg0"
+** ------- ------
+** | |---->"arg1"
+** ------
+** ....
+** ------
+** | |---->"argn"
+** ------
+** |NULL|
+** ------
+** argend
+** -------
+** ------- | |
+** | | __argc -------
+** ------- |
+** |
+** arghead V
+** ------ --------- ----------
+** | |---->| | |----> .... ---->| |NULL|
+** ------ --------- ----------
+** | |
+** V V
+** "narg0" "nargn"
+*/
+
+#define SLASHCHAR '\\'
+#define FWDSLASHCHAR '/'
+#define SLASH "\\"
+#define FWDSLASH "/"
+#define STAR "*.*"
+
+#define WILDSTRING "*?"
+
+
+extern int __argc;
+extern char **__argv;
+
+struct argnode {
+ char *argptr;
+ struct argnode *nextnode;
+};
+
+static struct argnode *arghead;
+static struct argnode *argend;
+
+static int _CALLTYPE4 match(char *, char *);
+static int _CALLTYPE4 add(char *);
+static void _CALLTYPE4 sort(struct argnode *);
+
+/***
+*int _cwild() - wildcard expander
+*
+*Purpose:
+* expands wildcard in file specs in argv
+*
+* handles '*' (none or more of any char), '?' (exactly one char), and
+* '[string]' (chars which match string chars or between n1 and n2
+* if 'n1-n2' in string inclusive)
+*
+*Entry:
+*
+*Exit:
+* returns 0 if successful, -1 if any malloc() calls fail
+* if problems with malloc, the old argc and argv are not touched
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CALLTYPE1 _cwild (
+ void
+ )
+{
+ REG1 char **argv = __argv;
+ REG2 struct argnode *nodeptr;
+ REG3 int argc;
+ REG4 char **tmp;
+ char *wchar;
+
+ arghead = argend = NULL;
+
+ for (argv = __argv; *argv; argv++) /* for each arg... */
+ if ( *(*argv)++ == '"' )
+ /* strip leading quote from quoted arg */
+ {
+ if (add(*argv))
+ return(-1);
+ }
+ else if (wchar = STRPBRK( *argv, WILDSTRING )) {
+ /* attempt to expand arg with wildcard */
+ if (match( *argv, wchar ))
+ return(-1);
+ }
+ else if (add( *argv )) /* normal arg, just add */
+ return(-1);
+
+ /* count the args */
+ for (argc = 0, nodeptr = arghead; nodeptr;
+ nodeptr = nodeptr->nextnode, argc++)
+ ;
+
+ /* try to get new arg vector */
+ if (!(tmp = (char **)malloc(sizeof(char *)*(argc+1))))
+ return(-1);
+
+ /* the new arg vector... */
+ __argv = tmp;
+
+ /* the new arg count... */
+ __argc = argc;
+
+ /* install the new args */
+ for (nodeptr = arghead; nodeptr; nodeptr = nodeptr->nextnode)
+ *tmp++ = nodeptr->argptr;
+
+ /* the terminal NULL */
+ *tmp = NULL;
+
+ /* free up local data */
+ for (nodeptr = arghead; nodeptr; nodeptr = arghead) {
+ arghead = arghead->nextnode;
+ free(nodeptr);
+ }
+
+ /* return success */
+ return(0);
+}
+
+
+/***
+*match(arg, ptr) - [STATIC]
+*
+*Purpose:
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static int _CALLTYPE4 match (
+ REG4 char *arg,
+ REG1 char *ptr
+ )
+{
+ REG2 char *new;
+ REG3 int length = 0;
+ char *all;
+ REG5 struct argnode *first;
+ REG6 int gotone = 0;
+
+ while (ptr != arg && *ptr != SLASHCHAR && *ptr != FWDSLASHCHAR
+ && *ptr != ':') {
+ /* find first slash or ':' before wildcard */
+#ifdef _MBCS
+ if (--ptr > arg)
+ ptr = _mbsdec(arg,ptr+1);
+#else
+ ptr--;
+#endif
+ }
+
+ if (*ptr == ':' && ptr != arg+1) /* weird name, just add it as is */
+ return(add(arg));
+
+ if (*ptr == SLASHCHAR || *ptr == FWDSLASHCHAR
+ || *ptr == ':') /* pathname */
+ length = ptr - arg + 1; /* length of dir prefix */
+
+ if (new = _find(arg)) { /* get the first file name */
+ first = argend;
+
+ do { /* got a file name */
+ if (strcmp(new, ".") && strcmp(new, "..")) {
+ if (*ptr != SLASHCHAR && *ptr != ':'
+ && *ptr != FWDSLASHCHAR ) {
+ /* current directory; don't need path */
+ if (!(arg = _strdup(new)) || add(arg))
+ return(-1);
+ }
+ else /* add full pathname */
+ if (!(all=malloc(length+strlen(new)+1))
+ || add(strcpy(strncpy(all,arg,length)+length,new)
+ - length))
+ return(-1);
+
+ gotone++;
+ }
+
+ }
+ while (new = _find(NULL)); /* get following files */
+
+ if (gotone) {
+ sort(first ? first->nextnode : arghead);
+ return(0);
+ }
+ }
+
+ return(add(arg)); /* no match */
+}
+
+/***
+*add(arg) - [STATIC]
+*
+*Purpose:
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static int _CALLTYPE4 add (
+ char *arg
+ )
+{
+ REG1 struct argnode *nodeptr;
+
+ if (!(nodeptr = (struct argnode *)malloc(sizeof(struct argnode))))
+ return(-1);
+
+ nodeptr->argptr = arg;
+ nodeptr->nextnode = NULL;
+
+ if (arghead)
+ argend->nextnode = nodeptr;
+ else
+ arghead = nodeptr;
+
+ argend = nodeptr;
+ return(0);
+}
+
+
+/***
+*sort(first) - [STATIC]
+*
+*Purpose:
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static void _CALLTYPE4 sort (
+ REG2 struct argnode *first
+ )
+{
+ REG1 struct argnode *nodeptr;
+ REG3 char *temp;
+
+ if (first) /* something to sort */
+ while (nodeptr = first->nextnode) {
+ do {
+#ifdef _POSIX
+ if (STRCMP(nodeptr->argptr, first->argptr) < 0) {
+#else
+ if (STRICMP(nodeptr->argptr, first->argptr) < 0) {
+#endif /* _POSIX_ */
+ temp = first->argptr;
+ first->argptr = nodeptr->argptr;
+ nodeptr->argptr = temp;
+ }
+ }
+ while (nodeptr = nodeptr->nextnode);
+
+ first = first->nextnode;
+ }
+}
diff --git a/private/crt32/startup/wincrt0.c b/private/crt32/startup/wincrt0.c
new file mode 100644
index 000000000..3286b94db
--- /dev/null
+++ b/private/crt32/startup/wincrt0.c
@@ -0,0 +1,6 @@
+#ifndef _POSIX_
+
+#define _WINMAIN_
+#include "crt0.c"
+
+#endif /* ndef _POSIX_ */