diff options
Diffstat (limited to 'private/crt32/startup')
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 */ + <lcritsect, /* 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] != <lcritsect ) + _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_ */ |