summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/misc')
-rw-r--r--private/crt32/misc/_strerr.c143
-rw-r--r--private/crt32/misc/abort.c96
-rw-r--r--private/crt32/misc/abs.c51
-rw-r--r--private/crt32/misc/alpha/chandler.c296
-rw-r--r--private/crt32/misc/alpha/divdat.s597
-rw-r--r--private/crt32/misc/alpha/divide.s1319
-rw-r--r--private/crt32/misc/alpha/divide2.s1002
-rw-r--r--private/crt32/misc/alpha/extv.s82
-rw-r--r--private/crt32/misc/alpha/extvvol.s98
-rw-r--r--private/crt32/misc/alpha/extzv.s83
-rw-r--r--private/crt32/misc/alpha/extzvvol.s101
-rw-r--r--private/crt32/misc/alpha/fastdiv.s662
-rw-r--r--private/crt32/misc/alpha/ghandler.c435
-rw-r--r--private/crt32/misc/alpha/insv.s158
-rw-r--r--private/crt32/misc/alpha/insvvol.s137
-rw-r--r--private/crt32/misc/alpha/jmpuwind.s167
-rw-r--r--private/crt32/misc/alpha/longjmp.s192
-rw-r--r--private/crt32/misc/alpha/ots_as.hs38
-rw-r--r--private/crt32/misc/alpha/ots_defs.hs3
-rw-r--r--private/crt32/misc/alpha/otsdiv.s1178
-rw-r--r--private/crt32/misc/alpha/otsjmp.s117
-rw-r--r--private/crt32/misc/alpha/otsjmpex.s84
-rw-r--r--private/crt32/misc/alpha/otsnote.txt115
-rw-r--r--private/crt32/misc/alpha/otsuwind.s80
-rw-r--r--private/crt32/misc/alpha/scmpeql.s295
-rw-r--r--private/crt32/misc/alpha/scmpeqlp.s443
-rw-r--r--private/crt32/misc/alpha/scmpleq.s338
-rw-r--r--private/crt32/misc/alpha/scmpleqp.s478
-rw-r--r--private/crt32/misc/alpha/scmplss.s339
-rw-r--r--private/crt32/misc/alpha/scmplssp.s478
-rw-r--r--private/crt32/misc/alpha/setjmp.s111
-rw-r--r--private/crt32/misc/alpha/setjmpex.s147
-rw-r--r--private/crt32/misc/alpha/sfill.s161
-rw-r--r--private/crt32/misc/alpha/sloc.s702
-rw-r--r--private/crt32/misc/alpha/smove.s652
-rw-r--r--private/crt32/misc/alpha/smovem.s667
-rw-r--r--private/crt32/misc/alpha/strans.s122
-rw-r--r--private/crt32/misc/alpha/strcmp_.s357
-rw-r--r--private/crt32/misc/alpha/strcpy_.s257
-rw-r--r--private/crt32/misc/alpha/strlen_.s95
-rw-r--r--private/crt32/misc/alpha/szero.s137
-rw-r--r--private/crt32/misc/assert.c66
-rw-r--r--private/crt32/misc/bsearch.c99
-rw-r--r--private/crt32/misc/cmiscdat.c68
-rw-r--r--private/crt32/misc/ctype.c161
-rw-r--r--private/crt32/misc/div.c59
-rw-r--r--private/crt32/misc/getenv.c167
-rw-r--r--private/crt32/misc/getpath.c174
-rw-r--r--private/crt32/misc/getqloc.c736
-rw-r--r--private/crt32/misc/i386/_initone.asm17
-rw-r--r--private/crt32/misc/i386/cinitone.asm78
-rw-r--r--private/crt32/misc/i386/exsup.asm299
-rw-r--r--private/crt32/misc/i386/exsup2.asm271
-rw-r--r--private/crt32/misc/i386/exsup3.asm290
-rw-r--r--private/crt32/misc/i386/longjmp.asm150
-rw-r--r--private/crt32/misc/i386/sehsupp.c59
-rw-r--r--private/crt32/misc/i386/setjmp.asm151
-rw-r--r--private/crt32/misc/i386/setjmp3.asm148
-rw-r--r--private/crt32/misc/i386/setjmpex.asm55
-rw-r--r--private/crt32/misc/initcoll.c51
-rw-r--r--private/crt32/misc/initctyp.c212
-rw-r--r--private/crt32/misc/inithelp.c143
-rw-r--r--private/crt32/misc/initmon.c191
-rw-r--r--private/crt32/misc/initnum.c129
-rw-r--r--private/crt32/misc/inittime.c301
-rw-r--r--private/crt32/misc/labs.c52
-rw-r--r--private/crt32/misc/lconv.c86
-rw-r--r--private/crt32/misc/ldiv.c59
-rw-r--r--private/crt32/misc/lfind.c79
-rw-r--r--private/crt32/misc/lsearch.c87
-rw-r--r--private/crt32/misc/makefile6
-rw-r--r--private/crt32/misc/makepath.c128
-rw-r--r--private/crt32/misc/mbval.c22
-rw-r--r--private/crt32/misc/mips/chandler.c219
-rw-r--r--private/crt32/misc/mips/jmpuwind.s138
-rw-r--r--private/crt32/misc/mips/longjmp.s128
-rw-r--r--private/crt32/misc/mips/setjmp.s101
-rw-r--r--private/crt32/misc/mips/setjmpex.s156
-rw-r--r--private/crt32/misc/mtest.c530
-rw-r--r--private/crt32/misc/nlsdata1.c38
-rw-r--r--private/crt32/misc/nlsdata2.c34
-rw-r--r--private/crt32/misc/nlsdata3.c34
-rw-r--r--private/crt32/misc/onexit.c286
-rw-r--r--private/crt32/misc/perror.c78
-rw-r--r--private/crt32/misc/ppc/chandler.c222
-rw-r--r--private/crt32/misc/ppc/cinitone.s41
-rw-r--r--private/crt32/misc/ppc/jmpuwind.s162
-rw-r--r--private/crt32/misc/ppc/longjmp.s143
-rw-r--r--private/crt32/misc/ppc/miscasm.s273
-rw-r--r--private/crt32/misc/ppc/setjmp.s138
-rw-r--r--private/crt32/misc/ppc/setjmpex.s194
-rw-r--r--private/crt32/misc/ppc/sources6
-rw-r--r--private/crt32/misc/purevirt.c42
-rw-r--r--private/crt32/misc/putenv.c453
-rw-r--r--private/crt32/misc/qsort.c329
-rw-r--r--private/crt32/misc/rand.c133
-rw-r--r--private/crt32/misc/rotl.c90
-rw-r--r--private/crt32/misc/rotr.c90
-rw-r--r--private/crt32/misc/searchen.c114
-rw-r--r--private/crt32/misc/setlocal.c620
-rw-r--r--private/crt32/misc/setmbval.c35
-rw-r--r--private/crt32/misc/sources129
-rw-r--r--private/crt32/misc/splitpat.c201
-rw-r--r--private/crt32/misc/strerror.c142
-rw-r--r--private/crt32/misc/syserr.c85
-rw-r--r--private/crt32/misc/umask.c55
-rw-r--r--private/crt32/misc/winsig.c709
-rw-r--r--private/crt32/misc/winxfltr.c618
-rw-r--r--private/crt32/misc/wrt2err.c84
109 files changed, 24457 insertions, 0 deletions
diff --git a/private/crt32/misc/_strerr.c b/private/crt32/misc/_strerr.c
new file mode 100644
index 000000000..8863e64c5
--- /dev/null
+++ b/private/crt32/misc/_strerr.c
@@ -0,0 +1,143 @@
+/***
+*_strerr.c - routine for indexing into system error list
+*
+* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Returns system error message index by errno; conforms to the
+* XENIX standard, much compatibility with 1983 uniforum draft standard.
+*
+*Revision History:
+* 02-24-87 JCR Renamed this routine from "strerror" to "_strerror"
+* for MS. The new "strerror" routine conforms to the
+* ANSI interface.
+* 11-10-87 SKS Remove IBMC20 switch
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-05-87 JCR Mthread support
+* 05-31-88 PHG Merged DLL and normal versions
+* 06-06-89 JCR 386 mthread support
+* 11-20-89 GJF Fixed copyright, indents. Removed unreferenced local.
+* Added const attribute to type of message
+* 03-13-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h> and removed #include <register.h>
+* 07-25-90 SBM Removed redundant include (stdio.h)
+* 10-04-90 GJF New-style function declarator.
+* 07-18-91 GJF Multi-thread support for Win32 [_WIN32_].
+* 02-17-93 GJF Changed for new _getptd().
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <errmsg.h>
+#include <syserr.h>
+#include <string.h>
+#include <malloc.h>
+#include <os2dll.h>
+
+/* Max length of message = user_string(94)+system_string+2 */
+/* [NOTE: The mthread error message buffer is shared by both strerror
+ and _strerror so must be the max length of both. */
+#define _ERRMSGLEN_ 94+_SYS_MSGMAX+2
+
+/***
+*char *_strerror(message) - get system error message
+*
+*Purpose:
+* builds an error message consisting of the users error message
+* (the message parameter), followed by ": ", followed by the system
+* error message (index through errno), followed by a newline. If
+* message is NULL or a null string, returns a pointer to just
+* the system error message.
+*
+*Entry:
+* char *message - user's message to prefix system error message
+*
+*Exit:
+* returns pointer to static memory containing error message.
+* returns NULL if malloc() fails in multi-thread versions.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+char * _CRTAPI1 _strerror (
+ REG1 const char *message
+ )
+{
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ struct _tiddata * tdata;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ _ptiddata ptd = _getptd();
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ char *bldmsg;
+
+#else
+
+ static char bldmsg[_ERRMSGLEN_];
+
+#endif
+
+
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ /* Use per thread buffer area (malloc space, if necessary) */
+ /* [NOTE: This buffer is shared between _strerror and streror.] */
+ tdata = _gettidtab(); /* get tid's data address */
+ if (tdata->_errmsg == NULL)
+ if ( (tdata->_errmsg = malloc(_ERRMSGLEN_)) == NULL)
+ return(NULL);
+ bldmsg = tdata->_errmsg;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ /* Use per thread buffer area (malloc space, if necessary) */
+ /* [NOTE: This buffer is shared between _strerror and streror.] */
+
+ if ( (ptd->_errmsg == NULL) && ((ptd->_errmsg = malloc(_ERRMSGLEN_))
+ == NULL) )
+ return(NULL);
+ bldmsg = ptd->_errmsg;
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+#endif
+
+ /* Build the error message */
+
+ bldmsg[0] = '\0';
+
+ if (message && *message) {
+ strcat( bldmsg, message );
+ strcat( bldmsg, ": " );
+ }
+
+ strcat( bldmsg, _sys_err_msg( errno ) );
+
+ return( strcat( bldmsg, "\n" ) );
+}
diff --git a/private/crt32/misc/abort.c b/private/crt32/misc/abort.c
new file mode 100644
index 000000000..b88d2fff0
--- /dev/null
+++ b/private/crt32/misc/abort.c
@@ -0,0 +1,96 @@
+/***
+*abort.c - abort a program by raising SIGABRT
+*
+* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines abort() - print a message and raise SIGABRT.
+*
+*Revision History:
+* 06-30-89 PHG module created, based on asm version
+* 03-13-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 07-26-90 SBM Removed bogus leading underscore from _NMSG_WRITE
+* 10-04-90 GJF New-style function declarator.
+* 10-11-90 GJF Now does raise(SIGABRT). Also changed _NMSG_WRITE()
+* interface.
+* 04-10-91 PNT Added _MAC_ conditional
+* 08-26-92 GJF Include unistd.h for POSIX build.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#ifdef _POSIX_
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <internal.h>
+#include <rterr.h>
+#include <signal.h>
+
+/***
+*void abort() - abort the current program by raising SIGABRT
+*
+*Purpose:
+* print out an abort message and raise the SIGABRT signal. If the user
+* hasn't defined an abort handler routine, terminate the program
+* with exit status of 3 without cleaning up.
+*
+* Multi-thread version does not raise SIGABRT -- this isn't supported
+* under multi-thread.
+*
+*Entry:
+* None.
+*
+*Exit:
+* Does not return.
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 abort (
+ void
+ )
+{
+ _NMSG_WRITE(_RT_ABORT); /* write the abort message */
+
+#ifdef _POSIX_
+
+ {
+ sigset_t set;
+
+ fflush(NULL);
+
+ signal(SIGABRT, SIG_DFL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGABRT);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ }
+
+#endif /* _POSIX_ */
+
+
+#ifndef _MAC_
+
+ raise(SIGABRT); /* raise abort signal */
+
+#endif /* ndef _MAC_ */
+
+ /* We usually won't get here, but it's possible that
+ SIGABRT was ignored. So hose the program anyway. */
+
+#ifdef _POSIX_
+ /* SIGABRT was ignored or handled, and the handler returned
+ normally. We need open streams to be flushed here. */
+
+ exit(3);
+#else /* not _POSIX_ */
+
+ _exit(3);
+#endif /* _POSIX */
+}
diff --git a/private/crt32/misc/abs.c b/private/crt32/misc/abs.c
new file mode 100644
index 000000000..cd5f3d1be
--- /dev/null
+++ b/private/crt32/misc/abs.c
@@ -0,0 +1,51 @@
+/***
+*abs.c - find absolute value
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines abs() - find the absolute value of an int.
+*
+*Revision History:
+* 04-22-87 JMB added function pragma for conversion to C 5.0 compiler
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned up
+* the formatting a bit.
+* 10-04-90 GJF New-style function declarator.
+* 12-28-90 SRW Added _CRUISER_ conditional around function pragma
+* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too.
+* 03-09-94 RDL Enable #pragma function for MIPS _WIN32_ builds too.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+#pragma function(abs)
+#endif
+
+/***
+*int abs(number) - find absolute value of number
+*
+*Purpose:
+* Returns the absolute value of number (if number >= 0, returns number,
+* else returns -number).
+*
+*Entry:
+* int number - number to find absolute value of
+*
+*Exit:
+* returns the aboslute value of number
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CALLTYPE1 abs (
+ int number
+ )
+{
+ return( number>=0 ? number : -number );
+}
diff --git a/private/crt32/misc/alpha/chandler.c b/private/crt32/misc/alpha/chandler.c
new file mode 100644
index 000000000..68251f1ca
--- /dev/null
+++ b/private/crt32/misc/alpha/chandler.c
@@ -0,0 +1,296 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ chandler.c
+
+Abstract:
+
+ This module implements the C specific exception handler that provides
+ structured condition handling for the C language.
+
+Author:
+
+ David N. Cutler (davec) 11-Sep-1990
+
+Environment:
+
+ Any mode.
+
+Revision History:
+
+ Thomas Van Baak (tvb) 29-Apr-1992
+
+ Adapted for Alpha AXP.
+
+--*/
+
+#include "nt.h"
+
+//
+// Define procedure prototypes for exception filter and termination handler
+// execution routines defined in jmpuwind.s.
+//
+
+LONG
+__C_ExecuteExceptionFilter (
+ PEXCEPTION_POINTERS ExceptionPointers,
+ EXCEPTION_FILTER ExceptionFilter,
+ ULONG EstablisherFrame
+ );
+
+VOID
+__C_ExecuteTerminationHandler (
+ BOOLEAN AbnormalTermination,
+ TERMINATION_HANDLER TerminationHandler,
+ ULONG EstablisherFrame
+ );
+
+EXCEPTION_DISPOSITION
+__C_specific_handler (
+ IN struct _EXCEPTION_RECORD *ExceptionRecord,
+ IN void *EstablisherFrame,
+ IN OUT struct _CONTEXT *ContextRecord,
+ IN OUT struct _DISPATCHER_CONTEXT *DispatcherContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function scans the scope tables associated with the specified
+ procedure and calls exception and termination handlers as necessary.
+
+ This language specific exception handler function is called on a
+ per-frame basis and in two different cases:
+
+ First, the IS_DISPATCHING case, it is called by the exception
+ dispatcher, RtlDispatchException, via the short assembler routine,
+ __C_ExecuteHandlerForException, when trying to locate exception
+ filters within the given frame.
+
+ Second, the IS_UNWINDING case, it is called by the frame unwinder,
+ RtlUnwind, via the short assembler routine, __C_ExecuteHandlerForUnwind,
+ when unwinding the stack and trying to locate termination handlers
+ within the given frame.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to an exception record.
+
+ EstablisherFrame - Supplies a pointer to frame of the establisher function.
+
+ ContextRecord - Supplies a pointer to a context record.
+
+ DispatcherContext - Supplies a pointer to the exception dispatcher or
+ unwind dispatcher context.
+
+Return Value:
+
+ If the exception is handled by one of the exception filter routines, then
+ there is no return from this routine and RtlUnwind is called. Otherwise,
+ an exception disposition value of continue execution or continue search is
+ returned.
+
+--*/
+
+{
+
+ ULONG ControlPc;
+ EXCEPTION_FILTER ExceptionFilter;
+ EXCEPTION_POINTERS ExceptionPointers;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG Index;
+ PSCOPE_TABLE ScopeTable;
+ ULONG TargetPc;
+ TERMINATION_HANDLER TerminationHandler;
+ LONG Value;
+
+ //
+ // Get the address of where control left the establisher, the address of
+ // the function table entry that describes the function, and the address of
+ // the scope table.
+ //
+
+ ControlPc = DispatcherContext->ControlPc;
+ FunctionEntry = DispatcherContext->FunctionEntry;
+ ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData);
+
+ //
+ // The scope table HandlerAddress is either the address of an exception
+ // filter or a termination handler. The C compiler wraps the code in the
+ // exception filter expression or the termination handler clause within
+ // an internal C function. The value of the scope table JumpTarget field
+ // is used to distinguish an exception filter function (JumpTarget non zero)
+ // from a termination handler function (JumpTarget is zero).
+ //
+
+ //
+ // If an unwind is not in progress, then scan the scope table and call
+ // the appropriate exception filter routines. Otherwise, scan the scope
+ // table and call the appropriate termination handlers using the target
+ // PC obtained from the context record.
+ //
+
+ if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // Set up the ExceptionPointers structure that is passed as the argument
+ // to the exception filter. It is used by the compiler to implement the
+ // intrinsic functions exception_code() and exception_info().
+ //
+
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+
+ //
+ // Scan the scope table and call the appropriate exception filter
+ // routines. The scope table entries are known to be sorted by
+ // increasing EndAddress order. Thus a linear scan will naturally
+ // hit inner scope exception clauses before outer scope clauses.
+ //
+
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) &&
+ (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) {
+
+ //
+ // Call the exception filter routine.
+ //
+
+ ExceptionFilter =
+ (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ Value = __C_ExecuteExceptionFilter(&ExceptionPointers,
+ ExceptionFilter,
+ (ULONG)EstablisherFrame);
+
+ //
+ // If the return value is less than zero, then dismiss the
+ // exception. Otherwise, if the value is greater than zero,
+ // then unwind to the target exception handler corresponding
+ // to the exception filter. Otherwise, continue the search for
+ // an exception filter.
+ //
+
+ //
+ // Exception filters will usually return one of the following
+ // defines, although the decision below is made only by sign:
+ //
+ // #define EXCEPTION_EXECUTE_HANDLER 1
+ // #define EXCEPTION_CONTINUE_SEARCH 0
+ // #define EXCEPTION_CONTINUE_EXECUTION -1
+ //
+
+ if (Value < 0) {
+ return ExceptionContinueExecution;
+
+ } else if (Value > 0) {
+
+ //
+ // Set the return value for the unwind to the exception
+ // code so the exception handler clause can retrieve it
+ // from v0. This is how GetExceptionCode() is implemented
+ // in exception handler clauses.
+ //
+
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget,
+ ExceptionRecord,
+ (PVOID)ExceptionRecord->ExceptionCode);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // Scan the scope table and call the appropriate termination handler
+ // routines.
+ //
+
+ TargetPc = (ULONG)ContextRecord->Fir;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) {
+
+ //
+ // If the target PC is within the same scope the control PC
+ // is within, then this is an uplevel goto out of an inner try
+ // scope or a long jump back into a try scope. Terminate the
+ // scan for termination handlers - because any other handlers
+ // will be outside the scope of both the goto and its label.
+ //
+ // N.B. The target PC can be just beyond the end of the scope,
+ // in which case it is a leave from the scope.
+ //
+
+ if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) {
+ break;
+
+ } else {
+
+ //
+ // If the scope table entry describes an exception filter
+ // and the associated exception handler is the target of
+ // the unwind, then terminate the scan for termination
+ // handlers. Otherwise, if the scope table entry describes
+ // a termination handler, then record the address of the
+ // end of the scope as the new control PC address and call
+ // the termination handler.
+ //
+ // Recording a new control PC is necessary to ensure that
+ // termination handlers are called only once even when a
+ // collided unwind occurs.
+ //
+
+ if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) {
+
+ //
+ // try/except - exception filter (JumpTarget != 0).
+ // After the exception filter is called, the exception
+ // handler clause is executed by the call to unwind
+ // above. Having reached this point in the scan of the
+ // scope tables, any other termination handlers will
+ // be outside the scope of the try/except.
+ //
+
+ if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) {
+ break;
+ }
+
+ } else {
+
+ //
+ // try/finally - termination handler (JumpTarget == 0).
+ //
+
+ //
+ // Unless the termination handler results in a long
+ // jump, execution will resume at the instruction after
+ // the exception handler clause.
+ //
+ // ## tvb - I'm still suspicious of the +4 below.
+
+ DispatcherContext->ControlPc =
+ ScopeTable->ScopeRecord[Index].EndAddress + 4;
+ TerminationHandler =
+ (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ (ULONG)EstablisherFrame);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Continue search for exception filters or termination handlers.
+ //
+
+ return ExceptionContinueSearch;
+}
diff --git a/private/crt32/misc/alpha/divdat.s b/private/crt32/misc/alpha/divdat.s
new file mode 100644
index 000000000..543d6237b
--- /dev/null
+++ b/private/crt32/misc/alpha/divdat.s
@@ -0,0 +1,597 @@
+
+ # Copyright 1992,1993, Digital Equipment Corporation
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+ # 009 15 Jul 1992 KDG - Can't have .end for Alpha/OSF - use
+ # new ots_data_end macro
+ # - Need .data for OSF
+ #
+ # 010 4 Sep 1992 KDG Switch PSECT from ots_div_data to ots_lit
+ #
+ # 011 26 Jan 1993 KDG Add underscore, OSF uses CS name
+ #
+ # 012 5 Apr 1993 WBN Use 16-byte entries, up to 512, and
+ # support computing 1/(a+x).
+
+#include "ots_defs.hs"
+
+ # Data area description
+ #
+ # The data area "ots_div_data" is an array of structures, indexed
+ # by the divisor value, with each array entry being 16 bytes in size
+ # formatted as follows:
+ #
+ # 6 1 1
+ # 3 6 5 6 5 0
+ # +-------+-------+-------+-------+-------+-------+-------+-------+
+ # | 32 bit reciprocal (48 bits) | recip^2 |shift|
+ # +-------+-------+-------+-------+-------+-------+-------+-------+
+ # | 64 bit reciprocal |
+ # +---------------------------------------------------------------+
+ #
+ # The 64-bit reciprocal has the leading '1' bit omitted, so it provides
+ # 65 bits of precision -- enough to handle unsigned 64-bit dividends.
+ #
+ # The first quadword contains the 6-bit shift amount needed to handle
+ # 64-bit cases and powers of two. For divisors between 256 and 512,
+ # this quadword also contains a 10-bit coefficient for linearly
+ # approximating larger reciprocals (1/(a+x) = 1/a - x/a^2 + ...).
+ #
+ # The 32-bit reciprocal has the shift count built in, so a UMULH gives
+ # the correct quotient without shifting. The reciprocal needs 33 bits
+ # of precision. The 10-bit reciprocal-squared, and 6-bit shift amount,
+ # are noise in the reciprocal that can be ignored for divisors less than
+ # 512. (The only possible exception is for 1/257, and it checks out OK.)
+ #
+ # Powers of two are flagged with a 32-bit reciprocal that is negative,
+ # and a 64-bit reciprocal that is zero.
+
+ # OTS division data table
+ #
+
+#ifdef VMS
+ .psect ots_lit
+ .align 4 # octaword alignment
+ots_div_data::
+#endif
+#ifdef OSF
+ .globl _OtsDivData
+ .data
+ .align 4
+_OtsDivData:
+#endif
+#ifdef WNT
+ .globl _OtsDivData
+ .data
+ .align 4
+_OtsDivData:
+#endif
+ # recip^2--. .-shift
+ #32b recip / \| 64 bit reciprocal divisor
+ .quad 0x0000000000000000, 0x0000000000000000 # 0
+ .quad 0x8000000000000000, 0x0000000000000000 # 1
+ .quad 0x8000000000000001, 0x0000000000000000 # 2
+ .quad 0x5555555555560002, 0x5555555555555556 # 3
+ .quad 0x8000000000000002, 0x0000000000000000 # 4
+ .quad 0x3333333333340003, 0x999999999999999A # 5
+ .quad 0x2AAAAAAAAAAB0003, 0x5555555555555556 # 6
+ .quad 0x24924924924A0003, 0x2492492492492493 # 7
+ .quad 0x8000000000000003, 0x0000000000000000 # 8
+ .quad 0x1C71C71C71C80004, 0xC71C71C71C71C71D # 9
+ .quad 0x19999999999A0004, 0x999999999999999A # 10
+ .quad 0x1745D1745D180004, 0x745D1745D1745D18 # 11
+ .quad 0x1555555555560004, 0x5555555555555556 # 12
+ .quad 0x13B13B13B13C0004, 0x3B13B13B13B13B14 # 13
+ .quad 0x1249249249250004, 0x2492492492492493 # 14
+ .quad 0x1111111111120004, 0x1111111111111112 # 15
+ .quad 0x8000000000000004, 0x0000000000000000 # 16
+ .quad 0x0F0F0F0F0F100005, 0xE1E1E1E1E1E1E1E2 # 17
+ .quad 0x0E38E38E38E40005, 0xC71C71C71C71C71D # 18
+ .quad 0x0D79435E50D80005, 0xAF286BCA1AF286BD # 19
+ .quad 0x0CCCCCCCCCCD0005, 0x999999999999999A # 20
+ .quad 0x0C30C30C30C40005, 0x8618618618618619 # 21
+ .quad 0x0BA2E8BA2E8C0005, 0x745D1745D1745D18 # 22
+ .quad 0x0B21642C85910005, 0x642C8590B21642C9 # 23
+ .quad 0x0AAAAAAAAAAB0005, 0x5555555555555556 # 24
+ .quad 0x0A3D70A3D70B0005, 0x47AE147AE147AE15 # 25
+ .quad 0x09D89D89D89E0005, 0x3B13B13B13B13B14 # 26
+ .quad 0x097B425ED0980005, 0x2F684BDA12F684BE # 27
+ .quad 0x0924924924930005, 0x2492492492492493 # 28
+ .quad 0x08D3DCB08D3E0005, 0x1A7B9611A7B9611B # 29
+ .quad 0x0888888888890005, 0x1111111111111112 # 30
+ .quad 0x0842108421090005, 0x0842108421084211 # 31
+ .quad 0x8000000000000005, 0x0000000000000000 # 32
+ .quad 0x07C1F07C1F080006, 0xF07C1F07C1F07C20 # 33
+ .quad 0x0787878787880006, 0xE1E1E1E1E1E1E1E2 # 34
+ .quad 0x0750750750760006, 0xD41D41D41D41D41E # 35
+ .quad 0x071C71C71C720006, 0xC71C71C71C71C71D # 36
+ .quad 0x06EB3E45306F0006, 0xBACF914C1BACF915 # 37
+ .quad 0x06BCA1AF286C0006, 0xAF286BCA1AF286BD # 38
+ .quad 0x06906906906A0006, 0xA41A41A41A41A41B # 39
+ .quad 0x0666666666670006, 0x999999999999999A # 40
+ .quad 0x063E7063E7070006, 0x8F9C18F9C18F9C19 # 41
+ .quad 0x0618618618620006, 0x8618618618618619 # 42
+ .quad 0x05F417D05F420006, 0x7D05F417D05F417E # 43
+ .quad 0x05D1745D17460006, 0x745D1745D1745D18 # 44
+ .quad 0x05B05B05B05C0006, 0x6C16C16C16C16C17 # 45
+ .quad 0x0590B21642C90006, 0x642C8590B21642C9 # 46
+ .quad 0x0572620AE4C50006, 0x5C9882B931057263 # 47
+ .quad 0x0555555555560006, 0x5555555555555556 # 48
+ .quad 0x05397829CBC20006, 0x4E5E0A72F0539783 # 49
+ .quad 0x051EB851EB860006, 0x47AE147AE147AE15 # 50
+ .quad 0x0505050505060006, 0x4141414141414142 # 51
+ .quad 0x04EC4EC4EC4F0006, 0x3B13B13B13B13B14 # 52
+ .quad 0x04D4873ECADF0006, 0x3521CFB2B78C1353 # 53
+ .quad 0x04BDA12F684C0006, 0x2F684BDA12F684BE # 54
+ .quad 0x04A7904A79050006, 0x29E4129E4129E413 # 55
+ .quad 0x04924924924A0006, 0x2492492492492493 # 56
+ .quad 0x047DC11F70480006, 0x1F7047DC11F7047E # 57
+ .quad 0x0469EE58469F0006, 0x1A7B9611A7B9611B # 58
+ .quad 0x0456C797DD4A0006, 0x15B1E5F75270D046 # 59
+ .quad 0x0444444444450006, 0x1111111111111112 # 60
+ .quad 0x04325C53EF370006, 0x0C9714FBCDA3AC11 # 61
+ .quad 0x0421084210850006, 0x0842108421084211 # 62
+ .quad 0x0410410410420006, 0x0410410410410411 # 63
+ .quad 0x8000000000000006, 0x0000000000000000 # 64
+ .quad 0x03F03F03F0400007, 0xF81F81F81F81F820 # 65
+ .quad 0x03E0F83E0F840007, 0xF07C1F07C1F07C20 # 66
+ .quad 0x03D226357E170007, 0xE9131ABF0B7672A1 # 67
+ .quad 0x03C3C3C3C3C40007, 0xE1E1E1E1E1E1E1E2 # 68
+ .quad 0x03B5CC0ED7310007, 0xDAE6076B981DAE61 # 69
+ .quad 0x03A83A83A83B0007, 0xD41D41D41D41D41E # 70
+ .quad 0x039B0AD120740007, 0xCD85689039B0AD13 # 71
+ .quad 0x038E38E38E390007, 0xC71C71C71C71C71D # 72
+ .quad 0x0381C0E070390007, 0xC0E070381C0E0704 # 73
+ .quad 0x03759F2298380007, 0xBACF914C1BACF915 # 74
+ .quad 0x0369D0369D040007, 0xB4E81B4E81B4E81C # 75
+ .quad 0x035E50D794360007, 0xAF286BCA1AF286BD # 76
+ .quad 0x03531DEC0D4D0007, 0xA98EF606A63BD81B # 77
+ .quad 0x0348348348350007, 0xA41A41A41A41A41B # 78
+ .quad 0x033D91D2A2070007, 0x9EC8E951033D91D3 # 79
+ .quad 0x0333333333340007, 0x999999999999999A # 80
+ .quad 0x0329161F9ADE0007, 0x948B0FCD6E9E0653 # 81
+ .quad 0x031F3831F3840007, 0x8F9C18F9C18F9C19 # 82
+ .quad 0x03159721ED7F0007, 0x8ACB90F6BF3A9A38 # 83
+ .quad 0x030C30C30C310007, 0x8618618618618619 # 84
+ .quad 0x0303030303040007, 0x8181818181818182 # 85
+ .quad 0x02FA0BE82FA10007, 0x7D05F417D05F417E # 86
+ .quad 0x02F149902F150007, 0x78A4C8178A4C8179 # 87
+ .quad 0x02E8BA2E8BA30007, 0x745D1745D1745D18 # 88
+ .quad 0x02E05C0B81710007, 0x702E05C0B81702E1 # 89
+ .quad 0x02D82D82D82E0007, 0x6C16C16C16C16C17 # 90
+ .quad 0x02D02D02D02E0007, 0x6816816816816817 # 91
+ .quad 0x02C8590B21650007, 0x642C8590B21642C9 # 92
+ .quad 0x02C0B02C0B030007, 0x6058160581605817 # 93
+ .quad 0x02B9310572630007, 0x5C9882B931057263 # 94
+ .quad 0x02B1DA46102C0007, 0x58ED2308158ED231 # 95
+ .quad 0x02AAAAAAAAAB0007, 0x5555555555555556 # 96
+ .quad 0x02A3A0FD5C600007, 0x51D07EAE2F8151D1 # 97
+ .quad 0x029CBC14E5E10007, 0x4E5E0A72F0539783 # 98
+ .quad 0x0295FAD40A580007, 0x4AFD6A052BF5A815 # 99
+ .quad 0x028F5C28F5C30007, 0x47AE147AE147AE15 # 100
+ .quad 0x0288DF0CAC5C0007, 0x446F86562D9FAEE5 # 101
+ .quad 0x0282828282830007, 0x4141414141414142 # 102
+ .quad 0x027C45979C960007, 0x3E22CBCE4A9027C5 # 103
+ .quad 0x0276276276280007, 0x3B13B13B13B13B14 # 104
+ .quad 0x0270270270280007, 0x3813813813813814 # 105
+ .quad 0x026A439F65700007, 0x3521CFB2B78C1353 # 106
+ .quad 0x02647C6945630007, 0x323E34A2B10BF66F # 107
+ .quad 0x025ED097B4260007, 0x2F684BDA12F684BE # 108
+ .quad 0x02593F69B0260007, 0x2C9FB4D812C9FB4E # 109
+ .quad 0x0253C8253C830007, 0x29E4129E4129E413 # 110
+ .quad 0x024E6A1710250007, 0x27350B88127350B9 # 111
+ .quad 0x0249249249250007, 0x2492492492492493 # 112
+ .quad 0x0243F6F024400007, 0x21FB78121FB78122 # 113
+ .quad 0x023EE08FB8240007, 0x1F7047DC11F7047E # 114
+ .quad 0x0239E0D5B4510007, 0x1CF06ADA2811CF07 # 115
+ .quad 0x0234F72C23500007, 0x1A7B9611A7B9611B # 116
+ .quad 0x0230230230240007, 0x1811811811811812 # 117
+ .quad 0x022B63CBEEA50007, 0x15B1E5F75270D046 # 118
+ .quad 0x0226B90226BA0007, 0x135C81135C81135D # 119
+ .quad 0x0222222222230007, 0x1111111111111112 # 120
+ .quad 0x021D9EAD7CD40007, 0x0ECF56BE69C8FDE3 # 121
+ .quad 0x02192E29F79C0007, 0x0C9714FBCDA3AC11 # 122
+ .quad 0x0214D0214D030007, 0x0A6810A6810A6811 # 123
+ .quad 0x0210842108430007, 0x0842108421084211 # 124
+ .quad 0x020C49BA5E360007, 0x0624DD2F1A9FBE77 # 125
+ .quad 0x0208208208210007, 0x0410410410410411 # 126
+ .quad 0x0204081020410007, 0x0204081020408103 # 127
+ .quad 0x8000000000000007, 0x0000000000000000 # 128
+ .quad 0x01FC07F01FC10008, 0xFC07F01FC07F01FD # 129
+ .quad 0x01F81F81F8200008, 0xF81F81F81F81F820 # 130
+ .quad 0x01F44659E4A50008, 0xF44659E4A4271580 # 131
+ .quad 0x01F07C1F07C20008, 0xF07C1F07C1F07C20 # 132
+ .quad 0x01ECC07B301F0008, 0xECC07B301ECC07B4 # 133
+ .quad 0x01E9131ABF0C0008, 0xE9131ABF0B7672A1 # 134
+ .quad 0x01E573AC901F0008, 0xE573AC901E573ACA # 135
+ .quad 0x01E1E1E1E1E20008, 0xE1E1E1E1E1E1E1E2 # 136
+ .quad 0x01DE5D6E3F890008, 0xDE5D6E3F8868A471 # 137
+ .quad 0x01DAE6076B990008, 0xDAE6076B981DAE61 # 138
+ .quad 0x01D77B654B830008, 0xD77B654B82C33918 # 139
+ .quad 0x01D41D41D41E0008, 0xD41D41D41D41D41E # 140
+ .quad 0x01D0CB58F6ED0008, 0xD0CB58F6EC07432E # 141
+ .quad 0x01CD8568903A0008, 0xCD85689039B0AD13 # 142
+ .quad 0x01CA4B3055EF0008, 0xCA4B3055EE19101D # 143
+ .quad 0x01C71C71C71D0008, 0xC71C71C71C71C71D # 144
+ .quad 0x01C3F8F01C400008, 0xC3F8F01C3F8F01C4 # 145
+ .quad 0x01C0E070381D0008, 0xC0E070381C0E0704 # 146
+ .quad 0x01BDD2B899410008, 0xBDD2B899406F74AF # 147
+ .quad 0x01BACF914C1C0008, 0xBACF914C1BACF915 # 148
+ .quad 0x01B7D6C3DDA40008, 0xB7D6C3DDA338B2B0 # 149
+ .quad 0x01B4E81B4E820008, 0xB4E81B4E81B4E81C # 150
+ .quad 0x01B2036406C90008, 0xB2036406C80D901C # 151
+ .quad 0x01AF286BCA1B0008, 0xAF286BCA1AF286BD # 152
+ .quad 0x01AC5701AC580008, 0xAC5701AC5701AC58 # 153
+ .quad 0x01A98EF606A70008, 0xA98EF606A63BD81B # 154
+ .quad 0x01A6D01A6D020008, 0xA6D01A6D01A6D01B # 155
+ .quad 0x01A41A41A41B0008, 0xA41A41A41A41A41B # 156
+ .quad 0x01A16D3F97A50008, 0xA16D3F97A4B01A17 # 157
+ .quad 0x019EC8E951040008, 0x9EC8E951033D91D3 # 158
+ .quad 0x019C2D14EE4B0008, 0x9C2D14EE4A1019C3 # 159
+ .quad 0x01999999999A0008, 0x999999999999999A # 160
+ .quad 0x01970E4F80CC0008, 0x970E4F80CB8727C1 # 161
+ .quad 0x01948B0FCD6F0008, 0x948B0FCD6E9E0653 # 162
+ .quad 0x01920FB49D0F0008, 0x920FB49D0E228D5A # 163
+ .quad 0x018F9C18F9C20008, 0x8F9C18F9C18F9C19 # 164
+ .quad 0x018D3018D3020008, 0x8D3018D3018D3019 # 165
+ .quad 0x018ACB90F6C00008, 0x8ACB90F6BF3A9A38 # 166
+ .quad 0x01886E5F0ABC0008, 0x886E5F0ABB04994C # 167
+ .quad 0x0186186186190008, 0x8618618618618619 # 168
+ .quad 0x0183C977AB2C0008, 0x83C977AB2BEDD28F # 169
+ .quad 0x0181818181820008, 0x8181818181818182 # 170
+ .quad 0x017F405FD0180008, 0x7F405FD017F405FE # 171
+ .quad 0x017D05F417D10008, 0x7D05F417D05F417E # 172
+ .quad 0x017AD2208E0F0008, 0x7AD2208E0ECC3546 # 173
+ .quad 0x0178A4C8178B0008, 0x78A4C8178A4C8179 # 174
+ .quad 0x01767DCE434B0008, 0x767DCE434A9B1018 # 175
+ .quad 0x01745D1745D20008, 0x745D1745D1745D18 # 176
+ .quad 0x01724287F46E0008, 0x724287F46DEBC05D # 177
+ .quad 0x01702E05C0B90008, 0x702E05C0B81702E1 # 178
+ .quad 0x016E1F76B4340008, 0x6E1F76B4337C6CB2 # 179
+ .quad 0x016C16C16C170008, 0x6C16C16C16C16C17 # 180
+ .quad 0x016A13CD15380008, 0x6A13CD153729043F # 181
+ .quad 0x0168168168170008, 0x6816816816816817 # 182
+ .quad 0x01661EC6A5130008, 0x661EC6A5122F9017 # 183
+ .quad 0x01642C8590B30008, 0x642C8590B21642C9 # 184
+ .quad 0x01623FA770170008, 0x623FA7701623FA78 # 185
+ .quad 0x0160581605820008, 0x6058160581605817 # 186
+ .quad 0x015E75BB8D020008, 0x5E75BB8D015E75BC # 187
+ .quad 0x015C9882B9320008, 0x5C9882B931057263 # 188
+ .quad 0x015AC056B0160008, 0x5AC056B015AC056C # 189
+ .quad 0x0158ED2308160008, 0x58ED2308158ED231 # 190
+ .quad 0x01571ED3C5070008, 0x571ED3C506B39A23 # 191
+ .quad 0x0155555555560008, 0x5555555555555556 # 192
+ .quad 0x015390948F410008, 0x5390948F40FEAC70 # 193
+ .quad 0x0151D07EAE300008, 0x51D07EAE2F8151D1 # 194
+ .quad 0x0150150150160008, 0x5015015015015016 # 195
+ .quad 0x014E5E0A72F10008, 0x4E5E0A72F0539783 # 196
+ .quad 0x014CAB88725B0008, 0x4CAB88725AF6E750 # 197
+ .quad 0x014AFD6A052C0008, 0x4AFD6A052BF5A815 # 198
+ .quad 0x0149539E3B2E0008, 0x49539E3B2D066EA3 # 199
+ .quad 0x0147AE147AE20008, 0x47AE147AE147AE15 # 200
+ .quad 0x01460CBC7F5D0008, 0x460CBC7F5CF9A1C1 # 201
+ .quad 0x01446F86562E0008, 0x446F86562D9FAEE5 # 202
+ .quad 0x0142D6625D520008, 0x42D6625D51F86EFA # 203
+ .quad 0x0141414141420008, 0x4141414141414142 # 204
+ .quad 0x013FB013FB020008, 0x3FB013FB013FB014 # 205
+ .quad 0x013E22CBCE4B0008, 0x3E22CBCE4A9027C5 # 206
+ .quad 0x013C995A47BB0008, 0x3C995A47BABE7441 # 207
+ .quad 0x013B13B13B140008, 0x3B13B13B13B13B14 # 208
+ .quad 0x013991C2C1880008, 0x3991C2C187F63372 # 209
+ .quad 0x0138138138140008, 0x3813813813813814 # 210
+ .quad 0x013698DF3DE10008, 0x3698DF3DE0747954 # 211
+ .quad 0x013521CFB2B80008, 0x3521CFB2B78C1353 # 212
+ .quad 0x0133AE45B57C0008, 0x33AE45B57BCB1E0D # 213
+ .quad 0x01323E34A2B20008, 0x323E34A2B10BF66F # 214
+ .quad 0x0130D190130E0008, 0x30D190130D190131 # 215
+ .quad 0x012F684BDA130008, 0x2F684BDA12F684BE # 216
+ .quad 0x012E025C04B90008, 0x2E025C04B8097013 # 217
+ .quad 0x012C9FB4D8130008, 0x2C9FB4D812C9FB4E # 218
+ .quad 0x012B404AD0130008, 0x2B404AD012B404AE # 219
+ .quad 0x0129E4129E420008, 0x29E4129E4129E413 # 220
+ .quad 0x01288B01288C0008, 0x288B01288B01288C # 221
+ .quad 0x0127350B88130008, 0x27350B88127350B9 # 222
+ .quad 0x0125E227080A0008, 0x25E22708092F1139 # 223
+ .quad 0x0124924924930008, 0x2492492492492493 # 224
+ .quad 0x0123456789AC0008, 0x23456789ABCDF013 # 225
+ .quad 0x0121FB7812200008, 0x21FB78121FB78122 # 226
+ .quad 0x0120B470C67D0008, 0x20B470C67C0D8876 # 227
+ .quad 0x011F7047DC120008, 0x1F7047DC11F7047E # 228
+ .quad 0x011E2EF3B3FC0008, 0x1E2EF3B3FB874432 # 229
+ .quad 0x011CF06ADA290008, 0x1CF06ADA2811CF07 # 230
+ .quad 0x011BB4A4046F0008, 0x1BB4A4046ED29012 # 231
+ .quad 0x011A7B9611A80008, 0x1A7B9611A7B9611B # 232
+ .quad 0x0119453808CB0008, 0x19453808CA29C047 # 233
+ .quad 0x0118118118120008, 0x1811811811811812 # 234
+ .quad 0x0116E06894280008, 0x16E0689427378EB5 # 235
+ .quad 0x0115B1E5F7530008, 0x15B1E5F75270D046 # 236
+ .quad 0x011485F0E0AD0008, 0x1485F0E0ACD3B68D # 237
+ .quad 0x01135C81135D0008, 0x135C81135C81135D # 238
+ .quad 0x0112358E75D40008, 0x12358E75D30336A1 # 239
+ .quad 0x0111111111120008, 0x1111111111111112 # 240
+ .quad 0x010FEF010FF00008, 0x0FEF010FEF010FF0 # 241
+ .quad 0x010ECF56BE6A0008, 0x0ECF56BE69C8FDE3 # 242
+ .quad 0x010DB20A88F50008, 0x0DB20A88F469598D # 243
+ .quad 0x010C9714FBCE0008, 0x0C9714FBCDA3AC11 # 244
+ .quad 0x010B7E6EC25A0008, 0x0B7E6EC259DC7936 # 245
+ .quad 0x010A6810A6820008, 0x0A6810A6810A6811 # 246
+ .quad 0x010953F390110008, 0x0953F39010953F3A # 247
+ .quad 0x0108421084220008, 0x0842108421084211 # 248
+ .quad 0x01073260A4800008, 0x073260A47F7C66D0 # 249
+ .quad 0x010624DD2F1B0008, 0x0624DD2F1A9FBE77 # 250
+ .quad 0x0105197F7D740008, 0x05197F7D73404147 # 251
+ .quad 0x0104104104110008, 0x0410410410410411 # 252
+ .quad 0x0103091B51F60008, 0x03091B51F5E1A4EF # 253
+ .quad 0x0102040810210008, 0x0204081020408103 # 254
+ .quad 0x0101010101020008, 0x0101010101010102 # 255
+ .quad 0x800000000000FFC8, 0x0000000000000000 # 256
+ .quad 0x00FF00FF0100FE09, 0xFE01FE01FE01FE02 # 257
+ .quad 0x00FE03F80FE1FC09, 0xFC07F01FC07F01FD # 258
+ .quad 0x00FD08E55010FA09, 0xFA11CAA01FA11CAB # 259
+ .quad 0x00FC0FC0FC10F849, 0xF81F81F81F81F820 # 260
+ .quad 0x00FB18856507F649, 0xF6310ACA0DBB574C # 261
+ .quad 0x00FA232CF253F489, 0xF44659E4A4271580 # 262
+ .quad 0x00F92FB22119F289, 0xF25F644230AB50CB # 263
+ .quad 0x00F83E0F83E1F0C9, 0xF07C1F07C1F07C20 # 264
+ .quad 0x00F74E3FC22DEF09, 0xEE9C7F8458E01EEA # 265
+ .quad 0x00F6603D9810ED09, 0xECC07B301ECC07B4 # 266
+ .quad 0x00F57403D5D1EB49, 0xEAE807ABA01EAE81 # 267
+ .quad 0x00F4898D5F86E989, 0xE9131ABF0B7672A1 # 268
+ .quad 0x00F3A0D52CBBE7C9, 0xE741AA59750E466D # 269
+ .quad 0x00F2B9D64810E649, 0xE573AC901E573ACA # 270
+ .quad 0x00F1D48BCEE1E489, 0xE3A9179DC1A733F5 # 271
+ .quad 0x00F0F0F0F0F1E2C9, 0xE1E1E1E1E1E1E1E2 # 272
+ .quad 0x00F00F00F010E109, 0xE01E01E01E01E01F # 273
+ .quad 0x00EF2EB71FC5DF89, 0xDE5D6E3F8868A471 # 274
+ .quad 0x00EE500EE501DDC9, 0xDCA01DCA01DCA01E # 275
+ .quad 0x00ED7303B5CDDC49, 0xDAE6076B981DAE61 # 276
+ .quad 0x00EC979118F4DAC9, 0xD92F2231E7F89B44 # 277
+ .quad 0x00EBBDB2A5C2D909, 0xD77B654B82C33918 # 278
+ .quad 0x00EAE56403ACD789, 0xD5CAC807572B201E # 279
+ .quad 0x00EA0EA0EA0FD609, 0xD41D41D41D41D41E # 280
+ .quad 0x00E939651FE3D489, 0xD272CA3FC5B1A6B9 # 281
+ .quad 0x00E865AC7B77D309, 0xD0CB58F6EC07432E # 282
+ .quad 0x00E79372E226D189, 0xCF26E5C44BFC61B3 # 283
+ .quad 0x00E6C2B4481DD009, 0xCD85689039B0AD13 # 284
+ .quad 0x00E5F36CB00FCE89, 0xCBE6D9601CBE6D97 # 285
+ .quad 0x00E525982AF8CD09, 0xCA4B3055EE19101D # 286
+ .quad 0x00E45932D7DDCBC9, 0xC8B265AFB8A4201D # 287
+ .quad 0x00E38E38E38FCA49, 0xC71C71C71C71C71D # 288
+ .quad 0x00E2C4A6886BC8C9, 0xC5894D10D4985C20 # 289
+ .quad 0x00E1FC780E20C789, 0xC3F8F01C3F8F01C4 # 290
+ .quad 0x00E135A9C976C609, 0xC26B5392EA01C26C # 291
+ .quad 0x00E070381C0FC4C9, 0xC0E070381C0E0704 # 292
+ .quad 0x00DFAC1F7435C389, 0xBF583EE868D8AEBF # 293
+ .quad 0x00DEE95C4CA1C209, 0xBDD2B899406F74AF # 294
+ .quad 0x00DE27EB2C42C0C9, 0xBC4FD65883E7B3A3 # 295
+ .quad 0x00DD67C8A60EBF89, 0xBACF914C1BACF915 # 296
+ .quad 0x00DCA8F158C8BE49, 0xB951E2B18FF23571 # 297
+ .quad 0x00DBEB61EED2BD09, 0xB7D6C3DDA338B2B0 # 298
+ .quad 0x00DB2F171DF8BBC9, 0xB65E2E3BEEE05232 # 299
+ .quad 0x00DA740DA741BA89, 0xB4E81B4E81B4E81C # 300
+ .quad 0x00D9BA4256C1B949, 0xB37484AD806CDD22 # 301
+ .quad 0x00D901B20365B809, 0xB2036406C80D901C # 302
+ .quad 0x00D84A598ECAB6C9, 0xB094B31D922A3E86 # 303
+ .quad 0x00D79435E50EB589, 0xAF286BCA1AF286BD # 304
+ .quad 0x00D6DF43FCA5B449, 0xADBE87F94905E01B # 305
+ .quad 0x00D62B80D62CB349, 0xAC5701AC5701AC58 # 306
+ .quad 0x00D578E97C40B209, 0xAAF1D2F87EBFCAA2 # 307
+ .quad 0x00D4C77B0354B0C9, 0xA98EF606A63BD81B # 308
+ .quad 0x00D417328988AFC9, 0xA82E65130E158A5C # 309
+ .quad 0x00D3680D3681AE89, 0xA6D01A6D01A6D01B # 310
+ .quad 0x00D2BA083B45AD89, 0xA574107688A4A157 # 311
+ .quad 0x00D20D20D20EAC49, 0xA41A41A41A41A41B # 312
+ .quad 0x00D161543E29AB49, 0xA2C2A87C51CA04E9 # 313
+ .quad 0x00D0B69FCBD3AA49, 0xA16D3F97A4B01A17 # 314
+ .quad 0x00D00D00D00EA909, 0xA01A01A01A01A01B # 315
+ .quad 0x00CF6474A882A809, 0x9EC8E951033D91D3 # 316
+ .quad 0x00CEBCF8BB5CA709, 0x9D79F176B682D396 # 317
+ .quad 0x00CE168A7726A609, 0x9C2D14EE4A1019C3 # 318
+ .quad 0x00CD712752A9A4C9, 0x9AE24EA5510DA484 # 319
+ .quad 0x00CCCCCCCCCDA3C9, 0x999999999999999A # 320
+ .quad 0x00CC29786C77A2C9, 0x9852F0D8EC0FF33E # 321
+ .quad 0x00CB8727C066A1C9, 0x970E4F80CB8727C1 # 322
+ .quad 0x00CAE5D85F1CA0C9, 0x95CBB0BE377AD92B # 323
+ .quad 0x00CA4587E6B89FC9, 0x948B0FCD6E9E0653 # 324
+ .quad 0x00C9A633FCDA9EC9, 0x934C67F9B2CE601A # 325
+ .quad 0x00C907DA4E889DC9, 0x920FB49D0E228D5A # 326
+ .quad 0x00C86A78900D9D09, 0x90D4F120190D4F13 # 327
+ .quad 0x00C7CE0C7CE19C09, 0x8F9C18F9C18F9C19 # 328
+ .quad 0x00C73293D78A9B09, 0x8E6527AF1373F071 # 329
+ .quad 0x00C6980C69819A09, 0x8D3018D3018D3019 # 330
+ .quad 0x00C5FE7403189949, 0x8BFCE8062FF3A019 # 331
+ .quad 0x00C565C87B609849, 0x8ACB90F6BF3A9A38 # 332
+ .quad 0x00C4CE07B00D9749, 0x899C0F601899C0F7 # 333
+ .quad 0x00C4372F855E9689, 0x886E5F0ABB04994C # 334
+ .quad 0x00C3A13DE6059589, 0x87427BCC092B8EE7 # 335
+ .quad 0x00C30C30C30D9489, 0x8618618618618619 # 336
+ .quad 0x00C2780613C193C9, 0x84F00C2780613C04 # 337
+ .quad 0x00C1E4BBD59692C9, 0x83C977AB2BEDD28F # 338
+ .quad 0x00C152500C169209, 0x82A4A0182A4A0183 # 339
+ .quad 0x00C0C0C0C0C19149, 0x8181818181818182 # 340
+ .quad 0x00C0300C03019049, 0x8060180601806019 # 341
+ .quad 0x00BFA02FE80C8F89, 0x7F405FD017F405FE # 342
+ .quad 0x00BF112A8AD38E89, 0x7E225515A4F1D1BA # 343
+ .quad 0x00BE82FA0BE98DC9, 0x7D05F417D05F417E # 344
+ .quad 0x00BDF59C91718D09, 0x7BEB3922E017BEB4 # 345
+ .quad 0x00BD691047088C49, 0x7AD2208E0ECC3546 # 346
+ .quad 0x00BCDD535DB28B49, 0x79BAA6BB6398B6F7 # 347
+ .quad 0x00BC52640BC68A89, 0x78A4C8178A4C8179 # 348
+ .quad 0x00BBC8408CD789C9, 0x77908119AC60D342 # 349
+ .quad 0x00BB3EE721A68909, 0x767DCE434A9B1018 # 350
+ .quad 0x00BAB656100C8849, 0x756CAC201756CAC3 # 351
+ .quad 0x00BA2E8BA2E98789, 0x745D1745D1745D18 # 352
+ .quad 0x00B9A7862A1086C9, 0x734F0C541FE8CB10 # 353
+ .quad 0x00B92143FA378609, 0x724287F46DEBC05D # 354
+ .quad 0x00B89BC36CE48549, 0x713786D9C7C08A75 # 355
+ .quad 0x00B81702E05D8489, 0x702E05C0B81702E1 # 356
+ .quad 0x00B79300B79483C9, 0x6F26016F26016F27 # 357
+ .quad 0x00B70FBB5A1A8309, 0x6E1F76B4337C6CB2 # 358
+ .quad 0x00B68D31340F8249, 0x6D1A62681C860FB1 # 359
+ .quad 0x00B60B60B60C8189, 0x6C16C16C16C16C17 # 360
+ .quad 0x00B58A48551980C9, 0x6B1490AA31A3CFC8 # 361
+ .quad 0x00B509E68A9C8009, 0x6A13CD153729043F # 362
+ .quad 0x00B48A39D4477F49, 0x691473A88D0BFD2E # 363
+ .quad 0x00B40B40B40C7E89, 0x6816816816816817 # 364
+ .quad 0x00B38CF9B00C7E09, 0x6719F36016719F37 # 365
+ .quad 0x00B30F63528A7D49, 0x661EC6A5122F9017 # 366
+ .quad 0x00B2927C29DB7C89, 0x6524F853B4AA339F # 367
+ .quad 0x00B21642C85A7C09, 0x642C8590B21642C9 # 368
+ .quad 0x00B19AB5C4577B49, 0x63356B88AC0DE017 # 369
+ .quad 0x00B11FD3B80C7A89, 0x623FA7701623FA78 # 370
+ .quad 0x00B0A59B418E7A09, 0x614B36831AE93AA7 # 371
+ .quad 0x00B02C0B02C17949, 0x6058160581605817 # 372
+ .quad 0x00AFB321A14A7889, 0x5F66434292DFBE1D # 373
+ .quad 0x00AF3ADDC6817809, 0x5E75BB8D015E75BC # 374
+ .quad 0x00AEC33E1F687749, 0x5D867C3ECE2A534A # 375
+ .quad 0x00AE4C415C9976C9, 0x5C9882B931057263 # 376
+ .quad 0x00ADD5E632407609, 0x5BABCC647FA9150D # 377
+ .quad 0x00AD602B580B7589, 0x5AC056B015AC056C # 378
+ .quad 0x00ACEB0F891F74C9, 0x59D61F123CCAA377 # 379
+ .quad 0x00AC7691840B7449, 0x58ED2308158ED231 # 380
+ .quad 0x00AC02B00AC17389, 0x5805601580560159 # 381
+ .quad 0x00AB8F69E2847309, 0x571ED3C506B39A23 # 382
+ .quad 0x00AB1CBDD3E37249, 0x56397BA7C52E1EC0 # 383
+ .quad 0x00AAAAAAAAAB71C9, 0x5555555555555556 # 384
+ .quad 0x00AA392F35DD7149, 0x54725E6BB82FE016 # 385
+ .quad 0x00A9C84A47A17089, 0x5390948F40FEAC70 # 386
+ .quad 0x00A957FAB5417009, 0x52AFF56A8054ABFE # 387
+ .quad 0x00A8E83F57186F89, 0x51D07EAE2F8151D1 # 388
+ .quad 0x00A87917088F6EC9, 0x50F22E111C4C56DF # 389
+ .quad 0x00A80A80A80B6E49, 0x5015015015015016 # 390
+ .quad 0x00A79C7B16EB6DC9, 0x4F38F62DD4C9A845 # 391
+ .quad 0x00A72F0539796D49, 0x4E5E0A72F0539783 # 392
+ .quad 0x00A6C21DF6E26CC9, 0x4D843BEDC2C4B900 # 393
+ .quad 0x00A655C4392E6C09, 0x4CAB88725AF6E750 # 394
+ .quad 0x00A5E9F6ED356B89, 0x4BD3EDDA68FE0E43 # 395
+ .quad 0x00A57EB502966B09, 0x4AFD6A052BF5A815 # 396
+ .quad 0x00A513FD6BB16A89, 0x4A27FAD76014A280 # 397
+ .quad 0x00A4A9CF1D976A09, 0x49539E3B2D066EA3 # 398
+ .quad 0x00A44029100B6989, 0x4880522014880523 # 399
+ .quad 0x00A3D70A3D7168C9, 0x47AE147AE147AE15 # 400
+ .quad 0x00A36E71A2CC6849, 0x46DCE34596066251 # 401
+ .quad 0x00A3065E3FAF67C9, 0x460CBC7F5CF9A1C1 # 402
+ .quad 0x00A29ECF163C6749, 0x453D9E2C776CA015 # 403
+ .quad 0x00A237C32B1766C9, 0x446F86562D9FAEE5 # 404
+ .quad 0x00A1D13985606649, 0x43A2730ABEE4D1DC # 405
+ .quad 0x00A16B312EA965C9, 0x42D6625D51F86EFA # 406
+ .quad 0x00A105A932F36549, 0x420B5265E595123E # 407
+ .quad 0x00A0A0A0A0A164C9, 0x4141414141414142 # 408
+ .quad 0x00A03C1688746449, 0x40782D10E6566065 # 409
+ .quad 0x009FD809FD8163C9, 0x3FB013FB013FB014 # 410
+ .quad 0x009F747A152E6349, 0x3EE8F42A5AF06DA1 # 411
+ .quad 0x009F1165E72662C9, 0x3E22CBCE4A9027C5 # 412
+ .quad 0x009EAECC8D546249, 0x3D5D991AA75C5BBE # 413
+ .quad 0x009E4CAD23DE6209, 0x3C995A47BABE7441 # 414
+ .quad 0x009DEB06C91A6189, 0x3BD60D923295482D # 415
+ .quad 0x009D89D89D8A6109, 0x3B13B13B13B13B14 # 416
+ .quad 0x009D2921C3D76089, 0x3A524387AC822610 # 417
+ .quad 0x009CC8E160C46009, 0x3991C2C187F63372 # 418
+ .quad 0x009C69169B315F89, 0x38D22D366088DBF4 # 419
+ .quad 0x009C09C09C0A5F09, 0x3813813813813814 # 420
+ .quad 0x009BAADE8E4B5EC9, 0x3755BD1C945EDC20 # 421
+ .quad 0x009B4C6F9EF15E49, 0x3698DF3DE0747954 # 422
+ .quad 0x009AEE72FCFA5DC9, 0x35DCE5F9F2AF821F # 423
+ .quad 0x009A90E7D95C5D49, 0x3521CFB2B78C1353 # 424
+ .quad 0x009A33CD67015D09, 0x34679ACE0134679B # 425
+ .quad 0x0099D722DABE5C89, 0x33AE45B57BCB1E0D # 426
+ .quad 0x00997AE76B515C09, 0x32F5CED6A1DFA014 # 427
+ .quad 0x00991F1A51595B89, 0x323E34A2B10BF66F # 428
+ .quad 0x0098C3BAC7505B49, 0x3187758E9EBB6014 # 429
+ .quad 0x009868C809875AC9, 0x30D190130D190131 # 430
+ .quad 0x00980E4156215A49, 0x301C82AC40260391 # 431
+ .quad 0x0097B425ED0A5A09, 0x2F684BDA12F684BE # 432
+ .quad 0x00975A750FF75989, 0x2EB4EA1FED14B15F # 433
+ .quad 0x0097012E025D5909, 0x2E025C04B8097013 # 434
+ .quad 0x0096A850096B58C9, 0x2D50A012D50A012E # 435
+ .quad 0x00964FDA6C0A5849, 0x2C9FB4D812C9FB4E # 436
+ .quad 0x0095F7CC72D257C9, 0x2BEF98E5A3710FD2 # 437
+ .quad 0x0095A025680A5789, 0x2B404AD012B404AE # 438
+ .quad 0x009548E4979F5709, 0x2A91C92F3C1053FA # 439
+ .quad 0x0094F2094F2156C9, 0x29E4129E4129E413 # 440
+ .quad 0x00949B92DDC15649, 0x293725BB804A4DCA # 441
+ .quad 0x0094458094465609, 0x288B01288B01288C # 442
+ .quad 0x0093EFD1C50F5589, 0x27DFA38A1CE4D6F9 # 443
+ .quad 0x00939A85C40A5509, 0x27350B88127350B9 # 444
+ .quad 0x0093459BE6B154C9, 0x268B37CD601268B4 # 445
+ .quad 0x0092F11384055449, 0x25E22708092F1139 # 446
+ .quad 0x00929CEBF48C5409, 0x2539D7E9177B21CB # 447
+ .quad 0x00924924924A5389, 0x2492492492492493 # 448
+ .quad 0x0091F5BCB8BC5349, 0x23EB79717605B39A # 449
+ .quad 0x0091A2B3C4D652C9, 0x23456789ABCDF013 # 450
+ .quad 0x0091500915015289, 0x22A0122A0122A013 # 451
+ .quad 0x0090FDBC09105209, 0x21FB78121FB78122 # 452
+ .quad 0x0090ABCC024351C9, 0x21579804855E6013 # 453
+ .quad 0x00905A38633F5189, 0x20B470C67C0D8876 # 454
+ .quad 0x00900900900A5109, 0x2012012012012013 # 455
+ .quad 0x008FB823EE0950C9, 0x1F7047DC11F7047E # 456
+ .quad 0x008F67A1E3FE5049, 0x1ECF43C7FB84C2F1 # 457
+ .quad 0x008F1779D9FE5009, 0x1E2EF3B3FB874432 # 458
+ .quad 0x008EC7AB39734FC9, 0x1D8F5672E4ABC83B # 459
+ .quad 0x008E78356D154F49, 0x1CF06ADA2811CF07 # 460
+ .quad 0x008E2917E0E84F09, 0x1C522FC1CE058D9B # 461
+ .quad 0x008DDA5202384E89, 0x1BB4A4046ED29012 # 462
+ .quad 0x008D8BE33F964E49, 0x1B17C67F2BAE2B21 # 463
+ .quad 0x008D3DCB08D44E09, 0x1A7B9611A7B9611B # 464
+ .quad 0x008CF008CF014D89, 0x19E0119E0119E012 # 465
+ .quad 0x008CA29C04664D49, 0x19453808CA29C047 # 466
+ .quad 0x008C55841C824D09, 0x18AB083902BDAB95 # 467
+ .quad 0x008C08C08C094C89, 0x1811811811811812 # 468
+ .quad 0x008BBC50C8DF4C49, 0x1778A191BD684181 # 469
+ .quad 0x008B70344A144C09, 0x16E0689427378EB5 # 470
+ .quad 0x008B246A87E24BC9, 0x1648D50FC3201165 # 471
+ .quad 0x008AD8F2FBAA4B49, 0x15B1E5F75270D046 # 472
+ .quad 0x008A8DCD1FEF4B09, 0x151B9A3FDD5C8CB9 # 473
+ .quad 0x008A42F870574AC9, 0x1485F0E0ACD3B68D # 474
+ .quad 0x0089F87469A34A49, 0x13F0E8D3447241C1 # 475
+ .quad 0x0089AE4089AF4A09, 0x135C81135C81135D # 476
+ .quad 0x0089645C4F6F49C9, 0x12C8B89EDC0ABBD8 # 477
+ .quad 0x00891AC73AEA4989, 0x12358E75D30336A1 # 478
+ .quad 0x0088D180CD3B4909, 0x11A3019A748267AF # 479
+ .quad 0x00888888888948C9, 0x1111111111111112 # 480
+ .quad 0x00883FDDF0094889, 0x107FBBE01107FBBF # 481
+ .quad 0x0087F78087F84849, 0x0FEF010FEF010FF0 # 482
+ .quad 0x0087AF6FD59A4809, 0x0F5EDFAB325A1A81 # 483
+ .quad 0x008767AB5F354789, 0x0ECF56BE69C8FDE3 # 484
+ .quad 0x00872032AC144749, 0x0E40655826010E41 # 485
+ .quad 0x0086D905447B4709, 0x0DB20A88F469598D # 486
+ .quad 0x00869222B1AD46C9, 0x0D24456359E39D2D # 487
+ .quad 0x00864B8A7DE74689, 0x0C9714FBCDA3AC11 # 488
+ .quad 0x0086053C345B4649, 0x0C0A7868B41708E7 # 489
+ .quad 0x0085BF37612D4609, 0x0B7E6EC259DC7936 # 490
+ .quad 0x0085797B91784589, 0x0AF2F722EECB5713 # 491
+ .quad 0x0085340853414549, 0x0A6810A6810A6811 # 492
+ .quad 0x0084EEDD357D4509, 0x09DDBA6AF836010A # 493
+ .quad 0x0084A9F9C80944C9, 0x0953F39010953F3A # 494
+ .quad 0x0084655D9BAC4489, 0x08CABB37565E2011 # 495
+ .quad 0x0084210842114449, 0x0842108421084211 # 496
+ .quad 0x0083DCF94DC84409, 0x07B9F29B8EAE19C2 # 497
+ .quad 0x00839930524043C9, 0x073260A47F7C66D0 # 498
+ .quad 0x008355ACE3C94389, 0x06AB59C7912FB620 # 499
+ .quad 0x0083126E978E4309, 0x0624DD2F1A9FBE77 # 500
+ .quad 0x0082CF75039442C9, 0x059EEA0727586633 # 501
+ .quad 0x00828CBFBEBA4289, 0x05197F7D73404147 # 502
+ .quad 0x00824A4E60B44249, 0x04949CC1664C578A # 503
+ .quad 0x0082082082094209, 0x0410410410410411 # 504
+ .quad 0x0081C635BC1341C9, 0x038C6B78247FBF1D # 505
+ .quad 0x0081848DA8FB4189, 0x03091B51F5E1A4EF # 506
+ .quad 0x00814327E3BA4149, 0x02864FC7729E8C5F # 507
+ .quad 0x0081020408114109, 0x0204081020408103 # 508
+ .quad 0x0080C121B28C40C9, 0x0182436517A37530 # 509
+ .quad 0x0080808080814089, 0x0101010101010102 # 510
+ .quad 0x0080402010094049, 0x0080402010080403 # 511
+ .quad 0x8000000000004009, 0x0000000000000000 # 512
+
diff --git a/private/crt32/misc/alpha/divide.s b/private/crt32/misc/alpha/divide.s
new file mode 100644
index 000000000..cff0254e7
--- /dev/null
+++ b/private/crt32/misc/alpha/divide.s
@@ -0,0 +1,1319 @@
+// TITLE("Slow Integer Division and Remainder")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+//
+// Module Name:
+//
+// divide.s
+//
+// Abstract:
+//
+// This module implements integer division and remainder routines that are
+// called by assembler pseudo-ops.
+//
+// Author:
+//
+// Ken Lesniak (lesniak) 15-Jun-1990
+// Thomas Van Baak (tvb) 13-Jun-1992
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Implementation Notes:
+//
+// There are no Alpha machine instructions for performing integer division
+// (divl, divlu, divq, divqu) or remainder (reml, remlu, remq, remqu). The
+// machine instructions generated for these assembler pseudo instructions
+// are dependent on the operands.
+//
+// Division and remainder by constant values are replaced with a sequence
+// of instructions that depend on the data type and the value of the
+// constant. Shifting or reciprocal multiplication are used in most cases
+// to generate the result.
+//
+// Division and remainder by non-constant values are replaced with a
+// procedure call to a library routine to perform the operation. This file
+// contains those routines.
+//
+// This code is adapted from the Alpha/OSF versions by Ken Lesniak and are
+// based on a simple shift/subtract algorithm. Higher performance versions
+// are available and so these functions are now obsolete.
+//
+// Longword register arguments are explicitly converted to canonical form
+// because these functions, with their non-standard calling sequence, act
+// more like instructions than procedure calls. Longword instructions do
+// not require canonical longword operands, but standard procedures with
+// longword register arguments, may assume the caller has passed canonical
+// longwords.
+//
+
+//
+// Define common stack frame for all the functions in this file.
+//
+
+ .struct 0
+
+DiS0: .space 8 // save register s0
+DiS1: .space 8 // save register s1
+
+DiS2: .space 8 // save register s2
+DiS3: .space 8 // save register s3
+
+DiTy: .space 8 // save register t11
+DiTr: .space 8 // save register t9
+
+DiRa: .space 8 // save register ra
+ .space 8 // ensure 16-byte stack alignment
+
+DiFrameLength: // length of stack frame
+
+//
+// Define non-standard calling standard arguments.
+//
+// These have been changed more than once so until they are permanent,
+// symbolic names will be used instead of conventional register names.
+//
+
+#define Tr t9 // return address
+#define Tx t10 // dividend and result
+#define Ty t11 // divisor
+
+ SBTTL("Signed Long Integer Division")
+//++
+//
+// LONG
+// __divl (
+// IN LONG Dividend,
+// IN LONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 32-bit integer by a signed 32-bit integer
+// and returns the signed 32-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (quotient) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__divl, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s2, DiS2(sp) // save non volatile registers
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+ addl Tx, 0, Tx // make sure dividend is in canonical form
+ addl Ty, 0, Ty // make sure divisor is in canonical form
+
+//
+// Check for division of the most negative integer (INT_MIN) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addl Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise
+ mov Tx, s1 // copy dividend
+ cmovne s0, 0, s1 // replace w/ 0 if divisor != -1
+ sublv zero, s1, s1 // trap if dividend = INT_MIN
+
+//
+// Save sign of quotient for later. Convert negative arguments to positive for
+// the division algorithm.
+//
+
+ xor Tx, Ty, s2 // compute sign of quotient
+ cmplt Tx, 0, s0 // sign of dividend is sign of remainder
+ bic s2, 1, s2 // use low bit for remainder sign
+ bis s0, s2, s2 // merge in with quotient sign
+
+ subl zero, Tx, s0 // negate dividend
+ cmovlt Tx, s0, Tx // get absolute value of dividend
+ subl zero, Ty, s0 // negate divisor
+ cmovlt Ty, s0, Ty // get absolute value of divisor
+
+//
+// Perform the shift/subtract loop 8 times and 4 bits per loop.
+//
+
+ ldiq s0, 32/4 // loop iterations
+
+ sll Ty, 32, Ty // move divisor up to high 32 bits
+ zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits
+
+10: addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ subq s0, 1, s0 // any more iterations?
+ bne s0, 10b //
+
+//
+// Restore sign of quotient and return value in Tx.
+//
+
+ addl Tx, 0, Tx // get quotient into canonical form
+
+ subl zero, Tx, s0 // negate quotient into a temp
+ cmovlt s2, s0, Tx // if quotient should be negative copy temp
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __divl
+
+ SBTTL("Unsigned Long Integer Division")
+//++
+//
+// ULONG
+// __divlu (
+// IN ULONG Dividend,
+// IN ULONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 32-bit integer by an unsigned 32-bit
+// integer and returns the unsigned 32-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (quotient) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__divlu, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s1, DiS1(sp) // save non volatile registers
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Perform the shift/subtract loop 8 times and 4 bits per loop.
+//
+
+ ldiq s0, 32/4 // set iteration count
+
+ sll Ty, 32, Ty // move divisor up to high 32 bits
+ zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits
+
+10: addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ subq s0, 1, s0 // any more iterations?
+ bne s0, 10b //
+
+//
+// Finished with return value in Tx.
+//
+
+ addl Tx, 0, Tx // get quotient into canonical form
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __divlu
+
+ SBTTL("Signed Quad Integer Division")
+//++
+//
+// QUAD
+// __divq (
+// IN QUAD Dividend,
+// IN QUAD Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 64-bit integer by a signed 64-bit integer
+// and returns the signed 64-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (quotient) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__divq, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s3, DiS3(sp) // save non volatile registers
+ stq s2, DiS2(sp) //
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Check for division of the most negative integer (QUAD_MIN) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addq Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise
+ mov Tx, s1 // copy dividend
+ cmovne s0, 0, s1 // replace w/ 0 if divisor != -1
+ subqv zero, s1, s1 // trap if dividend = LONG_MIN
+
+//
+// Save sign of quotient for later. Convert negative arguments to positive for
+// the division algorithm.
+//
+
+ xor Tx, Ty, s2 // compute sign of quotient
+ cmplt Tx, 0, s0 // sign of dividend is sign of remainder
+ bic s2, 1, s2 // use low bit for remainder sign
+ bis s0, s2, s2 // merge in with quotient sign
+
+ subq zero, Tx, s0 // negate dividend
+ cmovlt Tx, s0, Tx // get absolute value of dividend
+ subq zero, Ty, s0 // negate divisor
+ cmovlt Ty, s0, Ty // get absolute value of divisor
+
+//
+// Perform the shift/subtract loop 16 times and 4 bits per loop.
+//
+
+ ldiq s1, 0 // zero-extend dividend to 128 bits
+
+ ldiq s3, 64/4 // loop iterations
+
+10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ subq s3, 1, s3 // any more iterations?
+ bne s3, 10b //
+
+//
+// Restore sign of quotient and return value in Tx.
+//
+
+ subq zero, Tx, s0 // negate quotient into a temp
+ cmovlt s2, s0, Tx // if quotient should be negative copy temp
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+ ldq s3, DiS3(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __divq
+
+ SBTTL("Unsigned Quad Integer Division")
+//++
+//
+// UQUAD
+// __divqu (
+// IN UQUAD Dividend,
+// IN UQUAD Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 64-bit integer by an unsigned 64-bit
+// integer and returns the unsigned 64-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (quotient) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__divqu, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq s2, DiS2(sp) // save non volatile registers
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Perform the shift/subtract loop 16 times and 4 bits per loop.
+//
+
+ ldiq s2, 64/4 // set iteration count
+
+ ldiq s1, 0 // zero-extend dividend to 128 bits
+
+10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ subq s2, 1, s2 // any more iterations?
+ bne s2, 10b //
+
+//
+// Finished with return value in Tx.
+//
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __divqu
+
+ SBTTL("Signed Long Integer Remainder")
+//++
+//
+// LONG
+// __reml (
+// IN LONG Dividend,
+// IN LONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 32-bit integer by a signed 32-bit integer
+// and returns the signed 32-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (remainder) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__reml, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s2, DiS2(sp) // save non volatile registers
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+ addl Tx, 0, Tx // make sure dividend is in canonical form
+ addl Ty, 0, Ty // make sure divisor is in canonical form
+
+//
+// Check for division of the most negative integer (INT_MIN) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addl Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise
+ mov Tx, s1 // copy dividend
+ cmovne s0, 0, s1 // replace w/ 0 if divisor != -1
+ sublv zero, s1, s1 // trap if dividend = INT_MIN
+
+//
+// Save sign of quotient for later. Convert negative arguments to positive for
+// the division algorithm.
+//
+
+ xor Tx, Ty, s2 // compute sign of quotient
+ cmplt Tx, 0, s0 // sign of dividend is sign of remainder
+ bic s2, 1, s2 // use low bit for remainder sign
+ bis s0, s2, s2 // merge in with quotient sign
+
+ subl zero, Tx, s0 // negate dividend
+ cmovlt Tx, s0, Tx // get absolute value of dividend
+ subl zero, Ty, s0 // negate divisor
+ cmovlt Ty, s0, Ty // get absolute value of divisor
+
+//
+// Perform the shift/subtract loop 8 times and 4 bits per loop.
+//
+
+ ldiq s0, 32/4 // loop iterations
+
+ sll Ty, 32, Ty // move divisor up to high 32 bits
+ zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits
+
+10: addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ subq s0, 1, s0 // any more iterations?
+ bne s0, 10b //
+
+//
+// Restore sign of remainder and return value in Tx.
+//
+
+ sra Tx, 32, Tx // extract remainder in canonical form
+ subl zero, Tx, s0 // negate remainder into a temp
+ cmovlbs s2, s0, Tx // if remainder should be negative copy temp
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __reml
+
+ SBTTL("Unsigned Long Integer Remainder")
+//++
+//
+// ULONG
+// __remlu (
+// IN ULONG Dividend,
+// IN ULONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 32-bit integer by an unsigned 32-bit
+// integer and returns the unsigned 32-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (remainder) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__remlu, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s1, DiS1(sp) // save non volatile registers
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Perform the shift/subtract loop 8 times and 4 bits per loop.
+//
+
+ ldiq s0, 32/4 // set iteration count
+
+ sll Ty, 32, Ty // move divisor up to high 32 bits
+ zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits
+
+10: addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ addq Tx, Tx, Tx // shift dividend left a bit
+
+ cmpule Ty, Tx, s1 // is dividend >= divisor?
+ addq Tx, s1, Tx // set quotient bit if dividend >= divisor
+ subq Tx, Ty, s1 // subtract divisor from dividend...
+ cmovlbs Tx, s1, Tx // ...if dividend >= divisor
+
+ subq s0, 1, s0 // any more iterations?
+ bne s0, 10b //
+
+//
+// Finished with return value in Tx.
+//
+
+ sra Tx, 32, Tx // extract remainder in canonical form
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __remlu
+
+ SBTTL("Signed Quad Integer Remainder")
+//++
+//
+// QUAD
+// __remq (
+// IN QUAD Dividend,
+// IN QUAD Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 64-bit integer by a signed 64-bit integer
+// and returns the signed 64-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (remainder) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__remq, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq Ty, DiTy(sp) // save original divisor
+ stq s3, DiS3(sp) // save non volatile registers
+ stq s2, DiS2(sp) //
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Check for division of the most negative integer (QUAD_MIN) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addq Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise
+ mov Tx, s1 // copy dividend
+ cmovne s0, 0, s1 // replace w/ 0 if divisor != -1
+ subqv zero, s1, s1 // trap if dividend = LONG_MIN
+
+//
+// Save sign of quotient for later. Convert negative arguments to positive for
+// the division algorithm.
+//
+
+ xor Tx, Ty, s2 // compute sign of quotient
+ cmplt Tx, 0, s0 // sign of dividend is sign of remainder
+ bic s2, 1, s2 // use low bit for remainder sign
+ bis s0, s2, s2 // merge in with quotient sign
+
+ subq zero, Tx, s0 // negate dividend
+ cmovlt Tx, s0, Tx // get absolute value of dividend
+ subq zero, Ty, s0 // negate divisor
+ cmovlt Ty, s0, Ty // get absolute value of divisor
+
+//
+// Perform the shift/subtract loop 16 times and 4 bits per loop.
+//
+
+ ldiq s1, 0 // zero-extend dividend to 128 bits
+
+ ldiq s3, 64/4 // loop iterations
+
+10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ subq s3, 1, s3 // any more iterations?
+ bne s3, 10b //
+
+//
+// Restore sign of remainder and return value in Tx.
+//
+
+ subq zero, s1, Tx // copy negated remainder to return register
+ cmovlbc s2, s1, Tx // if positive remainder then overwrite
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+ ldq s3, DiS3(sp) //
+ ldq Ty, DiTy(sp) // restore original divisor
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __remq
+
+ SBTTL("Unsigned Quad Integer Remainder")
+//++
+//
+// UQUAD
+// __remqu (
+// IN UQUAD Dividend,
+// IN UQUAD Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 64-bit integer by an unsigned 64-bit
+// integer and returns the unsigned 64-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (remainder) is returned in register t10.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__remqu, DiFrameLength, Tr)
+
+ lda sp, -DiFrameLength(sp) // allocate stack frame
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ stq ra, DiRa(sp) // save ra register
+ stq ra, DiTr(sp) // backtrace return address
+ stq Tr, DiTr(sp) // save actual return address
+
+ stq s2, DiS2(sp) // save non volatile registers
+ stq s1, DiS1(sp) //
+ stq s0, DiS0(sp) //
+
+ PROLOGUE_END
+
+//
+// Check for division by zero.
+//
+
+ beq Ty, 20f // die if divisor is zero
+
+//
+// Perform the shift/subtract loop 16 times and 4 bits per loop.
+//
+
+ ldiq s2, 64/4 // set iteration count
+
+ ldiq s1, 0 // zero-extend dividend to 128 bits
+
+10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ cmplt Tx, 0, s0 // predict carry-out of low-dividend shift
+ addq Tx, Tx, Tx // shift low-dividend left
+ addq s1, s1, s1 // shift high-dividend left
+ bis s1, s0, s1 // merge in carry-out of low-dividend
+
+ cmpule Ty, s1, s0 // is dividend >= divisor?
+ addq Tx, s0, Tx // set quotient bit if dividend >= divisor
+ subq s1, Ty, s0 // subtract divisor from dividend...
+ cmovlbs Tx, s0, s1 // ...if dividend >= divisor
+
+ subq s2, 1, s2 // any more iterations?
+ bne s2, 10b //
+
+//
+// Finished with return value in Tx.
+//
+
+ mov s1, Tx // get remainder
+
+ ldq s0, DiS0(sp) // restore saved registers
+ ldq s1, DiS1(sp) //
+ ldq s2, DiS2(sp) //
+
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+//
+// Generate an exception for divide by zero. Return a zero quotient if the
+// caller continues execution.
+//
+
+20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldil Tx, 0 // return zero quotient
+ lda sp, DiFrameLength(sp) // deallocate stack frame
+ ret zero, (Tr) // return
+
+ .end __remqu
diff --git a/private/crt32/misc/alpha/divide2.s b/private/crt32/misc/alpha/divide2.s
new file mode 100644
index 000000000..2eb50c2ba
--- /dev/null
+++ b/private/crt32/misc/alpha/divide2.s
@@ -0,0 +1,1002 @@
+// TITLE("Fast Integer Division and Remainder")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// divide2.s
+//
+// Abstract:
+//
+// This module implements high-performance versions of the integer divide
+// and remainder routines that are called by assembler pseudo-ops.
+//
+// Author:
+//
+// Thomas Van Baak (tvb) 12-Jan-1993
+// Ken Lesniak (lesniak) 04-Nov-1992
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Implementation Notes:
+//
+// There are no Alpha machine instructions for performing integer division
+// (divl, divlu, divq, divqu) or remainder (reml, remlu, remq, remqu). The
+// machine instructions generated for these assembler pseudo instructions
+// are dependent on the type of operands.
+//
+// Division and remainder by constant values are replaced with a sequence
+// of instructions that depend on the data type and the value of the
+// constant. Shifting or reciprocal multiplication are used in most cases
+// to generate the result. No run-time code is necessary in these cases.
+//
+// Division and remainder by non-constant values are replaced with a
+// procedure call to a library routine to perform the operation. This file
+// contains those routines.
+//
+// This code is adapted from the Alpha/OSF version by Ken Lesniak.
+//
+// There are two sets of these eight functions. The __div set were used
+// by an earlier version of the acc compiler. This is the new __2div set.
+// The new functions are about an order of magnitude faster.
+//
+// The new function names differ from the original set of functions so
+// that the old and new compilers can co-exist for a time.
+//
+// Both the division algorithm code and the large division tables used by
+// the code are contained in the fastdiv.s file which is included several
+// times from this file.
+//
+
+//
+// Define common stack frame for functions in this file.
+//
+
+ .struct 0
+DvRa: .space 8 // save register ra
+DvJr: .space 8 // save register t9
+
+DvNu: .space 8 // save register t10
+DvDi: .space 8 // save register t11
+
+DvT0: .space 8 // save register t0
+DvT1: .space 8 // save register t1
+
+DvT2: .space 8 // save register t2
+DvT3: .space 8 // save register t3
+
+DvT4: .space 8 // save register a0
+ .space 8 // ensure 16-byte stack alignment
+DvFrameLength: // length of stack frame
+
+//
+// Define non-standard calling convention required by the compiler.
+//
+// The compiler uses t9, t10, t11, t12 as indicated below. All other
+// registers (except AT) must be preserved by this calling convention.
+//
+// For the fastdiv code, since register a0 must be preserved anyway (it
+// is used by gentrap), define temp register T4 to be a0. Similarly,
+// register J4 must be preserved, so define temp register T5 to be Jr.
+// And the fastdiv code allows Qu to also be temp register T6.
+//
+
+#define Jr t9 // ($23) return address
+#define Nu t10 // ($24) dividend (numerator)
+#define Di t11 // ($25) divisor (denominator)
+#define Qu t12 // ($27) result (quotient)
+#define Re Qu // ($27) result (remainder)
+
+#define T0 t0 // standard temp
+#define T1 t1 // standard temp
+#define T2 t2 // standard temp
+#define T3 t3 // standard temp
+#define T4 a0 // may use a0 as temp
+#define T5 Jr // may use Jr as temp
+#define T6 Qu // may overload Qu as temp T6 only
+
+#ifdef DIV2_DEBUG
+
+//
+// In order to debug locally, re-define some of the registers so that
+// these functions can be called using a standard calling convention.
+//
+
+#undef Jr
+#define Jr ra // standard return address register
+#undef Nu
+#define Nu a0 // dividend argument in a0
+#undef Di
+#define Di a1 // divisor argument in a1
+#undef Qu
+#define Qu v0 // quotient result in v0
+#undef Re
+#define Re v0 // remainder result in v0
+#undef T4
+#define T4 t4 // normal temp
+
+#endif
+
+ SBTTL("Signed Long Integer Division")
+//++
+//
+// LONG
+// __2divl (
+// IN LONG Dividend,
+// IN LONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 32-bit integer by a signed 32-bit integer
+// and returns the signed 32-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (quotient) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2divl, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+ addl Nu, 0, Nu // convert LONG dividend to quadword
+ addl Di, 0, Di // convert LONG divisor to quadword
+
+//
+// Check for division of the most negative integer (0x800...00) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addl Di, 1, t0 // 0 if Di == -1; != 0 otherwise
+ mov Nu, t1 // copy dividend
+ cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
+ sublv zero, t1, t1 // trap if dividend == 0x800..00
+
+//
+// Convert negative arguments to positive for the division algorithm.
+//
+
+ subq zero, Nu, t0 // negate dividend
+ cmovlt Nu, t0, Nu // get absolute value of dividend
+ subq zero, Di, t0 // negate divisor
+ cmovlt Di, t0, Di // get absolute value of divisor
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | DIVISION)
+
+#include "fastdiv.s"
+
+//
+// Restore some registers and set the correct sign of the quotient.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ addl Qu, 0, Qu // ensure quotient is in canonical form
+ subl zero, Qu, t1 // negate LONG quotient
+ xor Nu, Di, t0 // compute sign of quotient
+ addl t0, 0, t0 // ensure quotient is in canonical form
+ cmovlt t0, t1, Qu // use negated quotient if necessary
+
+//
+// Restore other saved registers and return with quotient in register Qu.
+//
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2divl
+
+ SBTTL("Unsigned Long Integer Division")
+//++
+//
+// ULONG
+// __2divlu (
+// IN ULONG Dividend,
+// IN ULONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 32-bit integer by an unsigned 32-bit
+// integer and returns the unsigned 32-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (quotient) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2divlu, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+ zap Nu, 0xf0, Nu // convert ULONG dividend to quadword
+ zap Di, 0xf0, Di // convert ULONG divisor to quadword
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | DIVISION)
+
+#include "fastdiv.s"
+
+//
+// Restore all saved registers and return with quotient in register Qu.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2divlu
+
+ SBTTL("Signed Quad Integer Division")
+//++
+//
+// LONGLONG
+// __2divq (
+// IN LONGLONG Dividend,
+// IN LONGLONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 64-bit integer by a signed 64-bit integer
+// and returns the signed 64-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (quotient) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2divq, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//
+// Check for division of the most negative integer (0x800..00) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addq Di, 1, t0 // 0 if Di == -1; != 0 otherwise
+ mov Nu, t1 // copy dividend
+ cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
+ subqv zero, t1, t1 // trap if dividend == 0x800..00
+
+//
+// Convert negative arguments to positive for the division algorithm.
+//
+
+ subq zero, Nu, t0 // negate dividend
+ cmovlt Nu, t0, Nu // get absolute value of dividend
+ subq zero, Di, t0 // negate divisor
+ cmovlt Di, t0, Di // get absolute value of divisor
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | DIVISION)
+
+#include "fastdiv.s"
+
+//
+// Restore some registers and set the correct sign of the quotient.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ subq zero, Qu, t1 // negate quadword quotient
+ xor Nu, Di, t0 // compute sign of quotient
+ cmovlt t0, t1, Qu // use negated quotient if necessary
+
+//
+// Restore other saved registers and return with quotient in register Qu.
+//
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2divq
+
+ SBTTL("Unsigned Quad Integer Division")
+//++
+//
+// ULONGLONG
+// __2divqu (
+// IN ULONGLONG Dividend,
+// IN ULONGLONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 64-bit integer by an unsigned 64-bit
+// integer and returns the unsigned 64-bit integer result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (quotient) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2divqu, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | DIVISION)
+
+#include "fastdiv.s"
+
+//
+// Restore all saved registers and return with quotient in register Qu.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2divqu
+
+ SBTTL("Signed Long Integer Remainder")
+//++
+//
+// LONG
+// __2reml (
+// IN LONG Dividend,
+// IN LONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 32-bit integer by a signed 32-bit integer
+// and returns the signed 32-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (remainder) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2reml, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+ addl Nu, 0, Nu // convert LONG dividend to quadword
+ addl Di, 0, Di // convert LONG divisor to quadword
+
+//
+// Check for division of the most negative integer (0x800..00) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addl Di, 1, t0 // 0 if Di == -1; != 0 otherwise
+ mov Nu, t1 // copy dividend
+ cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
+ sublv zero, t1, t1 // trap if dividend == 0x800..00
+
+//
+// Convert negative arguments to positive for the division algorithm.
+//
+
+ subq zero, Nu, t0 // negate dividend
+ cmovlt Nu, t0, Nu // get absolute value of dividend
+ subq zero, Di, t0 // negate divisor
+ cmovlt Di, t0, Di // get absolute value of divisor
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | REMAINDER)
+
+#include "fastdiv.s"
+
+//
+// Restore some registers and set the correct sign of the remainder.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ addl Qu, 0, Qu // ensure remainder is in canonical form
+ subl zero, Qu, t1 // negate LONG remainder
+ addl Nu, 0, t0 // get dividend in canonical form
+ cmovlt t0, t1, Qu // use negated remainder if necessary
+
+//
+// Restore other saved registers and return with remainder in register Qu.
+//
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2reml
+
+ SBTTL("Unsigned Long Integer Remainder")
+//++
+//
+// ULONG
+// __2remlu (
+// IN ULONG Dividend,
+// IN ULONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 32-bit integer by an unsigned 32-bit
+// integer and returns the unsigned 32-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 32-bit integer result (remainder) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2remlu, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+ zap Nu, 0xf0, Nu // convert ULONG dividend to quadword
+ zap Di, 0xf0, Di // convert ULONG divisor to quadword
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | REMAINDER)
+
+#include "fastdiv.s"
+
+//
+// Restore all saved registers and return with remainder in register Qu.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2remlu
+
+ SBTTL("Signed Quad Integer Remainder")
+//++
+//
+// LONGLONG
+// __2remq (
+// IN LONGLONG Dividend,
+// IN LONGLONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides a signed 64-bit integer by a signed 64-bit integer
+// and returns the signed 64-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (remainder) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2remq, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq Nu, DvNu(sp) // save original dividend
+ stq Di, DvDi(sp) // save original divisor
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//
+// Check for division of the most negative integer (0x800..00) by the least
+// negative (-1). The result would be an integer which is one greater than the
+// maximum positive integer. Since this cannot be represented, an overflow must
+// be generated.
+//
+
+ addq Di, 1, t0 // 0 if Di == -1; != 0 otherwise
+ mov Nu, t1 // copy dividend
+ cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
+ subqv zero, t1, t1 // trap if dividend == 0x800..00
+
+//
+// Convert negative arguments to positive for the division algorithm.
+//
+
+ subq zero, Nu, t0 // negate dividend
+ cmovlt Nu, t0, Nu // get absolute value of dividend
+ subq zero, Di, t0 // negate divisor
+ cmovlt Di, t0, Di // get absolute value of divisor
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | REMAINDER)
+
+#include "fastdiv.s"
+
+//
+// Restore some registers and set the correct sign of the remainder.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+ ldq Nu, DvNu(sp) // restore original dividend
+ ldq Di, DvDi(sp) // restore original divisor
+
+ subq zero, Qu, t1 // negate quadword remainder
+ cmovlt Nu, t1, Qu // use negated remainder if necessary
+
+//
+// Restore other saved registers and return with remainder in register Qu.
+//
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2remq
+
+ SBTTL("Unsigned Quad Integer Remainder")
+//++
+//
+// ULONGLONG
+// __2remqu (
+// IN ULONGLONG Dividend,
+// IN ULONGLONG Divisor
+// )
+//
+// Routine Description:
+//
+// This function divides an unsigned 64-bit integer by an unsigned 64-bit
+// integer and returns the unsigned 64-bit integer remainder result.
+//
+// Arguments:
+//
+// Dividend (t10) - Supplies the dividend (numerator) value.
+//
+// Divisor (t11) - Supplies the divisor (denominator) value.
+//
+// Return Value:
+//
+// The 64-bit integer result (remainder) is returned in register t12.
+//
+// Note:
+//
+// This function uses a non-standard calling procedure. The return address
+// is stored in the t9 register and the return value is in the t10 register.
+// No other registers are modified.
+//
+//--
+
+ NESTED_ENTRY(__2remqu, DvFrameLength, Jr)
+
+//
+// This prologue is magic. When executed during a call, it will save the
+// value of register ra (twice) and register t9 in the stack frame, even
+// though these registers are not modified by this function. The stores
+// appear to unnecessary.
+//
+// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
+// is reverse executed by virtual unwind to reset the stack pointer and to
+// obtain the return address. The return address is the value of RA the
+// first time it is restored, which will be the saved value of t9.
+//
+
+ .set noreorder
+ .set noat
+ lda sp, -DvFrameLength(sp) // allocate stack frame
+
+ stq ra, DvRa(sp) // save ra register
+ stq ra, DvJr(sp) // backtrace return address
+ stq Jr, DvJr(sp) // save actual return address
+
+ stq t0, DvT0(sp) // save temp registers
+ stq t1, DvT1(sp) //
+ stq t2, DvT2(sp) //
+ stq t3, DvT3(sp) //
+ stq T4, DvT4(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//
+// Set up defines and include the main body of the division code.
+//
+
+#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | REMAINDER)
+
+#include "fastdiv.s"
+
+//
+// Restore all saved registers and return with remainder in register Qu.
+//
+
+ ldq Jr, DvJr(sp) // restore return address
+
+ ldq t0, DvT0(sp) // restore temp registers
+ ldq t1, DvT1(sp) //
+ ldq t2, DvT2(sp) //
+ ldq t3, DvT3(sp) //
+ ldq T4, DvT4(sp) //
+
+ lda sp, DvFrameLength(sp) // deallocate stack frame
+ ret zero, (Jr) // return
+
+ .end __2remqu
+
+//
+// Now get one copy of the tables needed by the division code.
+//
+
+#define FASTDIV_TABLES
+
+#include "fastdiv.s"
diff --git a/private/crt32/misc/alpha/extv.s b/private/crt32/misc/alpha/extv.s
new file mode 100644
index 000000000..bd7e1b754
--- /dev/null
+++ b/private/crt32/misc/alpha/extv.s
@@ -0,0 +1,82 @@
+ #++
+ # Copyright 1991, Digital Equipment Corporation
+ #
+ # int ots_extv(char *addr, int position, unsigned size)
+ #
+ # Arbitrary signed bitfield extraction
+ #
+ # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_extv (just uses srl in place of sra in some cases...)
+ #
+ # 001 16 Aug 1991 KDG Initial version
+ #
+ # 002 4 Sep 1991 KDG Bugfix/improvements
+ #
+ # 003 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 004 22 Sep 1992 KDG Case-sensitive name
+ #
+ # 005 26 Jan 1993 KDG Add underscore
+
+#include "ots_defs.hs"
+
+ # Totally general field extract - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target.
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ #
+ # This is based on the code GEM generates when not using an out-of-line
+ # routine.
+ #
+ .globl _OtsFieldExtractSigned
+ .ent _OtsFieldExtractSigned
+_OtsFieldExtractSigned:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ ble r18, zero # check for zero size - no memory access
+ addq r16, r27, r16 # add to initial base addr.
+ ldq_u r0, (r16) # start load first or only quadword
+ and r16, 7, r27 # get byte-in-quadword of first bit
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ s8addq r27, r17, r17 # form the true bit offset in the quadword
+ addq r17, r18, r27 # get bit offset of bit following field
+ cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword
+ beq r28, double # handle double case if not
+ # common case - fall through, load result hopefully already available
+single: negq r27, r27 # <5:0> = bits for right shift
+ sll r0, r27, r0 # move to high bits
+ addq r27, r17, r27 # bits for left shift
+ sra r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+double: ldq_u r28, 8(r16) # load second quadword
+ srl r0, r27, r0 # move top piece over
+ negq r27, r27 # get shift bits for piece in 2nd word
+ sll r28, r27, r28 # move field in 2nd lw to high bits
+ bis r0, r28, r0 # form final value
+ negq r18, r27 # <5:0> = bits for right shift
+ sra r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+zero: mov 0, r0 # zero-sized field extracts return 0
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsFieldExtractSigned
diff --git a/private/crt32/misc/alpha/extvvol.s b/private/crt32/misc/alpha/extvvol.s
new file mode 100644
index 000000000..f64dfa2a2
--- /dev/null
+++ b/private/crt32/misc/alpha/extvvol.s
@@ -0,0 +1,98 @@
+ #++
+ # Copyright 1992, Digital Equipment Corporation
+ #
+ # int ots_extv_vol(char *addr, int position, unsigned size)
+ #
+ # Arbitrary signed bitfield extraction for volatile cases
+ #
+ # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_extv_vol (just uses srl in place of sra in some cases...)
+ #
+ # 001 16 Aug 1991 KDG Initial version
+ #
+ # 002 4 Sep 1991 KDG Bugfix/improvements
+ #
+ # 003 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 004 6 Oct 1992 KDG Initial volatile version (just add longword
+ # test)
+ #
+ # 005 10 Nov 1992 KDG Case-sensitive name
+ #
+ # 006 26 Jan 1993 KDG Add underscore
+ #
+ # 007 1 Sep 1994 RBG Fix aligned longword case
+ # check for bit 0 within byte GEM_BUGS #3545
+
+#include "ots_defs.hs"
+
+ # Totally general field extract - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target.
+ #
+ # This volatile version always uses exactly LDL for aligned 32 bit field
+ # extracts, and quadword operations for all other.
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ #
+ # This is based on the code GEM generates when not using an out-of-line
+ # routine.
+ #
+ .globl _OtsFieldExtractSignedVolatile
+ .ent _OtsFieldExtractSignedVolatile
+_OtsFieldExtractSignedVolatile:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ ble r18, zero # check for zero size - no memory access
+ cmpeq r17, 32, r0 # exactly longword size?
+ addq r16, r27, r16 # add to initial base addr.
+ and r16, 3, r28 # aligned longword?
+ cmpult r28, r0, r28 # true if ((addr & 3) == 0) && (size == 32) && ...
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ cmpult r17, r28, r28 # ... && (bit_in_byte == 0)
+ bne r28, longwd # go handle longword case specially
+ ldq_u r0, (r16) # start load first or only quadword
+ and r16, 7, r27 # get byte-in-quadword of first bit
+ s8addq r27, r17, r17 # form the true bit offset in the quadword
+ addq r17, r18, r27 # get bit offset of bit following field
+ cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword
+ beq r28, double # handle double case if not
+ # common case - fall through, load result hopefully already available
+single: negq r27, r27 # <5:0> = bits for right shift
+ sll r0, r27, r0 # move to high bits
+ addq r27, r17, r27 # bits for left shift
+ sra r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+double: ldq_u r28, 8(r16) # load second quadword
+ srl r0, r27, r0 # move top piece over
+ negq r27, r27 # get shift bits for piece in 2nd word
+ sll r28, r27, r28 # move field in 2nd lw to high bits
+ bis r0, r28, r0 # form final value
+ negq r18, r27 # <5:0> = bits for right shift
+ sra r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+zero: mov 0, r0 # zero-sized field extracts return 0
+ ret r31, (r26)
+longwd: ldl r0, (r16) # load sign-extended aligned longword
+ ret r31, (r26)
+ .set at
+ .set reorder
+ .end _OtsFieldExtractSignedVolatile
diff --git a/private/crt32/misc/alpha/extzv.s b/private/crt32/misc/alpha/extzv.s
new file mode 100644
index 000000000..fb73dfb8e
--- /dev/null
+++ b/private/crt32/misc/alpha/extzv.s
@@ -0,0 +1,83 @@
+ #++
+ # Copyright 1991, Digital Equipment Corporation
+ #
+ # int ots_extzv(char *addr, int position, unsigned size)
+ #
+ # Arbitrary unsigned bitfield extraction
+ #
+ # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_extv (just uses sra in place of srl in some cases...)
+ #
+ # 001 16 Aug 1991 KDG Initial version
+ #
+ # 002 4 Sep 1991 KDG Bugfix/improvements
+ #
+ # 003 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 004 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 005 26 Jan 1993 KDG Add underscore
+
+#include "ots_defs.hs"
+
+ #
+ # Totally general field extract - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target.
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ #
+ # This is based on the code GEM generates when not using an out-of-line
+ # routine.
+ #
+ .globl _OtsFieldExtractUnsigned
+ .ent _OtsFieldExtractUnsigned
+_OtsFieldExtractUnsigned:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ ble r18, zero # check for zero size - no memory access
+ addq r16, r27, r16 # add to initial base addr.
+ ldq_u r0, (r16) # start load first or only quadword
+ and r16, 7, r27 # get byte-in-quadword of first bit
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ s8addq r27, r17, r17 # form the true bit offset in the quadword
+ addq r17, r18, r27 # get bit offset of bit following field
+ cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword
+ beq r28, double # handle double case if not
+ # common case - fall through, load result hopefully already available
+single: negq r27, r27 # <5:0> = bits for right shift
+ sll r0, r27, r0 # move to high bits
+ addq r27, r17, r27 # bits for left shift
+ srl r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+double: ldq_u r28, 8(r16) # load second quadword
+ srl r0, r27, r0 # move top piece over
+ negq r27, r27 # get shift bits for piece in 2nd word
+ sll r28, r27, r28 # move field in 2nd lw to high bits
+ bis r0, r28, r0 # form final value
+ negq r18, r27 # <5:0> = bits for right shift
+ srl r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+zero: mov 0, r0 # zero-sized field extracts return 0
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsFieldExtractUnsigned
diff --git a/private/crt32/misc/alpha/extzvvol.s b/private/crt32/misc/alpha/extzvvol.s
new file mode 100644
index 000000000..7d3969561
--- /dev/null
+++ b/private/crt32/misc/alpha/extzvvol.s
@@ -0,0 +1,101 @@
+ #++
+ # Copyright 1991, Digital Equipment Corporation
+ #
+ # int ots_extzv_vol(char *addr, int position, unsigned size)
+ #
+ # Arbitrary unsigned bitfield extraction for volatile cases
+ #
+ # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_extv_vol (just uses sra in place of srl in some cases...)
+ #
+ # 001 16 Aug 1991 KDG Initial version
+ #
+ # 002 4 Sep 1991 KDG Bugfix/improvements
+ #
+ # 003 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 004 6 Oct 1992 KDG Initial volatile version (just add longword
+ # test)
+ #
+ # 005 10 Oct 1992 KDG Case-sensitive name
+ #
+ # 006 26 Jan 1993 KDG Add underscore
+ #
+ # 007 1 Sep 1994 RBG Fix aligned longword case
+ # check for bit 0 within byte GEM_BUGS #3545
+
+#include "ots_defs.hs"
+
+ #
+ # Totally general field extract - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target.
+ #
+ # This volatile version always uses exactly LDL for aligned 32 bit field
+ # extracts, and quadword operations for all other.
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ #
+ # This is based on the code GEM generates when not using an out-of-line
+ # routine.
+ #
+ .globl _OtsFieldExtractUnsignedVolatile
+ .ent _OtsFieldExtractUnsignedVolatile
+_OtsFieldExtractUnsignedVolatile:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ ble r18, zero # check for zero size - no memory access
+ cmpeq r17, 32, r0 # exactly longword size?
+ addq r16, r27, r16 # add to initial base addr.
+ and r16, 3, r28 # aligned longword?
+ cmpult r28, r0, r28 # true if ((addr & 3) == 0) && (size == 32) && ...
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ cmpult r17, r28, r28 # ... && (bit_in_byte == 0)
+ bne r28, longwd # go handle longword case specially
+ ldq_u r0, (r16) # start load first or only quadword
+ and r16, 7, r27 # get byte-in-quadword of first bit
+ s8addq r27, r17, r17 # form the true bit offset in the quadword
+ addq r17, r18, r27 # get bit offset of bit following field
+ cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword
+ beq r28, double # handle double case if not
+ # common case - fall through, load result hopefully already available
+single: negq r27, r27 # <5:0> = bits for right shift
+ sll r0, r27, r0 # move to high bits
+ addq r27, r17, r27 # bits for left shift
+ srl r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+double: ldq_u r28, 8(r16) # load second quadword
+ srl r0, r27, r0 # move top piece over
+ negq r27, r27 # get shift bits for piece in 2nd word
+ sll r28, r27, r28 # move field in 2nd lw to high bits
+ bis r0, r28, r0 # form final value
+ negq r18, r27 # <5:0> = bits for right shift
+ srl r0, r27, r0 # and shift into final position
+ ret r31, (r26)
+zero: mov 0, r0 # zero-sized field extracts return 0
+ ret r31, (r26)
+longwd: ldl r0, (r16) # load sign-extended aligned longword
+ zapnot r0, 15, r0
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsFieldExtractUnsignedVolatile
diff --git a/private/crt32/misc/alpha/fastdiv.s b/private/crt32/misc/alpha/fastdiv.s
new file mode 100644
index 000000000..600c89ef9
--- /dev/null
+++ b/private/crt32/misc/alpha/fastdiv.s
@@ -0,0 +1,662 @@
+// TITLE("High-Performance Division")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// fastdiv.s
+//
+// Abstract:
+//
+// This module implements a high-performance integer division routine
+// whose source is included from each of the division and remainder
+// functions.
+//
+// Author:
+//
+// Thomas Van Baak (tvb) 12-Jan-1993
+// Ken Lesniak (lesniak) 04-Nov-1992
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+//
+// Implementation Notes:
+//
+// This code is the main "guts" of the eight divide and remainder routines
+// in the C library. It is intended to be included by a wrapper function
+// that defines options to control 32 vs. 64-bit, division vs. remainder,
+// and signed vs. unsigned. The wrapper function is responsible for the
+// prologue and epilogue sequences, as well as overflow checking and sign
+// adjustment on both input arguments and the return value.
+//
+// The algorithm used here is based on long division and a table for
+// approximating inverses as discussed in the paper "Division by a Constant"
+// by Mary Payne and Robert Gries. If the divisor inverse can be constructed
+// from the table without an error, the division is performed as described
+// in the paper with a multiplication and a shift.
+//
+// If the inverse can not be found in the table, we improve the inverse with
+// a linear approximation, "I". A multiplication by "I" and a shift by
+// log2(y) is used to obtain an approximate quotient, "Q". Now, like long
+// division, the most significant bits are correct, therefore if we
+// calculate the remainder R = x-Q*y, R will be smaller than x, and R will
+// contain the true remainder and the error in Q, "e" multiplied by y.
+//
+// So if we do the same multiplication and shift, we will get an
+// approximation for e. This is just long division, and it will finish
+// when R, the remainder, is less than y.
+//
+// Both the division algorithm code and the large division tables used by
+// the code are contained in this source file (to keep them together).
+//
+
+//
+// The code below requires that the wrapper function define register numbers
+// for each of the following symbolic register names:
+//
+// Nu dividend (numerator)
+// Di divisor (denominator)
+// Qu quotient
+// Re remainder (may be the same as Qu)
+//
+// T0 temp
+// T1 temp
+// T2 temp
+// T3 temp
+// T4 temp
+// T5 temp
+// T6 temp (may be shared with Qu)
+//
+
+//
+// The code below requires that the wrapper function define the symbol
+// FASTDIV_OPTIONS as the logical sum of the following names:
+//
+
+#define THIRTY_TWO_BIT 1 // perform 32-bit computations, otherwise
+#define SIXTY_FOUR_BIT 0 // perform 64-bit computations
+
+#define UNSIGNED 2 // treat operands as unsigned, otherwise
+#define SIGNED 0 // treat operands as signed
+
+#define DIVISION 4 // return quotient in Qu register, and/or
+#define REMAINDER 8 // return remainder in Re register
+
+//
+// Define the symbols that actually control the code generation.
+//
+
+#define _THIRTYTWOBIT (FASTDIV_OPTIONS & THIRTY_TWO_BIT)
+#define _SIXTYFOURBIT (!(FASTDIV_OPTIONS & THIRTY_TWO_BIT))
+#define _UNSIGNED (FASTDIV_OPTIONS & UNSIGNED)
+#define _REMAINDER (FASTDIV_OPTIONS & REMAINDER)
+#define _QUOTIENT (FASTDIV_OPTIONS & DIVISION)
+
+//
+// These constants give the algorithm the best performance.
+//
+
+#define BIT_LENGTH 8
+#define BIT_VALUE (1 << BIT_LENGTH)
+#define BIT_MASK (BIT_VALUE - 1)
+
+#define K_BIT_LENGTH 8
+#define K_BIT_VALUE (1 << K_BIT_LENGTH)
+#define K_BIT_MASK (K_BIT_VALUE - 1)
+
+#define TABLE_BIAS 16384
+
+#define LOG2TAB -16384
+#define INV_FLAG -15360
+#define INV -14848
+#define INV_M -14840
+
+#ifndef FASTDIV_TABLES
+
+ .set noat
+
+ lda T3, __2divdata + TABLE_BIAS // set address of table
+ beq Di, 30f // if zero divisor, generate trap
+
+ cmpule Nu, Di, T0 // check if dividend <= divisor
+#if _THIRTYTWOBIT
+ addl Di, 0, T1 // sign extend longword to quadword
+ blt T1, 20f // high bit set so quotient <= 1
+#endif
+#if _SIXTYFOURBIT
+ blt Di, 20f // high bit set so quotient <= 1
+#endif
+
+ cmpbge zero, Di, T2 // perform 8 byte parallel compare
+ bne T0, 20f // dividend <= divisor so quotient <= 1
+
+ xor T2, 0xff, T0 //
+ s4addq T0, T3, T0 //
+ ldl AT, LOG2TAB(T0) //
+ extbl Di, AT, T0 //
+ s4addq T0, T3, T0 //
+ ldl T0, LOG2TAB(T0) //
+ s8addq AT, T0, AT //
+ ornot zero, AT, T0 //
+ sll Di, T0, T0 //
+ sll T0, BIT_LENGTH + 1, T1 //
+ bne T1, 40f //
+
+//
+// Short case.
+//
+
+ subq Di, 1, T1 // compute divisor - 1
+ and Di, T1, T2 // divisor & (divisor - 1)
+ srl T0, 63 - (BIT_LENGTH + 1), T6 //
+ beq T2, 10f // divisor is a power of two
+
+ subq T6, BIT_VALUE + BIT_VALUE, T6 //
+ bic T6, 1, T4 //
+ s8addq T4, T3, T4 //
+ ldq T5, INV(T4) //
+ ldq T4, INV_M(T4) //
+ subq T5, T4, T4 //
+ cmovlbs T6, T4, T5 //
+ addq T6, T3, T2 //
+ ldq_u T0, INV_FLAG(T2) //
+ extbl T0, T2, T2 //
+ addq Nu, T2, T1 //
+ umulh T1, T5, T3 //
+#if _SIXTYFOURBIT && _UNSIGNED
+ cmoveq T1, T5, T3 //
+#endif
+ srl T3, AT, Qu //
+#if _REMAINDER
+ mulq Qu, Di, T0 //
+ subq Nu, T0, Re //
+#endif
+ br zero, 90f // all done, branch to epilogue code
+
+10:
+
+//
+// The divisor is now known to be a power of two.
+//
+// - The quotient is the dividend shifted right by exponent bits and
+// the remainder is the low order exponent bits of the dividend.
+//
+// AT = log2(divisor)
+// T1 = divisor - 1
+//
+
+#if _REMAINDER
+ and Nu, T1, Re //
+#endif
+#if _QUOTIENT
+ srl Nu, AT, Qu //
+#endif
+ br zero, 90f // all done, branch to epilogue code
+
+20:
+
+//
+// The quotient is now known to be either 0 or 1.
+//
+// - if the high bit of the divisor is set, the quotient must be less
+// than 2, so the quotient is 0 or 1.
+//
+// - if the dividend is less than the divisor, the quotient is 0 and
+// the remainder is the dividend.
+//
+// - if the dividend is equal to the divisor, the quotient is 1 and
+// the remainder is 0.
+//
+// - if the dividend is greater than the divisor, the quotient is 1
+// and the remainder is the dividend minus the divisor.
+//
+
+#if _REMAINDER
+ cmpule Di, Nu, T0 // if divisor <= dividend
+ subq Nu, Di, Re // then remainder is dividend,
+ cmoveq T0, Nu, Re // else remainder is dividend - divisor
+#endif
+#if _QUOTIENT
+ cmpule Di, Nu, Qu // if divisor <= dividend, 1, else 0
+#endif
+ br zero, 90f // all done, branch to epilogue code
+
+//
+// Generate divide by zero exception. If execution is continued, return
+// a zero result.
+//
+
+30: ldiq a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
+
+ GENERATE_TRAP
+
+ ldiq Qu, 0 // supply 0 result if continued
+ br zero, 90f // branch to epilogue code
+
+//
+// Long case.
+//
+
+40: srl T0, 63-(BIT_LENGTH+K_BIT_LENGTH), T6 //
+ srl T6, K_BIT_LENGTH, T0 //
+ and T6, K_BIT_MASK, T6 //
+ addq T0, T0, T0 //
+ s8addq T0, T3, T1 //
+ ldq T2, INV-(16*BIT_VALUE)(T1) //
+ ldq T0, INV_M-(16*BIT_VALUE)(T1) //
+ mulq T0, T6, T0 //
+ srl T0, K_BIT_LENGTH-1, T0 //
+ subq T2, T0, T6 //
+ umulh Nu, T6, T4 //
+ srl T4, AT, T4 //
+ mulq T4, Di, T5 //
+ mov zero, T3 //
+#if _SIXTYFOURBIT
+ xor Nu, T5, T0 //
+ bge T0, 50f //
+
+ umulh Di, T4, T3 //
+50:
+#endif
+ subq Nu, T5, T5 //
+ beq T4, 70f //
+
+ cmpult Nu, T5, T0 //
+ or T0, T3, T3 //
+ negq T5, T1 //
+ cmovne T3, T1, T5 //
+ addq Di, Di, T0 //
+ cmpule T0, T5, T0 //
+ beq T0, 70f //
+
+//
+// do {
+//
+
+60: umulh T5, T6, T2 //
+ srl T2, AT, T2 //
+ negq T2, T0 //
+ cmoveq T3, T2, T0 //
+ addq T4, T0, T4 //
+ mulq T2, Di, T1 //
+ subq T5, T1, T5 //
+#if _SIXTYFOURBIT
+ ldiq T0, 1 //
+ cmovne T3, 0, T0 //
+ negq T5, T2 //
+ cmovlt T5, T0, T3 //
+ cmovlt T5, T2, T5 //
+#endif
+ addq Di, Di, T0 //
+ cmpule T5, T0, T0 //
+ cmovne T0, 0, T1 //
+ bne T1, 60b //
+
+//
+// } while
+//
+
+70: cmpule Di, T5, T0 //
+ beq T0, 80f //
+
+ subq T5, Di, T5 //
+ subq T4, 1, T0 //
+ addq T4, 1, T4 //
+ cmovne T3, T0, T4 //
+80:
+ cmoveq T5, 0, T3 //
+#if _REMAINDER
+ subq Di, T5, Re //
+ cmoveq T3, T5, Re //
+#endif
+#if _QUOTIENT
+ subq T4, 1, Qu //
+ cmoveq T3, T4, Qu //
+#endif
+
+90:
+ .set at
+
+#undef FASTDIV_OPTIONS
+
+#else
+
+//
+// The following data was machine generated. DO NOT EDIT MANUALLY.
+//
+
+ .globl __2divdata
+ .rdata
+ .align 4
+__2divdata:
+
+//
+// LOG2TAB
+//
+
+ .align 2
+ .long 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+ .long 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+ .long 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .long 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+ .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+ .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+ .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+
+//
+// INV_FLAG
+//
+
+ .align 3
+ .byte 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1
+ .byte 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0
+ .byte 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1
+ .byte 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0
+ .byte 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0
+ .byte 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
+ .byte 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1
+ .byte 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0
+ .byte 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1
+ .byte 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1
+ .byte 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1
+ .byte 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1
+ .byte 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1
+ .byte 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0
+ .byte 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1
+ .byte 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0
+ .byte 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1
+ .byte 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0
+ .byte 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1
+ .byte 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0
+ .byte 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1
+ .byte 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1
+ .byte 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1
+ .byte 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
+ .byte 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1
+ .byte 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0
+ .byte 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1
+ .byte 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1
+ .byte 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1
+ .byte 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1
+ .byte 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1
+ .byte 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1
+
+//
+// INV INV_M
+//
+
+ .align 4
+ .quad 0xffffffffffffffff, 0x007fc01ff007fc01, // 0
+ .quad 0xff00ff00ff00ff01, 0x007ec25bf68dabfe, // 1
+ .quad 0xfe03f80fe03f80fe, 0x007dc78930f5b971, // 2
+ .quad 0xfd08e5500fd08e55, 0x007ccf9c05f3157c, // 3
+ .quad 0xfc0fc0fc0fc0fc10, 0x007bda891528a983, // 4
+ .quad 0xfb18856506ddaba6, 0x007ae84535db391c, // 5
+ .quad 0xfa232cf252138ac0, 0x0079f8c575ac2ab0, // 6
+ .quad 0xf92fb2211855a865, 0x00790bff175cf1bf, // 7
+ .quad 0xf83e0f83e0f83e10, 0x007821e7919ad7f4, // 8
+ .quad 0xf74e3fc22c700f75, 0x00773a748dd2e48d, // 9
+ .quad 0xf6603d980f6603da, 0x0076559be70da3cb, // 10
+ .quad 0xf57403d5d00f5740, 0x00757353a8d2921b, // 11
+ .quad 0xf4898d5f85bb3950, 0x007493920e12f0da, // 12
+ .quad 0xf3a0d52cba872336, 0x0073b64d801bcc4b, // 13
+ .quad 0xf2b9d6480f2b9d65, 0x0072db7c958efc82, // 14
+ .quad 0xf1d48bcee0d399fa, 0x007203161162ec7b, // 15
+ .quad 0xf0f0f0f0f0f0f0f1, 0x00712d10e1e8f4b3, // 16
+ .quad 0xf00f00f00f00f00f, 0x007059641fda17d7, // 17
+ .quad 0xef2eb71fc4345238, 0x006f88070d69f229, // 18
+ .quad 0xee500ee500ee500f, 0x006eb8f1155fad72, // 19
+ .quad 0xed7303b5cc0ed730, 0x006dec19ca34cd01, // 20
+ .quad 0xec979118f3fc4da2, 0x006d2178e539a6a8, // 21
+ .quad 0xebbdb2a5c1619c8c, 0x006c590645bf5ef6, // 22
+ .quad 0xeae56403ab95900f, 0x006b92b9f0474060, // 23
+ .quad 0xea0ea0ea0ea0ea0f, 0x006ace8c0db7463d, // 24
+ .quad 0xe939651fe2d8d35c, 0x006a0c74ea93b5ce, // 25
+ .quad 0xe865ac7b7603a197, 0x00694c6cf63da0af, // 26
+ .quad 0xe79372e225fe30d9, 0x00688e6cc2362d3c, // 27
+ .quad 0xe6c2b4481cd85689, 0x0067d26d016682a0, // 28
+ .quad 0xe5f36cb00e5f36cb, 0x00671866876c373e, // 29
+ .quad 0xe525982af70c880e, 0x0066605247ea214c, // 30
+ .quad 0xe45932d7dc52100e, 0x0065aa2955dd6a6f, // 31
+ .quad 0xe38e38e38e38e38e, 0x0064f5e4e2f6c80c, // 32
+ .quad 0xe2c4a6886a4c2e10, 0x0064437e3ef7bb1b, // 33
+ .quad 0xe1fc780e1fc780e2, 0x006392eed713bb0b, // 34
+ .quad 0xe135a9c97500e136, 0x0062e43035553040, // 35
+ .quad 0xe070381c0e070382, 0x0062373c00062374, // 36
+ .quad 0xdfac1f74346c575f, 0x00618c0bf91c8837, // 37
+ .quad 0xdee95c4ca037ba57, 0x0060e299fdaa0972, // 38
+ .quad 0xde27eb2c41f3d9d1, 0x00603ae0054f3f9c, // 39
+ .quad 0xdd67c8a60dd67c8a, 0x005f94d821b23932, // 40
+ .quad 0xdca8f158c7f91ab8, 0x005ef07c7df83e6e, // 41
+ .quad 0xdbeb61eed19c5958, 0x005e4dc75e42ba41, // 42
+ .quad 0xdb2f171df7702919, 0x005dacb31f2f32ed, // 43
+ .quad 0xda740da740da740e, 0x005d0d3a355a3d88, // 44
+ .quad 0xd9ba4256c0366e91, 0x005c6f572ce55811, // 45
+ .quad 0xd901b2036406c80e, 0x005bd304a8ff968c, // 46
+ .quad 0xd84a598ec9151f43, 0x005b383d63711014, // 47
+ .quad 0xd79435e50d79435e, 0x005a9efc2c28f962, // 48
+ .quad 0xd6df43fca482f00d, 0x005a073be8ce5ae4, // 49
+ .quad 0xd62b80d62b80d62c, 0x005970f7945350f4, // 50
+ .quad 0xd578e97c3f5fe551, 0x0058dc2a3e8ac544, // 51
+ .quad 0xd4c77b03531dec0d, 0x005848cf0bc0912f, // 52
+ .quad 0xd4173289870ac52e, 0x0057b6e13453f8e0, // 53
+ .quad 0xd3680d3680d3680d, 0x0057265c04546fe2, // 54
+ .quad 0xd2ba083b445250ab, 0x0056973adb20982b, // 55
+ .quad 0xd20d20d20d20d20d, 0x005609792b076ce1, // 56
+ .quad 0xd161543e28e50274, 0x00557d1278eb8ad3, // 57
+ .quad 0xd0b69fcbd2580d0b, 0x0054f2025be888c5, // 58
+ .quad 0xd00d00d00d00d00d, 0x005468447cfa5248, // 59
+ .quad 0xcf6474a8819ec8e9, 0x0053dfd496a67807, // 60
+ .quad 0xcebcf8bb5b4169cb, 0x005358ae74a768fd, // 61
+ .quad 0xce168a7725080ce1, 0x0052d2cdf3998842, // 62
+ .quad 0xcd712752a886d242, 0x00524e2f00aa138f, // 63
+ .quad 0xcccccccccccccccd, 0x0051cacd9947cecc, // 64
+ .quad 0xcc29786c7607f99f, 0x005148a5cad5697f, // 65
+ .quad 0xcb8727c065c393e0, 0x0050c7b3b25d9315, // 66
+ .quad 0xcae5d85f1bbd6c95, 0x005047f37c48b368, // 67
+ .quad 0xca4587e6b74f0329, 0x004fc96164143d25, // 68
+ .quad 0xc9a633fcd967300d, 0x004f4bf9b40b9000, // 69
+ .quad 0xc907da4e871146ad, 0x004ecfb8c50260f1, // 70
+ .quad 0xc86a78900c86a789, 0x004e549afe109ef0, // 71
+ .quad 0xc7ce0c7ce0c7ce0c, 0x004dda9cd44fcaee, // 72
+ .quad 0xc73293d789b9f838, 0x004d61baca99ba10, // 73
+ .quad 0xc6980c6980c6980c, 0x004ce9f17148b95b, // 74
+ .quad 0xc5fe740317f9d00c, 0x004c733d65f90a5a, // 75
+ .quad 0xc565c87b5f9d4d1c, 0x004bfd9b534bb06e, // 76
+ .quad 0xc4ce07b00c4ce07b, 0x004b8907f0aa86ab, // 77
+ .quad 0xc4372f855d824ca6, 0x004b1580020d9680, // 78
+ .quad 0xc3a13de60495c773, 0x004aa30057c1a767, // 79
+ .quad 0xc30c30c30c30c30c, 0x004a3185ce30004a, // 80
+ .quad 0xc2780613c0309e02, 0x0049c10d4da7534b, // 81
+ .quad 0xc1e4bbd595f6e947, 0x00495193ca25cceb, // 82
+ .quad 0xc152500c152500c1, 0x0048e31643243fb8, // 83
+ .quad 0xc0c0c0c0c0c0c0c1, 0x00487591c36265c8, // 84
+ .quad 0xc0300c0300c0300c, 0x0048090360b4318c, // 85
+ .quad 0xbfa02fe80bfa02ff, 0x00479d683bd0279f, // 86
+ .quad 0xbf112a8ad278e8dd, 0x004732bd801ebb67, // 87
+ .quad 0xbe82fa0be82fa0bf, 0x0046c900638aa88c, // 88
+ .quad 0xbdf59c91700bdf5a, 0x0046602e26524361, // 89
+ .quad 0xbd69104707661aa3, 0x0045f84412d9ba97, // 90
+ .quad 0xbcdd535db1cc5b7b, 0x0045913f7d7e44a5, // 91
+ .quad 0xbc52640bc52640bc, 0x00452b1dc46a3383, // 92
+ .quad 0xbbc8408cd63069a1, 0x0044c5dc4f69e972, // 93
+ .quad 0xbb3ee721a54d880c, 0x004461788fc1a9a5, // 94
+ .quad 0xbab656100bab6561, 0x0043fdf000043fdf, // 95
+ .quad 0xba2e8ba2e8ba2e8c, 0x00439b4023ea7a13, // 96
+ .quad 0xb9a7862a0ff46588, 0x00433966882b6f4f, // 97
+ .quad 0xb92143fa36f5e02e, 0x0042d860c2558f4d, // 98
+ .quad 0xb89bc36ce3e0453a, 0x0042782c70a87632, // 99
+ .quad 0xb81702e05c0b8170, 0x004218c739ef8000, // 100
+ .quad 0xb79300b79300b793, 0x0041ba2ecd5d1788, // 101
+ .quad 0xb70fbb5a19be3659, 0x00415c60e266bc99, // 102
+ .quad 0xb68d31340e4307d8, 0x0040ff5b38a1bd6e, // 103
+ .quad 0xb60b60b60b60b60b, 0x0040a31b97a09f52, // 104
+ .quad 0xb58a485518d1e7e4, 0x0040479fced1329a, // 105
+ .quad 0xb509e68a9b94821f, 0x003fece5b55b4e37, // 106
+ .quad 0xb48a39d44685fe97, 0x003f92eb2a002f2f, // 107
+ .quad 0xb40b40b40b40b40b, 0x003f39ae12fa7858, // 108
+ .quad 0xb38cf9b00b38cf9b, 0x003ee12c5ddecee8, // 109
+ .quad 0xb30f63528917c80b, 0x003e8963ff7d1056, // 110
+ .quad 0xb2927c29da5519cf, 0x003e3252f3c21e56, // 111
+ .quad 0xb21642c8590b2164, 0x003ddbf73d9a3d87, // 112
+ .quad 0xb19ab5c45606f00b, 0x003d864ee6d403ca, // 113
+ .quad 0xb11fd3b80b11fd3c, 0x003d31580003d316, // 114
+ .quad 0xb0a59b418d749d53, 0x003cdd10a067ddc1, // 115
+ .quad 0xb02c0b02c0b02c0b, 0x003c8976e5ccb15f, // 116
+ .quad 0xafb321a1496fdf0e, 0x003c3688f472452e, // 117
+ .quad 0xaf3addc680af3ade, 0x003be444f6f1897b, // 118
+ .quad 0xaec33e1f671529a5, 0x003b92a91e2274fb, // 119
+ .quad 0xae4c415c9882b931, 0x003b41b3a1028dad, // 120
+ .quad 0xadd5e6323fd48a86, 0x003af162bc9bea7b, // 121
+ .quad 0xad602b580ad602b6, 0x003aa1b4b3ecab20, // 122
+ .quad 0xaceb0f891e6551bb, 0x003a52a7cfcee3c6, // 123
+ .quad 0xac7691840ac76918, 0x003a043a5ee0fa15, // 124
+ .quad 0xac02b00ac02b00ac, 0x0039b66ab56e7112, // 125
+ .quad 0xab8f69e28359cd11, 0x003969372d5921bb, // 126
+ .quad 0xab1cbdd3e2970f60, 0x00391c9e2602ddfa, // 127
+ .quad 0xaaaaaaaaaaaaaaab, 0x0038d09e04377bbb, // 128
+ .quad 0xaa392f35dc17f00b, 0x003885353217460a, // 129
+ .quad 0xa9c84a47a07f5638, 0x00383a621f01d214, // 130
+ .quad 0xa957fab5402a55ff, 0x0037f0233f8135f4, // 131
+ .quad 0xa8e83f5717c0a8e8, 0x0037a6770d359f5a, // 132
+ .quad 0xa87917088e262b6f, 0x00375d5c06c14806, // 133
+ .quad 0xa80a80a80a80a80b, 0x003714d0afb4c633, // 134
+ .quad 0xa79c7b16ea64d422, 0x0036ccd3907bb709, // 135
+ .quad 0xa72f05397829cbc1, 0x003685633649c151, // 136
+ .quad 0xa6c21df6e1625c80, 0x00363e7e3307ee8e, // 137
+ .quad 0xa655c4392d7b73a8, 0x0035f8231d4258ba, // 138
+ .quad 0xa5e9f6ed347f0721, 0x0035b25090162b0e, // 139
+ .quad 0xa57eb50295fad40a, 0x00356d052b1ff400, // 140
+ .quad 0xa513fd6bb00a5140, 0x0035283f926a46f2, // 141
+ .quad 0xa4a9cf1d96833751, 0x0034e3fe6e5cabea, // 142
+ .quad 0xa44029100a440291, 0x0034a0406baadbcc, // 143
+ .quad 0xa3d70a3d70a3d70a, 0x00345d043b44478a, // 144
+ .quad 0xa36e71a2cb033128, 0x00341a489243e8ca, // 145
+ .quad 0xa3065e3fae7cd0e0, 0x0033d80c29e05a93, // 146
+ .quad 0xa29ecf163bb6500a, 0x0033964dbf5c3891, // 147
+ .quad 0xa237c32b16cfd772, 0x0033550c13f6c382, // 148
+ .quad 0xa1d139855f7268ee, 0x00331445ecdcc986, // 149
+ .quad 0xa16b312ea8fc377d, 0x0032d3fa1319d0d6, // 150
+ .quad 0xa105a932f2ca891f, 0x00329427538983c8, // 151
+ .quad 0xa0a0a0a0a0a0a0a1, 0x003254cc7ec95ca2, // 152
+ .quad 0xa03c1688732b3032, 0x003215e8692a9028, // 153
+ .quad 0x9fd809fd809fd80a, 0x0031d779eaa43595, // 154
+ .quad 0x9f747a152d7836d0, 0x0031997fdec5aad6, // 155
+ .quad 0x9f1165e7254813e2, 0x00315bf924a933d8, // 156
+ .quad 0x9eaecc8d53ae2ddf, 0x00311ee49ee6d3cb, // 157
+ .quad 0x9e4cad23dd5f3a20, 0x0030e24133875f2f, // 158
+ .quad 0x9deb06c9194aa416, 0x0030a60dcbf7c5aa, // 159
+ .quad 0x9d89d89d89d89d8a, 0x00306a4954fc927a, // 160
+ .quad 0x9d2921c3d6411308, 0x00302ef2bea5a284, // 161
+ .quad 0x9cc8e160c3fb19b9, 0x002ff408fc420f05, // 162
+ .quad 0x9c69169b30446dfa, 0x002fb98b04544bcd, // 163
+ .quad 0x9c09c09c09c09c0a, 0x002f7f77d086781f, // 164
+ .quad 0x9baade8e4a2f6e10, 0x002f45ce5d9ee128, // 165
+ .quad 0x9b4c6f9ef03a3caa, 0x002f0c8dab74b53e, // 166
+ .quad 0x9aee72fcf957c10f, 0x002ed3b4bce4e6d7, // 167
+ .quad 0x9a90e7d95bc609a9, 0x002e9b4297c73e6e, // 168
+ .quad 0x9a33cd67009a33cd, 0x002e633644e39a62, // 169
+ .quad 0x99d722dabde58f06, 0x002e2b8ecfe75c01, // 170
+ .quad 0x997ae76b50efd00a, 0x002df44b475b00d8, // 171
+ .quad 0x991f1a515885fb37, 0x002dbd6abc97e780, // 172
+ .quad 0x98c3bac74f5db00a, 0x002d86ec43be3f17, // 173
+ .quad 0x9868c809868c8098, 0x002d50cef3ab208e, // 174
+ .quad 0x980e4156201301c8, 0x002d1b11e5eed122, // 175
+ .quad 0x97b425ed097b425f, 0x002ce5b436c32d10, // 176
+ .quad 0x975a750ff68a58af, 0x002cb0b5050239fa, // 177
+ .quad 0x97012e025c04b809, 0x002c7c13721ce019, // 178
+ .quad 0x96a850096a850097, 0x002c47cea211c9a1, // 179
+ .quad 0x964fda6c0964fda7, 0x002c13e5bb646783, // 180
+ .quad 0x95f7cc72d1b887e9, 0x002be057e7141b13, // 181
+ .quad 0x95a02568095a0257, 0x002bad24509383a7, // 182
+ .quad 0x9548e4979e0829fd, 0x002b7a4a25bfefbe, // 183
+ .quad 0x94f2094f2094f209, 0x002b47c896d8f0df, // 184
+ .quad 0x949b92ddc02526e5, 0x002b159ed67811bb, // 185
+ .quad 0x9445809445809446, 0x002ae3cc1988adbb, // 186
+ .quad 0x93efd1c50e726b7c, 0x002ab24f973fe99c, // 187
+ .quad 0x939a85c40939a85c, 0x002a81288914cc5b, // 188
+ .quad 0x93459be6b009345a, 0x002a50562ab877df, // 189
+ .quad 0x92f113840497889c, 0x002a1fd7ba0e80df, // 190
+ .quad 0x929cebf48bbd90e5, 0x0029efac7725656b, // 191
+ .quad 0x9249249249249249, 0x0029bfd3a42f218e, // 192
+ .quad 0x91f5bcb8bb02d9cd, 0x0029904c8579e17d, // 193
+ .quad 0x91a2b3c4d5e6f809, 0x002961166168d0d3, // 194
+ .quad 0x9150091500915009, 0x00293230806d0653, // 195
+ .quad 0x90fdbc090fdbc091, 0x0029039a2cfe8bab, // 196
+ .quad 0x90abcc0242af3009, 0x0028d552b39580c2, // 197
+ .quad 0x905a38633e06c43b, 0x0028a75962a35a0f, // 198
+ .quad 0x9009009009009009, 0x002879ad8a8c397c, // 199
+ .quad 0x8fb823ee08fb823f, 0x00284c4e7da06171, // 200
+ .quad 0x8f67a1e3fdc26178, 0x00281f3b9015c16f, // 201
+ .quad 0x8f1779d9fdc3a219, 0x0027f27418019bf5, // 202
+ .quad 0x8ec7ab397255e41d, 0x0027c5f76d52450e, // 203
+ .quad 0x8e78356d1408e783, 0x002799c4e9c8f94d, // 204
+ .quad 0x8e2917e0e702c6cd, 0x00276ddbe8f3cca0, // 205
+ .quad 0x8dda520237694809, 0x0027423bc827b0a6, // 206
+ .quad 0x8d8be33f95d71590, 0x002716e3e67a921c, // 207
+ .quad 0x8d3dcb08d3dcb08d, 0x0026ebd3a4bd8d01, // 208
+ .quad 0x8cf008cf008cf009, 0x0026c10a657736fa, // 209
+ .quad 0x8ca29c046514e023, 0x002696878cddffb1, // 210
+ .quad 0x8c55841c815ed5ca, 0x00266c4a80d2a6b2, // 211
+ .quad 0x8c08c08c08c08c09, 0x00264252a8dac681, // 212
+ .quad 0x8bbc50c8deb420c0, 0x0026189f6e1b7473, // 213
+ .quad 0x8b70344a139bc75a, 0x0025ef303b53f50e, // 214
+ .quad 0x8b246a87e19008b2, 0x0025c6047cd8847d, // 215
+ .quad 0x8ad8f2fba9386823, 0x00259d1ba08d32c5, // 216
+ .quad 0x8a8dcd1feeae465c, 0x0025747515e0d378, // 217
+ .quad 0x8a42f8705669db46, 0x00254c104dc80080, // 218
+ .quad 0x89f87469a23920e0, 0x002523ecbab82fae, // 219
+ .quad 0x89ae4089ae4089ae, 0x0024fc09d0a2dace, // 220
+ .quad 0x89645c4f6e055dec, 0x0024d46704f0b9de, // 221
+ .quad 0x891ac73ae9819b50, 0x0024ad03ce7d0f24, // 222
+ .quad 0x88d180cd3a4133d7, 0x002485dfa59104dc, // 223
+ .quad 0x8888888888888889, 0x00245efa03df1c1d, // 224
+ .quad 0x883fddf00883fddf, 0x00243852647eaccb, // 225
+ .quad 0x87f78087f78087f8, 0x002411e843e77632, // 226
+ .quad 0x87af6fd5992d0d40, 0x0023ebbb1fed4014, // 227
+ .quad 0x8767ab5f34e47ef1, 0x0023c5ca77bb8be3, // 228
+ .quad 0x872032ac13008720, 0x0023a015cbd155d3, // 229
+ .quad 0x86d905447a34acc6, 0x00237a9c9dfce59b, // 230
+ .quad 0x869222b1acf1ce96, 0x0023555e7157ae8e, // 231
+ .quad 0x864b8a7de6d1d608, 0x0023305aca423ed8, // 232
+ .quad 0x86053c345a0b8473, 0x00230b912e603d96, // 233
+ .quad 0x85bf37612cee3c9b, 0x0022e70124947795, // 234
+ .quad 0x85797b917765ab89, 0x0022c2aa34fcfa72, // 235
+ .quad 0x8534085340853408, 0x00229e8be8ef3de8, // 236
+ .quad 0x84eedd357c1b0085, 0x00227aa5caf45b0a, // 237
+ .quad 0x84a9f9c8084a9f9d, 0x002256f766c5512f, // 238
+ .quad 0x84655d9bab2f1008, 0x002233804947585d, // 239
+ .quad 0x8421084210842108, 0x0022104000884100, // 240
+ .quad 0x83dcf94dc7570ce1, 0x0021ed361bbae0a0, // 241
+ .quad 0x839930523fbe3368, 0x0021ca622b338b7a, // 242
+ .quad 0x8355ace3c897db10, 0x0021a7c3c0649abe, // 243
+ .quad 0x83126e978d4fdf3b, 0x0021855a6ddaff33, // 244
+ .quad 0x82cf750393ac3319, 0x00216325c73ae026, // 245
+ .quad 0x828cbfbeb9a020a3, 0x00214125613c4656, // 246
+ .quad 0x824a4e60b3262bc5, 0x00211f58d1a7d2cb, // 247
+ .quad 0x8208208208208208, 0x0020fdbfaf538145, // 248
+ .quad 0x81c635bc123fdf8e, 0x0020dc59921f7638, // 249
+ .quad 0x81848da8faf0d277, 0x0020bb2612f2d806, // 250
+ .quad 0x814327e3b94f462f, 0x00209a24cbb8b365, // 251
+ .quad 0x8102040810204081, 0x00207955575ceaab, // 252
+ .quad 0x80c121b28bd1ba98, 0x002058b751c92feb, // 253
+ .quad 0x8080808080808081, 0x0020384a57e209a8, // 254
+ .quad 0x8040201008040201, 0x0020180e0783e1f9, // 255
+
+#endif // FASTDIV_TABLES
diff --git a/private/crt32/misc/alpha/ghandler.c b/private/crt32/misc/alpha/ghandler.c
new file mode 100644
index 000000000..712d15fe4
--- /dev/null
+++ b/private/crt32/misc/alpha/ghandler.c
@@ -0,0 +1,435 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ghandler.c
+
+Abstract:
+
+ This module implements the C specific exception handler that provides
+ structured exception handling for code generated by the GEM compiler.
+
+Author:
+
+ John Parks (parks) 12-Jan-1993
+ Thomas Van Baak (tvb) 28-Jan-1993
+
+Environment:
+
+ Any mode.
+
+Revision History:
+
+--*/
+
+#include "nt.h"
+
+//
+// Define procedure prototypes for exception filter and termination handler
+// execution routines defined in jmpunwnd.s.
+//
+
+LONG
+__C_ExecuteExceptionFilter (
+ PEXCEPTION_POINTERS ExceptionPointers,
+ EXCEPTION_FILTER ExceptionFilter,
+ ULONG EstablisherFrame
+ );
+
+ULONG
+__C_ExecuteTerminationHandler (
+ BOOLEAN AbnormalTermination,
+ TERMINATION_HANDLER TerminationHandler,
+ ULONG EstablisherFrame
+ );
+
+//
+// Define local procedure prototypes.
+//
+
+EXCEPTION_DISPOSITION
+_OtsCSpecificHandler (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PVOID EstablisherFrame,
+ IN OUT PCONTEXT ContextRecord,
+ IN OUT PDISPATCHER_CONTEXT DispatcherContext
+ );
+
+ULONG
+_OtsLocalFinallyUnwind (
+ IN PSEH_CONTEXT SehContext,
+ IN PSEH_BLOCK TargetSeb,
+ IN PVOID RealFramePointer
+ );
+
+//
+// Define local macros.
+//
+
+#define IS_EXCEPT(Seb) ((Seb)->JumpTarget != 0)
+#define IS_FINALLY(Seb) ((Seb)->JumpTarget == 0)
+
+//
+// Initialize an exception record for the unwind with the SEB of the target
+// included as one information parameter. This is done so that the target
+// frame of the unwind may execute all the finally handlers necessary given
+// the SEB pointer at the unwind target.
+//
+
+#define MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, Seb) { \
+ ExceptionRecord->ExceptionCode = STATUS_UNWIND; \
+ ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING; \
+ ExceptionRecord->ExceptionRecord = NULL; \
+ ExceptionRecord->ExceptionAddress = 0; \
+ ExceptionRecord->NumberParameters = 1; \
+ ExceptionRecord->ExceptionInformation[0] = (ULONG)(Seb); \
+ }
+
+EXCEPTION_DISPOSITION
+_OtsCSpecificHandler (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PVOID EstablisherFrame,
+ IN OUT PCONTEXT ContextRecord,
+ IN OUT PDISPATCHER_CONTEXT DispatcherContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function walks up the list of SEB's associated with the specified
+ procedure and calls except filters and finally handlers as necessary.
+
+ It is called in two different contexts:
+ (i) by the exception dispatcher after an exception is raised
+ (ii) by the unwinder during an unwind operation
+
+ In the first case, is searches the SEB list for except filters to evaluate.
+ In the second case, it searches for finally handlers to execute.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to an exception record.
+
+ EstablisherFrame - Supplies a (virtual frame) pointer to the frame of the
+ establisher function.
+
+ ContextRecord - Supplies a pointer to a context record.
+
+ DispatcherContext - Supplies a pointer to the exception dispatcher or
+ unwind dispatcher context.
+
+Return Value:
+
+ If the exception is handled by one of the exception filter routines, then
+ there is no return from this routine and RtlUnwind is called. Otherwise,
+ an exception disposition value of continue execution or continue search is
+ returned.
+
+Notes:
+ In context (i) there are 3 possibilities:
+
+ (a) If an exception filter returns a value greater that 0 (meaning
+ that the associated handler should be invoked) there is no
+ return from this function. RtlUnwind is called to unwind the
+ stack to the exception handler corresponding to that filter.
+
+ (b) If an exception filter returns a value less than 0 (meaning
+ that the exception should be dismissed), this routine returns
+ value ExceptionContinueExecution.
+
+ (c) If every filter returns value 0 (meaning that the search for a
+ handler should continue elsewhere), this function returns
+ ExceptionContinueSearch.
+
+ In context (ii) there are 2 possibilities:
+
+ (d) If no branches are detected out of finally handlers, this
+ function returns ExceptionContinueSearch.
+
+ (e) If a branch is detected out of a finally handler, there is no
+ return from this routine. RtlUnwind is called to unwind to the
+ branch target (and cancel the current unwind).
+
+ There may be long jumps out of both except filters and finally handlers
+ in which case this routine will be peeled off the stack without returning.
+
+--*/
+
+{
+
+ ULONG ContinuationAddress;
+ EXCEPTION_FILTER ExceptionFilter;
+ PVOID ExceptionHandler;
+ EXCEPTION_POINTERS ExceptionPointers;
+ LONG FilterValue;
+ ULONG RealFramePointer;
+ PSEH_BLOCK Seb;
+ PSEH_CONTEXT SehContext;
+ PSEH_BLOCK TargetSeb;
+ TERMINATION_HANDLER TerminationHandler;
+
+ //
+ // Get the address of the SEH context which is at some negative offset
+ // from the virtual frame pointer. For GEM, the handler data field of
+ // the function entry contains that offset. The current SEB pointer and
+ // the RFP (static link) are obtained from the SEH context.
+ //
+
+ SehContext = (PSEH_CONTEXT)((ULONG)EstablisherFrame +
+ (LONG)DispatcherContext->FunctionEntry->HandlerData);
+ RealFramePointer = SehContext->RealFramePointer;
+
+ //
+ // If this is a dispatching context, walk up the list of SEBs evaluating
+ // except filters.
+ //
+
+ if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // Set up the ExceptionPointers structure that is used by except
+ // filters to obtain data for the GetExceptionInformation intrinsic
+ // function. Copy the current SEB pointer into a local variable
+ // because the real SEB pointer is only modified in unwind contexts.
+ //
+
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+
+ for (Seb = SehContext->CurrentSeb; Seb != NULL; Seb = Seb->ParentSeb) {
+ if (IS_EXCEPT(Seb)) {
+
+ //
+ // This is an except filter. Get the addresses of the filter
+ // and exception handler from the SEB, then call the except
+ // filter.
+ //
+
+ ExceptionFilter = (EXCEPTION_FILTER)Seb->HandlerAddress;
+ ExceptionHandler = (PVOID)Seb->JumpTarget;
+
+ FilterValue = __C_ExecuteExceptionFilter(&ExceptionPointers,
+ ExceptionFilter,
+ RealFramePointer);
+
+ //
+ // If the except filter < 0, dismiss the exception. If > 0,
+ // store the exception code on the stack for the except
+ // handler, modify the given ExceptionRecord so that finally
+ // handlers will be called properly during the unwind, then
+ // unwind down to the except handler. If = 0, resume the
+ // search for except filters.
+ //
+
+ if (FilterValue < 0) {
+ return ExceptionContinueExecution;
+
+ } else if (FilterValue > 0) {
+ SehContext->ExceptionCode = ExceptionRecord->ExceptionCode;
+ MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
+ Seb->ParentSeb);
+ RtlUnwind(EstablisherFrame,
+ ExceptionHandler,
+ ExceptionRecord,
+ 0);
+ }
+ }
+ }
+
+ } else if (!IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // This is an unwind but is not the target frame. Since the function
+ // is being terminated, finally handlers for all try bodies that are
+ // presently in scope must be executed. Walk up the SEB list all the
+ // way to the top executing finally handlers. This corresponds to
+ // exiting all try bodies that are presently in scope.
+ //
+
+ while (SehContext->CurrentSeb != NULL) {
+
+ //
+ // Get the address of the SEB and then update the SEH context.
+ //
+
+ Seb = SehContext->CurrentSeb;
+ SehContext->CurrentSeb = Seb->ParentSeb;
+
+ if (IS_FINALLY(Seb)) {
+
+ //
+ // This is a finally handler. Get the address of the handler
+ // from the SEB and call the finally handler.
+ //
+
+ TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress;
+ ContinuationAddress =
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ RealFramePointer);
+
+ //
+ // If the finally handler returns a non-zero result, there
+ // was a branch out of the handler (to that address) and this
+ // routine should unwind to that target.
+ //
+
+ if (ContinuationAddress != 0) {
+ MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
+ SehContext->CurrentSeb);
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ContinuationAddress,
+ ExceptionRecord,
+ 0);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // This is the target frame of an unwind. Since the target may be
+ // in a different try scope than the one defined by the current SEB
+ // pointer, finally handlers between the two scopes must execute.
+ // Walk up the SEB list from the current SEB to the target SEB and
+ // execute all finally handlers encountered.
+ //
+
+ TargetSeb = (PSEH_BLOCK)ExceptionRecord->ExceptionInformation[0];
+ ContinuationAddress = _OtsLocalFinallyUnwind(SehContext,
+ TargetSeb,
+ (PVOID)RealFramePointer);
+ if (ContinuationAddress != 0) {
+
+ //
+ // A non-zero result indicates there was a branch out of a
+ // finally handler that was being executed during the unwind.
+ // This routine should unwind to that address.
+ //
+
+ MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
+ SehContext->CurrentSeb);
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ContinuationAddress,
+ ExceptionRecord,
+ 0);
+ }
+ }
+
+ //
+ // Continue search for exception or termination handlers.
+ //
+
+ return ExceptionContinueSearch;
+}
+
+ULONG
+_OtsLocalFinallyUnwind (
+ IN PSEH_CONTEXT SehContext,
+ IN PSEH_BLOCK TargetSeb,
+ IN PVOID RealFramePointer
+ )
+
+/*++
+
+Routine Description:
+
+ This function walks up the SEB tree of the current procedure from the
+ current SEB to the target SEB and executes all the finally handlers it
+ encounters.
+
+ Calls to this function are inserted into user code by the compiler when
+ there are branches out of guarded regions that may require finally
+ handlers to execute.
+
+ This function is also called from _OtsCSpecificHandler when the target
+ frame is reached during an unwind operation. There may be finally handlers
+ that should execute before resuming execution at the unwind target.
+
+Arguments:
+
+ SehContext - Supplies the address of the SEH context structure which is
+ located in the stack frame.
+
+ TargetSeb - Supplies the address of the SEB corresponding to the branch
+ target address.
+
+ RealFramePointer - Supplies the (real frame) pointer of the establisher
+ frame, which is the current stack frame. This is used to set up the
+ static link if a finally handler is invoked.
+
+Return Value:
+
+ If a branch out of a finally handler is detected, the function value is
+ the address of the branch target. Otherwise, the function value is zero.
+
+--*/
+
+{
+
+ ULONG ContinuationAddress;
+ BOOLEAN Nested;
+ PSEH_BLOCK Seb;
+ TERMINATION_HANDLER TerminationHandler;
+
+ //
+ // If the SEB pointers are the same, no finally handlers need to execute.
+ // The branch is to a target location in the same guarded scope.
+ //
+
+ if (SehContext->CurrentSeb == TargetSeb) {
+ return 0;
+ }
+
+ //
+ // If the current SEB scope is not nested within the target SEB scope, no
+ // finally handlers need to execute. Reset the current SEB pointer to the
+ // target SEB pointer and return.
+ //
+
+ Nested = FALSE;
+ Seb = SehContext->CurrentSeb;
+
+ while (Seb != NULL) {
+ Seb = Seb->ParentSeb;
+ if (Seb == TargetSeb) {
+ Nested = TRUE;
+ break;
+ }
+ }
+ if (Nested == FALSE) {
+ SehContext->CurrentSeb = TargetSeb;
+ return 0;
+ }
+
+ //
+ // Walk up the list of SEB blocks executing finally handlers. If a branch
+ // out of a finally is encountered along the way, return the target
+ // address, otherwise return 0.
+ //
+
+ while (SehContext->CurrentSeb != TargetSeb) {
+
+ //
+ // Get the address of the SEB and then update the SEH context.
+ //
+
+ Seb = SehContext->CurrentSeb;
+ SehContext->CurrentSeb = Seb->ParentSeb;
+
+ if (IS_FINALLY(Seb)) {
+ TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress;
+ ContinuationAddress =
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ (ULONG)RealFramePointer);
+ if (ContinuationAddress != 0) {
+ return ContinuationAddress;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/private/crt32/misc/alpha/insv.s b/private/crt32/misc/alpha/insv.s
new file mode 100644
index 000000000..7d0956103
--- /dev/null
+++ b/private/crt32/misc/alpha/insv.s
@@ -0,0 +1,158 @@
+ #+
+ # Copyright 1991, 1994 Digital Equipment Corporation
+ #
+ # int ots_insv(char *addr, int position, unsigned size, int value)
+ #
+ # Arbitrary bitfield insertion, longword granularity
+ #
+ # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_ext[z]v
+ #
+ # 001 5 Sep 1991 KDG Initial version
+ #
+ # 002 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 003 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 004 26 Jan 1993 KDG Add underscore
+ #
+ # 005 19 Apr 1994 kdg Longword granularity version based on quadword
+ # granularity version 004
+
+#include "ots_defs.hs"
+
+ # Totally general field insertion - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target. Longword granularity.
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ # r19 - input value
+ #
+ # This is based on the original insert routine modified for longword
+ # granularity. This routine could probably be improved. (It does
+ # a "reasonable" job, but hasn't had as much attention as the quadword
+ # granularity version. Fields contained in a single longword are
+ # roughly the same cost as the quadword granularity version. Fields
+ # contained in two longwords in the same quadword are somewhat slower,
+ # while the two longword spanning a quadword case is roughly comparable.
+ # The 3 longword case is relatively slow [2 mispredicted branches,
+ # on unnecessary safe speculative load, could potentially use better
+ # scheduling too.])
+ #
+ .globl _OtsFieldInsert
+ .ent _OtsFieldInsert
+_OtsFieldInsert:
+ .set noat
+ .set noreorder
+ ble r18, noacc # check for zero size - no memory access
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ addq r16, r27, r16 # add to initial base addr.
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ and r16, 3, r27 # get byte-in-longword (must be clean for compares)
+ bic r16, 3, r16 # get a longword aligned address
+ s8addq r27, r17, r17 # form the true bit offset in the longword
+ ldl r28, (r16) # load first or only longword
+ addq r17, r18, r27 # get bit offset of bit following field
+ subq r27, 32, r0 # if <=32, field is contained in 1 longword
+ bgt r0, multiple # handle multi-longword case if not
+ # Common case of field in single LW - fall through
+ negq r27, r27 # <5:0> = bits for right shift
+ negq r18, r0 # bits for left shift (wordlength-is)
+ not r31, r1 # all ones
+ sll r1, r0, r1 # shift mask to high bits
+ sll r19, r0, r19 # shift source to high bits (hand interleaving for better sched)
+ srl r1, r27, r1 # and into position
+ srl r19, r27, r19 # and into position
+ bic r28, r1, r28 # clear the bits...
+ bis r28, r19, r28 # insert them
+ stl r28, (r16) # put the value back...
+noacc: ret r31, (r26)
+
+ # At this point:
+ # Field is known to be contained in at least 2 longwords
+ # r0 is bit position past end of field, -32
+ # r1 junk
+ # r16 is longword aligned
+ # r17 is bit offset in longword
+ # r18 is field size
+ # r19 is value to store
+ # r27 is bit position past end of field
+ # r28 first lw from memory
+ #
+multiple:
+ subq r0, 32, r27 # if <=64, the field is contained in 2 longwords
+ ldl r1, 4(r16) # load the 2nd longword (safe)
+ bgt r27, three # handle 3 longword case (rare...)
+ not r31, r27 # all ones
+ sll r27, r17, r27 # get mask in correct place
+ sll r19, r17, r17 # get insert value to top of register
+ bic r28, r27, r28 # clear bits in target
+ bis r28, r17, r28 # merge the field in
+ srl r1, r0, r1 # clear bits in target
+ negq r18, r27 #
+ sll r19, r27, r19 # shift to high bits
+ negq r0, r27 #
+ srl r19, r27, r19 # and into position
+ sll r1, r0, r1 #
+ stl r28, (r16) # store the first longword
+ bis r1, r19, r1 # merge
+ stl r1, 4(r16) # store back the second longword
+ ret r31, (r26)
+
+ # At this point:
+ # Field is known to be contained in exactly 3 longwords
+ # r0 is bit position past end of field, -32
+ # r1 value loaded for 2nd longword (which will be totally overwritten - i.e. junk)
+ # r16 is longword aligned
+ # r17 is bit offset in longword
+ # r18 is field size
+ # r19 is value to store
+ # r27 is bit position past end of field -64
+ # r28 first lw from memory
+ #
+ # Three word case is roughly similar to two word case, except
+ # the middle store isn't a merge, just a real store, and the offsets
+ # for the 3rd word need to be adjusted. (This case hasn't
+ # received much attention and could probably be improved by
+ # at least a few instructions...)
+ #
+three:
+ not r31, r0 # all ones
+ sll r0, r17, r0 # get mask in correct place
+ sll r19, r17, r1 # get insert value to top of register
+ bic r28, r0, r28 # clear bits in target
+ bis r28, r1, r28 # merge the field in
+ ldl r1, 8(r16) # load the 3rd longword
+ lda r0, 32(r31) # load 32
+ stl r28, (r16) # store the first longword
+ subq r0, r17, r0 # shift amount
+ srl r19, r0, r28 # discard bits already stored
+ negq r18, r0 #
+ srl r1, r27, r1 # clear bits in target
+ sll r19, r0, r19 # shift to high bits
+ negq r27, r0 #
+ srl r19, r0, r19 # and into position
+ sll r1, r27, r1 #
+ stl r28, 4(r16) # store second complete longword
+ bis r1, r19, r1 # merge
+ stl r1, 8(r16) # store back the third longword
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsFieldInsert
diff --git a/private/crt32/misc/alpha/insvvol.s b/private/crt32/misc/alpha/insvvol.s
new file mode 100644
index 000000000..11c0c3eed
--- /dev/null
+++ b/private/crt32/misc/alpha/insvvol.s
@@ -0,0 +1,137 @@
+ #+
+ # Copyright 1991, Digital Equipment Corporation
+ #
+ # int ots_insv_vol(char *addr, int position, unsigned size, int value)
+ #
+ # Arbitrary signed bitfield extraction for volatile cases
+ #
+ # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # See also: ots_ext[z]v
+ #
+ # 001 5 Sep 1991 KDG Initial version
+ #
+ # 002 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 003 5 Oct 1992 KDG Initial volatile version based on non-volatile
+ # version
+ #
+ # 004 10 Nov 1992 KDG Case-sensitive name
+ #
+ # 005 26 Jan 1993 KDG Add underscore
+ #
+ # 006 1 Sep 1994 RBG Fix aligned longword and quadword cases,
+ # check for bit 0 within byte GEM_BUGS #3545
+
+#include "ots_defs.hs"
+
+ # Totally general field insertion - arbitrary run-time field of 0-64 bits
+ # at an unknown alignment target.
+ #
+ # Volatile/byte granularity version notes:
+ #
+ # - Aligned quadword stores must be done using exactly STQ
+ #
+ # - Aligned longword stores must be done using exactly STL
+ #
+ # - All other stores must be done using LDx_L/STx_C to avoid
+ # corrupting any adjacent data and provide atomic updates
+ # for aligned data
+ #
+ # The first two items are required in case this routine is called for
+ # volatile references so that I/O space accesses are handled correctly.
+ # (Normally, those references are handled in-line, but if for some
+ # reason they wind up coming through here, they must still be correct.)
+ #
+ # Conceptually, this operation takes a 67 bit bit-address, which is the sum
+ # of a byte-aligned memory address and the bit offset (which is signed).
+ #
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b|
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ #
+ # Inputs:
+ # r16 - input address
+ # r17 - input bit offset
+ # r18 - input size
+ # r19 - input value
+ #
+ # This is based on the code GEM generates when not using an out-of-line
+ # routine, though it has better by-hand register packing to allow
+ # multiple issue.
+ #
+ .globl _OtsFieldInsertVolatile
+ .ent _OtsFieldInsertVolatile
+_OtsFieldInsertVolatile:
+ .set noat
+ .set noreorder
+ sra r17, 3, r27 # get byte part of bit offset (signed!)
+ ble r18, noacc # check for zero size - no memory access
+ cmpeq r18, 32, r28 # Aligned longword(1) - is the size exactly 32b?
+ addq r16, r27, r16 # add to initial base addr.
+ and r16, 3, r27 # check for special case of an aligned longword
+ cmpult r27, r28, r28 # Aligned longword(2) - byte 0 within longword
+ and r17, 7, r17 # get bit-in-byte from bit offset
+ cmpult r17, r28, r28 # Aligned longword(3) - bit 0 within byte
+ cmpeq r18, 64, r0 # Aligned quadword(1) - is the size exactly 64b?
+ and r16, 7, r27 # get byte-in-quadword (must be clean for cmpule)
+ bne r28, longwd # if aligned longword, store exactly a longword using stl
+ cmpult r27, r0, r0 # Aligned quadword(2) - byte 0 within quadword
+ cmpult r17, r0, r0 # Aligned quadword(3) - bit 0 within byte
+ s8addq r27, r17, r17 # form the true bit offset in the quadword
+ bne r0, quadwd # if aligned quadword, store exactly a quadword using stq
+ addq r17, r18, r27 # get bit offset of bit following field
+ cmpule r27, 64, r0 # if <=64, field is contained in 1 quadword
+ bic r16, 7, r16 # clear unaligned bits in address for locked operations
+ not r31, r1 # all ones
+ beq r0, double # handle double case if not
+ # Common case of field in single QW - fall through
+ negq r27, r27 # <5:0> = bits for right shift
+ addq r27, r17, r0 # bits for left shift (wordlength-is)
+ sll r1, r0, r1 # shift mask to high bits
+ sll r19, r0, r19 # shift source to high bits (hand interleaving for better sched)
+ srl r1, r27, r1 # and into position
+ srl r19, r27, r19 # and into position
+sinrty: ldq_l r28, (r16) # load first or only quadword
+ bic r28, r1, r28 # clear the bits...
+ bis r28, r19, r28 # insert them
+ stq_c r28, (r16) # put the value back...
+ blbc r28, sinfl # check for failing interlock/retry
+noacc: ret r31, (r26)
+
+double:
+ sll r1, r17, r0 # get mask in correct place
+ sll r19, r17, r17 # get insert value to top of register
+ negq r18, r1 #
+ sll r19, r1, r19 # shift to high bits
+ negq r27, r1 #
+ srl r19, r1, r19 # and into position
+firrty: ldq_l r28, (r16) # load first or only quadword
+ bic r28, r0, r28 # clear bits in target
+ bis r28, r17, r28 # merge the field in
+ stq_c r28, (r16) # store the first word
+ blbc r28, firfl # check for failing interlock/retry
+secrty: ldq_l r28, 8(r16) # load the 2nd quadword
+ srl r28, r27, r28 # clear bits in target
+ sll r28, r27, r28 #
+ bis r28, r19, r28 # merge
+ stq_c r28, 8(r16) # store back
+ blbc r28, secfl # check for failing interlock/retry
+ ret r31, (r26)
+longwd: stl r19, (r16) # store aligned longword
+ ret r31, (r26)
+quadwd: stq r19, (r16) # store aligned quadword
+ ret r31, (r26)
+ # out-of-line retry cases
+sinfl: br r31, sinrty # re-try the locked operation for the single case
+firfl: br r31, firrty # re-try the locked operation for the 1st part of the two-part case
+secfl: br r31, secrty # re-try the locked operation for the 2nd part of the two-part case
+
+ .set at
+ .set reorder
+ .end _OtsFieldInsertVolatile
diff --git a/private/crt32/misc/alpha/jmpuwind.s b/private/crt32/misc/alpha/jmpuwind.s
new file mode 100644
index 000000000..934b9d549
--- /dev/null
+++ b/private/crt32/misc/alpha/jmpuwind.s
@@ -0,0 +1,167 @@
+// TITLE("Handler Stubs and Jump to Unwind")
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// jmpuwind.s
+//
+// Abstract:
+//
+// This module implements the Alpha acc compiler specific routines to call
+// exception handlers and to jump to the runtime library unwind routines.
+//
+// Author:
+//
+// David N. Cutler (davec) 12-Sep-1990
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Thomas Van Baak (tvb) 30-Apr-1992
+//
+// Adapted for Alpha AXP.
+//
+//--
+
+#include "ksalpha.h"
+
+ SBTTL("Execute Exception Filter")
+//++
+//
+// ULONG
+// __C_ExecuteExceptionFilter (
+// PEXCEPTION_POINTERS ExceptionPointers,
+// EXCEPTION_FILTER ExceptionFilter,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// exception filter routine.
+//
+// Arguments:
+//
+// ExceptionPointers (a0) - Supplies a pointer to the exception pointers
+// structure.
+//
+// ExceptionFilter (a1) - Supplies the address of the exception filter
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// The value returned by the exception filter routine.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteExceptionFilter)
+
+//
+// The protocol for calling exception filters used by the acc compiler is
+// that the uplevel frame pointer is passed in register v0 and the pointer
+// to the exception pointers structure is passed in register a0. The GEM
+// C compiler expects the static link in t0. Here both registers are set.
+//
+
+ mov a2, v0 // set static link
+ mov a2, t0 // set alternate static link
+ jmp zero, (a1) // transfer control to exception filter
+
+ .end __C_ExecuteExceptionFilter
+
+ SBTTL("Execute Termination Handler")
+//++
+//
+// ULONG
+// __C_ExecuteTerminationHandler (
+// BOOLEAN AbnormalTermination,
+// TERMINATION_HANDLER TerminationHandler,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// termination handler routine.
+//
+// Arguments:
+//
+// AbnormalTermination (a0) - Supplies a boolean value that determines
+// whether the termination is abnormal.
+//
+// TerminationHandler (a1) - Supplies the address of the termination handler
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// The value returned by the termination handler routine, if any.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteTerminationHandler)
+
+//
+// The protocol for calling termination handlers used by the acc compiler
+// is that the uplevel frame pointer is passed in register v0 and the boolean
+// abnormal termination value is passed in register a0. The GEM C compiler
+// expects the static link in t0. Here both registers are set.
+//
+
+ mov a2, v0 // set static link
+ mov a2, t0 // set alternate static link
+ jmp zero, (a1) // transfer control to termination handler
+
+ .end __C_ExecuteTerminationHandler
+
+ SBTTL("Jump to Unwind")
+//++
+//
+// VOID
+// __jump_unwind (
+// IN PVOID EstablishFrame,
+// IN PVOID TargetPc
+// )
+//
+// Routine Description:
+//
+// This function transfers control to unwind. It is used by the acc
+// compiler when a goto out of the body of a try statement occurs.
+//
+// Arguments:
+//
+// EstablishFrame (a0) - Supplies the establisher frame pointer of the
+// target of the unwind.
+//
+// TargetPc (a1) - Supplies the target instruction address where control
+// is to be transferred to after the unwind operation is complete.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(__jump_unwind)
+
+//
+// The first two arguments are the same as those required by unwind. Set the
+// second two arguments and jump to unwind. This thunk is necessary to avoid
+// name space pollution. The compiler should not generate a call directly to
+// RtlUnwind.
+//
+
+ mov zero, a2 // set NULL exception record address
+ mov zero, a3 // set target return value of 0
+ br zero, RtlUnwind // unwind to specified target
+
+ .end __jump_unwind
diff --git a/private/crt32/misc/alpha/longjmp.s b/private/crt32/misc/alpha/longjmp.s
new file mode 100644
index 000000000..412e3e655
--- /dev/null
+++ b/private/crt32/misc/alpha/longjmp.s
@@ -0,0 +1,192 @@
+// TITLE("Long Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// longjmp.s
+//
+// Abstract:
+//
+// This module implements the Alpha specific routine to perform a long
+// jump operation. Three jump buffer types are supported: unsafe, safe
+// acc-style (virtual frame pointer, PC mapped SEH scope), and safe
+// GEM-style (real frame pointer, SEB-based SEH context).
+//
+// N.B. This routine conditionally provides UNSAFE handling of longjmp
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an unitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Thomas Van Baak (tvb) 22-Apr-1993
+//
+// Adapted for Alpha AXP.
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Define jump buffer types.
+//
+// _JMPBUF_TYPE_ZERO was used for Beta2 which functions the same as
+// _JMPBUF_TYPE_ACC.
+//
+// _JMPBUF_TYPE_FAST is for jump buffers containing the set of
+// non-volatile integer and floating registers. This form
+// of setjmp/longjmp is not compatible with SEH.
+//
+// _JMPBUF_TYPE_ACC is for setjmp/longjmp compatible with SEH.
+// The Alpha acc compiler uses a virtual frame pointer.
+//
+// _JMPBUF_TYPE_GEM is for setjmp/longjmp compatible with SEH.
+// The Alpha GEM C compiler uses a real frame pointer, and
+// SEH scope is maintained with a SEB pointer.
+//
+
+#define _JMPBUF_TYPE_ZERO 0
+#define _JMPBUF_TYPE_FAST 1
+#define _JMPBUF_TYPE_ACC 2
+#define _JMPBUF_TYPE_GEM 3
+
+ SBTTL("Long Jump")
+//++
+//
+// int
+// longjmp (
+// IN jmp_buf JumpBuffer,
+// IN int ReturnValue
+// )
+//
+// Routine Description:
+//
+// This function performs a long jump to the context specified by the
+// jump buffer.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer that contains
+// jump information.
+//
+// ReturnValue (a1) - Supplies the value that is to be returned to the
+// caller of set jump.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(longjmp)
+
+ ldil t0, 1 // force nonzero value, if
+ cmoveq a1, t0, a1 // given return value is zero
+
+ ldl t1, JbType(a0) // get setjmp context type flag
+ subq t1, 1, t2 // if eq 1, fast, unsafe longjmp
+ bne t2, 10f // otherwise, provide safe longjmp
+
+//
+// Type 0x1: Provide unsafe handling of longjmp.
+//
+
+ mov a1, v0 // set return value
+
+ ldt f2, JbFltF2(a0) // restore floating registers f2 - f9
+ ldt f3, JbFltF3(a0) //
+ ldt f4, JbFltF4(a0) //
+ ldt f5, JbFltF5(a0) //
+ ldt f6, JbFltF6(a0) //
+ ldt f7, JbFltF7(a0) //
+ ldt f8, JbFltF8(a0) //
+ ldt f9, JbFltF9(a0) //
+
+ ldq s0, JbIntS0(a0) // restore integer registers s0 - s6/fp
+ ldq s1, JbIntS1(a0) //
+ ldq s2, JbIntS2(a0) //
+ ldq s3, JbIntS3(a0) //
+ ldq s4, JbIntS4(a0) //
+ ldq s5, JbIntS5(a0) //
+ ldq fp, JbIntS6(a0) //
+
+ ldq a1, JbFir(a0) // get setjmp return address
+ ldq sp, JbIntSp(a0) // restore stack pointer
+ jmp zero, (a1) // jump back to setjmp site
+
+//
+// Type 0x0: Provide safe handling of longjmp (idw 404 style).
+// Type 0x2: Provide safe handling of longjmp (acc style).
+//
+
+10: bic t1, 0x2, t2 // if 0 or 2, safe acc longjmp
+ bne t2, longjmpRfp // if not, safe GEM longjmp
+
+ mov a1, a3 // set return value
+ mov zero, a2 // set exception record addres
+ ldl a1, JbPc(a0) // set target instruction address
+ ldl a0, JbFp(a0) // set target virtual frame pointer
+ br zero, RtlUnwind // finish in common code
+
+ .end longjmp
+
+ SBTTL("Long Jump - GEM")
+
+ .struct 0
+LjRa: .space 8 // saved return address
+ .space 8 // padding for 16-byte stack alignment
+LjEr: .space ExceptionRecordLength // local exception record
+LongjmpFrameLength:
+
+//
+// Type 0x3: Provide safe handling of longjmp (GEM style).
+//
+
+ NESTED_ENTRY(longjmpRfp, LongjmpFrameLength, ra)
+
+ lda sp, -LongjmpFrameLength(sp) // allocate stack frame
+ stq ra, LjRa(sp) // save return address
+
+ PROLOGUE_END
+
+//
+// Set up the following local exception record:
+//
+// ExceptionRecord.ExceptionCode = STATUS_UNWIND;
+// ExceptionRecord.ExceptionFlags = EXCEPTION_UNWINDING;
+// ExceptionRecord.ExceptionRecord = NULL;
+// ExceptionRecord.ExceptionAddress = 0;
+// ExceptionRecord.NumberParameters = 1;
+// ExceptionRecord.ExceptionInformation[0] = Seb;
+//
+
+10: mov a1, a3 // set return value
+ lda a2, LjEr(sp) // set exception record address
+
+ ldil t0, STATUS_UNWIND // get status code
+ stl t0, ErExceptionCode(a2) // store in exception record
+ ldil t1, EXCEPTION_UNWINDING // get exception flags
+ stl t1, ErExceptionFlags(a2) // store in exception record
+ stl zero, ErExceptionRecord(a2) // store in exception record
+ stl zero, ErExceptionAddress(a2) // store in exception record
+ ldil t2, 1 // get number of parameters
+ stl t2, ErNumberParameters(a2) // store in exception record
+ ldl t3, JbSeb(a0) // get SEB pointer
+ stl t3, ErExceptionInformation(a2) // store in exception record
+ ldl a1, JbPc(a0) // set target instruction address
+ ldl a0, JbFp(a0) // set target real frame pointer
+
+ bsr ra, RtlUnwindRfp // finish in common code
+
+ .end longjmpRfp
diff --git a/private/crt32/misc/alpha/ots_as.hs b/private/crt32/misc/alpha/ots_as.hs
new file mode 100644
index 000000000..127fe6382
--- /dev/null
+++ b/private/crt32/misc/alpha/ots_as.hs
@@ -0,0 +1,38 @@
+/* Definitions common to all systems using the "as" assembler (OSF,WNT) */
+/* Define mov to be bis from $31 so it can take a literal... */
+#define mov bis $31,
+#define not ornot $31,
+/* Define register aliases */
+#define r0 $0
+#define r1 $1
+#define r2 $2
+#define r3 $3
+#define r4 $4
+#define r5 $5
+#define r6 $6
+#define r7 $7
+#define r8 $8
+#define r9 $9
+#define r10 $10
+#define r11 $11
+#define r12 $12
+#define r13 $13
+#define r14 $14
+#define r15 $15
+#define r16 $16
+#define r17 $17
+#define r18 $18
+#define r19 $19
+#define r20 $20
+#define r21 $21
+#define r22 $22
+#define r23 $23
+#define r24 $24
+#define r25 $25
+#define r26 $26
+#define r27 $27
+#define r28 $28
+#define r29 $29
+#define sp $sp
+#define gp $gp
+#define r31 $31
diff --git a/private/crt32/misc/alpha/ots_defs.hs b/private/crt32/misc/alpha/ots_defs.hs
new file mode 100644
index 000000000..d3a62a478
--- /dev/null
+++ b/private/crt32/misc/alpha/ots_defs.hs
@@ -0,0 +1,3 @@
+/* OSF-specific definitions */
+#define WNT 1
+#include "ots_as.hs"
diff --git a/private/crt32/misc/alpha/otsdiv.s b/private/crt32/misc/alpha/otsdiv.s
new file mode 100644
index 000000000..cafb9b87e
--- /dev/null
+++ b/private/crt32/misc/alpha/otsdiv.s
@@ -0,0 +1,1178 @@
+
+ # Copyright 1992, Digital Equipment Corporation
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+ # 008 17 Jun 1992 KDG/wbn Most of initial tailored version. (See
+ # commentary below.)
+ #
+ # 009 4 Jul 1992 KDG Continue work on initial tailored version,
+ # including bugfixes and mod entry points
+ #
+ # 010 15 Jul 1992 KDG - Final touches for V1 (other than any bugfixes)
+ # - .aligns commented out to allow older assembler versions
+ #
+ # 011 16 Jul 1992 KDG - Bugfix for ots_div_l for -maxint dividend
+ # - OSF-only source changes for BL7
+ #
+ # 012 10 Aug 1992 KDG Fix overflow division entry points
+ #
+ # 013 23 Sep 1992 KDG Add case-sensitive entry names
+ #
+ # 014 4 Jan 1993 KDG Tweak for OSF assembler
+ #
+ # 015 26 Jan 1993 KDG Add underscore prefix, OSF uses CS names
+ #
+ # 016 5 Apr 1993 WBN Speed up core 64-bit, shrink table entry to 2 QWs
+
+ #++
+ # Entry points defined in this module:
+ #
+ # -- 32 bit division/remainder support
+ # unsigned ots_rem_ui(unsigned dividend, unsigned divisor)
+ # unsigned ots_div_ui(unsigned dividend, unsigned divisor)
+ # int ots_mod_i(int dividend, int modulus)
+ # int ots_rem_i(int dividend, int divisor)
+ # int ots_div_i_o(int dividend, int divisor)
+ # int ots_div_i(int dividend, int divisor) | "hot spot"
+ # {core routine - div32} |
+ #
+ # -- 64 bit division support
+ # {core routine - div64} | (uses div32 for 32b cases)
+ # long ots_div_l_o(long dividend, long divisor)
+ # long ots_div_l(long dividend, long divisor) | "hot spot"
+ # long ots_rem_l(long dividend, long divisor)
+ # long ots_mod_l(long dividend, long modulus)
+ # unsigned long ots_div_ul(unsigned long dividend, unsigned long divisor)
+ # unsigned long ots_rem_ul(unsigned long dividend, unsigned long divisor)
+ #
+ # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # NOTE: This set of routines may start using stack space at some
+ # future point in time.
+ #
+ # -- Possible future entry points include:
+ # (These all return results in r0/r1)
+ # {int quotient, int remainder} ots_div_mod_i(int dividend, int divisor)
+ # {int quotient, int remainder} ots_div_mod_i_o(int dividend, int divisor)
+ # {int quotient, int remainder} ots_div_rem_i(int dividend, int divisor)
+ # {int quotient, int remainder} ots_div_rem_i_o(int dividend, int divisor)
+ # {unsigned quotient, unsigned remainder} ots_div_rem_ui(unsigned dividend, unsigned divisor)
+ #
+ # {long quotient, long remainder} ots_div_mod_i(long dividend, long divisor)
+ # {long quotient, long remainder} ots_div_mod_i_o(long dividend, long divisor)
+ # {long quotient, long remainder} ots_div_rem_i(long dividend, long divisor)
+ # {long quotient, long remainder} ots_div_rem_i_o(long dividend, long divisor)
+ # {unsigned long quotient, unsigned long remainder}
+ # ots_div_rem_ui(unsigned long dividend, unsigned long divisor)
+ #
+ #
+ # General commentary:
+ #
+ # This is an attempt at a fairly high performance version using relatively
+ # straightforward algorithms. Note that the code is intended to be scheduled
+ # well for EV4, but still reasonably for LCA/EV5.
+ #
+ # Also, note that there was only so much time available for this, so it
+ # is far from "perfect". "Better is the enemy of done"...
+ #
+ # Possible future areas of improvement (and unfinished business):
+ #
+ # - Another possible way of doing things for the "slow" (divnn cases)
+ # is to use an approximate inverse and convergence. Given the speed
+ # of the multiplier on EV4, and given "time to market", this wasn't
+ # done for V1.) I have some mail with the algorithm from Bob Gries
+ # (through Scott Robinson).
+ #
+ # - When the divisor is too large for the table, but has n low-order zero
+ # bits, see if divisor/2^n fits in the table, and use that entry with
+ # dividend/2^n
+ #
+ # - Use UMULH for the 'mod' routines.
+ #
+ # This version can do a table lookup division (divisors with <=tablesize)
+ # in roughly 32 cycles on an EV4 (with cache hits for all loads), of which
+ # 21 are for the umulh. There is a strong bias toward the table-lookup case.
+ # Note that for many cases, the umulh is the last thing before the return,
+ # so the multiply can occur in parallel with the procedure return.
+ # (It is interesting that the R3000 hardware divide instruction takes 33
+ # cycles and the R4000 takes 76(!) ...) Small powers of 2 are retired in
+ # roughly 20 cycles. Larger divisors take considerably longer at this point.
+ #
+
+#include "ots_defs.hs"
+
+#ifdef OSF
+ # to get the PAL_gentrap literal
+#include <alpha/pal.h>
+#endif
+
+ # Data area description
+ #
+ # The data area "ots_div_data" is an array of structures, indexed
+ # by the divisor value, with each array entry being 16 bytes in size
+ # formatted as follows:
+ #
+ # 6
+ # 3 6 0
+ # +-------+-------+-------+-------+-------+-------+-------+-------+
+ # | 32 bit reciprocal (58 bits) |shift|
+ # +-------+-------+-------+-------+-------+-------+-------+-------+
+ # | 64 bit reciprocal |
+ # +---------------------------------------------------------------+
+ #
+ # The 64-bit reciprocal has the leading '1' bit omitted, so it provides
+ # 65 bits of precision -- enough to handle unsigned 64-bit values.
+ #
+ # The first longword contains the 6-bit shift amount needed to handle
+ # 64-bit cases and powers of two.
+ #
+ # The 32-bit reciprocal has the shift count built in, so a UMULH gives
+ # the correct quotient without shifting. The reciprocal needs 33 bits
+ # of precision. The 6-bit shift amount is noise in the reciprocal that
+ # can be ignored.
+ #
+ # (Oh, you want proof?) For divisors up to 2^k, we store k-1 leading
+ # zero bits, 33 bits of fraction, (25-k) more bits of fraction, and
+ # 6 bits of noise. The standard method would round at the 33rd fraction
+ # bit. We need to ensure that the value actually stored is geq the
+ # infinite reciprocal, but leq the standard value. For divisors up to
+ # 2^k, there will be a zero bit somewhere in the k bits below the 33rd,
+ # so as long as we round below the (33+k)th bit, the rounded value
+ # plus any noise is still less than the standard value. This requires
+ # k < 12.
+ #
+ # The actual data is declared in ots_div_data_alpha.
+ #
+ # Offsets to the various fields in the data structure
+ #
+#define shift_o 0
+#define recip64_o 8
+#define recip32_o 0
+ #
+ # Note that the shift/add ops used to compute the table entries
+ # "know" that the table size is 16. (i.e. addq -> s8addq -> ldq)
+ # By changing the first instruction, it's fairly easy to change the
+ # table entry size to 24, 32, or 40 bytes (using s4add/sub), or
+ # 56/64/72 bytes using s8add/sub, should that be desirable.
+
+ # Maximum divisor present in the table
+ #
+#define table_max 512
+
+ # Division by zero gentrap code
+ #
+#define GEN_INTDIV -2
+
+ # Address of division data area (shared by all entry points)
+ #
+#ifdef VMS
+ .psect ots_link
+ots_div_addr:
+ .address ots_div_data
+ .psect ots_code
+#endif
+
+ # Dummy entry point for the module
+ #
+ .globl _OtsDivide
+ .ent _OtsDivide
+_OtsDivide:
+ .set noat
+ .set noreorder
+#ifdef OSF
+ .frame sp, 0, r26
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+#endif
+
+
+ # unsigned ots_rem_ui(unsigned dividend, unsigned divisor)
+ # unsigned 32 bit remainder support
+ #
+ #.align 4
+ .globl _OtsRemainder32Unsigned
+ .aent _OtsRemainder32Unsigned
+_OtsRemainder32Unsigned:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_rem_ui>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ lda r28, -table_max(r17) # test for table lookup
+ subl r17, 1, r1 # first part of power-of-2 check
+ blt r17, rui_big # big divisors can (must) be handled by a simple comparison
+ and r17, r1, r18 # second part of power-of-2 check
+ bgt r28, rui_lrgdiv # branch if large divisor
+ addq r17, r17, r0 # compute divisor*2 for table lookup
+ beq r18, rui_pwr2 # if zero, divisor is a power of 2
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ ldq r1, recip32_o(r27) # load approximate reciprocal
+ cmpult r16, r17, r18 # is the dividend < divisor?
+ zap r16, 0xF0, r0 # kill the propagated sign bit
+ bne r18, rui_lss # if dividend < divisor, fast exit
+ umulh r0, r1, r0 # multiplication for division step
+ mull r0, r17, r0 # multiply back to get value to subtract
+ subl r16, r0, r0
+ ret r31, (r26) # and return
+
+rui_pwr2:
+ beq r17, divzer # check for 0
+ and r16, r1, r0 # use x-1 to mask
+ ret r31, (r26)
+
+rui_lss:
+ mov r16, r0
+ ret r31, (r26)
+
+rui_lrgdiv:
+ zap r16, 0xf0, r16 # zero-extend the dividend
+ bsr r28, div32 # use the core routine getting the remainder in r1
+ sextl r1, r0
+ ret r31, (r26)
+
+ # divisors with the sign bit set. two possible results,
+ # dividend if dividend < divisor, or dividend-divisor otherwise
+rui_big:
+ cmpult r16, r17, r1
+ subl r16, r17, r0
+ cmovne r1, r16, r0
+ ret r31, (r26)
+
+
+ # unsigned ots_div_ui(unsigned dividend, unsigned divisor)
+ # unsigned 32 bit division support
+ #
+
+ #.align 4
+ .globl _OtsDivide32Unsigned
+ .aent _OtsDivide32Unsigned
+_OtsDivide32Unsigned:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_ui>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ lda r28, -table_max(r17) # test for table lookup
+ blt r17, dui_big # big divisors can (must) be handled by a simple comparison
+ addq r17, r17, r18 # compute divisor*2
+ cmpule r17, r16, r0 # is the dividend < divisor?
+ beq r17, divzer # check for 0
+ s8addq r18, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ beq r0, dui_end # fast out for divisor > dividend
+ bgt r28, dui_lrgdiv # branch if large divisor
+ ldq r1, recip32_o(r27) # load approximate reciprocal
+ zap r16, 0xF0, r16 # kill the propagated sign bit
+ blt r1, dui_smpwr2 # go handle powers of 2 specially
+ umulh r16, r1, r0 # start multiplication for division step
+dui_end:ret r31, (r26) # and return
+ nop
+dui_smpwr2:
+ srl r16, r1, r0 # shift the result into place
+ sextl r0, r0 # reinsert sign if dividing by 1
+ ret r31, (r26) #
+dui_lrgdiv:
+ zap r16, 0xf0, r16 # zero-extend the dividend
+ bsr r28, div32 # use the core routine getting the remainder in r1
+ sextl r0, r0 # make sure the result is in normal form for uint32
+ ret r31, (r26)
+
+ # divisor with the sign bit set. two possible results,
+ # 1 if divisor <= dividend, or 0 otherwise
+dui_big:
+ cmpule r17, r16, r0
+ ret r31, (r26)
+
+
+ # int ots_mod_i(int dividend, int modulus)
+ # signed 32 bit modulus support
+ #
+ # This entry could be MUCH more optimized. It doesn't even try to use
+ # UMULH division currently... (A casualty of time-to-market.)
+ # Note that mod is only used by Ada and PL/I.
+ #
+ #.align 4
+ .globl _OtsModulus32
+ .aent _OtsModulus32
+_OtsModulus32:
+ negq r17, r18 # first part of abs(divisor)
+ cmovge r17, r17, r18 # second part of abs(divisor)
+ subq r18, 1, r1 # start checking for power of 2
+ beq r17, divzer # check for 0
+ and r18, r1, r0 # second part of power-of-2 check
+ beq r0, mi_p2 # for powers of two, simply do a mask
+ # (note that the power-of-2 case MUST be used to handle
+ # the -maxint case due to the way the fix-up info is
+ # saved across the core routine call)
+ xor r16, r17, r28 # get xor of signs
+ clr r19 # don't need a bias if dividend and divisor have same sign
+ cmovlt r28, r17, r19 # bias is original divisor for different sign case
+ and r16, r17, r27 # if both dividend & divisor were neg. need to negate result
+ mov r18, r17 # move abs(divisor) into r17
+ negq r16, r18 # first part of abs(dividend)
+ cmovlt r16, r18, r16 # second part of abs(dividend)
+ cmplt r27, r31, r0 # get 1 if both operands were <0
+ sll r0, 63, r0 # get bit as the high bit
+ bis r0, r19, r19 # and MERGE with bias (0 -> no fixup, -maxint -> negate result,
+ # divisor > 0 - subtract remainder if non-zero, divisor < 0 -
+ # add remainder if non-zero)
+ bsr r28, div32 # use the core routine getting the remainder in r1
+ cmoveq r1, r31, r19 # don't do any fix-up if the remainder was zero
+ addq r19, r19, r18 # check to see if this is the negative/negative case, which just gets a negated remainder
+ subq r19, 1, r28 # wrap -maxint to positive
+ negl r1, r0 # move negated value, may abort later
+ cmovlt r28, r1, r0 # if both positive, or negative divisor, keep positive remainder
+ cmoveq r18, r31, r19 # now that negation is done, treat -maxint case as 0
+ addl r19, r0, r0 # add any bias (original divisor or 0)
+ ret r31, (r26) # and return
+
+mi_p2: cmovge r17, r31, r17 # no bias if divisor was >= 0
+ and r16, r1, r1 # use the divisor-1 mask that's already in r1
+ cmoveq r1, r31, r17 # use zero if result was zero
+ addl r17, r1, r0 # do any biasing, and ensure the result is sign ext
+ ret r31, (r26) # and return
+
+ # int ots_rem_i(int dividend, int divisor)
+ # signed 32 bit remainder support
+ #
+ #.align 4
+ .globl _OtsRemainder32
+ .aent _OtsRemainder32
+_OtsRemainder32:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_rem_i>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ negq r17, r18 # first part of abs(divisor)
+ cmovlt r17, r18, r17 # second part of abs(divisor)
+ subq r17, 1, r1 # start checking for power of 2
+ and r17, r1, r0 # finish check for power of 2
+ sra r16, 63, r19 # get -1/0 if dividend was negative
+ negq r16, r18 # first part of abs(dividend)
+ cmovlt r16, r18, r16 # second part of abs(dividend)
+ beq r0, ri_pwr2 # for powers of two, simply do a mask (not power of 2 include 0 and 80000000)
+ lda r28, -table_max(r17) # test for table lookup
+ bgt r28, ri_lrgdiv # branch if large divisor
+ addq r17, r17, r0 # compute divisor*2 for table lookup
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ ldq r1, recip32_o(r27) # load approximate reciprocal
+ umulh r16, r1, r0 # multiplication for division step
+ mull r0, r17, r0 # multiply back to get value to subtract
+ subl r16, r0, r0 # get abs of final result
+ xor r0, r19, r0 # start compliment if original dividend was <0
+ subl r0, r19, r0 # finish compliement
+ ret r31, (r26) # and return
+
+ # Handle powers of 2, including 0 and 80000000
+ri_pwr2:
+ and r16, r1, r0 # use the divisor-1 mask in r1
+ beq r17, divzer # division by zero
+ xor r0, r19, r0 # start compliment if original dividend was <0
+ subl r0, r19, r0 # finish compliement
+ ret r31, (r26)
+
+ nop
+ri_lrgdiv:
+ bsr r28, div32 # use the core routine getting the remainder in r1
+ xor r1, r19, r0 # start compliment if original dividend was <0
+ subl r0, r19, r0 # finish compliement
+ ret r31, (r26)
+
+
+ # int ots_div_i_o(int dividend, int divisor)
+ # signed 32 bit division support, overflow detection
+ #
+ #.align 4
+ .globl _OtsDivide32Overflow
+ .aent _OtsDivide32Overflow
+_OtsDivide32Overflow:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_i_o>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ not r17, r1 # is the divisor -1?
+ bne r1, di_skip # continue if not
+ neglv r16, r0 # quotient = -dividend, overflow on ^x800000000
+ ret r31, (r26)
+
+ # int ots_div_i(int dividend, int divisor)
+ # signed 32 bit division support, no overflow detection
+ #
+ nop #.align 4
+ .globl _OtsDivide32
+ .aent _OtsDivide32
+_OtsDivide32:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_i>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+di_skip:
+di_retry:
+ lda r28, -table_max(r17) # test for table lookup
+ ble r17, di_notpos # not a positive divisor case
+ addq r17, r17, r0 # compute divisor*2
+ negq r16, r18 # part 1 of abs(dividend) -> r18. (Note 0xffffffff 80000000 => 0x00000000 80000000)
+ bgt r28, di_lrgdiv # branch if large divisor
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ cmpule r17, r18, r0 # divisor <= dividend?
+ cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18
+ beq r0, di_end # if not, result is zero
+ ldq r1, recip32_o(r27) # load approximate reciprocal
+ blt r1, di_smpwr2 # go handle powers of 2 specially
+ umulh r18, r1, r0 # start multiplication
+ blt r16, di_negres # negate result? (done as a branch to allow umulh to "hang out" over end for common case)
+di_end: ret r31, (r26) # return for same-sign (common) case
+di_negres:
+ negl r0, r0 # different signs - compliment result
+ ret r31, (r26) # return for different-sign (uncommon) case
+di_smpwr2:
+ srl r18, r1, r18 # shift the result into place
+ sra r16, 63, r16 # get 0/-1 based on sign of dividend
+ xor r18, r16, r18 # conditionally compliment
+ subl r18, r16, r0 # and increment for the final value
+ ret r31, (r26) # (note subl is required for sign ext for %x80000000/1 case)
+
+ # Zero or negative divisor case. If just a negative divisor,
+ # compliment both dividend and divisor and do things again.
+di_notpos:
+ beq r17, divzer # division by zero
+ negl r17, r17 # |divisor|, note that 0x80000000 still appears negative
+ negq r16, r16 # compliment dividend (negq so that 0xffffffff 80000000 => 0x00000000 80000000
+ bgt r17, di_retry # dispatch back for normal case (not 0x80000000 or 0)
+ sextl r16, r16 #
+ cmpeq r16, r17, r0 # -maxint/-maxint = 1, all others 0
+ ret r31, (r26) # done
+
+ # Large divisor for signed 32/32 case
+ #
+ nop #.align 3
+di_lrgdiv:
+ sra r16, 63, r19 # get 0/-1 based on sign of dividend
+ cmovlt r16, r18, r16 #
+ bsr r28, div32 # go use core routine
+ xor r0, r19, r0 # conditionally compliment
+ subl r0, r19, r0 # and increment for the final value (subl ensures normalized result)
+ ret r31, (r26) # done
+
+
+ # Large divisor case core routine for 32b
+ # (wbn)
+ #
+ # r0 - quotient (output)
+ # r1 - remainder (output)
+ # r16 - dividend (range 0..2^32-1, zero extended)
+ # r17 - divisor (range 1..2^31-1 - overwritten)
+ # r18 - scratch
+ # r19 - not used (one temp for 'caller')
+ # r26 - not used (expected to contain main return address)
+ # [r27 - scratch] (not currently written)
+ # r28 - this "subroutine" return address
+ #
+ # Some tightened up bit-at-a-time code for dividing 32-bit integers.
+ # It uses two tricks: keep the running remainder and the quotient in
+ # the same 64-bit register (MQ?), and add 1 while subtracting the divisor,
+ # so that a single CMOV sets both the new remainder and the new quotient.
+ # I start off by trying to skip 8 bits at a time; should this skip a
+ # smaller amount, so the main loop iterates less often? If the divisor
+ # is already known to be large enough, the last case in this test is never
+ # used...
+ #
+ # This code expects as input two integers in the range 0 <= x < 2^31
+ # (that is, it doesn't work for general unsigned longwords, and doesn't
+ # include sign manipulation.)
+ #
+ # The code here takes about 34n+11 cycles for a quotient occupying n bytes.
+ #
+ # Inputs: dividend in r16, divisor in r17
+ # Outputs: quotient in r0, remainder in r1
+ # Destroys: [r16,]r17,r18,[r27]
+ #
+ # How many quotient bytes will there be: 0, 1, 2, 3, 4?
+ #
+ #.align 4
+div32: cmpule r17, r16, r0 # Divisor leq dividend?
+ sll r17, 32, r18 # Position divisor for loop
+ sll r17, 8, r1 # Prepare for next compare
+ beq r0, d32end # Dividend less, quotient is zero.
+ediv32: mov 8-3, r17 # Hope to skip 3 bytes of loop
+ cmpule r1, r16, r0 # Shifted divisor still leq dividend?
+ sll r1, 8, r1 # Prepare for next compare
+ beq r0, d32ent # Go loop over just one byte
+ mov 8-2, r17 # Hope to skip 2 bytes of loop
+ cmpule r1, r16, r0 # Shifted divisor still leq dividend?
+ sll r1, 8, r1 # Prepare for next compare
+ beq r0, d32ent # Go loop over just two bytes
+ mov 8-1, r17 # Hope to skip 1 byte of loop
+ cmpule r1, r16, r0 # Shifted divisor still leq dividend?
+ nop # stall - align d32ent and d32loop
+ cmovne r0, 8, r17 # If we can't skip any bytes
+
+ # start loop generating quotient bits. NOTE: The loop setup requires
+ # an even number of iterations.
+ #
+d32ent: extqh r16, r17, r0 # Shift dividend left for skipped bytes
+ subq r18, 1, r1 # Divisor in high LW - 1 in low LW
+ s8subq r17, 34, r17 # Convert bytes to bits and adjust
+
+ addq r0, r0, r0 # Shift left to start first iteration
+d32loop:subq r0, r1, r18 # Can we subtract divisor from it?
+ cmovge r18, r18, r0 # If so, set new remainder & quotient
+ # stall
+ addq r0, r0, r0 # Shift remainder and quotient left
+ subq r0, r1, r18 # Can we subtract divisor from it?
+ cmovge r18, r18, r0 # If so, set new remainder & quotient
+ subq r17, 2, r17 # Loop counter
+ addq r0, r0, r0 # Shift remainder and quotient left
+ bgt r17, d32loop # Repeat
+ subq r0, r1, r18 # Can we subtract divisor from it?
+ cmovge r18, r18, r0 # If so, set new remainder & quotient
+ # stall
+ addq r0, r0, r0 # Shift remainder and quotient left
+ subq r0, r1, r18 # Finish last iteration
+ cmovge r18, r18, r0
+ # stall
+ srl r0, 32, r1 # Get remainder in r1
+ zap r0, 0xf0, r0 # Keep only quotient in r0
+ nop # for alignment
+d32end: cmoveq r0, r16, r1 # Move remainder to r1 for quotient=0 case
+ ret r31, (r28) # Not a real software procedure return
+
+
+ # Large divisor case core routine for 64b
+ #
+ # r0 - quotient (output)
+ # r1 - remainder (output)
+ # r16 - dividend (range 0..2^64-1 - overwritten)
+ # r17 - divisor (range 1..2^63-1 - overwritten)
+ # r18 - scratch
+ # r19 - not used (one temp for 'caller')
+ # r26 - not used (expected to contain main return address)
+ # r27 - points to table of inverses (overwritten)
+ # r28 - this "subroutine" return address
+ #
+ # Inputs: dividend in r16, divisor in r17
+ # Outputs: quotient in r0, remainder in r1
+ # Destroys: r16,r17,r18,r27
+ #
+ # Note- this routine could save a few cycles if we could use
+ # another scratch register -- perhaps by pushing one on the stack?
+ #
+ #.align 4
+div64: sll r17, 32, r18 # Position for ediv32
+ cmpule r17, r16, r0 # Is divisor leq dividend?
+ srl r17, 31, r1 # Is divisor geq 2^31?
+ beq r0, d64end # If divisor > dividend, quotient=0
+ cmpule r18, r16, r0 # Is divisor*2^32 leq dividend?
+ sll r17, 8, r1 # Position for ediv32 checking
+ or r1, r0, r0 # 0 if divisor & quotient fit in 32 bits
+ beq r0, ediv32 # Use 32-bit routine if OK
+
+ # Full 64-bit divide needed. Use the table of shift amounts to compute
+ # the number of leading zero bits in the divisor. Find the leftmost
+ # nonzero byte, then the leftmost nonzero bit in that byte. Table entry
+ # #n+1 contains the number of bits needed to hold n (1..8). We know the
+ # divisor is nonzero here.
+ #
+ cmpbge r31, r17, r0 # Get a zero bit for each nonzero byte
+ #stall
+ sll r0, 4, r0 # *16 bytes per table entry
+ #stall
+ subq r27, r0, r0 # table base plus complement...
+ #stall
+ ldq r1, 256*16(r0) # get position of first nonzero
+ #2 stalls
+ subq r1, 1, r1 # byte number of first nonzero
+ extbl r17, r1, r0 # get first nonzero byte
+ #stall
+ addq r0, r0, r0 # *2
+ s8addq r0, r27, r0 # *16 bytes per table entry
+ #stall
+ ldq r0, 16(r0) # bit number of first nonzero
+ negq r1, r1 # 1 + #leading zero bytes (mod 8)
+ #stall
+ s8subq r1, r0, r0 # number of leading zero bits
+ and r0, 0x3F, r0 # discard other junk
+
+ # The following code does a similar normalize calculation without the table.
+ #===
+ # extll r17, #4, r18 ; Normalize the divisor and
+ # mov #63, r0 ; count leading zeros
+ # cmovne r18, #31, r0
+ # cmoveq r18, r17, r18
+ # ;stall
+ # extwl r18, #2, r1
+ # ;stall
+ # cmovne r1, r1, r18
+ # cmovne r1, #16, r1
+ # ;stall
+ # subq r0, r1, r0
+ # extbl r18, #1, r1
+ # ;stall
+ # cmovne r1, r1, r18
+ # cmovne r1, #8, r1
+ # ;stall
+ # subq r0, r1, r0
+ # andnot r18, #^x0f, r1
+ # cmovne r1, r1, r18
+ # cmovne r1, #4, r1
+ # ;stall
+ # subq r0, r1, r0
+ # andnot r18, #^x33, r1
+ # cmovne r1, r1, r18
+ # cmovne r1, #2, r1
+ # ;stall
+ # subq r0, r1, r0
+ # andnot r18, #^x55, r1
+ # cmovne r1, #1, r1
+ # ;stall
+ # subq r0, r1, r0
+ #===
+
+ # R0 contains number of leading zero bits in the divisor.
+
+ sll r17, r0, r17 # Normalize: MSB is set.
+
+ # Now break divisor into pieces a+x, where a is the leading
+ # 9 bits, rounded, and x is the rest. Use a linear
+ # approximation for 1/divisor = 1/a - x/a^2 [+ x^2/a^3 -...]
+ #
+ srl r17, 64-10, r1 # Keep 10 bits of divisor
+ #stall
+ addq r1, 1, r1 # Round to form 'a'
+ andnot r1, 1, r1
+ s8addq r1, r27, r27 # Index table of 1/a and 1/a^2
+ sll r1, 64-10, r1 # shift 'a' to match divisor
+ ldq r18, (r27) # Load QW containing 1/a^2
+ subq r1, r17, r1 # -x = a - divisor
+ beq r1, d64_easy # Use table directly if x=0
+ inswl r18, 6, r18 # position 1/a^2
+ blt r1, d64_sub # correct for sign of -x
+ umulh r1, r18, r1 # -x/a^2
+ ldq r27, 8(r27) # Load QW containing 1/a - 1
+ br r31, d64_cont
+
+d64_sub:umulh r1, r18, r1 # -x/a^2
+ ldq r27, 8(r27) # load QW containing 1/a - 1
+ # 2 stalls
+ s4addq r18, 0, r18
+ subq r27, r18, r27 # correct for sign of -x
+d64_cont:
+ # many stalls
+ s4addq r1, r27, r18 # 1/divisor approx= 1/a - x/a^2
+
+ # Now one or two Newton iterations to get 24 or 56 good bits of the inverse.
+ # Each computes inv = inv * (2 - inv*divisor). We could skip out early
+ # here or above if the dividend and/or quotient is small enough for the
+ # amount of precision we've developed...
+ #
+ # We handle quadwords with the radix point on the left. The divisor has
+ # been normalized to the range 0.5 < divisor < 1.0; the inverses are in
+ # the range 1.0 < inverse < 2.0, and are represented without the leading 1.
+ #
+ umulh r18, r17, r1 # (inv0 - 1) * divisor
+ # many stalls
+ addq r1, r17, r1 # add hidden bit * divisor
+ negq r1, r1 # 2 - inv0*divisor, very near 1.0
+ umulh r18, r1, r27 # (inv0 - 1) * (2 - inv0*divisor)
+ cmovlt r1, 0, r18 # keep inv0 if (2-inv0*divisor) > 1.0
+ #stall
+ addq r18, r1, r1 # add it to hidden bit * (2-inv0*divisor)
+ # many stalls
+ addq r27, r1, r18 # inv1 = inv0 * (2 - inv0*divisor)
+
+ umulh r18, r17, r1 # (inv1 - 1) * divisor
+ # many stalls
+ addq r1, r17, r1 # add hidden bit * divisor
+ negq r1, r1 # 2 - inv1*divisor, very near 1.0
+ umulh r18, r1, r27 # (inv1 - 1) * (2 - inv1*divisor)
+ cmovlt r1, 0, r18 # keep inv1 if (2-inv1*divisor) > 1.0
+ addq r18, r1, r1 # add it to hidden bit * (2-inv1*divisor)
+ # many stalls
+ addq r27, r1, r1 # inverse = inv1 * (2 - inv1*divisor)
+ umulh r1, r16, r18 # dividend * (1/divisor - 1)
+ srl r17, r0, r17 # un-normalize divisor
+ negq r0, r0
+ subq r0, 8, r0 # how far right after first byte
+ # many stalls
+ addq r18, r16, r18 # add hidden bit * dividend
+ cmpult r18, r16, r1 # did it carry?
+ srl r18, 8, r18 # start to shift
+ sll r1, 56, r1 # position the carry
+ #stall
+ addq r1, r18, r1 # add the carry
+ srl r1, r0, r0 # final shift
+ mulq r17, r0, r1 # try out this quotient
+ # many stalls
+ subq r16, r1, r1 # form remainder
+ cmpule r17, r1, r18 # must be less than divisor
+ subq r1, r17, r27
+ cmovne r18, r27, r1 # if not, decrement remainder
+ addq r0, r18, r0 # and increment quotient
+ ret r31, (r28) # done
+
+d64_easy:
+ ldq r1, 8(r27) # get 1/divisor, except hidden bit
+ srl r17, r0, r17 # un-normalize divisor again
+ blt r18, d64_pow2 # skip if power of 2
+ umulh r1, r16, r18 # dividend/divisor
+ negq r0, r0 # how far right to shift
+ and r16, 0x0ff, r1 # pieces of dividend
+ subq r0, 8, r0 # how far right after first byte
+ srl r16, 8, r27
+ # many stalls
+ addq r18, r1, r1 # add low piece of dividend, no carry
+ srl r1, 8, r1 # make room for high piece
+ #stall
+ addq r1, r27, r1 # finish adding hidden bit * dividend
+ srl r1, r0, r0 # final shift
+ mulq r17, r0, r1 # need to compute remainder too
+ # many stalls
+ subq r16, r1, r1
+ ret r31, (r28) # done
+
+d64_pow2:
+ not r0, r0 # how far right to shift quotient
+ subq r17, 1, r1 # mask for remainder
+ srl r16, r0, r0 # shift for quotient
+ and r16, r1, r1 # get remainder
+ ret r31, (r28) # done
+
+d64end: mov r16, r1 # Remainder to r1 for small quotient case
+ ret r31, (r28) # Not a real software procedure return
+
+ # long ots_div_l_o(long dividend, long divisor)
+ # signed 64 bit division support, overflow detection
+ #
+ #.align 4
+ .globl _OtsDivide64Overflow
+ .aent _OtsDivide64Overflow
+_OtsDivide64Overflow:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_l_o>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ not r17, r1 # is the divisor -1?
+ bne r1, dl_skip # continue if not
+ negqv r16, r0 # q = -dividend, oflow on ^x800000000 00000000
+ ret r31, (r26)
+ nop
+
+ # long ots_div_l(long dividend, long divisor)
+ # signed 64 bit division support, no overflow detection
+ #
+ .globl _OtsDivide64
+ .aent _OtsDivide64
+_OtsDivide64:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_l>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+dl_skip:
+ xor r16, r17, r19 # sign bit = result needs to be complimented (here to handle -maxint correctly)
+dl_retry:
+ lda r28, -table_max(r17) # test for table lookup
+ ble r17, dl_notpos # not a positive divisor case
+ addq r17, r17, r0 # compute divisor*2
+ negq r16, r18 # part 1 of abs(dividend) -> r18
+ bgt r28, dl_lrgdiv # branch if large divisor
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ srl r16, 33, r1 # can this be handled via a 32 bit case?
+ cmpule r17, r18, r0 # divisor <= dividend?
+ bne r1, dl_64bit # does this need to be a real 64 bit case?
+ cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18
+ beq r0, dl_end # if not, result is zero
+ ldq r27, recip32_o(r27) # load 32b approximate reciprocal
+ sra r19, 63, r19 # get 0/-1
+ blt r27, dl_smpwr2 # skip umulh for powers of 2 specially
+ umulh r18, r27, r0 # start multiplication
+ beq r19, dl_end # if compliment not required, let umulh "hang out"
+ negq r0, r0 # compliment case
+ ret r31, (r26) #
+dl_64bit:
+ cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18
+ beq r0, dl_end # if not, result is zero
+ ldq r1, recip64_o(r27) # load approximate reciprocal
+ sra r19, 63, r19 # get 0/-1
+ ldq r27, shift_o(r27) # load shift count (low 6 bits are all that matters)
+ beq r1, dl_smpwr2 # skip umulh for powers of 2 specially
+ umulh r18, r1, r0 # start multiplication
+ addq r0, r18, r18 # add hidden bit
+dl_smpwr2:
+ srl r18, r27, r18 # shift the result into place
+ xor r18, r19, r18 # conditionally compliment
+ subq r18, r19, r0 # and increment for the final value
+dl_end: ret r31, (r26) #
+
+ # Zero or negative divisor case. If just a negative divisor,
+ # compliment both dividend and divisor and do things again.
+dl_notpos:
+ beq r17, divzer # division by zero
+ negq r17, r17 # |divisor|, note that 0x80000000 00000000 still appears negative
+ negq r16, r16 # compliment dividend
+ bgt r17, dl_retry # dispatch back for normal case (not 0x80000000 00000000 or 0)
+ cmpeq r16, r17, r0 # -maxint/-maxint = 1, all others 0
+ ret r31, (r26) # done
+
+ # Large divisor for signed 64/64 case
+ #
+dl_lrgdiv:
+ sra r19, 63, r19 # get 0/-1
+ cmovlt r16, r18, r16 #
+ bsr r28, div64 # go use core routine
+ xor r0, r19, r0 # conditionally compliment
+ subq r0, r19, r0 # and increment for the final value
+ ret r31, (r26) # done
+
+
+ # long ots_rem_l(long dividend, long divisor)
+ # signed 64 bit remainder support
+ #
+ #.align 4
+ .globl _OtsRemainder64
+ .aent _OtsRemainder64
+_OtsRemainder64:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_rem_l>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ negq r17, r18 # first part of abs(divisor)
+ cmovlt r17, r18, r17 # second part of abs(divisor)
+ subq r17, 1, r1 # start checking for power of 2
+ and r17, r1, r0 # finish check for power of 2
+ sra r16, 63, r19 # get -1/0 if dividend was negative
+ negq r16, r18 # first part of abs(dividend)
+ cmovlt r16, r18, r16 # second part of abs(dividend)
+ beq r0, rl_pwr2 # for powers of two, simply do a mask (not power of 2 include 0 and 80000000)
+ lda r28, -table_max(r17) # test for table lookup
+ bgt r28, rl_lrgdiv # branch if large divisor
+ addq r17, r17, r0 # compute divisor*2 for table lookup
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ ldq r1, recip64_o(r27) # load approximate reciprocal
+ ldq r18, shift_o(r27) # load shift amount
+ umulh r16, r1, r0 # multiplication for division step
+ addq r0, r16, r0 # add hidden bit
+ srl r0, r18, r0
+ mulq r0, r17, r0 # multiply back to get value to subtract
+ subq r16, r0, r0 # get abs of final result
+ xor r0, r19, r0 # start compliment if original dividend was <0
+ subq r0, r19, r0 # finish compliement
+ ret r31, (r26) # and return
+
+ # Handle powers of 2, including 0 and 80000000 00000000
+rl_pwr2:
+ negq r16, r18 # first part of abs(dividend)
+ cmovlt r16, r18, r16 # second part of abs(dividend)
+ and r16, r1, r0 # use the divisor-1 mask in r1
+ beq r17, divzer # division by zero
+ xor r0, r19, r0 # start compliment if original dividend was <0
+ subq r0, r19, r0 # finish compliement
+ ret r31, (r26)
+
+rl_lrgdiv:
+ bsr r28, div64 # use the core routine getting the remainder in r1
+ xor r1, r19, r0 # start compliment if original dividend was <0
+ subq r0, r19, r0 # finish complement
+ ret r31, (r26)
+
+ # long ots_mod_l(long dividend, long modulus)
+ # signed 64 bit modulus support
+ #
+ # This entry could be MUCH more optimized. It doesn't even try to use
+ # UMULH division currently... (A casualty of time-to-market.)
+ # Note that mod is only used by Ada and PL/I.
+ #
+ #.align 4
+ .globl _OtsModulus64
+ .aent _OtsModulus64
+_OtsModulus64:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_rem_l>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ negq r17, r18 # first part of abs(divisor)
+ cmovge r17, r17, r18 # second part of abs(divisor)
+ subq r18, 1, r1 # start checking for power of 2
+ beq r17, divzer # check for 0
+ and r18, r1, r0 # second part of power-of-2 check
+ beq r0, ml_p2 # for powers of two, simply do a mask
+ # (note that the power-of-2 case MUST be used to handle
+ # the -maxint case due to the way the fix-up info is
+ # saved across the core routine call)
+ xor r16, r17, r28 # get xor of signs
+ clr r19 # don't need a bias if dividend and divisor have same sign
+ cmovlt r28, r17, r19 # bias is original divisor for different sign case
+ and r16, r17, r28 # if both dividend & divisor were neg. need to negate result
+ mov r18, r17 # move abs(divisor) into r17
+ negq r16, r18 # first part of abs(dividend)
+ cmovlt r16, r18, r16 # second part of abs(dividend)
+ cmplt r28, r31, r0 # get 1 if both operands were <0
+ sll r0, 63, r0 # get bit as the high bit
+ bis r0, r19, r19 # and MERGE with bias (0 -> no fixup, -maxint -> negate result,
+ # divisor > 0 - subtract remainder if non-zero, divisor < 0 -
+ # add remainder if non-zero)
+ bsr r28, div64 # use the core routine getting the remainder in r1
+ cmoveq r1, r31, r19 # don't do any fix-up if the remainder was zero
+ addq r19, r19, r18 # check to see if this is the negative/negative case, which just gets a negated remainder
+ subq r19, 1, r28 # wrap -maxint to positive
+ negq r1, r0 # move negated value, may abort later
+ cmovlt r28, r1, r0 # if both positive, or negative divisor, keep positive remainder
+ cmoveq r18, r31, r19 # now that negation is done, treat -maxint case as 0
+ addq r19, r0, r0 # add any bias (original divisor or 0)
+ ret r31, (r26) # and return
+
+ml_p2: cmovge r17, r31, r17 # no bias if divisor was >= 0
+ and r16, r1, r1 # use the divisor-1 mask that's already in r1
+ cmoveq r1, r31, r17 # use zero if result was zero
+ addq r17, r1, r0 # do any biasing
+ ret r31, (r26) # and return
+
+
+ # unsigned long ots_div_ul(unsigned long dividend, unsigned long divisor)
+ # unsigned 64 bit division support
+ #
+ nop #.align 4
+ .globl _OtsDivide64Unsigned
+ .aent _OtsDivide64Unsigned
+_OtsDivide64Unsigned:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_div_ul>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ lda r28, -table_max(r17) # test for table lookup
+ blt r17, dul_big # big divisors can (must) be handled by a simple comparison
+ addq r17, r17, r18 # compute divisor*2
+ srl r16, 33, r19 # can this be handled via the fast path for 31 bit dividends?
+ beq r17, divzer # check for 0
+ s8addq r18, r27, r18 # finish computing table entry addr (table addr+divisor*16)
+ bgt r28, dul_lrgdiv # branch if large divisor
+ cmpule r17, r16, r0 # is the dividend < divisor?
+ bne r19, dul_64bit # if the dividend doesn't fit in 31 bits, use the larger umulh form
+ ldq r27, recip32_o(r18) # load approximate 32b reciprocal & shift count
+ beq r0, dul_end # fast out for divisor > dividend
+ blt r27, dul_smpwr2 # go handle powers of 2 specially
+ umulh r16, r27, r0 # 32b recip
+ ret r31, (r26) #
+
+ # the 64 bit case is at a disadvantage to the 32b case because it needs
+ # a fix-up at the end, which prevents the latency of the umulh from
+ # being partially absorbed by the procedure return and anything that
+ # immediately follows that doesn't interlock.
+ nop
+dul_64bit:
+ ldq r1, recip64_o(r18) # load approximate 64b reciprocal
+ ldq r27, shift_o(r18) # load shift count (low 6 bits are all that matters)
+ beq r0, dul_end # fast out for divisor > dividend
+ beq r1, dul_smpwr2 # go handle powers of 2 specially
+ umulh r16, r1, r0 # start multiplication for division step
+ zap r16, 0x0f, r18 # split dividend into two parts
+ zapnot r16, 0x0f, r16
+ srl r18, r27, r18 # position the high part
+ addq r0, r16, r0 # add hidden * low dividend (no carry)
+ srl r0, r27, r0 # shift into place
+ addq r0, r18, r0 # add hidden * high dividend
+ ret r31, (r26)
+
+dul_smpwr2:
+ srl r16, r27, r0 # shift the result into place
+dul_end: ret r31, (r26) #
+
+dul_lrgdiv:
+ bsr r28, div64 # use the core routine
+ ret r31, (r26)
+
+ # divisor with the sign bit set. two possible results,
+ # 1 if divisor <= dividend, or 0 otherwise
+dul_big:
+ cmpule r17, r16, r0
+ ret r31, (r26)
+
+
+ # long unsigned ots_rem_ul(long unsigned dividend, long unsigned divisor)
+ # unsigned 64 bit remainder support
+ #
+ #.align 4
+ .globl _OtsRemainder64Unsigned
+ .aent _OtsRemainder64Unsigned
+_OtsRemainder64Unsigned:
+#ifdef VMS
+ ldq r27, <ots_div_addr-ots_rem_ul>(r27)# start loading address of division data area
+#endif
+#ifdef OSF
+ ldgp gp, 0(r27) # load the global pointer
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # start loading address of the division data area
+#endif
+#ifdef WNT
+ .frame sp, 0, r26
+ lda r27, _OtsDivData # load the division data table address
+#endif
+ lda r28, -table_max(r17) # test for table lookup
+ subq r17, 1, r1 # first part of power-of-2 check
+ blt r17, rul_big # big divisors can (must) be handled by a simple comparison
+ and r17, r1, r18 # second part of power-of-2 check
+ bgt r28, rul_lrgdiv # branch if large divisor
+ addq r17, r17, r0 # compute divisor*2 for table lookup
+ beq r18, rul_pwr2 # if zero, divisor is a power of 2
+ s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16)
+ ldq r1, recip64_o(r27) # load approximate reciprocal
+ cmpult r16, r17, r18 # is the dividend < divisor?
+ bne r18, rul_lss # if so, fast exit
+ ldq r19, shift_o(r27) # load the shift count
+ umulh r16, r1, r0 # multiplication for division step
+ blt r16, rul_carry # careful handling if >= 2^63
+ addq r0, r16, r0 # add hidden bit * dividend
+ srl r0, r19, r0
+ mulq r0, r17, r0 # multiply back to get value to subtract
+ subq r16, r0, r0
+ ret r31, (r26) # and return
+
+rul_carry:
+ zap r16, 0x0f, r18 # split dividend into two parts
+ zapnot r16, 0x0f, r1
+ srl r18, r19, r18 # position the high part
+ addq r0, r1, r0 # add hidden * low dividend (no carry)
+ srl r0, r19, r0 # shift into place
+ addq r0, r18, r0 # add hidden * high dividend
+ mulq r0, r17, r0 # multiply back to get value to subtract
+ subq r16, r0, r0
+ ret r31, (r26)
+
+rul_pwr2:
+ beq r17, divzer # check for 0
+ and r16, r1, r0 # use x-1 to mask
+ ret r31, (r26)
+
+rul_lss:
+ mov r16, r0
+ ret r31, (r26)
+
+ # divisors with the sign bit set. two possible results,
+ # dividend if dividend < divisor, or dividend-divisor otherwise
+rul_big:
+ cmpult r16, r17, r1
+ subq r16, r17, r0
+ cmovne r1, r16, r0
+ ret r31, (r26)
+
+ nop
+rul_lrgdiv:
+ bsr r28, div64 # use the core routine getting the remainder in r1
+ mov r1, r0 # return remainder as the result in r0
+ ret r31, (r26)
+
+
+ # Division-by-zero handling
+ # (forward branch from all routines, out of the way here as well.)
+ #
+divzer: lda r16, GEN_INTDIV(r31) # load GENTRAP code for division by zero
+ clr r0 # return 0 for the result
+ clr r1 #
+#ifdef VMS
+ gentrap # signal the error
+#endif
+#ifdef OSF
+ call_pal PAL_gentrap
+#endif
+#ifdef WNT
+ # Since I couldn't find this in a header file anywhere for NT...
+#define PAL_gentrap 0xaa
+ call_pal PAL_gentrap
+#endif
+ ret r31, (r26) # return (in case someone tries to continue)
+
+ .set at
+ .set reorder
+ .end _OtsDiv
diff --git a/private/crt32/misc/alpha/otsjmp.s b/private/crt32/misc/alpha/otsjmp.s
new file mode 100644
index 000000000..9c49751f9
--- /dev/null
+++ b/private/crt32/misc/alpha/otsjmp.s
@@ -0,0 +1,117 @@
+// TITLE("Set Jump")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// otsjmp.s
+//
+// Abstract:
+//
+// This module implements the Alpha C8/GEM C compiler specific routine to
+// perform a setjmp.
+//
+// N.B. This module conditionally provides UNSAFE handling of setjmp and
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an uninitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// Thomas Van Baak (tvb) 22-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe or unsafe with
+// respect to structured exception handling.
+//
+
+ .globl _Otssetjmpexused
+ .comm _Otssetjmpexused, 4
+
+ SBTTL("Set Jump - GEM version")
+//++
+//
+// int
+// _Otssetjmp3 (
+// IN OUT jmp_buf JumpBuffer,
+// IN PVOID RealFramePointer,
+// IN PVOID SebPointer
+// )
+//
+// Routine Description:
+//
+// This function saves the current nonvolatile register state in the
+// specified jump buffer and returns a function value of zero.
+//
+// N.B. The name `_Otssetjmp3' was chosen to avoid collision with an
+// earlier implementation named _Otssetjmp. This version has three
+// arguments.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// RealFramePointer (a1) - Supplies the real frame pointer value.
+//
+// SebPointer (a2) - Supplies the pointer to the current SEB or NULL
+// if the call was made outside of any SEH scope.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY(_Otssetjmp3)
+
+ ldl v0, _Otssetjmpexused // get value of switch variable
+ bne v0, 10f // if ne, provide safe setjmp
+
+//
+// Provide unsafe handling of setjmp.
+//
+
+ stt f2, JbFltF2(a0) // save floating registers f2 - f9
+ stt f3, JbFltF3(a0) //
+ stt f4, JbFltF4(a0) //
+ stt f5, JbFltF5(a0) //
+ stt f6, JbFltF6(a0) //
+ stt f7, JbFltF7(a0) //
+ stt f8, JbFltF8(a0) //
+ stt f9, JbFltF9(a0) //
+
+ stq s0, JbIntS0(a0) // save integer registers s0 - s6/fp
+ stq s1, JbIntS1(a0) //
+ stq s2, JbIntS2(a0) //
+ stq s3, JbIntS3(a0) //
+ stq s4, JbIntS4(a0) //
+ stq s5, JbIntS5(a0) //
+ stq fp, JbIntS6(a0) //
+
+ ldil t0, 1 // get unsafe setjmp flag
+ stl t0, JbType(a0) // set jump buffer context type
+ stq sp, JbIntSp(a0) // save stack pointer
+ stq ra, JbFir(a0) // get setjmp return address
+
+ mov zero, v0 // set zero return value
+ ret zero, (ra) // return
+
+//
+// Provide safe handling of setjmp.
+//
+
+10: jmp zero, (v0) // finish in _setjmpex code
+
+ .end _Otssetjmp3
diff --git a/private/crt32/misc/alpha/otsjmpex.s b/private/crt32/misc/alpha/otsjmpex.s
new file mode 100644
index 000000000..eaf78190b
--- /dev/null
+++ b/private/crt32/misc/alpha/otsjmpex.s
@@ -0,0 +1,84 @@
+// TITLE("Set Jump Extended")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// otsjmpex.s
+//
+// Abstract:
+//
+// This module implements the Alpha C8/GEM C compiler specific routine to
+// provide SAFE handling of setjmp/longjmp with respect to structured
+// exception handling.
+//
+// Author:
+//
+// Thomas Van Baak (tvb) 22-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe with respect
+// to structured exception handling.
+//
+
+ .globl _Otssetjmpexused
+ .data
+_Otssetjmpexused:
+ .long _Otssetjmpex3 // set address of safe setjmp routine
+
+ SBTTL("Set Jump Extended - GEM version")
+//++
+//
+// int
+// _Otssetjmpex3 (
+// IN OUT jmp_buf JumpBuffer,
+// IN PVOID RealFramePointer,
+// IN PVOID SebPointer
+// )
+//
+// Routine Description:
+//
+// This function implements a safe setjmp.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// RealFramePointer (a1) - Supplies the real frame pointer value.
+//
+// SebPointer (a2) - Supplies the pointer to the current SEB or NULL
+// if the call was made outside of any SEH scope.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY(_Otssetjmpex3)
+
+//
+// Save the given set jump context in the jump buffer.
+//
+
+ stl a1, JbFp(a0) // save real frame pointer
+ stl ra, JbPc(a0) // save target instruction address
+ stl a2, JbSeb(a0) // save SEB pointer
+ ldil t0, 3 // get GEM safe setjmp flag
+ stl t0, JbType(a0) // set jump buffer context type
+ mov zero, v0 // set return value
+ ret zero, (ra) // return
+
+ .end _Otssetjmpex3
diff --git a/private/crt32/misc/alpha/otsnote.txt b/private/crt32/misc/alpha/otsnote.txt
new file mode 100644
index 000000000..af99f6697
--- /dev/null
+++ b/private/crt32/misc/alpha/otsnote.txt
@@ -0,0 +1,115 @@
+Alpha AXP MSCGEM OTS C run-time library notes.
+
+- The following OTS source files were obtained from Kent Glossop on
+ 27-Jan-1993. I believe the version number is X1.0-4.
+
+ div.s
+ divdat.s
+
+ extv.s
+ extvvol.s
+ extzv.s
+ extzvvol.s
+
+ insv.s
+ insvvol.s
+
+ ots_as.hs
+ ots_defs.hs
+
+ scmpeql.s
+ scmpeqlp.s
+ scmpleq.s
+ scmpleqp.s
+ scmplss.s
+ scmplssp.s
+
+ sfill.s
+ sloc.s
+ smove.s
+ smovem.s
+ strans.s
+ szero.s
+
+- The six strcmp/cpy/len functions were obtained through Rich Peterson
+ on 25-Jan-1993.
+
+ strcmp.s
+ strcmp_.s
+ strcpy.s
+ strcpy_.s
+ strlen.s
+ strlen_.s
+
+- For now, and in the interest of maintenance, we have left the source
+ files intact in spite of the fact that they don't follow conventions
+ of all other NT/Alpha assembler code.
+
+- The following files had a non-ascii 0xa9 character instead of a (c)
+ in the copyright line. These have been fixed so slm works right.
+
+ scmpeql.s
+ scmpeqlp.s
+ scmpleq.s
+ scmpleqp.s
+ scmplss.s
+ scmplssp.s
+ sloc.s
+ strans.s
+
+- The goal is to provide compatible C runtime support for both acc and
+ GEM compilers through the existing NT C libraries.
+
+- Both compilers, header files, runtime libraries, and object files are
+ compatible with each other now, with these exceptions:
+
+ o The setjmp/longjmp functions are not compatible since the data in
+ the jump buffer differs between the two compilers. SEH is 100%
+ compatible, however.
+
+ o Calls to setjmp would actually work with acc even if setjmp.h was
+ not included. With GEM, the include file is required for proper
+ operation.
+
+ o As of 930205, small structures are still passed and returned by
+ value incompatibly between the two compilers. This will be fixed
+ by upgrading acc to follow the GEM calling standard, and/or by
+ using a GEM switch to be acc compatible.
+
+ o The above is not quite correct: as of 930217, GEM is using an option
+ to follow the acc convention, not the calling standard convention.
+ It looks like both acc and GEM will have options to handle small
+ structures both ways.
+
+- The str functions will conflict with the portable versions in the
+ ..\string directory. The portable ones should be #ifdef'ed out for
+ Alpha.
+
+- The two or three different versions of divide routines may get
+ sorted out later when we have a chance to do better performance
+ work.
+
+- A _OtsUnwindRfp was added to jmpuwind.s. This may not be used by GEM/C,
+ but will be used by GEM/Pascal.
+
+930728
+
+- _OtsUnwindRfp is permanent and is also used by C for gotos out of finally
+ handlers and by the GEM C specific handler function. All DLLs that exported
+ RtlUnwind now also export RtlUnwindRfp.
+
+- Both compilers pass and return small structures in registers. This change
+ was made some months ago. The object file magic number was changed at the
+ same time to eliminate any calling standard mismatch.
+
+- The contents of the jump buffer is not the same between the two compilers
+ but a jump buffer type field is set by setjmp and there is only one longjmp
+ function so there are now no interoperability problems between the two
+ compilers.
+
+- A new set of OTS source files was obtained from Patsy Griffin on 1-Jun-1993.
+ The version number is V1.0. The only changes are in div.s (renamed otsdiv.s
+ for NT) and divdat.s. These implement a faster division algorithm, similar
+ to the one already used in fastdiv.s for acc.
+
+tvb
diff --git a/private/crt32/misc/alpha/otsuwind.s b/private/crt32/misc/alpha/otsuwind.s
new file mode 100644
index 000000000..c53a511fa
--- /dev/null
+++ b/private/crt32/misc/alpha/otsuwind.s
@@ -0,0 +1,80 @@
+// TITLE("Jump to Unwind")
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// otsuwind.s
+//
+// Abstract:
+//
+// This module implements the Alpha C8/GEM compiler specific routine to
+// jump to the runtime library unwind routine.
+//
+// Author:
+//
+// Thomas Van Baak (tvb) 30-Apr-1992
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+ SBTTL("Jump to Unwind - GEM version")
+//++
+//
+// VOID
+// _OtsUnwindRfp (
+// IN PVOID TargetRealFrame OPTIONAL,
+// IN PVOID TargetPc OPTIONAL,
+// IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
+// IN PVOID ReturnValue
+// )
+//
+// Routine Description:
+//
+// This function transfers control to unwind. It is used by the GEM
+// compiler when a non-local goto occurs and structured exception handling
+// is not involved. The unwind routine called is the variant that expects
+// a real frame pointer instead of the usual virtual frame pointer.
+//
+// Arguments:
+//
+// TargetRealFrame (a0) - Supplies an optional pointer to the call frame
+// that is the target of the unwind. If this parameter is not specified,
+// then an exit unwind is performed.
+//
+// TargetPc (a1) - Supplies an optional target instruction address where
+// control is to be transferred to after the unwind operation is
+// complete. This address is ignored if the target frame parameter is
+// not specified.
+//
+// ExceptionRecord (a2) - Supplies an optional pointer to an exception
+// record.
+//
+// ReturnValue (a3) - Supplies a value that is to be placed in the integer
+// function return register just before continuing execution.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(_OtsUnwindRfp)
+
+//
+// All four arguemnts are the same as those required by unwind. Just jump to
+// the unwind function. This thunk is necessary to avoid name space pollution.
+// The compiler should not generate a call directly to RtlUnwindRfp.
+//
+
+ br zero, RtlUnwindRfp // unwind to specified target
+
+ .end _OtUnwindRfp
diff --git a/private/crt32/misc/alpha/scmpeql.s b/private/crt32/misc/alpha/scmpeql.s
new file mode 100644
index 000000000..2d9f82fcc
--- /dev/null
+++ b/private/crt32/misc/alpha/scmpeql.s
@@ -0,0 +1,295 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_eqls(char *str1, long strlen, char *str2);
+ # compares two strings of the same length.
+ # returns r0=1 if str1=str2, r0=0 otherwise.
+
+ # long ots_strcmp_eql(char *str1, long str1len, char *str2, long str2len);
+ # compares two strings of different lengths, without padding.
+ # returns r0=1 if str1=str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r21 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004
+ #
+ # 006 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 007 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 008 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = len
+ # r18 --> B
+ # returns r0=1 if equal, r0=0 if not equal
+ # destroys r16-r21, r27-r28
+
+ #.align octa
+ .globl _OtsStringCompareEqlSameLen
+ .ent _OtsStringCompareEqlSameLen
+_OtsStringCompareEqlSameLen:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ subq r17, 8, r19 # More than 8 bytes to compare?
+ beq r17, equal # Done if empty strings
+
+join: ldq_u r20, (r16) # Get first QW containing part of A
+ addq r18, r17, r27 # Point to end of B
+
+ ldq_u r21, (r18) # Get first QW containing part of B
+ bgt r19, big # Skip if more than 8 bytes
+
+ ldq_u r27, -1(r27) # Get last QW containing part of B
+ addq r16, r17, r28 # Point to end of A
+
+ extql r20, r16, r20 # Get first part of A
+
+ ldq_u r28, -1(r28) # Get last QW containing part of A
+
+ extql r21, r18, r21 # Get first part of B
+
+ extqh r27, r18, r27 # Get last part of B
+
+ extqh r28, r16, r28 # Get last part of A
+
+ or r21, r27, r27 # Combine B
+
+ or r20, r28, r28 # Combine A
+
+ xor r28, r27, r0 # Are they different?
+
+ extqh r0, r19, r0 # Discard differences after length
+
+ nop
+
+ cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not
+ ret r31, (r26)
+
+equal: mov 1, r0 # Return true
+ ret r31, (r26)
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # returns r0=1 if equal, r0=0 if not equal
+ # destroys r16-r21, r27-r28
+ #
+ nop #.align octa
+ nop
+
+ .globl _OtsStringCompareEql
+ .aent _OtsStringCompareEql
+_OtsStringCompareEql:
+ .frame sp,0,r26
+ cmpeq r17, r19, r0 # Are lengths equal?
+ beq r17, done # If one is zero, no compares needed
+
+ subq r17, 8, r19 # More than 8 bytes to compare?
+ blbs r0, join # Only compare if lengths equal
+
+done: ret r31, (r26) # Return result of length comparison
+
+ #.odd
+big: and r16, 7, r0 # A alignment, or amount not compared
+
+ subq r18, r0, r18 # Back up B pointer that much
+
+ and r18, 7, r17 # Is B now aligned?
+
+ addq r19, r0, r19 # (Len-8+align) is amount left to do
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r19, 16, r19 # More than 2 QW's left?
+ bne r17, unalign # Skip if B alignment doesn't match
+
+ xor r20, r21, r0 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r0, r16, r0 # Discard junk preceding strings
+ ble r19, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: ldq_u r20, 16(r16) # Get yet another QW of A
+ bne r0, not_eq # Done if difference in prior compare
+
+ xor r28, r27, r0 # Compare prior QW's
+ ldq r21, 16(r18) # Get yet another QW of B
+
+ subq r19, 16, r19 # Decrement length
+ bne r0, not_eq # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r20, r21, r0 # Compare QW's loaded at top of loop
+ bgt r19, loop # Repeat until two or less QWs left
+
+bottom: addq r19, 8, r19 # More than 1 QW left?
+ bne r0, not_eq # Done if difference in prior compare
+
+ xor r28, r27, r0 # Compare QW's just loaded
+ ble r19, last # Skip if this is last compare
+
+ ldq_u r28, 16(r16) # Get last QW of A
+ bne r0, not_eq # Done if difference in this compare
+
+ ldq r27, 16(r18) # Get last QW of B
+
+ #2 stalls
+
+ xor r28, r27, r0 # Compare last QW's
+
+last: extqh r0, r19, r0 # Discard diffs after length
+
+ nop
+
+ cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r21, r18, r21 # Get first part of B
+
+ extqh r27, r18, r0 # Get second part of B
+
+ #stall
+
+ or r0, r21, r21 # Combine pieces of B
+
+ xor r20, r21, r0 # Compare with A
+
+ mskqh r0, r16, r0 # Trim junk preceding strings
+ blt r19, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r21, 16(r18) # Get more B
+ subq r19, 16, r19 # Decrement length
+
+ extql r27, r18, r17 # Get piece of B from prior QW
+ bne r0, not_eq # Done if r1.ne.r2
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r21, r18, r0 # Get piece of B from first QW in loop
+
+ ldq_u r20, 16(r16) # Get still more A
+ extql r21, r18, r21 # Get second piece of B from there
+
+ or r17, r0, r17 # Combine pieces for first B
+
+ xor r28, r17, r0 # Compare with first A
+
+ extqh r27, r18, r17 # Start building second B
+ bne r0, not_eq # Done if r28.ne.r17
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r17, r21, r21 # Combine pieces for second B
+
+ xor r20, r21, r0 # Compare with second A
+ bge r19, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r19, 8, r17 # At least 8 more bytes?
+ bne r0, not_eq # Done if r1.ne.r2
+
+ and r19, 7, r19 # How many odd bytes?
+ beq r17, last_u # Skip if not a whole QW
+
+ extql r27, r18, r17 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r0 # Get a piece of new B QW
+
+ #stall
+
+ or r17, r0, r17 # Combine pieces
+
+ xor r28, r17, r0 # Compare with A
+
+ nop
+ bne r0, not_eq # Done if r28.ne.r17
+
+last_u: addq r18, r19, r17 # Point to end of B
+ beq r19, eql_u # Return true if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+
+ ldq_u r20, 7(r17) # Get QW containing end of B
+
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ #stall
+
+ extqh r20, r18, r0 # Get a piece of last B QW
+
+ #stall
+
+ or r27, r0, r27 # Combine
+
+ xor r28, r27, r0 # Compare with A
+
+ mskql r0, r19, r0 # Discard diffs after strings
+
+ nop
+
+eql_u: cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not
+ ret r31, (r26)
+
+
+not_eq: clr r0 # Return false
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareEqlSameLen
diff --git a/private/crt32/misc/alpha/scmpeqlp.s b/private/crt32/misc/alpha/scmpeqlp.s
new file mode 100644
index 000000000..85836d587
--- /dev/null
+++ b/private/crt32/misc/alpha/scmpeqlp.s
@@ -0,0 +1,443 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_eqlp(char *str1, long str1len,
+ # char *str2, long str2len, char pad);
+ # compares two strings of different lengths with padding.
+ # returns r0=1 if str1=str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r22 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 006 28 May 1992 WBN Initial version, replacing BLISS -005
+ #
+ # 007 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 008 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # r20 = pad
+ # returns r0=1 if strings equal, r0=0 if not equal
+ # destroys r16-r22, r27-r28
+ #
+ .globl _OtsStringCompareEqlPadded
+ .ent _OtsStringCompareEqlPadded
+_OtsStringCompareEqlPadded:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ subq r17, r19, r21 # A length - B length
+ beq r17, a_empty # If A empty, go compare B with pad
+
+ cmovgt r21, r19, r17 # R17 = min length
+ ldq_u r0, (r16) # Get first QW of A
+
+ sll r20, 8, r28 # Start replicating pad
+ beq r19, b_empty # If B empty, go compare A with pad
+
+ subq r17, 8, r17 # Is min length > 8?
+ ldq_u r19, (r18) # Get first QW of B
+
+ or r20, r28, r20 # Pad in bytes 0,1 of R20
+ bgt r17, big # Go handle strings > 8 bytes
+
+ addq r18, r17, r18 # Point to end of B
+ addq r16, r17, r16 # Point to end of A
+
+ extql r0, r16, r0 # Position start of string A
+ ldq_u r27, 7(r18) # Get end of string B
+
+ extql r19, r18, r19 # Position start of string B
+ ldq_u r28, 7(r16) # Get end of string A
+
+ subq r31, r17, r17 # R17 = 8 - length
+ extqh r27, r18, r27 # Position end of string B
+
+ extqh r28, r16, r28 # Position end of string A
+ or r19, r27, r19 # Combine parts of B
+
+ or r0, r28, r28 # Combine parts of A
+ xor r28, r19, r27 # Are they different?
+
+ mskqh r27, r17, r27 # Clear off diffs preceding strings
+ sll r20, 16, r19 # Replicate pad while waiting
+
+ clr r0 # Prepare to return false
+ beq r27, eq_so_far # Skip if entire min_length matched
+
+ ret r31, (r26) # Strings differ, return false
+
+ # Come here if min length > 8
+ #
+ # r0 = first QW of A
+ # r16 -> A
+ # r17 = min length - 8
+ # r18 -> B
+ # r19 = first QW of B
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+ #.odd
+big: and r16, 7, r28 # A alignment, or amount not compared
+
+ subq r18, r28, r18 # Back up B pointer that much
+
+ addq r17, r28, r17 # (Len-8+align) is amount left to do
+
+ and r18, 7, r22 # Is B now aligned?
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r17, 16, r17 # More than 2 QW's left?
+ bne r22, unalign # Skip if B alignment doesn't match
+
+ xor r0, r19, r22 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r22, r16, r22 # Discard junk preceding strings
+ ble r17, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: bne r22, neq # Done if difference in prior compare
+ ldq_u r0, 16(r16) # Get yet another QW of A
+
+ xor r28, r27, r22 # Compare prior QW's
+ ldq r19, 16(r18) # Get yet another QW of B
+
+ subq r17, 16, r17 # Decrement length
+ bne r22, neq # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r0, r19, r22 # Compare QW's loaded at top of loop
+ bgt r17, loop # Repeat until two or less QWs left
+
+bottom: addq r17, 8, r19 # More than 1 QW left?
+ bne r22, neq # Done if difference in prior compare
+
+ andnot r16, 7, r16 # Get actual A pointer
+ ble r19, last # Skip if this is last compare
+
+ xor r28, r27, r22 # Compare QW's just loaded
+ ldq r27, 16(r18) # Get last QW of B
+
+ bne r22, neq # Done if difference in this compare
+ ldq r28, 16(r16) # Get last QW of A
+
+ mov r17, r19
+
+ nop
+
+last: xor r28, r27, r22 # Compare last QW's
+ beq r19, ck_last
+
+ mskql r22, r19, r22 # Discard diffs after length
+
+ck_last:
+ bne r22, neq # See which is greater
+
+ addq r17, 16, r17 # Get actual remaining length
+ sll r20, 16, r19 # Start shifting pad some more
+
+ addq r16, r17, r16 # Point to end-8 of each string
+ addq r18, r17, r18
+
+ # Come here if strings match thru min_length
+ #
+ # r0
+ # r16 -> A[min_length-8] (8 before first uncompared byte of A)
+ # r17
+ # r18 -> B[min_length-8] (8 before first uncompared byte of B)
+ # r19 = pad in bytes 2,3
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+eq_so_far:
+ or r20, r19, r27 # Pad in bytes 0-3
+ beq r21, equal # Strings same length, return equal
+
+ sll r27, 32, r0 # Replicate pad some more
+ blt r21, b_longer # Go compare pad with B
+
+ and r16, 7, r17 # Alignment of remaining A
+ ldq_u r28, 8(r16) # Get first data to compare with pad
+
+ subq r21, 8, r21 # Length - 8
+ or r27, r0, r27 # Pad in bytes 0-7
+
+ addq r21, r17, r21 # Remaining length after this QW
+ xor r28, r27, r22 # Compare A QW with pad
+
+ mskqh r22, r16, r22 # Discard bytes preceding end of B
+ ble r21, a_last # Skip if this is last QW
+
+ ldq_u r0, 16(r16) # Get QW 2 of A
+ subq r21, 16, r21 # Are there two more QW's?
+
+ ble r21, a_bot # Skip loop if not
+a_pad: bne r22, neq # Exit if diff in R28
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ xor r0, r27, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq # Exit if diff in R0
+
+ ldq_u r0, 32(r16) # Get next QW of A
+ addq r16, 16, r16 # Update pointer
+
+ xor r28, r27, r22 # Compare prior QW
+ bgt r21, a_pad # Repeat if more to compare
+
+a_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq # Exit if diff in R28
+
+ mov r0, r28 # Move this QW to common location
+ ble r21, a_skip # Skip if this is last QW
+
+ ldq_u r28, 24(r16) # Next QW of A
+ xor r0, r27, r22 # Compare prior QW
+
+ subq r21, 8, r21
+ bne r22, neq # Exit if diff in R0
+
+a_skip: xor r28, r27, r22 # Compare last QW
+a_last: beq r21, a_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of string
+ nop
+
+a_end: cmpeq r22, 0, r0 # Return 1/0 for strings equal/not
+ ret r31, (r26)
+
+ # Come here if A is nonempty, but B is empty.
+ #
+b_empty:
+ subq r16, 8, r16 # Back up A pointer as expected
+ or r20, r28, r20 # Pad in bytes 0-1
+
+ sll r20, 16, r19
+ br r31, eq_so_far # Go compare A with pad
+
+ # Come here if A is empty (B might be empty too).
+ #
+ nop #.odd
+a_empty:
+ sll r20, 8, r28 # Start replicating pad
+
+ subq r18, 8, r18 # Back up B pointer as expected
+ beq r19, equal # Done if both strings empty
+
+ or r20, r28, r20 # Pad in bytes 0-1
+ sll r20, 16, r0
+
+ or r20, r0, r27 # Pad in bytes 0-3
+ sll r27, 32, r0
+
+b_longer:
+ and r18, 7, r17 # Alignment of remaining B
+ ldq_u r28, 8(r18) # Get first data to compare with pad
+
+ addq r21, 8, r21 # - Length + 8
+ or r27, r0, r0 # Pad in bytes 0-7
+
+ subq r17, r21, r21 # Remaining length after this QW
+ xor r0, r28, r22 # Compare B QW with pad
+
+ mskqh r22, r18, r22 # Discard bytes preceding end of A
+ ble r21, b_last # Skip if last QW
+
+ ldq_u r19, 16(r18) # Get QW 2 of B
+ subq r21, 16, r21 # Two more QW's?
+
+ ble r21, b_bot # Skip if not
+b_pad: bne r22, neq # Exit if diff in r28
+
+ ldq_u r28, 24(r18) # Get next QW of B
+ xor r0, r19, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq # Exit if diff in R19
+
+ ldq_u r19, 32(r18) # Get next QW of B
+ addq r18, 16, r18 # Update pointer
+
+ xor r0, r28, r22 # Compare prior QW
+ bgt r21, b_pad # Repeat if more to compare
+
+b_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq # Exit if diff in R28
+
+ xor r0, r19, r22 # Check another QW
+ ble r21, b_last # Skip if that's the last one
+
+ ldq_u r28, 24(r18) # Fetch another QW
+ bne r22, neq # Exit if diff in R19
+
+ subq r21, 8, r21
+ nop
+
+ xor r0, r28, r22 # Check that QW
+b_last: beq r21, b_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of B
+ nop
+
+b_end: cmpeq r22, 0, r0 # Return 1/0 as strings equal/not
+ ret r31, (r26)
+
+equal: mov 1, r0 # Strings equal, return true
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r19, r18, r19 # Get first part of B
+
+ extqh r27, r18, r22 # Get second part of B
+
+ #stall
+
+ or r22, r19, r19 # Combine pieces of B
+
+ xor r0, r19, r22 # Compare with A
+
+ mskqh r22, r16, r22 # Trim junk preceding strings
+ blt r17, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r19, 16(r18) # Get more B
+ subq r17, 16, r17 # Decrement length
+
+ bne r22, neq # Done if r0.ne.r19
+ extql r27, r18, r0 # Get piece of B from prior QW
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r19, r18, r22 # Get piece of B from first QW in loop
+
+ extql r19, r18, r19 # Get second piece of B from there
+
+ or r0, r22, r22 # Combine pieces for first B
+
+ ldq_u r0, 16(r16) # Get still more A
+ xor r28, r22, r22 # Compare with first A
+
+ bne r22, neq # Done if r28.ne.r22
+ extqh r27, r18, r22 # Start building second B
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r22, r19, r19 # Combine pieces for second B
+
+ xor r0, r19, r22 # Compare with second A
+ bge r17, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r17, 8, r28 # At least 8 more bytes?
+ bne r22, neq # Done if r0.ne.r19
+
+ and r17, 7, r17 # How many odd bytes?
+ beq r28, last_u # Skip if not a whole QW
+
+ extql r27, r18, r0 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r22 # Get a piece of new B QW
+
+ # stall
+
+ or r0, r22, r0 # Combine pieces
+
+ xor r28, r0, r22 # Compare with A
+
+ bne r22, neq # Done if r28.ne.r0
+
+last_u: andnot r16, 7, r16 # What's the real address of A?
+
+ sll r20, 16, r19 # Start replicating pad
+ beq r17, eq_so_far # Check padding if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+ addq r18, r17, r0 # Point to end-8 of B
+
+ ldq_u r0, 7(r0) # Get QW containing end of B
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ addq r16, r17, r16 # Point to end-8 of A
+
+ extqh r0, r18, r22 # Get a piece of last B QW
+
+ addq r18, r17, r18 # Point to end-8 of B
+
+ or r27, r22, r27 # Combine
+
+ xor r28, r27, r22 # Compare with A
+
+ mskql r22, r17, r22 # Discard diffs after strings
+
+ nop
+
+ beq r22, eq_so_far # If still equal, go check pad
+
+neq: clr r0 # Return false
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareEqlPadded
diff --git a/private/crt32/misc/alpha/scmpleq.s b/private/crt32/misc/alpha/scmpleq.s
new file mode 100644
index 000000000..6370ac284
--- /dev/null
+++ b/private/crt32/misc/alpha/scmpleq.s
@@ -0,0 +1,338 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_leqs(char *str1, long strlen, char *str2);
+ # compares two strings of the same length.
+ # returns r0=1 if str1<=str2, r0=0 otherwise.
+ #
+ # long ots_strcmp_leq(char *str1, long str1len, char *str2, long str2len);
+ # compares two strings of different lengths without padding.
+ # returns r0=1 if str1<=str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r21 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004
+ #
+ # 006 29 Jan 1992 WBN Use .otsent macro
+ #
+ # 007 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 008 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 009 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # returns r0=1 if A less/equal, r0=0 if A greater
+ # destroys r16-r21, r27-r28
+ #
+ .globl _OtsStringCompareLeq
+ .ent _OtsStringCompareLeq
+_OtsStringCompareLeq:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ subq r17, r19, r21 # A_len - B_len
+ cmovgt r21, r19, r17 # r17 = min length
+ br r31, join
+
+ # r16 --> A
+ # r17 = len
+ # r18 --> B
+ # returns r0=1 if A less/equal, r0=0 if A greater
+ # destroys r16-r21, r27-r28
+ #
+ .globl _OtsStringCompareLeqSameLen
+ .aent _OtsStringCompareLeqSameLen
+_OtsStringCompareLeqSameLen:
+ .frame sp,0,r26
+
+ clr r21 # Lengths are equal
+
+join: subq r17, 8, r19 # More than 8 bytes to compare?
+ beq r17, equal # Done if empty strings
+
+ ldq_u r20, (r16) # Get first QW containing part of A
+ addq r18, r17, r27 # Point to end of B
+
+ ldq_u r17, (r18) # Get first QW containing part of B
+ bgt r19, big # Skip if more than 8 bytes
+
+ ldq_u r27, -1(r27) # Get last QW containing part of B
+ addq r16, r19, r28 # Point to end of A
+
+ extql r20, r16, r20 # Get first part of A
+
+ ldq_u r28, 7(r28) # Get last QW containing part of A
+
+ extql r17, r18, r17 # Get first part of B
+
+ extqh r27, r18, r27 # Get last part of B
+
+ extqh r28, r16, r28 # Get last part of A
+
+ or r17, r27, r27 # Combine B
+
+ or r20, r28, r28 # Combine A
+
+ xor r28, r27, r0 # Are they different?
+
+ beq r19, ck_leq
+ mskql r0, r19, r0 # Discard differences after length
+
+ #stall
+
+ck_leq: cmpbge r31, r0, r17 # Where is B = A?
+ beq r0, equal # (Skip if they're equal?)
+
+ cmpbge r27, r28, r28 # Where is B >= A?
+
+ addq r17, 1, r0 # Flip first difference
+
+ andnot r28, r17, r28 # Where is B > A?
+
+ and r28, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.odd
+big: and r16, 7, r28 # A alignment, or amount not compared
+
+ subq r18, r28, r18 # Back up B pointer that much
+
+ and r18, 7, r0 # Is B now aligned?
+
+ addq r19, r28, r19 # (Len-8+align) is amount left to do
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r19, 16, r19 # More than 2 QW's left?
+ bne r0, unalign # Skip if B alignment doesn't match
+
+ xor r20, r17, r0 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r0, r16, r0 # Discard junk preceding strings
+ ble r19, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: bne r0, neq_2017 # Done if difference in prior compare
+ ldq_u r20, 16(r16) # Get yet another QW of A
+
+ xor r28, r27, r0 # Compare prior QW's
+ ldq r17, 16(r18) # Get yet another QW of B
+
+ subq r19, 16, r19 # Decrement length
+ bne r0, neq_2827 # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r20, r17, r0 # Compare QW's loaded at top of loop
+ bgt r19, loop # Repeat until two or less QWs left
+
+bottom: addq r19, 8, r19 # More than 1 QW left?
+ bne r0, neq_2017 # Done if difference in prior compare
+
+ xor r28, r27, r0 # Compare QW's just loaded
+ ble r19, last # Skip if this is last compare
+
+ bne r0, neq_2827 # Done if difference in this compare
+ ldq_u r28, 16(r16) # Get last QW of A
+
+ ldq r27, 16(r18) # Get last QW of B
+ subq r19, 8, r19
+
+ #2 stalls
+
+ xor r28, r27, r0 # Compare last QW's
+last: beq r19, ck_last
+
+ mskql r0, r19, r0 # Discard diffs after length
+
+ck_last:
+ bne r0, neq_2827 # See which is greater
+
+equal: cmple r21, r31, r0 # Equal: return A_len <= B_len
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r17, r18, r17 # Get first part of B
+
+ extqh r27, r18, r0 # Get second part of B
+
+ #stall
+
+ or r0, r17, r17 # Combine pieces of B
+
+ xor r20, r17, r0 # Compare with A
+
+ mskqh r0, r16, r0 # Trim junk preceding strings
+ blt r19, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r17, 16(r18) # Get more B
+ subq r19, 16, r19 # Decrement length
+
+ bne r0, neq_20xx # Done if r20.ne.r17
+ extql r27, r18, r20 # Get piece of B from prior QW
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r17, r18, r0 # Get piece of B from first QW in loop
+
+ extql r17, r18, r17 # Get second piece of B from there
+
+ or r20, r0, r0 # Combine pieces for first B
+
+ ldq_u r20, 16(r16) # Get still more A
+ xor r28, r0, r0 # Compare with first A
+
+ bne r0, neq_28xx # Done if r28.ne.r0
+ extqh r27, r18, r0 # Start building second B
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r0, r17, r17 # Combine pieces for second B
+
+ xor r20, r17, r0 # Compare with second A
+ bge r19, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r19, 8, r28 # At least 8 more bytes?
+ bne r0, neq_2017 # Done if r20.ne.r17
+
+ and r19, 7, r19 # How many odd bytes?
+ beq r28, last_u # Skip if not a whole QW
+
+ extql r27, r18, r20 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r0 # Get a piece of new B QW
+
+ #stall
+
+ or r20, r0, r20 # Combine pieces
+
+ xor r28, r20, r0 # Compare with A
+
+ nop
+ bne r0, neq_28xx # Done if r28.ne.r20
+
+last_u: addq r18, r19, r17 # Point to end of B
+ beq r19, eql_u # Check length diff if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+
+ ldq_u r20, 7(r17) # Get QW containing end of B
+
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ #stall
+
+ extqh r20, r18, r0 # Get a piece of last B QW
+
+ #stall
+
+ or r27, r0, r27 # Combine
+
+ xor r28, r27, r0 # Compare with A
+
+ mskql r0, r19, r0 # Discard diffs after strings
+
+ #stall
+
+ beq r0, eql_u # Done if they're still equal
+
+ #.align quad
+neq_28xx:
+ xor r28, r0, r27 # Recover B from A and xor
+neq_2827:
+ cmpbge r31, r0, r17 # Where is B = A?
+
+ cmpbge r27, r28, r20 # Where is B >= A?
+
+ addq r17, 1, r0 # Flip first difference
+
+ andnot r20, r17, r20 # Where is B > A?
+
+ and r20, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.align quad
+neq_20xx:
+ xor r20, r0, r17 # Recover B from A and xor
+neq_2017:
+ cmpbge r31, r0, r27 # Where is B = A?
+
+ cmpbge r17, r20, r20 # Where is B >= A?
+
+ addq r27, 1, r0 # Flip first difference
+
+ andnot r20, r27, r20 # Where is B > A?
+
+ and r20, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+
+eql_u: cmple r21, r31, r0 # Equal: return A_len <= B_len
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareLeq
diff --git a/private/crt32/misc/alpha/scmpleqp.s b/private/crt32/misc/alpha/scmpleqp.s
new file mode 100644
index 000000000..b58fe2907
--- /dev/null
+++ b/private/crt32/misc/alpha/scmpleqp.s
@@ -0,0 +1,478 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_leqp(char *str1, long str1len,
+ # char *str2, long str2len, char pad);
+ # compares two strings of different lengths with padding.
+ # returns r0=1 if str1<=str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r22 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 006 28 May 1992 WBN Initial version, replacing BLISS -005
+ #
+ # 007 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 008 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # r20 = pad
+ # returns r0=1 if A less/equal, r0=0 if A greater
+ # destroys r16-r22, r27-r28
+ #
+ .globl _OtsStringCompareLeqPadded
+ .ent _OtsStringCompareLeqPadded
+_OtsStringCompareLeqPadded:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ subq r17, r19, r21 # A length - B length
+ beq r17, a_empty # If A empty, go compare B with pad
+
+ cmovgt r21, r19, r17 # R17 = min length
+ ldq_u r0, (r16) # Get first QW of A
+
+ sll r20, 8, r28 # Start replicating pad
+ beq r19, b_empty # If B empty, go compare A with pad
+
+ subq r17, 8, r17 # Is min length > 8?
+ ldq_u r19, (r18) # Get first QW of B
+
+ or r20, r28, r20 # Pad in bytes 0,1 of R20
+ bgt r17, big # Go handle strings > 8 bytes
+
+ addq r18, r17, r18 # Point to end of B
+ addq r16, r17, r16 # Point to end of A
+
+ extql r0, r16, r0 # Position start of string A
+ ldq_u r27, 7(r18) # Get end of string B
+
+ extql r19, r18, r19 # Position start of string B
+ ldq_u r28, 7(r16) # Get end of string A
+
+ subq r31, r17, r17 # R17 = 8 - length
+ extqh r27, r18, r27 # Position end of string B
+
+ extqh r28, r16, r28 # Position end of string A
+ or r19, r27, r19 # Combine parts of B
+
+ or r0, r28, r28 # Combine parts of A
+ xor r28, r19, r27 # Are they different?
+
+ mskqh r27, r17, r27 # Clear off diffs preceding strings
+ sll r20, 16, r0 # Replicate pad while waiting
+
+ cmpbge r31, r27, r17 # Make 1's where strings matched
+ beq r27, eq_so_far # Skip if entire min_length matched
+
+ cmpbge r19, r28, r19 # Make 1's where B >= A
+ addq r17, 1, r0 # Flip first mismatch
+
+ andnot r19, r17, r19 # 1's where A < B
+ and r19, r0, r0 # nonzero if A < B at first mismatch
+
+ cmovne r0, 1, r0 # 1 if string A < string B
+ ret r31, (r26)
+
+ # Come here if min length > 8
+ #
+ # r0 = first QW of A
+ # r16 -> A
+ # r17 = min length - 8
+ # r18 -> B
+ # r19 = first QW of B
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+ nop #.odd
+big: and r16, 7, r28 # A alignment, or amount not compared
+
+ subq r18, r28, r18 # Back up B pointer that much
+
+ addq r17, r28, r17 # (Len-8+align) is amount left to do
+
+ and r18, 7, r22 # Is B now aligned?
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r17, 16, r17 # More than 2 QW's left?
+ bne r22, unalign # Skip if B alignment doesn't match
+
+ xor r0, r19, r22 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r22, r16, r22 # Discard junk preceding strings
+ ble r17, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: bne r22, neq_019 # Done if difference in prior compare
+ ldq_u r0, 16(r16) # Get yet another QW of A
+
+ xor r28, r27, r22 # Compare prior QW's
+ ldq r19, 16(r18) # Get yet another QW of B
+
+ subq r17, 16, r17 # Decrement length
+ bne r22, neq_2827 # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r0, r19, r22 # Compare QW's loaded at top of loop
+ bgt r17, loop # Repeat until two or less QWs left
+
+bottom: addq r17, 8, r19 # More than 1 QW left?
+ bne r22, neq_0xx # Done if difference in prior compare
+
+ andnot r16, 7, r16 # Get actual A pointer
+ ble r19, last # Skip if this is last compare
+
+ xor r28, r27, r22 # Compare QW's just loaded
+ ldq r27, 16(r18) # Get last QW of B
+
+ bne r22, neq_28xx # Done if difference in this compare
+ ldq r28, 16(r16) # Get last QW of A
+
+ mov r17, r19
+
+ nop
+
+last: xor r28, r27, r22 # Compare last QW's
+ beq r19, ck_last
+
+ mskql r22, r19, r22 # Discard diffs after length
+
+ck_last:
+ bne r22, neq_2827 # See which is greater
+
+ addq r17, 16, r17 # Get actual remaining length
+ sll r20, 16, r0 # Start shifting pad some more
+
+ addq r16, r17, r16 # Point to end-8 of each string
+ addq r18, r17, r18
+
+ # Come here if strings match thru min_length
+ #
+ # r0 = pad in bytes 2,3
+ # r16 -> A[min_length-8] (8 before first uncompared byte of A)
+ # r17
+ # r18 -> B[min_length-8] (8 before first uncompared byte of B)
+ # r19
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+eq_so_far:
+ or r20, r0, r27 # Pad in bytes 0-3
+ beq r21, equal # Strings same length, return equal
+
+ sll r27, 32, r0 # Replicate pad some more
+ blt r21, b_longer # Go compare pad with B
+
+ and r16, 7, r17 # Alignment of remaining A
+ ldq_u r28, 8(r16) # Get first data to compare with pad
+
+ subq r21, 8, r21 # Length - 8
+ or r27, r0, r27 # Pad in bytes 0-7
+
+ addq r21, r17, r21 # Remaining length after this QW
+ xor r28, r27, r22 # Compare A QW with pad
+
+ mskqh r22, r16, r22 # Discard bytes preceding end of B
+ ble r21, a_last # Skip if this is last QW
+
+ ldq_u r0, 16(r16) # Get QW 2 of A
+ subq r21, 16, r21 # Are there two more QW's?
+
+ ble r21, a_bot # Skip loop if not
+a_pad: bne r22, neq_2827 # Exit if diff in R28
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ xor r0, r27, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq_0xx # Exit if diff in R0
+
+ ldq_u r0, 32(r16) # Get next QW of A
+ addq r16, 16, r16 # Update pointer
+
+ xor r28, r27, r22 # Compare prior QW
+ bgt r21, a_pad # Repeat if more to compare
+
+a_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq_2827 # Exit if diff in R28
+
+ mov r0, r28 # Move this QW to common location
+ ble r21, a_skip # Skip if this is last QW
+
+ ldq_u r28, 24(r16) # Next QW of A
+ xor r0, r27, r22 # Compare prior QW
+
+ subq r21, 8, r21
+ bne r22, neq_0xx # Exit if diff in R0
+
+a_skip: xor r28, r27, r22 # Compare last QW
+a_last: beq r21, a_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of string
+a_end: bne r22, neq_2827 # Exit if diff in R28
+
+ mov 1, r0 # Strings equal, return true
+ ret r31, (r26)
+
+ # Come here if A is nonempty, but B is empty.
+ #
+b_empty:
+ subq r16, 8, r16 # Back up A pointer as expected
+ or r20, r28, r20 # Pad in bytes 0-1
+
+ sll r20, 16, r0
+ br r31, eq_so_far # Go compare A with pad
+
+ # Come here if A is empty (B might be empty too).
+ #
+ nop #.odd
+a_empty:
+ sll r20, 8, r28 # Start replicating pad
+
+ subq r18, 8, r18 # Back up B pointer as expected
+ beq r19, equal # Done if both strings empty
+
+ or r20, r28, r20 # Pad in bytes 0-1
+ sll r20, 16, r0
+
+ or r20, r0, r27 # Pad in bytes 0-3
+ sll r27, 32, r0
+
+b_longer:
+ and r18, 7, r17 # Alignment of remaining B
+ ldq_u r28, 8(r18) # Get first data to compare with pad
+
+ addq r21, 8, r21 # - Length + 8
+ or r27, r0, r0 # Pad in bytes 0-7
+
+ subq r17, r21, r21 # Remaining length after this QW
+ xor r0, r28, r22 # Compare B QW with pad
+
+ mskqh r22, r18, r22 # Discard bytes preceding end of A
+ ble r21, b_last # Skip if last QW
+
+ ldq_u r19, 16(r18) # Get QW 2 of B
+ subq r21, 16, r21 # Two more QW's?
+
+ ble r21, b_bot # Skip if not
+b_pad: bne r22, neq_0xx # Exit if diff in r28
+
+ ldq_u r28, 24(r18) # Get next QW of B
+ xor r0, r19, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq_019 # Exit if diff in R19
+
+ ldq_u r19, 32(r18) # Get next QW of B
+ addq r18, 16, r18 # Update pointer
+
+ xor r0, r28, r22 # Compare prior QW
+ bgt r21, b_pad # Repeat if more to compare
+
+b_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq_0xx # Exit if diff in R28
+
+ xor r0, r19, r22 # Check another QW
+ ble r21, b_last # Skip if that's the last one
+
+ ldq_u r28, 24(r18) # Fetch another QW
+ bne r22, neq_019 # Exit if diff in R19
+
+ subq r21, 8, r21
+ nop
+
+ xor r0, r28, r22 # Check that QW
+b_last: beq r21, b_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of B
+b_end: bne r22, neq_0xx # Exit if diff seen
+
+equal: mov 1, r0 # Strings equal, return true
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r19, r18, r19 # Get first part of B
+
+ extqh r27, r18, r22 # Get second part of B
+
+ #stall
+
+ or r22, r19, r19 # Combine pieces of B
+
+ xor r0, r19, r22 # Compare with A
+
+ mskqh r22, r16, r22 # Trim junk preceding strings
+ blt r17, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r19, 16(r18) # Get more B
+ subq r17, 16, r17 # Decrement length
+
+ bne r22, neq_0xx # Done if r0.ne.r19
+ extql r27, r18, r0 # Get piece of B from prior QW
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r19, r18, r22 # Get piece of B from first QW in loop
+
+ extql r19, r18, r19 # Get second piece of B from there
+
+ or r0, r22, r22 # Combine pieces for first B
+
+ ldq_u r0, 16(r16) # Get still more A
+ xor r28, r22, r22 # Compare with first A
+
+ bne r22, neq_28xx # Done if r28.ne.r22
+ extqh r27, r18, r22 # Start building second B
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r22, r19, r19 # Combine pieces for second B
+
+ xor r0, r19, r22 # Compare with second A
+ bge r17, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r17, 8, r28 # At least 8 more bytes?
+ bne r22, neq_019 # Done if r0.ne.r19
+
+ and r17, 7, r17 # How many odd bytes?
+ beq r28, last_u # Skip if not a whole QW
+
+ extql r27, r18, r0 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r22 # Get a piece of new B QW
+
+ # stall
+
+ or r0, r22, r0 # Combine pieces
+
+ xor r28, r0, r22 # Compare with A
+
+ bne r22, neq_28xx # Done if r28.ne.r0
+
+last_u: andnot r16, 7, r16 # What's the real address of A?
+
+ sll r20, 16, r0 # Start replicating pad
+ beq r17, eq_so_far # Check padding if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+ addq r18, r17, r19 # Point to end-8 of B
+
+ ldq_u r19, 7(r19) # Get QW containing end of B
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ addq r16, r17, r16 # Point to end-8 of A
+
+ extqh r19, r18, r22 # Get a piece of last B QW
+
+ addq r18, r17, r18 # Point to end-8 of B
+
+ or r27, r22, r27 # Combine
+
+ xor r28, r27, r22 # Compare with A
+
+ mskql r22, r17, r22 # Discard diffs after strings
+
+ nop
+
+ beq r22, eq_so_far # If still equal, go check pad
+
+ #.align quad
+neq_28xx:
+ xor r28, r22, r27 # Recover B from A and xor
+neq_2827:
+ cmpbge r31, r22, r19 # Where is B = A?
+
+ cmpbge r27, r28, r0 # Where is B >= A?
+
+ addq r19, 1, r22 # Flip first difference
+
+ andnot r0, r19, r0 # Where is B > A?
+
+ and r0, r22, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.align quad
+neq_0xx:
+ xor r0, r22, r19 # Recover B from A and xor
+neq_019:
+ cmpbge r31, r22, r27 # Where is B = A?
+
+ cmpbge r19, r0, r0 # Where is B >= A?
+
+ addq r27, 1, r22 # Flip first difference
+
+ andnot r0, r27, r0 # Where is B > A?
+
+ and r0, r22, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareLeqPadded
diff --git a/private/crt32/misc/alpha/scmplss.s b/private/crt32/misc/alpha/scmplss.s
new file mode 100644
index 000000000..ab043fb8f
--- /dev/null
+++ b/private/crt32/misc/alpha/scmplss.s
@@ -0,0 +1,339 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_lsss(char *str1, long strlen, char *str2);
+ # compares two strings of the same length.
+ # returns r0=1 if str1<str2, r0=0 otherwise.
+ #
+ # long ots_strcmp_lss(char *str1, long str1len, char *str2, long str2len);
+ # compares two strings of different lengths without padding.
+ # returns r0=1 if str1<str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r21 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004
+ #
+ # 006 29 Jan 1992 WBN Use .otsent macro
+ #
+ # 007 19 May 1992 KDG Changes for common VMS/OSF sources
+ #
+ # 008 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 009 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # returns r0=1 if A less, r0=0 if A greater/equal
+ # destroys r16-r21, r27-r28
+ #
+ .globl _OtsStringCompareLss
+ .ent _OtsStringCompareLss
+_OtsStringCompareLss:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ subq r17, r19, r21 # A_len - B_len
+ cmovgt r21, r19, r17 # r17 = min length
+ br r31, join
+
+ # r16 --> A
+ # r17 = len
+ # r18 --> B
+ # returns r0=1 if A less, r0=0 if A greater/equal
+ # destroys r16-r21, r27-r28
+ #
+ .globl _OtsStringCompareLssSameLen
+ .aent _OtsStringCompareLssSameLen
+_OtsStringCompareLssSameLen:
+ .frame sp,0,r26
+
+ clr r21 # Lengths are equal
+
+join: subq r17, 8, r19 # More than 8 bytes to compare?
+ beq r17, equal # Done if empty strings
+
+ ldq_u r20, (r16) # Get first QW containing part of A
+ addq r18, r17, r27 # Point to end of B
+
+ ldq_u r17, (r18) # Get first QW containing part of B
+ bgt r19, big # Skip if more than 8 bytes
+
+ ldq_u r27, -1(r27) # Get last QW containing part of B
+ addq r16, r19, r28 # Point to end of A
+
+ extql r20, r16, r20 # Get first part of A
+
+ ldq_u r28, 7(r28) # Get last QW containing part of A
+
+ extql r17, r18, r17 # Get first part of B
+
+ extqh r27, r18, r27 # Get last part of B
+
+ extqh r28, r16, r28 # Get last part of A
+
+ or r17, r27, r27 # Combine B
+
+ or r20, r28, r28 # Combine A
+
+ xor r28, r27, r0 # Are they different?
+
+ beq r19, ck_leq
+ mskql r0, r19, r0 # Discard differences after length
+
+ #stall
+
+ck_leq: cmpbge r31, r0, r17 # Where is B = A?
+ beq r0, equal # (Skip if they're equal?)
+
+ cmpbge r27, r28, r28 # Where is B >= A?
+
+ addq r17, 1, r0 # Flip first difference
+
+ andnot r28, r17, r28 # Where is B > A?
+
+ and r28, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.odd
+big: and r16, 7, r28 # A alignment, or amount not compared
+
+ subq r18, r28, r18 # Back up B pointer that much
+
+ and r18, 7, r0 # Is B now aligned?
+
+ addq r19, r28, r19 # (Len-8+align) is amount left to do
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r19, 16, r19 # More than 2 QW's left?
+ bne r0, unalign # Skip if B alignment doesn't match
+
+ xor r20, r17, r0 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r0, r16, r0 # Discard junk preceding strings
+ ble r19, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: bne r0, neq_2017 # Done if difference in prior compare
+ ldq_u r20, 16(r16) # Get yet another QW of A
+
+ xor r28, r27, r0 # Compare prior QW's
+ ldq r17, 16(r18) # Get yet another QW of B
+
+ subq r19, 16, r19 # Decrement length
+ bne r0, neq_2827 # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r20, r17, r0 # Compare QW's loaded at top of loop
+ bgt r19, loop # Repeat until two or less QWs left
+
+bottom: addq r19, 8, r19 # More than 1 QW left?
+ bne r0, neq_2017 # Done if difference in prior compare
+
+ xor r28, r27, r0 # Compare QW's just loaded
+ ble r19, last # Skip if this is last compare
+
+ bne r0, neq_2827 # Done if difference in this compare
+ ldq_u r28, 16(r16) # Get last QW of A
+
+ ldq r27, 16(r18) # Get last QW of B
+ subq r19, 8, r19
+
+ #2 stalls
+
+ xor r28, r27, r0 # Compare last QW's
+last: beq r19, ck_last
+
+ mskql r0, r19, r0 # Discard diffs after length
+
+ck_last:
+ bne r0, neq_2827 # See which is greater
+
+equal: cmplt r21, r31, r0 # Equal: return A_len < B_len
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r17, r18, r17 # Get first part of B
+
+ extqh r27, r18, r0 # Get second part of B
+
+ #stall
+
+ or r0, r17, r17 # Combine pieces of B
+
+ xor r20, r17, r0 # Compare with A
+
+ mskqh r0, r16, r0 # Trim junk preceding strings
+ blt r19, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r17, 16(r18) # Get more B
+ subq r19, 16, r19 # Decrement length
+
+ bne r0, neq_20xx # Done if r20.ne.r17
+ extql r27, r18, r20 # Get piece of B from prior QW
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r17, r18, r0 # Get piece of B from first QW in loop
+
+ extql r17, r18, r17 # Get second piece of B from there
+
+ or r20, r0, r0 # Combine pieces for first B
+
+ ldq_u r20, 16(r16) # Get still more A
+ xor r28, r0, r0 # Compare with first A
+
+ bne r0, neq_28xx # Done if r28.ne.r0
+ extqh r27, r18, r0 # Start building second B
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r0, r17, r17 # Combine pieces for second B
+
+ xor r20, r17, r0 # Compare with second A
+ bge r19, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r19, 8, r28 # At least 8 more bytes?
+ bne r0, neq_2017 # Done if r20.ne.r17
+
+ and r19, 7, r19 # How many odd bytes?
+ beq r28, last_u # Skip if not a whole QW
+
+ extql r27, r18, r20 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r0 # Get a piece of new B QW
+
+ #stall
+
+ or r20, r0, r20 # Combine pieces
+
+ xor r28, r20, r0 # Compare with A
+
+ nop
+ bne r0, neq_28xx # Done if r28.ne.r20
+
+last_u: addq r18, r19, r17 # Point to end of B
+ beq r19, eql_u # Check length diff if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+
+ ldq_u r20, 7(r17) # Get QW containing end of B
+
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ #stall
+
+ extqh r20, r18, r0 # Get a piece of last B QW
+
+ #stall
+
+ or r27, r0, r27 # Combine
+
+ xor r28, r27, r0 # Compare with A
+
+ mskql r0, r19, r0 # Discard diffs after strings
+
+ #stall
+
+ beq r0, eql_u # Done if they're still equal
+
+ #.align quad
+neq_28xx:
+ xor r28, r0, r27 # Recover B from A and xor
+neq_2827:
+ cmpbge r31, r0, r17 # Where is B = A?
+
+ cmpbge r27, r28, r20 # Where is B >= A?
+
+ addq r17, 1, r0 # Flip first difference
+
+ andnot r20, r17, r20 # Where is B > A?
+
+ and r20, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.align quad
+neq_20xx:
+ xor r20, r0, r17 # Recover B from A and xor
+neq_2017:
+ cmpbge r31, r0, r27 # Where is B = A?
+
+ cmpbge r17, r20, r20 # Where is B >= A?
+
+ addq r27, 1, r0 # Flip first difference
+
+ andnot r20, r27, r20 # Where is B > A?
+
+ and r20, r0, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+
+eql_u: cmplt r21, r31, r0 # Equal: return A_len < B_len
+ ret r31, (r26)
+
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareLss
diff --git a/private/crt32/misc/alpha/scmplssp.s b/private/crt32/misc/alpha/scmplssp.s
new file mode 100644
index 000000000..4243965d8
--- /dev/null
+++ b/private/crt32/misc/alpha/scmplssp.s
@@ -0,0 +1,478 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ #
+ #
+ # long ots_strcmp_lssp(char *str1, long str1len,
+ # char *str2, long str2len, char pad);
+ # compares two strings of different lengths with padding.
+ # returns r0=1 if str1<str2, r0=0 otherwise.
+ #
+ # Special conventions: No stack space, r16-r22 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 006 28 May 1992 WBN Initial version, replacing BLISS -005
+ #
+ # 007 22 Sep 1992 KDG Add case-sensitive name
+ #
+ # 008 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 --> A
+ # r17 = A_len
+ # r18 --> B
+ # r19 = B_len
+ # r20 = pad
+ # returns r0=1 if A less, r0=0 if A greater/equal
+ # destroys r16-r22, r27-r28
+ #
+ .globl _OtsStringCompareLssPadded
+ .ent _OtsStringCompareLssPadded
+_OtsStringCompareLssPadded:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ subq r17, r19, r21 # A length - B length
+ beq r17, a_empty # If A empty, go compare B with pad
+
+ cmovgt r21, r19, r17 # R17 = min length
+ ldq_u r0, (r16) # Get first QW of A
+
+ sll r20, 8, r28 # Start replicating pad
+ beq r19, b_empty # If B empty, go compare A with pad
+
+ subq r17, 8, r17 # Is min length > 8?
+ ldq_u r19, (r18) # Get first QW of B
+
+ or r20, r28, r20 # Pad in bytes 0,1 of R20
+ bgt r17, big # Go handle strings > 8 bytes
+
+ addq r18, r17, r18 # Point to end of B
+ addq r16, r17, r16 # Point to end of A
+
+ extql r0, r16, r0 # Position start of string A
+ ldq_u r27, 7(r18) # Get end of string B
+
+ extql r19, r18, r19 # Position start of string B
+ ldq_u r28, 7(r16) # Get end of string A
+
+ subq r31, r17, r17 # R17 = 8 - length
+ extqh r27, r18, r27 # Position end of string B
+
+ extqh r28, r16, r28 # Position end of string A
+ or r19, r27, r19 # Combine parts of B
+
+ or r0, r28, r28 # Combine parts of A
+ xor r28, r19, r27 # Are they different?
+
+ mskqh r27, r17, r27 # Clear off diffs preceding strings
+ sll r20, 16, r0 # Replicate pad while waiting
+
+ cmpbge r31, r27, r17 # Make 1's where strings matched
+ beq r27, eq_so_far # Skip if entire min_length matched
+
+ cmpbge r19, r28, r19 # Make 1's where B >= A
+ addq r17, 1, r0 # Flip first mismatch
+
+ andnot r19, r17, r19 # 1's where A < B
+ and r19, r0, r0 # nonzero if A < B at first mismatch
+
+ cmovne r0, 1, r0 # 1 if string A < string B
+ ret r31, (r26)
+
+ # Come here if min length > 8
+ #
+ # r0 = first QW of A
+ # r16 -> A
+ # r17 = min length - 8
+ # r18 -> B
+ # r19 = first QW of B
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+ nop #.odd
+big: and r16, 7, r28 # A alignment, or amount not compared
+
+ subq r18, r28, r18 # Back up B pointer that much
+
+ addq r17, r28, r17 # (Len-8+align) is amount left to do
+
+ and r18, 7, r22 # Is B now aligned?
+ ldq_u r27, 8(r18) # Get next QW of B
+
+ subq r17, 16, r17 # More than 2 QW's left?
+ bne r22, unalign # Skip if B alignment doesn't match
+
+ xor r0, r19, r22 # Compare first (partial) QW
+ ldq_u r28, 8(r16) # Get next QW of A
+
+ mskqh r22, r16, r22 # Discard junk preceding strings
+ ble r17, bottom # Skip if two quadwords or less to go
+
+ # stall
+
+loop: bne r22, neq_019 # Done if difference in prior compare
+ ldq_u r0, 16(r16) # Get yet another QW of A
+
+ xor r28, r27, r22 # Compare prior QW's
+ ldq r19, 16(r18) # Get yet another QW of B
+
+ subq r17, 16, r17 # Decrement length
+ bne r22, neq_2827 # Done if difference in this compare
+
+ ldq r27, 24(r18) # Get next QW of B
+ addq r18, 16, r18 # Increment pointer
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ addq r16, 16, r16 # Increment pointer
+
+ xor r0, r19, r22 # Compare QW's loaded at top of loop
+ bgt r17, loop # Repeat until two or less QWs left
+
+bottom: addq r17, 8, r19 # More than 1 QW left?
+ bne r22, neq_0xx # Done if difference in prior compare
+
+ andnot r16, 7, r16 # Get actual A pointer
+ ble r19, last # Skip if this is last compare
+
+ xor r28, r27, r22 # Compare QW's just loaded
+ ldq r27, 16(r18) # Get last QW of B
+
+ bne r22, neq_28xx # Done if difference in this compare
+ ldq r28, 16(r16) # Get last QW of A
+
+ mov r17, r19
+
+ nop
+
+last: xor r28, r27, r22 # Compare last QW's
+ beq r19, ck_last
+
+ mskql r22, r19, r22 # Discard diffs after length
+
+ck_last:
+ bne r22, neq_2827 # See which is greater
+
+ addq r17, 16, r17 # Get actual remaining length
+ sll r20, 16, r0 # Start shifting pad some more
+
+ addq r16, r17, r16 # Point to end-8 of each string
+ addq r18, r17, r18
+
+ # Come here if strings match thru min_length
+ #
+ # r0 = pad in bytes 2,3
+ # r16 -> A[min_length-8] (8 before first uncompared byte of A)
+ # r17
+ # r18 -> B[min_length-8] (8 before first uncompared byte of B)
+ # r19
+ # r20 = pad in bytes 0,1
+ # r21 = A length - B length
+ # r22
+ # r27
+ # r28
+ #
+eq_so_far:
+ or r20, r0, r27 # Pad in bytes 0-3
+ beq r21, equal # Strings same length, return equal
+
+ sll r27, 32, r0 # Replicate pad some more
+ blt r21, b_longer # Go compare pad with B
+
+ and r16, 7, r17 # Alignment of remaining A
+ ldq_u r28, 8(r16) # Get first data to compare with pad
+
+ subq r21, 8, r21 # Length - 8
+ or r27, r0, r27 # Pad in bytes 0-7
+
+ addq r21, r17, r21 # Remaining length after this QW
+ xor r28, r27, r22 # Compare A QW with pad
+
+ mskqh r22, r16, r22 # Discard bytes preceding end of B
+ ble r21, a_last # Skip if this is last QW
+
+ ldq_u r0, 16(r16) # Get QW 2 of A
+ subq r21, 16, r21 # Are there two more QW's?
+
+ ble r21, a_bot # Skip loop if not
+a_pad: bne r22, neq_2827 # Exit if diff in R28
+
+ ldq_u r28, 24(r16) # Get next QW of A
+ xor r0, r27, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq_0xx # Exit if diff in R0
+
+ ldq_u r0, 32(r16) # Get next QW of A
+ addq r16, 16, r16 # Update pointer
+
+ xor r28, r27, r22 # Compare prior QW
+ bgt r21, a_pad # Repeat if more to compare
+
+a_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq_2827 # Exit if diff in R28
+
+ mov r0, r28 # Move this QW to common location
+ ble r21, a_skip # Skip if this is last QW
+
+ ldq_u r28, 24(r16) # Next QW of A
+ xor r0, r27, r22 # Compare prior QW
+
+ subq r21, 8, r21
+ bne r22, neq_0xx # Exit if diff in R0
+
+a_skip: xor r28, r27, r22 # Compare last QW
+a_last: beq r21, a_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of string
+a_end: bne r22, neq_2827 # Exit if diff in R28
+
+ clr r0 # Strings equal, return false
+ ret r31, (r26)
+
+ # Come here if A is nonempty, but B is empty.
+ #
+b_empty:
+ subq r16, 8, r16 # Back up A pointer as expected
+ or r20, r28, r20 # Pad in bytes 0-1
+
+ sll r20, 16, r0
+ br r31, eq_so_far # Go compare A with pad
+
+ # Come here if A is empty (B might be empty too).
+ #
+ nop #.odd
+a_empty:
+ sll r20, 8, r28 # Start replicating pad
+
+ subq r18, 8, r18 # Back up B pointer as expected
+ beq r19, equal # Done if both strings empty
+
+ or r20, r28, r20 # Pad in bytes 0-1
+ sll r20, 16, r0
+
+ or r20, r0, r27 # Pad in bytes 0-3
+ sll r27, 32, r0
+
+b_longer:
+ and r18, 7, r17 # Alignment of remaining B
+ ldq_u r28, 8(r18) # Get first data to compare with pad
+
+ addq r21, 8, r21 # - Length + 8
+ or r27, r0, r0 # Pad in bytes 0-7
+
+ subq r17, r21, r21 # Remaining length after this QW
+ xor r0, r28, r22 # Compare B QW with pad
+
+ mskqh r22, r18, r22 # Discard bytes preceding end of A
+ ble r21, b_last # Skip if last QW
+
+ ldq_u r19, 16(r18) # Get QW 2 of B
+ subq r21, 16, r21 # Two more QW's?
+
+ ble r21, b_bot # Skip if not
+b_pad: bne r22, neq_0xx # Exit if diff in r28
+
+ ldq_u r28, 24(r18) # Get next QW of B
+ xor r0, r19, r22 # Check prior QW
+
+ subq r21, 16, r21 # 2 more QW's?
+ bne r22, neq_019 # Exit if diff in R19
+
+ ldq_u r19, 32(r18) # Get next QW of B
+ addq r18, 16, r18 # Update pointer
+
+ xor r0, r28, r22 # Compare prior QW
+ bgt r21, b_pad # Repeat if more to compare
+
+b_bot: addq r21, 8, r21 # Another QW?
+ bne r22, neq_0xx # Exit if diff in R28
+
+ xor r0, r19, r22 # Check another QW
+ ble r21, b_last # Skip if that's the last one
+
+ ldq_u r28, 24(r18) # Fetch another QW
+ bne r22, neq_019 # Exit if diff in R19
+
+ subq r21, 8, r21
+ nop
+
+ xor r0, r28, r22 # Check that QW
+b_last: beq r21, b_end # Can't use MSKQL if whole QW
+
+ mskql r22, r21, r22 # Keep only up to end of B
+b_end: bne r22, neq_0xx # Exit if diff seen
+
+equal: clr r0 # Strings equal, return false
+ ret r31, (r26)
+
+ #.align quad
+unalign:
+ extql r19, r18, r19 # Get first part of B
+
+ extqh r27, r18, r22 # Get second part of B
+
+ #stall
+
+ or r22, r19, r19 # Combine pieces of B
+
+ xor r0, r19, r22 # Compare with A
+
+ mskqh r22, r16, r22 # Trim junk preceding strings
+ blt r17, bott_u # Skip if fewer than 16 bytes left
+
+loop_u: ldq_u r19, 16(r18) # Get more B
+ subq r17, 16, r17 # Decrement length
+
+ bne r22, neq_0xx # Done if r0.ne.r19
+ extql r27, r18, r0 # Get piece of B from prior QW
+
+ ldq_u r27, 24(r18) # Get still more B
+ addq r18, 16, r18 # Increment B pointer
+
+ ldq_u r28, 8(r16) # Get more A
+ extqh r19, r18, r22 # Get piece of B from first QW in loop
+
+ extql r19, r18, r19 # Get second piece of B from there
+
+ or r0, r22, r22 # Combine pieces for first B
+
+ ldq_u r0, 16(r16) # Get still more A
+ xor r28, r22, r22 # Compare with first A
+
+ bne r22, neq_28xx # Done if r28.ne.r22
+ extqh r27, r18, r22 # Start building second B
+
+ addq r16, 16, r16 # Increment A pointer
+
+ or r22, r19, r19 # Combine pieces for second B
+
+ xor r0, r19, r22 # Compare with second A
+ bge r17, loop_u # Repeat if at least 16 more bytes
+
+bott_u: and r17, 8, r28 # At least 8 more bytes?
+ bne r22, neq_019 # Done if r0.ne.r19
+
+ and r17, 7, r17 # How many odd bytes?
+ beq r28, last_u # Skip if not a whole QW
+
+ extql r27, r18, r0 # Get a piece of B
+ ldq_u r27, 16(r18) # Load another QW of B
+
+ addq r18, 8, r18 # Increment B pointer
+ ldq_u r28, 8(r16) # Load another QW of A
+
+ addq r16, 8, r16 # Increment A pointer
+
+ extqh r27, r18, r22 # Get a piece of new B QW
+
+ # stall
+
+ or r0, r22, r0 # Combine pieces
+
+ xor r28, r0, r22 # Compare with A
+
+ bne r22, neq_28xx # Done if r28.ne.r0
+
+last_u: andnot r16, 7, r16 # What's the real address of A?
+
+ sll r20, 16, r0 # Start replicating pad
+ beq r17, eq_so_far # Check padding if no more bytes
+
+ ldq_u r28, 8(r16) # Get last QW of A
+ addq r18, r17, r19 # Point to end-8 of B
+
+ ldq_u r19, 7(r19) # Get QW containing end of B
+ extql r27, r18, r27 # Get piece of prior B QW
+
+ addq r16, r17, r16 # Point to end-8 of A
+
+ extqh r19, r18, r22 # Get a piece of last B QW
+
+ addq r18, r17, r18 # Point to end-8 of B
+
+ or r27, r22, r27 # Combine
+
+ xor r28, r27, r22 # Compare with A
+
+ mskql r22, r17, r22 # Discard diffs after strings
+
+ nop
+
+ beq r22, eq_so_far # If still equal, go check pad
+
+ #.align quad
+neq_28xx:
+ xor r28, r22, r27 # Recover B from A and xor
+neq_2827:
+ cmpbge r31, r22, r19 # Where is B = A?
+
+ cmpbge r27, r28, r0 # Where is B >= A?
+
+ addq r19, 1, r22 # Flip first difference
+
+ andnot r0, r19, r0 # Where is B > A?
+
+ and r0, r22, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ #.align quad
+neq_0xx:
+ xor r0, r22, r19 # Recover B from A and xor
+neq_019:
+ cmpbge r31, r22, r27 # Where is B = A?
+
+ cmpbge r19, r0, r0 # Where is B >= A?
+
+ addq r27, 1, r22 # Flip first difference
+
+ andnot r0, r27, r0 # Where is B > A?
+
+ and r0, r22, r0 # Keep only first difference
+
+ cmovne r0, 1, r0 # Return 1 if A < B at first difference
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringCompareLssPadded
diff --git a/private/crt32/misc/alpha/setjmp.s b/private/crt32/misc/alpha/setjmp.s
new file mode 100644
index 000000000..65453c8be
--- /dev/null
+++ b/private/crt32/misc/alpha/setjmp.s
@@ -0,0 +1,111 @@
+// TITLE("Set Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// setjmp.s
+//
+// Abstract:
+//
+// This module implements the Alpha acc compiler specific routine to
+// perform a setjmp.
+//
+// N.B. This module conditionally provides UNSAFE handling of setjmp and
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an uninitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 7-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Thomas Van Baak (tvb) 22-Apr-1993
+//
+// Adapted for Alpha AXP.
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe or unsafe with
+// respect to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .comm _setjmpexused, 4
+
+ SBTTL("Set Jump - acc version")
+//++
+//
+// int
+// setjmp (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function saves the current nonvolatile register state in the
+// specified jump buffer and returns a function value of zero.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY(setjmp)
+
+ ldl v0, _setjmpexused // get value of switch variable
+ bne v0, 10f // if ne, provide safe setjmp
+
+//
+// Provide unsafe handling of setjmp.
+//
+
+ stt f2, JbFltF2(a0) // save floating registers f2 - f9
+ stt f3, JbFltF3(a0) //
+ stt f4, JbFltF4(a0) //
+ stt f5, JbFltF5(a0) //
+ stt f6, JbFltF6(a0) //
+ stt f7, JbFltF7(a0) //
+ stt f8, JbFltF8(a0) //
+ stt f9, JbFltF9(a0) //
+
+ stq s0, JbIntS0(a0) // save integer registers s0 - s6/fp
+ stq s1, JbIntS1(a0) //
+ stq s2, JbIntS2(a0) //
+ stq s3, JbIntS3(a0) //
+ stq s4, JbIntS4(a0) //
+ stq s5, JbIntS5(a0) //
+ stq fp, JbIntS6(a0) //
+
+ ldil t0, 1 // get unsafe setjmp flag
+ stl t0, JbType(a0) // set jump buffer context type
+ stq sp, JbIntSp(a0) // save stack pointer
+ stq ra, JbFir(a0) // get setjmp return address
+
+ mov zero, v0 // set zero return value
+ ret zero, (ra) // return
+
+//
+// Provide safe handling of setjmp.
+//
+
+10: jmp zero, (v0) // finish in _setjmpex code
+
+ .end setjmp
diff --git a/private/crt32/misc/alpha/setjmpex.s b/private/crt32/misc/alpha/setjmpex.s
new file mode 100644
index 000000000..3f39baa7b
--- /dev/null
+++ b/private/crt32/misc/alpha/setjmpex.s
@@ -0,0 +1,147 @@
+// TITLE("Set Jump Extended")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// setjmpex.s
+//
+// Abstract:
+//
+// This module implements the Alpha acc compiler specific routine to
+// provide SAFE handling of setjmp/longjmp with respect to structured
+// exception handling.
+//
+// Author:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Thomas Van Baak (tvb) 22-Apr-1993
+//
+// Adapted for Alpha AXP.
+//
+//--
+
+#include "ksalpha.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe with respect
+// to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .data
+_setjmpexused:
+ .long _setjmpex // set address of safe setjmp routine
+
+ SBTTL("Set Jump Extended")
+//++
+//
+// int
+// _setjmpex (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function implements a safe setjmp.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ .struct 0
+SjRa: .space 8 // saved return address
+SjS0: .space 8 // saved integer register s0
+SjFl: .space 8 // InFunction flag variable
+SjEf: .space 8 // EstablisherFrame(s) structure
+SjCx: .space ContextFrameLength // context frame
+SetjmpFrameLength:
+
+ NESTED_ENTRY(_setjmpex, SetjmpFrameLength, zero)
+
+ lda sp, -SetjmpFrameLength(sp) // allocate stack frame
+ stq ra, SjRa(sp) // save return address
+ stq s0, SjS0(sp) // save integer register s0
+
+ PROLOGUE_END
+
+//
+// Save the nonvolatile machine state.
+//
+
+ lda t0, SjCx(sp) // address of context record
+
+ stt f2, CxFltF2(t0) // save floating registers f2 - f9
+ stt f3, CxFltF3(t0) //
+ stt f4, CxFltF4(t0) //
+ stt f5, CxFltF5(t0) //
+ stt f6, CxFltF6(t0) //
+ stt f7, CxFltF7(t0) //
+ stt f8, CxFltF8(t0) //
+ stt f9, CxFltF9(t0) //
+
+ stq s0, CxIntS0(t0) // save integer registers s0 - fp/s6
+ stq s1, CxIntS1(t0) //
+ stq s2, CxIntS2(t0) //
+ stq s3, CxIntS3(t0) //
+ stq s4, CxIntS4(t0) //
+ stq s5, CxIntS5(t0) //
+ stq fp, CxIntFp(t0) //
+ stq gp, CxIntGp(t0) // save integer register gp
+
+ lda v0, SetjmpFrameLength(sp) // compute stack pointer address
+ stq v0, CxIntSp(t0) // save stack pointer
+ stq ra, CxIntRa(t0) // save return address
+ stq ra, CxFir(t0) // save continuation address
+
+ ldil t1, 2 // get acc safe setjmp flag
+ stl t1, JbType(a0) // set jump buffer context type
+ stl ra, JbPc(a0) // save target instruction address
+ mov a0, s0 // preserve jump buffer address
+
+//
+// Perform unwind to determine the virtual frame pointer of the caller.
+//
+
+ subl ra, 4, a0 // compute control PC address
+ bsr RtlLookupFunctionEntry // lookup function table address
+
+ ldq a0, SjRa(sp) // get return address
+ subl a0, 4, a0 // compute control PC address
+ mov v0, a1 // set address of function entry
+ lda a2, SjCx(sp) // address of context record
+ lda a3, SjFl(sp) // set address of in function variable
+ lda a4, SjEf(sp) // set frame pointers address
+ mov zero, a5 // set context pointer array address
+ bsr RtlVirtualUnwind // compute virtual frame pointer value
+
+//
+// Set return value, restore registers, deallocate stack frame, and return.
+//
+
+ ldl t0, SjEf(sp) // get virtual frame pointer
+ stl t0, JbFp(s0) // save virtual frame pointer address
+ mov zero, v0 // set return value
+
+ ldq s0, SjS0(sp) // restore integer register s0
+ ldq ra, SjRa(sp) // restore return address
+ lda sp, SetjmpFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end _setjmpex
diff --git a/private/crt32/misc/alpha/sfill.s b/private/crt32/misc/alpha/sfill.s
new file mode 100644
index 000000000..35814b321
--- /dev/null
+++ b/private/crt32/misc/alpha/sfill.s
@@ -0,0 +1,161 @@
+ #++
+ # Copyright 1991, 1994, Digital Equipment Corporation
+ #
+ # ots_fill(char *dstptr, long dstlen, unsigned char fill)
+ #
+ # Fill dstlen bytes of memory at *dstptr with "fill"
+ #
+ # Special conventions: No stack space, r16-r19 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # This is a GEM support routine for filling memory with a specified value,
+ # basically identical to the System V routine memset, with the 2nd two
+ # parameters reversed. This is optimized for extremely high performance
+ # both for small blocks (string padding) and large blocks (memory fill).
+ # In order to reduce overhead for small cases, they are retired as quickly
+ # as possible, more case analysis is reserved for cases which will do
+ # more.
+ #
+ # This version of OTS_FILL provides longword granularity for Alpha.
+ #
+ # 011 30 Aug 1994 WBN Longword granularity version based on
+ # OTS_FILL_ALPHA.M64 edit 010.
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 = dst
+ # r17 = len
+ # r18 = fill byte
+ # destroys r16-r19, r27-r28
+
+ .globl _OtsFill
+ .ent _OtsFill
+_OtsFill:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+
+ sll r18, 8, r19 # Start propagating byte to quadword
+ beq r17, done # No memory refs if len=0
+ subq r17, 4, r28 # Length-4
+ or r19, r18, r18 # Fill in bytes 0-1
+ sll r18, 16, r19
+ and r16, 3, r27 # Dst alignment (0-3)
+ or r19, r18, r18 # Fill in bytes 0-3
+ andnot r16, 3, r16 # LW aligned dst pointer
+ addq r27, r28, r17 # Alignment + length - 4
+ bge r28, geq4 # Lengths >= 4 may not need load
+ ldl r28, (r16) # Load first LW of dst
+ bgt r17, double # Skip if it crosses to next LW
+ addq r17, 4, r17 # Find endpoint within LW
+ xor r28, r18, r28 # Pre-flip all fill bits in dest
+ mskql r28, r27, r27 # Clear from startpoint thru 7
+ mskqh r28, r17, r28 # Clear from 0 to endpoint
+ xor r27, r18, r27 # Combine fill with masked dest
+ xor r28, r27, r27 # Result is fill in center part only
+ stl r27, (r16)
+ ret r31, (r26)
+
+double: mskqh r18, r27, r19 # Discard fill preceding startpoint
+ mskql r28, r27, r28 # Clear from startpoint in first LW
+ ldl r27, 4(r16) # Load second LW of dst
+ mskql r18, r17, r18 # Discard fill following endpoint
+ or r28, r19, r28 # Insert fill in first LW
+ stl r28, (r16)
+ mskqh r27, r17, r27 # Clear up to endpoint in second LW
+ or r27, r18, r27 # Insert fill in second LW
+ stl r27, 4(r16)
+ ret r31, (r26)
+
+ # Come here if length to be zeroed is >= 4.
+ # r16-> dst aligned to LW
+ # r17 = alignment + length - 4
+ # r18 = fill in bytes 0-3
+ # r27 = dst alignment within LW
+ # r28 = length-4
+
+ #.align quad
+
+geq4: and r16, 4, r28 # Which LW in QW to store first?
+ beq r17, simple # Go handle single aligned LW
+ sll r18, 32, r19
+ bne r28, longs # Go use QW stores
+quad: subq r17, 4, r17 # Does dest end in first QW?
+ or r18, r19, r18 # Fill in bytes 0-7
+ blt r17, shortq # Ends within first QW
+ mskqh r18, r27, r28 # Clear initial bytes of fill
+ beq r27, wh_qw # Store a whole QW
+ ldq r19, (r16) # Load first QW of dest
+ mskql r19, r27, r19 # Clear from startpoint
+ or r19, r28, r28 # Combine first QW with fill
+wh_qw: stq r28, (r16) # Store first QW of dest
+ br r31, join # Go fill rest of string
+
+simple: stl r18, (r16) # Single aligned LW
+ ret r31, (r26)
+
+shortq: ldq r28, (r16) # Load QW of dest
+ xor r28, r18, r28 # Pre-flip all fill bits in dest
+ mskql r28, r27, r27 # Clear from startpoint thru 7
+ mskqh r28, r17, r28 # Clear from 0 up to endpoint
+ xor r27, r18, r27 # Combine fill with masked dest
+ xor r28, r27, r27 # Result is fill in center part only
+ stq r27, (r16) # Store
+ ret r31, (r26)
+
+longs: mskqh r18, r27, r28 # Clear initial bytes of LW fill
+ or r18, r19, r18 # Fill in bytes 0-7
+ beq r27, wh_lw # Store a whole LW
+ ldl r19, (r16) # Load first LW of dest
+ mskql r19, r27, r19 # Clear from startpoint
+ or r19, r28, r28 # Combine first LW with fill
+wh_lw: stl r28, (r16) # Store first LW of dest
+join: subq r17, 32, r17 # At least 4 more quadwords?
+ and r17, 24, r27 # How many after multiple of 4?
+ bge r17, unroll # Taken branch for long strings
+short: and r17, 7, r17 # How many odd bytes?
+ beq r27, last # Skip if no more whole QWs
+ stq_u r18, 8(r16) # Clear one...
+ subq r27, 16, r27 # Map 8/16/24 to -8/0/8
+ addq r16, 8, r16 # Update dest pointer
+ blt r27, last # Skip if no more whole QWs
+ #stall
+ stq_u r18, 8(r16) # Clear two...
+ addq r16, 8, r16 # Update dest pointer
+ nop
+ beq r27, last # Skip if no more whole QWs
+ stq_u r18, 8(r16) # Clear three...
+ addq r16, 8, r16 # Update dest pointer
+last: beq r17, done # Finished if no odd bytes
+ ldq_u r27, 8(r16) # Load last QW of dest
+ subq r17, 4, r28 # More than a LW left?
+ andnot r16, 7, r16 # Clean pointer for STL
+ mskql r18, r17, r18 # Discard unneeded fill bytes
+ #stall
+ mskqh r27, r17, r27 # Clear up to endpoint in last QW
+ #stall
+ or r27, r18, r27 # Combine fill with last QW
+ bgt r28, lastq # Go store a QW
+ stl r27, 8(r16) # LW store for last piece
+done: ret r31, (r26)
+
+lastq: stq r27, 8(r16) # QW store for last piece
+ ret r31, (r26)
+
+
+unroll: stq_u r18, 8(r16) # Store 4 QWs per iteration
+ stq_u r18, 16(r16)
+ stq_u r18, 24(r16)
+ subq r17, 32, r17 # Decrement remaining count
+ stq_u r18, 32(r16)
+ addq r16, 32, r16 # Update dest pointer
+ bge r17, unroll # repeat until done
+ br r31, short # Then handle leftovers
+
+ .set at
+ .set reorder
+ .end _OtsFill
diff --git a/private/crt32/misc/alpha/sloc.s b/private/crt32/misc/alpha/sloc.s
new file mode 100644
index 000000000..30fda8c6e
--- /dev/null
+++ b/private/crt32/misc/alpha/sloc.s
@@ -0,0 +1,702 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ # This module provides support for string index, search, and verify.
+ #
+ # Authors:
+ #
+ # Bill Noyce
+ # Kent Glossop
+ #
+ # long ots_index(const char *str, long strlen, const char *pat, long patlen);
+ #
+ # Searches a string for a substring
+ # returns r0=zero-based position if found, or -1 if not.
+ # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra)
+ #
+ # long ots_search(const char *str, long strlen, const char *cset, long csetlen);
+ #
+ # Searches a string for any character in a set of characters
+ # returns r0=zero-based position if found, or -1 if not.
+ # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra)
+ #
+ # long ots_search_char(const char *str, long strlen, char pat);
+ # (also known as ots_index_char)
+ #
+ # Searches a string for a signle pattern character
+ # returns r0=zero-based position if found, or -1 if not.
+ # Register usage: r0, r16-r18 and r27-r28 ONLY (r26 is ra)
+ # (Note: GEM presumes r19 is also killed)
+ #
+ # long ots_search_mask(const char *str, long strlen, const char maskvec[], int mask)
+ #
+ # Searches a string until a character matching at least one bit
+ # in a mask is found in a table (similar to a VAX SCANC instruction.)
+ # returns r0=zero-based position if found, or -1 if not.
+ # Register usage: r0-1, r16-r21 and r27-r28 ONLY (r26 is ra)
+ #
+ # long ots_verify(char *str, long strlen, char *cset, long csetlen);
+ #
+ # Verifies a string against a set of characters
+ # returns r0=zero-based position for mismatch, or -1 if all validate.
+ # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra)
+ #
+ # long ots_verify_char(char *str, long strlen, char pat);
+ #
+ # Verifies a string against a single character
+ # returns r0=zero-based position for mismatch, or -1 if not.
+ # Register usage: r0, r16-r18 and r27-r28 ONLY (r26 is ra)
+ # (Note: GEM presumes r19 is also killed)
+ #
+ # long ots_verify_mask(const char *str, long strlen, const char maskvec[], int mask)
+ #
+ # Verifies a string until a character not matching at least one bit
+ # in a mask is found in a table (similar to a VAX SPANC instruction.)
+ # returns r0=zero-based position if found, or -1 if not.
+ # Register usage: r0-1, r16-r21 and r27-r28 ONLY (r26 is ra)
+ #
+ # Special conventions for all:
+ # No stack space
+ # No linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 006 28 May 1992 WBN Initial version, replacing BLISS -005
+ #
+ # 007 22 Sep 1992 KDG Add case-sensitive names
+ #
+ # 008 14 Nov 1992 KDG - Merge modules together (allows index/search/verify
+ # to use the single-character versions w/o calls)
+ # - initial multi-character index/search/verify
+ #
+ # 009 4 Dec 1992 KDG Fix bgt that should have been bge (GEM_BUGS #2091)
+ #
+ # 010 26 Jan 1993 KDG Add underscore
+ #
+ # All of the routines other than the single character search/verify could
+ # be significantly improved at some point in the future
+ #--
+
+#include "ots_defs.hs"
+
+ # "Package"
+ #
+ .globl _OtsLocation
+ .ent _OtsLocation
+_OtsLocation:
+ .set noat
+ .set noreorder
+
+ # ots_index
+ # This is currently a primitive brute-force string index (only marginally
+ # better than the original compiled code. Should be tailored to compare
+ # up to 8 at a time, particularly for patterns <= 8 characters.)
+
+ # register use
+ # r0 - remaining match positions counter (-1)
+ # r1 - loop counter [rlen]
+ # r16 - source pointer (incremented on each match)
+ # r17 - source length
+ # r18 - pattern pointer
+ # r19 - pattern length
+ # r20 - loop source pointer [rsp]
+ # r21 - loop source temp [rs]
+ # r22 - loop pattern pointer [rpp]
+ # r23 - loop pattern temp [rp]
+ # r27 - available
+ # r28 - available
+
+ .globl _OtsStringIndex
+ .aent _OtsStringIndex
+_OtsStringIndex:
+ .frame sp,0,r26
+
+ cmpeq r19, 1, r20 # check for single-character index
+ beq r19, i_ret0 # pattern length 0 always matches @0
+ subq r17, r19, r0 # number of match positions - 1
+ bne r20, search_single # single character index
+ blt r0, i_retm1 # return -1 if no match positions
+
+ # outer loop
+i_outlp:
+ lda r20, -1(r16) # initialize source pointer
+ lda r22, -1(r18) # initialize pattern pointer
+ mov r19, r1 # initialize length counter
+
+ # core brute-force matching loop
+i_matlp:
+ ldq_u r21, 1(r20) # load qw containing source byte
+ lda r20, 1(r20) # bump source pointer
+ ldq_u r23, 1(r22) # load qw containing pattern byte
+ lda r22, 1(r22) # bump pattern pointer
+ subq r1, 1, r1 # decrement length
+ extbl r21, r20, r21 # extract source byte
+ extbl r23, r22, r23 # extract pattern byte
+ xor r21, r23, r21 # match?
+ bne r21, i_mismat # if not, try pattern at next position
+ bgt r1, i_matlp # continue matching pattern at current position?
+
+ # matched
+i_ret:
+ subq r17, r19, r1 # number of match positions - 1
+ subq r1, r0, r0 # actual position
+ ret r31, (r26)
+
+ # mismatch at current position - advance to next if more positions
+i_mismat:
+ subq r0, 1, r0 # decrement match positions
+ lda r16, 1(r16) # set r16 to next match position
+ bge r0, i_outlp # if remaining positions, attempt match
+
+i_retm1:
+ lda r0, -1(r31) # return -1
+ ret r31, (r26)
+
+i_ret0: clr r0
+ ret r31, (r26)
+
+ # ots_search
+ # R16 -> string
+ # R17 = length
+ # R18 -> character set
+ # R19 = character set length
+ # result in R0: -1 if all matched, or position in range 0..length-1
+ # destroys R0-R1, R16-R23, R27-R28
+ #
+ # This routine could definitely be improved. (It should only
+ # be necessary to go to memory for every 8th character for both
+ # the string and the character set, and for character sets
+ # <= 8 characters, it should be possible to simply keep the
+ # set in a register while the string is being processed.)
+ #
+ .globl _OtsStringSearch
+ .aent _OtsStringSearch
+_OtsStringSearch:
+ .frame sp,0,r26
+
+ cmpeq r19, 1, r0 # check for single-character search, clear r0 otherwise
+ ble r19, s_retm1 # return -1 if no characters in the match set
+ bne r0, search_single # single character search
+ nop
+
+ # outer loop
+s_outlp:
+ ldq_u r20, (r16) # load qw containing source byte
+ lda r22, -1(r18) # initialize character set pointer
+ mov r19, r1 # initialize character set length counter
+ extbl r20, r16, r20 # extract the source byte to match
+
+ # core brute-force matching loop
+s_matlp:
+ ldq_u r23, 1(r22) # load qw containing character set byte
+ lda r22, 1(r22) # bump character set pointer
+ subq r1, 1, r1 # decrement remaining cset length
+ extbl r23, r22, r23 # extract character set byte
+ xor r20, r23, r21 # match?
+ beq r21, s_match # if match, we're done
+ bgt r1, s_matlp # continue matching pattern at current position?
+
+ # no current position - advance to next if more positions
+ lda r16, 1(r16) # bump source pointer
+ addq r0, 1, r0 # increment position
+ subq r17, 1, r17 # decrement match count
+ bgt r17, s_outlp # if remaining positions, attempt match
+s_retm1:lda r0, -1(r31) # if not, return -1
+s_match:ret r31, (r26)
+
+search_single:
+ ldq_u r19, (r18) # load the quadword containing the byte
+ extbl r19, r18, r18 # extract the byte of interest
+ # and fall through to the character search rtn
+
+ # ots_search_char (ots_index_char)
+ # r16 -> string
+ # r17 = length
+ # r18 = character to find
+ # result in r0: -1 if not found, or position in range 0..length-1
+ # destroys r16-r18, r27-r28
+ #
+ .globl _OtsStringSearchChar
+ .aent _OtsStringSearchChar
+_OtsStringSearchChar:
+ .globl _OtsStringIndexChar
+ .aent _OtsStringIndexChar
+_OtsStringIndexChar:
+ .frame sp,0,r26
+search_char:
+ sll r18, 8, r28 # Replicate char in the quadword...
+ beq r17, sc_fail # Quick exit if length=0
+
+ ldq_u r27, (r16) # First quadword of string
+ addq r16, r17, r0 # Point to end of string
+
+ subq r17, 8, r17 # Length > 8?
+ or r18, r28, r18 # ...
+
+ sll r18, 16, r28 # ...
+ bgt r17, sc_long # Skip if length > 8
+
+ ldq_u r16, -1(r0) # Last quadword of string
+ extql r27, r0, r27 # Position string at high end of QW
+
+ or r18, r28, r18 # ...
+ sll r18, 32, r28 # ...
+
+ extqh r16, r0, r16 # Position string at high end of QW
+ or r18, r28, r18 # Pattern fills a quadword
+
+ or r27, r16, r27 # String fills a quadword
+ xor r27, r18, r27 # Diff betw. string and pattern
+
+ cmpbge r31, r27, r27 # Set 1's where string=pattern
+ subq r31, r17, r17 # Compute 8 - length
+
+ srl r27, r17, r27 # Shift off bits not part of string
+ clr r0 # Set return value
+
+ and r27, 0xF, r28 # One of first 4 characters?
+ blbs r27, sc_done # Return 0 if first char matched
+
+ subq r27, 1, r0 # Flip the first '1' bit
+ beq r28, sc_geq_4 # Skip if no match in first 4
+
+ andnot r27, r0, r0 # Make one-bit mask of first match
+ srl r0, 2, r0 # Map 2/4/8 -> 0/1/2
+
+ # stall
+
+ addq r0, 1, r0 # Bump by 1
+ ret r31, (r26) # return
+
+sc_geq_4:
+ andnot r27, r0, r28 # Make one-bit mask of first match
+ beq r27, sc_done # Return -1 if there were none
+
+ srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4
+ srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1
+
+ addq r27, 4, r0 # Bump by 4
+ subq r0, r28, r0 # and correct
+
+sc_done:ret r31, (r26)
+
+ # Enter here if string length > 8.
+ # R16 -> start of string
+ # R17 = length - 8
+ # R18 = fill in bytes 0,1
+ # R27 = 1st QW of string
+ # R28 = fill in bytes 2,3
+
+ #.odd
+sc_long:or r18, r28, r18 # R18 has pattern in low 4 bytes
+
+ sll r18, 32, r28 # ...
+ and r16, 7, r0 # Where in QW did we start?
+
+ or r18, r28, r18 # Pattern fills a QW
+ ldq_u r28, 8(r16) # Get next QW (string B)
+
+ xor r27, r18, r27 # Diff Betw. string and pattern
+ cmpbge r31, r27, r27 # Set 1's where string=pattern
+
+ addq r17, r0, r17 # Remaining length after 1st QW
+ srl r27, r0, r27 # Discard bits preceding string
+
+ subq r17, 16, r17 # More than two QW's to go?
+ sll r27, r0, r27 # Reposition like other bits
+
+ subq r17, r0, r0 # Remember start point to compute len
+ ble r17, sc_bottom # Skip the loop if 2 QW's or less
+
+sc_loop:xor r28, r18, r28 # Diff betw string B and pattern
+ bne r27, sc_done_a # Exit if a match in string A
+
+ cmpbge r31, r28, r28 # 1's where string B = pattern
+ ldq_u r27, 16(r16) # Load string A
+
+ subq r17, 16, r17 # Decrement remaining length
+ bne r28, sc_done_b # Exit if a match in string B
+
+ ldq_u r28, 24(r16) # Load string B
+ addq r16, 16, r16 # Increment pointer
+
+ xor r27, r18, r27 # Diff betw string A and pattern
+ cmpbge r31, r27, r27 # 1's where string A = pattern
+
+ bgt r17, sc_loop # Repeat if more than 2 QW's left
+
+ nop #.align quad
+
+sc_bottom:
+ bne r27, sc_done_a # Exit if a match in string A
+ addq r17, 8, r27 # More than 1 QW left?
+
+ xor r28, r18, r28 # Diff betw string B and pattern
+ ble r27, sc_last # Skip if this is last QW
+
+ cmpbge r31, r28, r27 # 1's where string B = pattern
+ ldq_u r28, 16(r16) # Load string A
+
+ subq r17, 8, r17 # Adjust len for final return
+ bne r27, sc_done_a # Exit if a match in string B
+
+ addq r17, 8, r27 # Ensure -7 <= (r27=len-8) <= 0
+ xor r28, r18, r28 # Diff betw string A and pattern
+
+sc_last:mskqh r27, r27, r27 # Nonzero in bytes beyond string
+ subq r17, 8, r17 # Adjust len for final return
+
+ or r28, r27, r28 # Zeros only for matches within string
+ cmpbge r31, r28, r27 # Where are the matches?
+
+ bne r27, sc_done_a # Compute index if a match found
+sc_fail:lda r0, -1(r31) # Else return -1
+
+ ret r31, (r26)
+
+ nop #.align 8
+
+sc_done_b:
+ addq r17, 8, r17 # Adjust length
+ mov r28, r27 # Put mask where it's expected
+
+sc_done_a:
+ subq r0, r17, r0 # (start - remaining) = base index
+ blbs r27, sc_exit # Return R0 if first char matched
+
+ and r27, 0xF, r16 # One of first 4 characters?
+ subq r27, 1, r28 # Flip the first '1' bit
+
+ andnot r27, r28, r28 # Make one-bit mask of first match
+ beq r16, sc_geq_4x # Skip if no match in first 4
+
+ srl r28, 2, r28 # Map 2/4/8 -> 0/1/2
+ addq r0, 1, r0 # Bump by 1
+
+ addq r0, r28, r0 # Add byte offset
+sc_exit:ret r31, (r26) # return
+
+sc_geq_4x:
+ addq r0, 4, r0 # Bump by 4
+ srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4
+
+ srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1
+ addq r0, r27, r0 # Add 0/1/2/4
+
+ subq r0, r28, r0 # and correct
+ ret r31, (r26)
+
+ # ots_search_mask
+ # This routine could be tailored by loading a longword or
+ # a quadword at a time and doing table lookups on the
+ # characters largely in parallel.
+ #
+ .globl _OtsStringSearchMask
+ .aent _OtsStringSearchMask
+_OtsStringSearchMask:
+ .frame sp,0,r26
+
+ lda r16, -1(r16) # bias initial address for better loop code
+ nop # should be lnop (unop) or fnop to dual issue
+ lda r0, -1(r31) # initialize position to -1
+ ble r17, sm_ret # return -1 if source len is zero
+ # slow way - ~14 cycles/byte
+sm_loop:
+ ldq_u r21, 1(r16) # load qw containing the byte
+ lda r16, 1(r16) # bump pointer
+ addq r0, 1, r0 # bump position
+ subq r17, 1, r17 # decrement the length
+ extbl r21, r16, r21 # extract the byte
+ addq r21, r18, r21 # get the byte in the table
+ ldq_u r20, (r21) # load qw from table containing lookup
+ extbl r20, r21, r20 # extract table byte
+ and r20, r19, r20 # check if any bits in the mask match
+ beq r17, sm_end # if last character, handle specially
+ beq r20, sm_loop # if no match, go do the loop again
+sm_ret:
+ ret r31, (r26) # if not a match, we're done
+sm_end: lda r21, -1(r31) # get -1
+ cmoveq r20, r21, r0 # -1 if last char didn't match
+ ret r31, (r26)
+
+ # ots_verify
+ # R16 -> string
+ # R17 = length
+ # R18 -> character set
+ # R19 = character set length
+ # result in R0: -1 if all matched, or position in range 0..length-1
+ # destroys R0-R1, R16-R23, R27-R28
+ #
+ # This routine could definitely be improved. (It should only
+ # be necessary to go to memory for every 8th character for both
+ # the string and the character set, and for character sets
+ # <= 8 characters, it should be possible to simply keep the
+ # set in a register while the string is being processed.)
+ #
+ .globl _OtsStringVerify
+ .aent _OtsStringVerify
+_OtsStringVerify:
+ .frame sp,0,r26
+
+ cmpeq r19, 1, r0 # check for single-character search, clear r0 otherwise
+ ble r19, v_ret0 # return 0 if no characters in the match set
+ bne r0, verify_single # single character verify
+ nop
+ # outer loop
+v_outlp:
+ ldq_u r20, (r16) # load qw containing source byte
+ lda r22, -1(r18) # initialize character set pointer
+ mov r19, r1 # initialize character set length counter
+ extbl r20, r16, r20 # extract the source byte to match
+
+ # core brute-force matching loop
+v_matlp:
+ ldq_u r23, 1(r22) # load qw containing character set byte
+ lda r22, 1(r22) # bump character set pointer
+ subq r1, 1, r1 # decrement remaining cset length
+ extbl r23, r22, r23 # extract character set byte
+ xor r20, r23, r21 # match?
+ beq r21, v_match # if match, move to the next character
+ bgt r1, v_matlp # continue matching pattern at current position?
+ # if we made it through the whole character set, this is a mismatch
+v_ret0: ret r31, (r26)
+v_match: # match at current position - advance to next if more positions
+ lda r16, 1(r16) # bump source pointer
+ addq r0, 1, r0 # increment position
+ subq r17, 1, r17 # decrement match count
+ bgt r17, v_outlp # if remaining positions, attempt match
+ lda r0, -1(r31) # if everything verified, return -1
+ ret r31, (r26)
+
+verify_single:
+ ldq_u r19, (r18) # load the quadword containing the byte
+ extbl r19, r18, r18 # extract the byte of interest
+ # and fall through to the character verify rtn
+
+ # ots_verify_char
+ # R16 -> string
+ # R17 = length
+ # R18 = character to check
+ # result in R0: -1 if all matched, or position in range 0..length-1
+ # destroys R16-R18, R27-R28
+ #
+ .globl _OtsStringVerifyChar
+ .aent _OtsStringVerifyChar
+_OtsStringVerifyChar:
+ .frame sp,0,r26
+
+ sll r18, 8, r28 # Replicate char in the quadword...
+ beq r17, vc_fail # Quick exit if length=0
+
+ ldq_u r27, (r16) # First quadword of string
+ addq r16, r17, r0 # Point to end of string
+
+ subq r17, 8, r17 # Length > 8?
+ or r18, r28, r18 # ...
+
+ sll r18, 16, r28 # ...
+ bgt r17, vc_long # Skip if length > 8
+
+ ldq_u r16, -1(r0) # Last quadword of string
+ extql r27, r0, r27 # Position string at high end of QW
+
+ or r18, r28, r18 # ...
+ sll r18, 32, r28 # ...
+
+ extqh r16, r0, r16 # Position string at high end of QW
+ or r18, r28, r18 # Pattern fills a quadword
+
+ or r27, r16, r27 # String fills a quadword
+ xor r27, r18, r18 # Diff betw. string and pattern
+
+ subq r31, r17, r17 # 8 - length
+ extql r18, r17, r28 # Shift off bytes preceding string
+
+ lda r0, -1(r31) # Prepare to return -1 for all matched
+ cmpbge r31, r28, r27 # Set 1's where string=pattern
+
+ addl r28, 0, r18 # Is first LW all zero?
+ beq r28, vc_done # Quick exit if all matched
+
+ addq r27, 1, r28 # Flip the first '0' bit
+ beq r18, vc_geq_4 # No diffs in first longword
+
+ andnot r28, r27, r28 # Make one-bit mask of first diff
+ srl r28, 2, r0 # Map 1/2/4/8 -> 0/0/1/2
+
+ and r27, 1, r27 # 1 if first character matched
+ addq r0, r27, r0 # Bump by 1 if so
+
+ ret r31, (r26) # return
+
+ nop #.align 8
+
+vc_geq_4:
+ andnot r28, r27, r28 # Make one-bit mask of first diff
+ srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4
+
+ srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1
+ addq r27, 4, r0 # Bump by 4
+
+ subq r0, r28, r0 # and correct 4/5/6/8 -> 4/5/6/7
+vc_done:ret r31, (r26)
+
+ # Enter here if string length > 8.
+ # R16 -> start of string
+ # R17 = length - 8
+ # R18 = fill in bytes 0,1
+ # R27 = 1st QW of string
+ # R28 = fill in bytes 2,3
+
+ #.align 8
+vc_long:and r16, 7, r0 # Where in QW did we start?
+ or r18, r28, r18 # R18 has pattern in low 4 bytes
+
+ sll r18, 32, r28 # ...
+ addq r17, r0, r17 # Remaining length after 1st QW
+
+ or r18, r28, r18 # Pattern fills a QW
+ ldq_u r28, 8(r16) # Get next QW (string B)
+
+ xor r27, r18, r27 # Diff Betw. string and pattern
+ mskqh r27, r0, r27 # Discard diffs before string
+
+ subq r17, 16, r17 # More than two QW's to go?
+ subq r17, r0, r0 # Remember start point to compute len
+
+ ble r17, vc_bottom # Skip the loop if 2 QW's or less
+vc_loop:bne r27, vc_done_a
+
+ ldq_u r27, 16(r16) # Load string A
+ xor r28, r18, r28 # Diff betw string B and pattern
+
+ subq r17, 16, r17 # Decrement remaining length
+ bne r28, vc_done_b # Exit if a diff in string B
+
+ ldq_u r28, 24(r16) # Load string B
+ addq r16, 16, r16 # Increment pointer
+
+ xor r27, r18, r27 # Diff betw string A and pattern
+ bgt r17, vc_loop # Repeat if more than 2 QW's left
+
+vc_bottom:
+ bne r27, vc_done_a # Exit if a match in string A
+ addq r17, 8, r17 # More than 1 QW left?
+
+ xor r28, r18, r27 # Diff betw string B and pattern
+ ble r17, vc_last # Skip if this is last QW
+
+ subq r17, 16, r17 # Adjust len for final return
+ bne r27, vc_done_a # Exit if a match in string B
+
+ ldq_u r28, 16(r16) # Load string A
+ addq r17, 8, r17 # Ensure -7 <- (r17=len-8) <= 0
+
+ nop
+ xor r28, r18, r27 # Diff betw string A and pattern
+
+vc_last:mskqh r17, r17, r28 # -1 in bytes beyond string
+ subq r17, 16, r17 # Adjust len for final return
+
+ andnot r27, r28, r27 # Nonzeros only for diffs within string
+ bne r27, vc_done_a # Compute index if a diff found
+
+vc_fail:lda r0, -1(r31) # Else return -1
+ ret r31, (r26)
+
+vc_done_b:
+ addq r17, 8, r17 # Adjust length
+ mov r28, r27 # Put difference where it's expected
+
+vc_done_a:
+ cmpbge r31, r27, r28 # 1's where they match
+ subq r0, r17, r0 # (start - remaining) = base index
+
+ addl r27, 0, r16 # First longword all zero?
+ blbc r28, vc_exit # Return R0 if first char different
+
+ addq r28, 1, r27 # Flip the first '0' bit
+ beq r16, vc_geq_4x # Skip if no match in first 4
+
+ andnot r27, r28, r28 # Make one-bit mask of first match
+ srl r28, 2, r28 # Map 2/4/8 -> 0/1/2
+
+ addq r0, 1, r0 # Bump by 1
+ addq r0, r28, r0 # Add byte offset
+
+vc_exit:ret r31, (r26) # return
+
+vc_geq_4x:
+ andnot r27, r28, r28 # Make one-bit mask of first match
+
+ srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4
+ addq r0, 4, r0 # Bump by 4
+
+ srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1
+ addq r0, r27, r0 # Add 0/1/2/4
+
+ subq r0, r28, r0 # and correct
+ ret r31, (r26)
+
+ # ots_verify_mask
+ # This routine could be tailored by loading a longword or
+ # a quadword at a time and doing table lookups on the
+ # characters largely in parallel.
+ #
+ .globl _OtsStringVerifyMask
+ .aent _OtsStringVerifyMask
+_OtsStringVerifyMask:
+ .frame sp,0,r26
+
+ lda r16, -1(r16) # bias initial address for better loop code
+ nop # should be lnop (unop) or fnop to dual issue
+ lda r0, -1(r31) # initialize position to -1
+ ble r17, vm_ret # return -1 if source len is zero
+ # slow way - ~14 cycles/byte
+vm_loop:
+ ldq_u r21, 1(r16) # load qw containing the byte
+ lda r16, 1(r16) # bump pointer
+ addq r0, 1, r0 # bump position
+ subq r17, 1, r17 # decrement the length
+ extbl r21, r16, r21 # extract the byte
+ addq r21, r18, r21 # get the byte in the table
+ ldq_u r20, (r21) # load qw from table containing lookup
+ extbl r20, r21, r20 # extract table byte
+ and r20, r19, r20 # check if any bits in the mask match
+ beq r17, vm_end # if last character, handle specially
+ bne r20, vm_loop # if match, go do the loop again
+vm_ret:
+ ret r31, (r26) # if not a match, we're done
+vm_end: lda r21, -1(r31) # get -1
+ cmovne r20, r21, r0 # -1 if last char matched
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsLocation
diff --git a/private/crt32/misc/alpha/smove.s b/private/crt32/misc/alpha/smove.s
new file mode 100644
index 000000000..7428e97a8
--- /dev/null
+++ b/private/crt32/misc/alpha/smove.s
@@ -0,0 +1,652 @@
+ #++
+ # Copyright 1991, 1994, Digital Equipment Corporation
+ #
+ # ots_move(char *dstptr INOUT, long dstlen, char *srcptr)
+ #
+ # Move dstlen characters from *srcptr to *dstptr, possibly overlapping
+ #
+ # Special conventions: No stack space, r16-r20 and r27-r28 ONLY,
+ # no linkage pointer required, r16 is INOUT and points to the address
+ # following the move. (Warning: The auto-loader potentially takes
+ # some regs across the call if this is being used in a shared lib.
+ # environment.)
+ #
+ # This is a GEM support routine for moving (possibly overlapping) memory
+ # from one address to another. This is optimized for extremely high
+ # performance both for small blocks and large moves. In order to reduce
+ # overhead for small cases, they are retired as quickly as possible,
+ # more case analysis is reserved for cases which will do more. Note
+ # that while overlapping moves are supported, (unlike Sys V memcpy)
+ # routines), they are not quite as fast.
+ #
+ # Warning - This code is basically "expanded microcode". Since it is
+ # executed so frequently in many contexts, it has been extensively "hand-
+ # optimized"...
+ #
+ # Note that this routine and ots_movem are basically similar in many
+ # respects (same basic code), so maintenance should be done both
+ # places. This routine is primarily provided for lower overhead (for
+ # short strings).
+ #
+ # This version of OTS_MOVE provides longword granularity.
+ #
+ # 015 30 Aug 1994 WBN Longword granularity version, based on
+ # OTS_MOVE_ALPHA.M64 version 014.
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 = dst --> r16 = end
+ # r17 = len
+ # r18 = src
+ # destroys r17-r20, r27-r28
+
+ .globl _OtsMove
+ .ent _OtsMove
+_OtsMove:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+ beq r17, done # No memory accesses if length=0
+ subq r17, 4, r20 # Get length-4
+ ldq_u r28, (r18) # Load first QW of source
+ addq r17, r18, r27 # Point to end of source
+ andnot r16, 3, r19 # LW-aligned dst pointer
+ bge r20, geq4 # Go handle lengths >= 4
+ ldq_u r27, -1(r27) # Load last QW of source
+ and r16, 3, r16 # Get dst alignment within LW
+ ldl r17, (r19) # Load first LW of destination
+ addq r20, r16, r20 # Get alignment+length-4
+ extql r28, r18, r28 # Extract first bytes of source
+ bgt r20, double # Go handle LW crossing
+ extqh r27, r18, r27 # Extract last bytes of source
+ addq r20, 4, r20 # Get ending alignment in LW
+ or r27, r28, r28 # Combine halves of source
+ insql r28, r16, r28 # Position low part of source
+ mskql r17, r16, r18 # Keep low bytes of destination
+ mskql r28, r20, r28 # Trim off high bytes of source
+ mskqh r17, r20, r17 # Keep high bytes of destination
+ or r18, r28, r28 # Combine source with low dest
+ or r17, r28, r28 # Combine with high dest
+ stl r28, (r19) # Store to destination
+ addq r19, r20, r16 # Point to end of dest for return
+ ret r31, (r26)
+
+double: extqh r27, r18, r27 # Extract last bytes of source
+ ldl r18, 4(r19) # Load second LW of destination
+ mskql r17, r16, r17 # Keep low bytes of 1st dest LW
+ or r27, r28, r28 # Combine parts of source
+ insql r28, r16, r27 # Position start of source
+ addq r16, 4, r16 # Compute virtual start in LW
+ insqh r28, r16, r28 # Position end of source
+ addq r19, 4, r19 # Prepare to compute end address
+ mskqh r18, r20, r18 # Keep high bytes of 2nd dest LW
+ mskql r28, r20, r28 # Trim end of source to length
+ or r27, r17, r17 # Combine low source with 1st LW
+ stl r17, -4(r19)
+ or r28, r18, r18 # Combine high source with 2nd LW
+ stl r18, (r19)
+ addq r19, r20, r16 # Point to end of dest for return
+done: ret r31, (r26)
+
+ # Come here to move >= 4 bytes.
+ #
+ # r16-> dst
+ # r17 = length
+ # r18-> src
+ # r19-> LW-aligned dst
+ # r20 = len-4
+ # r27 = src+len
+ # r28 = first src QW
+
+geq4: subq r20, 4, r17 # At least 8 bytes to move?
+ subq r16, r27, r27 # Check if dst >= src+len
+ blt r17, lss8 # Move 4..7 bytes
+ subq r18, r16, r17 # Check if src >= dst
+ bge r27, ok1 # Forward OK if whole src precedes dst
+ blt r17, reverse # Go backwards if src < dst < src+len
+ok1: and r16, 7, r16
+ addq r16, r20, r27 # Alignment + length - 4
+ bne r16, part # Part of first QW to be skipped
+ subq r20, 4, r20 # At least 8 bytes to be stored?
+ beq r27, simple # Only low LW to be stored
+ and r18, 7, r27 # Is src address now aligned?
+ blt r20, shortq # Dst ends in first QW
+ subq r20, 32, r17 # At least 4 quadwords left to move?
+ beq r27, align # Go handle matching alignment
+
+ # Src alignment differs from dst alignment.
+ # r16 = dst alignment
+ # r17
+ # r18 = src-8 after 1st move
+ # r19 = initial dst
+ # r20 = initial length-8
+ # r27 = dst QW if dst wasn't aligned
+ # r28 = source QW
+
+misal: or r16, r19, r19 # Put alignment back with dst ptr ***
+ ldq_u r17, 8(r18) # Load same or next source QW
+ extql r28, r18, r28 # Get first part of source to store
+ addq r20, r16, r20 # Adjust length for partial move
+ mskql r27, r19, r27 # Trim destination for merge
+ extqh r17, r18, r16 # Get second part of source
+ subq r20, 24, r20 # At least 4 more quadwords?
+ or r28, r16, r28 # Combine pieces of source
+ mskqh r28, r19, r28 # Trim low junk off source
+ andnot r19, 7, r19 # Adjust dst for partial move
+ bge r20, unrol2 # Taken branch for long strings
+ addq r20, 16, r16 # Add back: how many whole QW's?
+ nop
+short2: and r20, 7, r20 # How many odd bytes?
+ blt r16, last # Skip if no more whole QW's
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r19)
+ extql r17, r18, r27 # Get last part of prior src QW
+ ldq_u r17, 16(r18) # Load another src QW
+ addq r19, 8, r19 # Update dst
+ subq r16, 8, r16 # More whole QW's?
+ addq r18, 8, r18 # Update src
+ blt r16, lastx # Skip if no more whole QWs
+ extqh r17, r18, r28 # Get first part of this src QW
+ addq r18, 8, r18 # Update src again
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r19)
+ extql r17, r18, r27 # Get last part of this src QW
+ ldq_u r17, 8(r18) # Load another src QW
+ addq r19, 8, r19 # Update dst
+lastx: extqh r17, r18, r28 # Get first part of this src QW
+last: addq r18, r20, r16 # Point to end-8 of src
+ beq r20, done_u # Skip if no odd bytes
+ or r28, r27, r28 # Combine parts of last whole QW
+ ldq_u r27, 7(r16) # Load final (maybe same) src QW
+ subq r20, 4, r16 # More than 4 bytes left?
+ stq r28, (r19) # Store last whole QW
+ extql r17, r18, r17 # Get last part of this src QW
+ extqh r27, r18, r27 # Get what we need from final src QW
+joinx: ldq r28, 8(r19) # Load last QW of destination
+ or r17, r27, r27 # Combine pieces of source
+ mskql r27, r20, r27 # Trim to length
+ mskqh r28, r20, r28 # Make room in destination
+ bgt r16, done_u # Go store a whole QW
+ addq r20, 8, r20 # Increment length for return
+ or r28, r27, r28 # Insert src into dst
+ stl r28, 8(r19) # Final LW
+ addq r19, r20, r16 # Point to end of dst for return
+ ret r31, (r26)
+
+ # Come here to move 4 thru 7 bytes.
+ #
+lss8: addq r18, r17, r27 # Recover src+len-8
+ and r16, 3, r16 # Dst alignment within LW
+ ldq_u r27, 7(r27) # Load last part of source
+ extql r28, r18, r28 # Extract first part of source
+ beq r16, lw # Handle LW-aligned dst
+ extqh r27, r18, r27 # Extract last part of source
+ ldl r18, (r19) # Load first LW of dst
+ addq r16, r20, r20 # align+len-4 of dst
+ or r28, r27, r28 # Complete source
+ mskql r28, r17, r28 # Trim source to length
+ mskql r18, r16, r18 # Make room in dst
+ insql r28, r16, r27 # Position src like dst
+ addq r16, r17, r17 # Align+len-8 of dst
+ or r27, r18, r18 # Merge
+ stl r18, (r19) # Store first LW of dst
+ extql r27, 4, r27 # Position next LW of src
+ blt r17, zz # Skip if not a whole LW
+ stl r27, 4(r19) # Store the whole LW
+ addq r19, 4, r19 # Adjust pointer
+ subq r20, 4, r20 # Adjust ending alignment
+ beq r17, donezz # Exit if done
+ insqh r28, r16, r27 # Position remainder of src
+zz: ldl r28, 4(r19) # Load last dst LW
+ mskqh r28, r20, r28 # Make room in dst
+ or r28, r27, r27 # Merge
+ stl r27, 4(r19) # Final store
+donezz: addq r19, r20, r16 # End address -4
+ addq r16, 4, r16
+ ret r31, (r26)
+
+lw: extqh r27, r18, r27 # Extract last part of source
+ addq r19, 4, r16 # Adjust for return value
+ beq r20, lwdone # Skip if exactly 4 bytes
+ ldl r17, 4(r19) # Load next dst LW
+ or r27, r28, r28 # Complete source
+ stl r28, (r19) # Store first LW
+ extql r28, 4, r28 # Position rest of source
+ mskqh r17, r20, r27 # Make room in dst
+ mskql r28, r20, r28 # Trim src
+ or r27, r28, r28 # Merge
+ stl r28, 4(r19)
+ addq r16, r20, r16 # Update return value
+ ret r31, (r26)
+
+lwdone: or r27, r28, r28 # Merge
+ stl r28, (r19)
+ ret r31, (r26)
+
+ # Move 4 bytes to an aligned LW.
+ #
+simple: ldq_u r27, 3(r18) # Load last QW of source
+ extql r28, r18, r28 # Position first QW
+ addq r19, 4, r16 # Point to end of dst for return
+ extqh r27, r18, r27 # Position last QW
+ or r28, r27, r28 # Merge
+ stl r28, (r19) # Store
+ ret r31, (r26)
+
+
+ # Dst is not aligned. Check whether first write is to a LW or a QW,
+ # and whether that finishes the move. Then see if src alignment
+ # matches, and read/rewrite the first dst quadword.
+ #
+ # r16 = dst alignment in QW
+ # r17
+ # r18-> src
+ # r19-> LW-aligned dst
+ # r20 = len-4
+ # r27 = QW_alignment + length - 4
+ # r28 = first src QW
+
+ #.align quad
+
+part: subq r27, 4, r17 # Does dst end in first QW?
+ ldq_u r27, (r19) # Load first dst QW
+ blt r17, shortu # Go handle short store
+ and r16, 4, r17 # Does it start in high LW?
+ subq r18, r16, r18 # Adjust src for this partial move
+ beq r17, quad # Whole QW to be touched
+ extql r28, r18, r17 # Position first part of source
+ ldq_u r28, 7(r18) # Get next (or same) src QW
+ mskql r27, r16, r27 # Trim destination for merge
+ addq r20, r16, r20 # Len + alignment...
+ extqh r28, r18, r28 # Position second part of source
+ subq r20, 4, r20 # Len+alignment-8 = remaining len
+ or r28, r17, r28 # Pieces of source
+ mskqh r28, r16, r17 # Trim junk preceding source
+ ldq_u r28, 7(r18) # Get src QW again **
+ or r27, r17, r17 # Combine other source piece
+ extql r17, 4, r17 # Get the high LW
+ stl r17, (r19) # Store just that
+
+ # Now at a QW boundary. Is there a QW left to store?
+ # Is the source QW aligned?
+
+ andnot r19, 7, r19 # Adjust dst pointer to next-8
+ subq r20, 8, r17 # Got a QW more?
+ and r18, 7, r27 # Src aligned?
+ blt r17, short3 # Too short
+ addq r19, 8, r19
+ subq r20, 8, r20
+ ldq_u r28, 8(r18)
+ addq r18, 8, r18
+ subq r20, 32, r17 # Prepare for unrolled loop
+ beq r27, align # Alignment matches
+ or r31, r31, r27
+ or r31, r31, r16
+ br r31, misal
+
+shortu: addq r18, r20, r20 # Point to end-4 of src
+ ldq_u r20, 3(r20) # Get last QW of source
+ extql r28, r18, r28 # Fetch first QW of source
+ extqh r20, r18, r20 # Fetch last QW of source
+ mskql r27, r16, r18 # Clear from start thru end of dst
+ mskqh r27, r17, r27 # Clear from 0 to end of dst
+ or r28, r20, r28 # Combine src pieces
+ insql r28, r16, r28 # Position src
+ or r27, r18, r27 # Combine dst pieces
+ mskql r28, r17, r28 # Trim src
+ addq r19, r17, r20 # Final pointer for return
+ or r28, r27, r28 # Merge src & dst
+ stq_u r28, (r19) # Store it
+ addq r20, 8, r16
+ ret r31, (r26)
+
+quad: and r18, 7, r17 # Is src address now aligned?
+ subq r20, 4, r20 # Get length-8
+ bne r17, misal # Go handle mismatched alignment
+ mskqh r28, r16, r28 # Keep desired part of source
+ addq r20, r16, r20 # Adjust count for this partial move
+ mskql r27, r16, r27 # Keep desired part of destination QW
+ subq r20, 32, r17 # At least 4 quadwords left to move?
+ or r27, r28, r28 # Merge source and destination
+
+ # Src alignment matches.
+ # r16
+ # r17 = remaining length -32
+ # r18 = next src pointer -8
+ # r19 = dst pointer
+ # r20
+ # r27
+ # r28 = dst quadword
+
+align: and r17, 24, r20 # How many after a multiple of 4?
+ bge r17, unrol1 # Taken branch for long strings
+ nop
+short1: and r17, 7, r17 # How many odd bytes?
+ beq r20, last28 # Skip if no more whole QWs after r28
+ ldq r27, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r28, (r19) # Store prior QW
+ subq r20, 16, r20 # Map 8/16/24 to -8/0/8
+ addq r19, 8, r19
+ blt r20, last27 # Skip if no more after r27
+ ldq r28, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r27, (r19) # Store prior QW
+ addq r19, 8, r19
+ nop
+ beq r20, last28
+ ldq r27, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r28, (r19) # Store prior QW
+ addq r19, 8, r19
+last27: beq r17, done27 # Skip if no odd bytes
+ ldq r28, 8(r18) # Load one more src QW
+ ldq r18, 8(r19) # Load last destination QW
+ subq r17, 4, r16 # More than 4 bytes to store?
+ stq r27, (r19) # Store prior QW
+ mskql r28, r17, r27 # Trim source
+ mskqh r18, r17, r18 # Trim destination
+ ble r16, lastl # Go store just a LW
+lastq: addq r19, r17, r19 # End-8 of dst for return
+ or r27, r18, r27 # Merge src & dst
+done27: stq_u r27, 7(r19) # Store last destination QW
+ addq r19, 8, r16 # End of dst for return
+ ret r31, (r26)
+
+short3: addq r18, r20, r16 # Point to end-8 of src
+ beq r20, donexx # Completely done?
+ ldq_u r17, 7(r16) # Load final src QW
+ subq r20, 4, r16 # Got more than a LW?
+ beq r27, joinx # Don't include prior src if aligned
+ extql r28, r18, r27 # Last part of prior src QW
+ extqh r17, r18, r17 # First part of this src QW
+ br joinx
+
+donexx: addq r19, r20, r16
+ addq r16, 8, r16
+ ret r31, (r26)
+
+last28: beq r17, done28 # Skip if no odd bytes
+ ldq r27, 8(r18) # Load one more src QW
+ ldq r18, 8(r19) # Load last destination QW
+ subq r17, 4, r16 # More than 4 bytes to store?
+ stq r28, (r19) # Store prior QW
+ mskql r27, r17, r27 # Trim source
+ mskqh r18, r17, r18 # Trim destination
+ bgt r16, lastq # Go store a QW
+lastl: addq r17, 8, r17 # Increment length for return
+ or r27, r18, r27 # Merge src & dst
+ stl r27, 8(r19) # Store last destination LW
+ addq r19, r17, r16 # End of dst for return
+ ret r31, (r26)
+
+shortq: addq r18, r20, r16 # Point to end-8 of src
+ ldq r27, (r19) # Get dst QW
+ extql r28, r18, r28 # Position first src QW
+ ldq_u r17, 7(r16) # Get last QW of src
+ mskqh r27, r20, r27 # Mask dst QW
+ extqh r17, r18, r17 # Position last src QW
+ or r17, r28, r28 # Merge
+ mskql r28, r20, r28 # Trim src QW
+done_u: addq r19, r20, r19 # End-8 of dst for return
+ or r28, r27, r28 # Combine pieces
+done28: stq_u r28, 7(r19) # Store last destination QW
+ addq r19, 8, r16 # End of dst for return
+ ret r31, (r26)
+
+ # Unrolled loop for long moves with matching alignment within QW.
+ # Each iteration moves two cache blocks.
+ # We try to schedule the cache misses to avoid a double miss
+ # in EV4 pass 2.1 chips. If the source alignment within a cache
+ # block is exactly 3, alter it, since that case runs slower.
+ #
+ # R19 = dst pointer
+ # R17 = remaining length (to load) - 32
+ # R18 = src pointer
+ # R16
+ # R20 = length & 24 (needed at return)
+ # R27
+ # R28 = QW from 0(R18) to store at 0(R19), both on input and at return
+ #
+
+ #.align quad
+
+unrol1: ldq r27, 32(r18) # Cache miss here; later loads hit.
+ subq r17, 48, r16 # Six more quadwords?
+ and r18, 16, r20 # Starting in 2nd half of cache block?
+ blt r16, uent1 # If not 6 more, don't adjust.
+ ldq r16, 8(r18)
+ beq r20, utop1 # If in 1st half, don't adjust.
+ ldq r27, 48(r18) # Cache miss here
+ addq r18, 16, r18
+ stq r28, (r19) # Adjust by going ahead 1/2 block.
+ addq r19, 16, r19
+ ldq r28, (r18)
+ subq r17, 16, r17
+ stq r16, -8(r19)
+ nop
+ ldq r16, 8(r18)
+utop1: subq r17, 32, r17
+
+uloop1: ldq r20, 64(r18) # Cache miss here
+ stq r28, (r19)
+ ldq r28, 16(r18)
+ stq r16, 8(r19)
+ ldq r16, 24(r18)
+ addq r18, 64, r18
+ stq r28, 16(r19)
+ mov r20, r28
+ stq r16, 24(r19)
+ addq r19, 64, r19
+ ldq r20, -24(r18)
+ subq r17, 32, r17
+ blt r17, uexit1
+ ldq r16, 32(r18) # Cache miss here
+ stq r27, -32(r19)
+ ldq r27, -16(r18)
+ stq r20, -24(r19)
+ ldq r20, -8(r18)
+ stq r27, -16(r19)
+ mov r16, r27
+ stq r20, -8(r19)
+uent1: subq r17, 32, r17
+ ldq r16, 8(r18)
+ bge r17, uloop1
+
+ # finish last block of 4 quadwords
+ #
+ubot1: stq r28, (r19)
+ mov r27, r28 # Position last QW for return
+ ldq r27, 16(r18)
+ addq r18, 32, r18
+ stq r16, 8(r19)
+ addq r19, 32, r19
+uex1a: ldq r16, -8(r18)
+ and r17, 24, r20 # Recover count of remaining QW's
+ stq r27, -16(r19)
+ stq r16, -8(r19)
+ br r31, short1
+
+ nop
+uexit1: stq r27, -32(r19) # Here if exit from middle of loop
+ ldq r27, -16(r18)
+ stq r20, -24(r19)
+ br r31, uex1a # Join common exit sequence
+
+ #.align quad
+
+unrol2: ldq_u r16, 16(r18) # Load next src QW
+ extql r17, r18, r17 # Get last part of prior one
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r19) # Store prior dst QW
+ subq r20, 24, r20 # Update loop counter
+ extqh r16, r18, r28 # Get first part of a src QW
+ ldq_u r27, 24(r18) # Load next src QW
+ extql r16, r18, r16 # Get last part of prior one
+ or r28, r17, r28 # Combine pieces
+ stq r28, 8(r19) # Store prior dst QW
+ addq r19, 24, r19 # Update dst pointer
+ extqh r27, r18, r28 # Get first part of a src QW
+ ldq_u r17, 32(r18) # Load next src QW
+ extql r27, r18, r27 # Get last part of prior one
+ or r28, r16, r28 # Combine pieces
+ stq r28, -8(r19) # Store prior dst QW
+ addq r18, 24, r18 # Update src pointer
+ extqh r17, r18, r28 # Get first part of a src QW
+ bge r20, unrol2 # Repeat as needed
+ addq r20, 16, r16 # How many whole quadwords left?
+ br r31, short2 # Go handle leftovers
+ nop
+
+ # Must move in reverse order because of overlap.
+ # r16 = dst address
+ # r17
+ # r18 = src address
+ # r19
+ # r20 = len-4 (>= 0)
+ # r27
+ # r28
+
+ # Not yet LW-granularity...
+
+reverse:
+ subq r20, 4, r20 # This code expects len-8
+ addq r20, r18, r18 # Point to end-8 of source
+ addq r20, r16, r17 # Point to end-8 of destination
+ and r17, 7, r19 # Is destination aligned?
+ ldq_u r28, 7(r18) # Get source QW
+ addq r17, 8, r16 # Point to end of dst for return
+ bne r19, rpart # Skip if partial write needed
+ and r18, 7, r27 # Is source aligned too?
+ beq r27, ralign # Skip if so
+ ldq_u r19, (r18) # Handle aligned dst, unaligned src
+ subq r20, 8, r20
+ extqh r28, r18, r28
+ extql r19, r18, r27
+ br r31, rwhole
+
+rmis: ldq_u r19, (r18) # Load same or preceding src QW
+ extqh r28, r18, r28 # Get last part of source to store
+ mskqh r27, r16, r27 # Keep high-address part of dst
+ extql r19, r18, r19
+ subq r20, 8, r20 # How many more whole QW's?
+ or r19, r28, r28
+ ldq_u r19, (r18) # Reload source QW
+ mskql r28, r16, r28 # Trim source to length
+rwhole: blt r20, rlast2 # Skip if no more whole QW's
+rloop2: or r28, r27, r28 # Combine pieces
+ stq r28, (r17)
+rent2: extqh r19, r18, r27
+ ldq_u r19, -8(r18)
+ subq r20, 8, r20
+ subq r17, 8, r17
+ extql r19, r18, r28
+ subq r18, 8, r18
+ bge r20, rloop2
+rlast2: and r20, 7, r20
+ beq r20, rdone2
+ or r28, r27, r28
+ subq r18, r20, r27
+ stq r28, (r17)
+rl2ent: subq r31, r20, r20
+ ldq_u r27, (r27)
+ extqh r19, r18, r19
+ ldq r28, -8(r17)
+ subq r17, 8, r17
+ extql r27, r18, r27
+ mskql r28, r20, r28
+ or r27, r19, r27
+ mskqh r27, r20, r27
+ and r20, 4, r19 # Ending in high LW?
+ bne r19, rdone3 # Only longword store at the end
+rdone2: or r28, r27, r28
+ stq r28, (r17)
+ ret r31, (r26)
+
+rdone3: or r28, r27, r28
+ extql r28, 4, r28
+ stl r28, 4(r17)
+ ret r31, (r26)
+
+rpart: ldq_u r27, 7(r17) # Get dst QW
+ subq r19, 8, r19 # Get negative of bytes not moved
+ subq r18, r19, r18 # From src-8, get src after partial
+ subq r20, r19, r20 # Adjust length for partial move
+ subq r17, r19, r17 # Adjust dst pointer
+ addq r19, 4, r19 # End alignment - 4
+ ble r19, r_lw # Only storing the low longword?
+ and r18, 7, r19 # Src alignment now matching dst?
+ bne r19, rmis # Go back if not
+ mskql r28, r16, r28 # Keep low addresses of src QW
+ mskqh r27, r16, r27 # Keep high address of dst QW
+ralign: subq r20, 8, r20 # How many more whole QW's?
+ or r27, r28, r28 # Combine
+ blt r20, rlast1 # Skip if this is the end
+rloop1: stq r28, (r17) # Store one QW
+rent1: subq r20, 8, r20 # Decrement length
+ ldq r28, -8(r18) # Load preceding QW
+ subq r17, 8, r17 # Decrement dst pointer
+ subq r18, 8, r18 # Decrement src pointer
+ bge r20, rloop1 # Repeat for each whole QW
+rlast1: and r20, 7, r20 # How many odd bytes?
+ beq r20, rdone # Skip if none
+ ldq r27, -8(r18) # Get another source QW
+ subq r31, r20, r20 # Get byte # to end at
+ stq r28, (r17)
+rl_ent: ldq r28, -8(r17)
+ subq r17, 8, r17 # Adjust dst pointer again
+ mskqh r27, r20, r27 # Keep top of src QW
+ and r20, 4, r19 # Ending in high LW?
+ mskql r28, r20, r28 # Keep bottom of dst QW
+ bne r19, rdone4 # Only longword store at the end
+ or r27, r28, r28 # Combine
+rdone: stq r28, (r17) # Store last QW
+ ret r31, (r26)
+
+rdone4: or r27, r28, r28 # Combine
+ extql r28, 4, r28 # Get high part
+ stl r28, 4(r17) # Store last LW
+ ret r31, (r26)
+
+r_lw: and r18, 7, r19 # Src alignment now matching dst?
+ bne r19, rmislw # Go back if not
+ mskql r28, r16, r28 # Keep low addresses of src QW
+ mskqh r27, r16, r27 # Keep high address of dst QW
+ subq r20, 8, r20 # How many more whole QW's?
+ or r27, r28, r28 # Combine
+ blt r20, rlast1_lw # Skip if this is the end
+ stl r28, (r17) # Store one QW
+ br r31, rent1
+
+rlast1_lw:
+ and r20, 7, r20 # How many odd bytes?
+ ldq r27, -8(r18) # Get another source QW
+ subq r31, r20, r20 # Get byte # to end at
+ stl r28, (r17)
+ br rl_ent
+
+rmislw: ldq_u r19, (r18) # Load same or preceding src QW
+ extqh r28, r18, r28 # Get last part of source to store
+ mskqh r27, r16, r27 # Keep high-address part of dst
+ extql r19, r18, r19
+ subq r20, 8, r20 # How many more whole QW's?
+ or r19, r28, r28
+ ldq_u r19, (r18) # Reload source QW
+ mskql r28, r16, r28 # Trim source to length
+ blt r20, rlast2_lw # Skip if no more whole QW's
+ or r28, r27, r28 # Combine pieces
+ stl r28, (r17)
+ br r31, rent2
+
+rlast2_lw:
+ and r20, 7, r20
+ or r28, r27, r28
+ subq r18, r20, r27
+ stl r28, (r17)
+ br r31, rl2ent
+
+ .set at
+ .set reorder
+ .end _OtsMove
diff --git a/private/crt32/misc/alpha/smovem.s b/private/crt32/misc/alpha/smovem.s
new file mode 100644
index 000000000..11f859f20
--- /dev/null
+++ b/private/crt32/misc/alpha/smovem.s
@@ -0,0 +1,667 @@
+ #++
+ # Copyright 1991, 1994, Digital Equipment Corporation
+ #
+ # ots_movem(char *dstptr INOUT, long dstlen INOUT,
+ # char *srcptr, long srclen)
+ #
+ # Move dstlen characters from *srcptr to *dstptr, possibly overlapping
+ #
+ # Special conventions: No stack space, r16-r21 and r27-r28 ONLY,
+ # no linkage pointer required, r16 is INOUT and points to the address
+ # following the move, r17 is INOUT and has the remaining destination
+ # length following the move.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # This is a GEM support routine for moving (possibly overlapping) memory
+ # from one address to another. This is optimized for extremely high
+ # performance both for small blocks and large moves. In order to reduce
+ # overhead for small cases, they are retired as quickly as possible,
+ # more case analysis is reserved for cases which will do more. Note
+ # that while overlapping moves are supported, (unlike Sys V memcpy)
+ # routines), they are not quite as fast.
+ #
+ # Warning - This code is basically "expanded microcode". Since it is
+ # executed so frequently in many contexts, it has been extensively "hand-
+ # optimized"...
+ #
+ # Note that this routine and ots_move are basically similar in many
+ # respects (same basic code), so maintenance should be done both
+ # places. This routine is primarily provided for lower overhead (for
+ # short strings).
+ # [Except for the first few instructions, the recipe for creating OTS_MOVEM
+ # from OTS_MOVE is to change uses of R19->R21 and then R17->R19.]
+ #
+ # This version of OTS_MOVEM provides longword granularity.
+ #
+ # 015 1 Sep 1994 WBN Longword granularity version, based on
+ # OTS_MOVEM_ALPHA.M64 version 014 and
+ # OTS_MOVE_ALPHA_WNT.M64 version 015.
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 = dst --> r16 = end
+ # r19 = dst_len --> r17 = remaining
+ # r18 = src
+ # r19 = src_len
+ # destroys r18-r21, r27-r28
+
+ .globl _OtsMoveMinimum
+ .ent _OtsMoveMinimum
+_OtsMoveMinimum:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+ subq r17, r19, r20 # Which length is larger?
+ cmovlt r20, r17, r19 # Min to r19
+ andnot r16, 3, r21 # LW-aligned dst pointer
+ subq r19, 4, r20 # Get length-4
+ beq r19, done # No memory accesses if length=0
+ ldq_u r28, (r18) # Load first QW of source
+ addq r19, r18, r27 # Point to end of source
+ subq r17, r19, r17 # Set remaining length for return
+ bge r20, geq4 # Go handle lengths >= 4
+ ldq_u r27, -1(r27) # Load last QW of source
+ and r16, 3, r16 # Get dst alignment within LW
+ ldl r19, (r21) # Load first LW of destination
+ addq r20, r16, r20 # Get alignment+length-4
+ extql r28, r18, r28 # Extract first bytes of source
+ bgt r20, double # Go handle LW crossing
+ extqh r27, r18, r27 # Extract last bytes of source
+ addq r20, 4, r20 # Get ending alignment in LW
+ or r27, r28, r28 # Combine halves of source
+ insql r28, r16, r28 # Position low part of source
+ mskql r19, r16, r18 # Keep low bytes of destination
+ mskql r28, r20, r28 # Trim off high bytes of source
+ mskqh r19, r20, r19 # Keep high bytes of destination
+ or r18, r28, r28 # Combine source with low dest
+ or r19, r28, r28 # Combine with high dest
+ stl r28, (r21) # Store to destination
+ addq r21, r20, r16 # Point to end of dest for return
+ ret r31, (r26)
+
+double: extqh r27, r18, r27 # Extract last bytes of source
+ ldl r18, 4(r21) # Load second LW of destination
+ mskql r19, r16, r19 # Keep low bytes of 1st dest LW
+ or r27, r28, r28 # Combine parts of source
+ insql r28, r16, r27 # Position start of source
+ addq r16, 4, r16 # Compute virtual start in LW
+ insqh r28, r16, r28 # Position end of source
+ addq r21, 4, r21 # Prepare to compute end address
+ mskqh r18, r20, r18 # Keep high bytes of 2nd dest LW
+ mskql r28, r20, r28 # Trim end of source to length
+ or r27, r19, r19 # Combine low source with 1st LW
+ stl r19, -4(r21)
+ or r28, r18, r18 # Combine high source with 2nd LW
+ stl r18, (r21)
+ addq r21, r20, r16 # Point to end of dest for return
+done: ret r31, (r26)
+
+ # Come here to move >= 4 bytes.
+ #
+ # r16-> dst
+ # r17 = remaining length for return
+ # r18-> src
+ # r19 = length
+ # r20 = len-4
+ # r21-> LW-aligned dst
+ # r27 = src+len
+ # r28 = first src QW
+
+geq4: subq r20, 4, r19 # At least 8 bytes to move?
+ subq r16, r27, r27 # Check if dst >= src+len
+ blt r19, lss8 # Move 4..7 bytes
+ subq r18, r16, r19 # Check if src >= dst
+ bge r27, ok1 # Forward OK if whole src precedes dst
+ blt r19, reverse # Go backwards if src < dst < src+len
+ok1: and r16, 7, r16
+ addq r16, r20, r27 # Alignment + length - 4
+ bne r16, part # Part of first QW to be skipped
+ subq r20, 4, r20 # At least 8 bytes to be stored?
+ beq r27, simple # Only low LW to be stored
+ and r18, 7, r27 # Is src address now aligned?
+ blt r20, shortq # Dst ends in first QW
+ subq r20, 32, r19 # At least 4 quadwords left to move?
+ beq r27, align # Go handle matching alignment
+
+ # Src alignment differs from dst alignment.
+ # r16 = dst alignment
+ # r17 = remaining length for return
+ # r18 = src-8 after 1st move
+ # r19
+ # r20 = initial length-8
+ # r21 = initial dst
+ # r27 = dst QW if dst wasn't aligned
+ # r28 = source QW
+
+misal: or r16, r21, r21 # Put alignment back with dst ptr ***
+ ldq_u r19, 8(r18) # Load same or next source QW
+ extql r28, r18, r28 # Get first part of source to store
+ addq r20, r16, r20 # Adjust length for partial move
+ mskql r27, r21, r27 # Trim destination for merge
+ extqh r19, r18, r16 # Get second part of source
+ subq r20, 24, r20 # At least 4 more quadwords?
+ or r28, r16, r28 # Combine pieces of source
+ mskqh r28, r21, r28 # Trim low junk off source
+ andnot r21, 7, r21 # Adjust dst for partial move
+ bge r20, unrol2 # Taken branch for long strings
+ addq r20, 16, r16 # Add back: how many whole QW's?
+ nop
+short2: and r20, 7, r20 # How many odd bytes?
+ blt r16, last # Skip if no more whole QW's
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r21)
+ extql r19, r18, r27 # Get last part of prior src QW
+ ldq_u r19, 16(r18) # Load another src QW
+ addq r21, 8, r21 # Update dst
+ subq r16, 8, r16 # More whole QW's?
+ addq r18, 8, r18 # Update src
+ blt r16, lastx # Skip if no more whole QWs
+ extqh r19, r18, r28 # Get first part of this src QW
+ addq r18, 8, r18 # Update src again
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r21)
+ extql r19, r18, r27 # Get last part of this src QW
+ ldq_u r19, 8(r18) # Load another src QW
+ addq r21, 8, r21 # Update dst
+lastx: extqh r19, r18, r28 # Get first part of this src QW
+last: addq r18, r20, r16 # Point to end-8 of src
+ beq r20, done_u # Skip if no odd bytes
+ or r28, r27, r28 # Combine parts of last whole QW
+ ldq_u r27, 7(r16) # Load final (maybe same) src QW
+ subq r20, 4, r16 # More than 4 bytes left?
+ stq r28, (r21) # Store last whole QW
+ extql r19, r18, r19 # Get last part of this src QW
+ extqh r27, r18, r27 # Get what we need from final src QW
+joinx: ldq r28, 8(r21) # Load last QW of destination
+ or r19, r27, r27 # Combine pieces of source
+ mskql r27, r20, r27 # Trim to length
+ mskqh r28, r20, r28 # Make room in destination
+ bgt r16, done_u # Go store a whole QW
+ addq r20, 8, r20 # Increment length for return
+ or r28, r27, r28 # Insert src into dst
+ stl r28, 8(r21) # Final LW
+ addq r21, r20, r16 # Point to end of dst for return
+ ret r31, (r26)
+
+ # Come here to move 4 thru 7 bytes.
+ #
+lss8: addq r18, r19, r27 # Recover src+len-8
+ and r16, 3, r16 # Dst alignment within LW
+ ldq_u r27, 7(r27) # Load last part of source
+ extql r28, r18, r28 # Extract first part of source
+ beq r16, lw # Handle LW-aligned dst
+ extqh r27, r18, r27 # Extract last part of source
+ ldl r18, (r21) # Load first LW of dst
+ addq r16, r20, r20 # align+len-4 of dst
+ or r28, r27, r28 # Complete source
+ mskql r28, r19, r28 # Trim source to length
+ mskql r18, r16, r18 # Make room in dst
+ insql r28, r16, r27 # Position src like dst
+ addq r16, r19, r19 # Align+len-8 of dst
+ or r27, r18, r18 # Merge
+ stl r18, (r21) # Store first LW of dst
+ extql r27, 4, r27 # Position next LW of src
+ blt r19, zz # Skip if not a whole LW
+ stl r27, 4(r21) # Store the whole LW
+ addq r21, 4, r21 # Adjust pointer
+ subq r20, 4, r20 # Adjust ending alignment
+ beq r19, donezz # Exit if done
+ insqh r28, r16, r27 # Position remainder of src
+zz: ldl r28, 4(r21) # Load last dst LW
+ mskqh r28, r20, r28 # Make room in dst
+ or r28, r27, r27 # Merge
+ stl r27, 4(r21) # Final store
+donezz: addq r21, r20, r16 # End address -4
+ addq r16, 4, r16
+ ret r31, (r26)
+
+lw: extqh r27, r18, r27 # Extract last part of source
+ addq r21, 4, r16 # Adjust for return value
+ beq r20, lwdone # Skip if exactly 4 bytes
+ ldl r19, 4(r21) # Load next dst LW
+ or r27, r28, r28 # Complete source
+ stl r28, (r21) # Store first LW
+ extql r28, 4, r28 # Position rest of source
+ mskqh r19, r20, r27 # Make room in dst
+ mskql r28, r20, r28 # Trim src
+ or r27, r28, r28 # Merge
+ stl r28, 4(r21)
+ addq r16, r20, r16 # Update return value
+ ret r31, (r26)
+
+lwdone: or r27, r28, r28 # Merge
+ stl r28, (r21)
+ ret r31, (r26)
+
+ # Move 4 bytes to an aligned LW.
+ #
+simple: ldq_u r27, 3(r18) # Load last QW of source
+ extql r28, r18, r28 # Position first QW
+ addq r21, 4, r16 # Point to end of dst for return
+ extqh r27, r18, r27 # Position last QW
+ or r28, r27, r28 # Merge
+ stl r28, (r21) # Store
+ ret r31, (r26)
+
+
+ # Dst is not aligned. Check whether first write is to a LW or a QW,
+ # and whether that finishes the move. Then see if src alignment
+ # matches, and read/rewrite the first dst quadword.
+ #
+ # r16 = dst alignment in QW
+ # r17 = remaining length for return
+ # r18-> src
+ # r19
+ # r20 = len-4
+ # r21-> LW-aligned dst
+ # r27 = QW_alignment + length - 4
+ # r28 = first src QW
+
+ #.align quad
+
+part: subq r27, 4, r19 # Does dst end in first QW?
+ ldq_u r27, (r21) # Load first dst QW
+ blt r19, shortu # Go handle short store
+ and r16, 4, r19 # Does it start in high LW?
+ subq r18, r16, r18 # Adjust src for this partial move
+ beq r19, quad # Whole QW to be touched
+ extql r28, r18, r19 # Position first part of source
+ ldq_u r28, 7(r18) # Get next (or same) src QW
+ mskql r27, r16, r27 # Trim destination for merge
+ addq r20, r16, r20 # Len + alignment...
+ extqh r28, r18, r28 # Position second part of source
+ subq r20, 4, r20 # Len+alignment-8 = remaining len
+ or r28, r19, r28 # Pieces of source
+ mskqh r28, r16, r19 # Trim junk preceding source
+ ldq_u r28, 7(r18) # Get src QW again **
+ or r27, r19, r19 # Combine other source piece
+ extql r19, 4, r19 # Get the high LW
+ stl r19, (r21) # Store just that
+
+ # Now at a QW boundary. Is there a QW left to store?
+ # Is the source QW aligned?
+
+ andnot r21, 7, r21 # Adjust dst pointer to next-8
+ subq r20, 8, r19 # Got a QW more?
+ and r18, 7, r27 # Src aligned?
+ blt r19, short3 # Too short
+ addq r21, 8, r21
+ subq r20, 8, r20
+ ldq_u r28, 8(r18)
+ addq r18, 8, r18
+ subq r20, 32, r19 # Prepare for unrolled loop
+ beq r27, align # Alignment matches
+ or r31, r31, r27
+ or r31, r31, r16
+ br r31, misal
+
+shortu: addq r18, r20, r20 # Point to end-4 of src
+ ldq_u r20, 3(r20) # Get last QW of source
+ extql r28, r18, r28 # Fetch first QW of source
+ extqh r20, r18, r20 # Fetch last QW of source
+ mskql r27, r16, r18 # Clear from start thru end of dst
+ mskqh r27, r19, r27 # Clear from 0 to end of dst
+ or r28, r20, r28 # Combine src pieces
+ insql r28, r16, r28 # Position src
+ or r27, r18, r27 # Combine dst pieces
+ mskql r28, r19, r28 # Trim src
+ addq r21, r19, r20 # Final pointer for return
+ or r28, r27, r28 # Merge src & dst
+ stq_u r28, (r21) # Store it
+ addq r20, 8, r16
+ ret r31, (r26)
+
+quad: and r18, 7, r19 # Is src address now aligned?
+ subq r20, 4, r20 # Get length-8
+ bne r19, misal # Go handle mismatched alignment
+ mskqh r28, r16, r28 # Keep desired part of source
+ addq r20, r16, r20 # Adjust count for this partial move
+ mskql r27, r16, r27 # Keep desired part of destination QW
+ subq r20, 32, r19 # At least 4 quadwords left to move?
+ or r27, r28, r28 # Merge source and destination
+
+ # Src alignment matches.
+ # r16
+ # r17 = remaining length for return
+ # r18 = next src pointer -8
+ # r19 = remaining length -32
+ # r20
+ # r21 = dst pointer
+ # r27
+ # r28 = dst quadword
+
+align: and r19, 24, r20 # How many after a multiple of 4?
+ bge r19, unrol1 # Taken branch for long strings
+ nop
+short1: and r19, 7, r19 # How many odd bytes?
+ beq r20, last28 # Skip if no more whole QWs after r28
+ ldq r27, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r28, (r21) # Store prior QW
+ subq r20, 16, r20 # Map 8/16/24 to -8/0/8
+ addq r21, 8, r21
+ blt r20, last27 # Skip if no more after r27
+ ldq r28, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r27, (r21) # Store prior QW
+ addq r21, 8, r21
+ nop
+ beq r20, last28
+ ldq r27, 8(r18) # Load next QW
+ addq r18, 8, r18
+ stq r28, (r21) # Store prior QW
+ addq r21, 8, r21
+last27: beq r19, done27 # Skip if no odd bytes
+ ldq r28, 8(r18) # Load one more src QW
+ ldq r18, 8(r21) # Load last destination QW
+ subq r19, 4, r16 # More than 4 bytes to store?
+ stq r27, (r21) # Store prior QW
+ mskql r28, r19, r27 # Trim source
+ mskqh r18, r19, r18 # Trim destination
+ ble r16, lastl # Go store just a LW
+lastq: addq r21, r19, r21 # End-8 of dst for return
+ or r27, r18, r27 # Merge src & dst
+done27: stq_u r27, 7(r21) # Store last destination QW
+ addq r21, 8, r16 # End of dst for return
+ ret r31, (r26)
+
+short3: addq r18, r20, r16 # Point to end-8 of src
+ beq r20, donexx # Completely done?
+ ldq_u r19, 7(r16) # Load final src QW
+ subq r20, 4, r16 # Got more than a LW?
+ beq r27, joinx # Don't include prior src if aligned
+ extql r28, r18, r27 # Last part of prior src QW
+ extqh r19, r18, r19 # First part of this src QW
+ br joinx
+
+donexx: addq r21, r20, r16
+ addq r16, 8, r16
+ ret r31, (r26)
+
+last28: beq r19, done28 # Skip if no odd bytes
+ ldq r27, 8(r18) # Load one more src QW
+ ldq r18, 8(r21) # Load last destination QW
+ subq r19, 4, r16 # More than 4 bytes to store?
+ stq r28, (r21) # Store prior QW
+ mskql r27, r19, r27 # Trim source
+ mskqh r18, r19, r18 # Trim destination
+ bgt r16, lastq # Go store a QW
+lastl: addq r19, 8, r19 # Increment length for return
+ or r27, r18, r27 # Merge src & dst
+ stl r27, 8(r21) # Store last destination LW
+ addq r21, r19, r16 # End of dst for return
+ ret r31, (r26)
+
+shortq: addq r18, r20, r16 # Point to end-8 of src
+ ldq r27, (r21) # Get dst QW
+ extql r28, r18, r28 # Position first src QW
+ ldq_u r19, 7(r16) # Get last QW of src
+ mskqh r27, r20, r27 # Mask dst QW
+ extqh r19, r18, r19 # Position last src QW
+ or r19, r28, r28 # Merge
+ mskql r28, r20, r28 # Trim src QW
+done_u: addq r21, r20, r21 # End-8 of dst for return
+ or r28, r27, r28 # Combine pieces
+done28: stq_u r28, 7(r21) # Store last destination QW
+ addq r21, 8, r16 # End of dst for return
+ ret r31, (r26)
+
+ # Unrolled loop for long moves with matching alignment within QW.
+ # Each iteration moves two cache blocks.
+ # We try to schedule the cache misses to avoid a double miss
+ # in EV4 pass 2.1 chips. If the source alignment within a cache
+ # block is exactly 3, alter it, since that case runs slower.
+ #
+ # R16
+ # R17 = remaining length for return
+ # R18 = src pointer
+ # R19 = remaining length (to load) - 32
+ # R20 = length & 24 (needed at return)
+ # R21 = dst pointer
+ # R27
+ # R28 = QW from 0(R18) to store at 0(R21), both on input and at return
+ #
+
+ #.align quad
+
+unrol1: ldq r27, 32(r18) # Cache miss here; later loads hit.
+ subq r19, 48, r16 # Six more quadwords?
+ and r18, 16, r20 # Starting in 2nd half of cache block?
+ blt r16, uent1 # If not 6 more, don't adjust.
+ ldq r16, 8(r18)
+ beq r20, utop1 # If in 1st half, don't adjust.
+ ldq r27, 48(r18) # Cache miss here
+ addq r18, 16, r18
+ stq r28, (r21) # Adjust by going ahead 1/2 block.
+ addq r21, 16, r21
+ ldq r28, (r18)
+ subq r19, 16, r19
+ stq r16, -8(r21)
+ nop
+ ldq r16, 8(r18)
+utop1: subq r19, 32, r19
+
+uloop1: ldq r20, 64(r18) # Cache miss here
+ stq r28, (r21)
+ ldq r28, 16(r18)
+ stq r16, 8(r21)
+ ldq r16, 24(r18)
+ addq r18, 64, r18
+ stq r28, 16(r21)
+ mov r20, r28
+ stq r16, 24(r21)
+ addq r21, 64, r21
+ ldq r20, -24(r18)
+ subq r19, 32, r19
+ blt r19, uexit1
+ ldq r16, 32(r18) # Cache miss here
+ stq r27, -32(r21)
+ ldq r27, -16(r18)
+ stq r20, -24(r21)
+ ldq r20, -8(r18)
+ stq r27, -16(r21)
+ mov r16, r27
+ stq r20, -8(r21)
+uent1: subq r19, 32, r19
+ ldq r16, 8(r18)
+ bge r19, uloop1
+
+ # finish last block of 4 quadwords
+ #
+ubot1: stq r28, (r21)
+ mov r27, r28 # Position last QW for return
+ ldq r27, 16(r18)
+ addq r18, 32, r18
+ stq r16, 8(r21)
+ addq r21, 32, r21
+uex1a: ldq r16, -8(r18)
+ and r19, 24, r20 # Recover count of remaining QW's
+ stq r27, -16(r21)
+ stq r16, -8(r21)
+ br r31, short1
+
+ nop
+uexit1: stq r27, -32(r21) # Here if exit from middle of loop
+ ldq r27, -16(r18)
+ stq r20, -24(r21)
+ br r31, uex1a # Join common exit sequence
+
+ #.align quad
+
+unrol2: ldq_u r16, 16(r18) # Load next src QW
+ extql r19, r18, r19 # Get last part of prior one
+ or r28, r27, r28 # Combine pieces
+ stq r28, (r21) # Store prior dst QW
+ subq r20, 24, r20 # Update loop counter
+ extqh r16, r18, r28 # Get first part of a src QW
+ ldq_u r27, 24(r18) # Load next src QW
+ extql r16, r18, r16 # Get last part of prior one
+ or r28, r19, r28 # Combine pieces
+ stq r28, 8(r21) # Store prior dst QW
+ addq r21, 24, r21 # Update dst pointer
+ extqh r27, r18, r28 # Get first part of a src QW
+ ldq_u r19, 32(r18) # Load next src QW
+ extql r27, r18, r27 # Get last part of prior one
+ or r28, r16, r28 # Combine pieces
+ stq r28, -8(r21) # Store prior dst QW
+ addq r18, 24, r18 # Update src pointer
+ extqh r19, r18, r28 # Get first part of a src QW
+ bge r20, unrol2 # Repeat as needed
+ addq r20, 16, r16 # How many whole quadwords left?
+ br r31, short2 # Go handle leftovers
+ nop
+
+ # Must move in reverse order because of overlap.
+ # r16 = dst address
+ # r17 = remaining length for return
+ # r18 = src address
+ # r19
+ # r20 = len-4 (>= 0)
+ # r21
+ # r27
+ # r28
+
+ # Not yet LW-granularity...
+
+reverse:
+ subq r20, 4, r20 # This code expects len-8
+ addq r20, r18, r18 # Point to end-8 of source
+ addq r20, r16, r19 # Point to end-8 of destination
+ and r19, 7, r21 # Is destination aligned?
+ ldq_u r28, 7(r18) # Get source QW
+ addq r19, 8, r16 # Point to end of dst for return
+ bne r21, rpart # Skip if partial write needed
+ and r18, 7, r27 # Is source aligned too?
+ beq r27, ralign # Skip if so
+ ldq_u r21, (r18) # Handle aligned dst, unaligned src
+ subq r20, 8, r20
+ extqh r28, r18, r28
+ extql r21, r18, r27
+ br r31, rwhole
+
+rmis: ldq_u r21, (r18) # Load same or preceding src QW
+ extqh r28, r18, r28 # Get last part of source to store
+ mskqh r27, r16, r27 # Keep high-address part of dst
+ extql r21, r18, r21
+ subq r20, 8, r20 # How many more whole QW's?
+ or r21, r28, r28
+ ldq_u r21, (r18) # Reload source QW
+ mskql r28, r16, r28 # Trim source to length
+rwhole: blt r20, rlast2 # Skip if no more whole QW's
+rloop2: or r28, r27, r28 # Combine pieces
+ stq r28, (r19)
+rent2: extqh r21, r18, r27
+ ldq_u r21, -8(r18)
+ subq r20, 8, r20
+ subq r19, 8, r19
+ extql r21, r18, r28
+ subq r18, 8, r18
+ bge r20, rloop2
+rlast2: and r20, 7, r20
+ beq r20, rdone2
+ or r28, r27, r28
+ subq r18, r20, r27
+ stq r28, (r19)
+rl2ent: subq r31, r20, r20
+ ldq_u r27, (r27)
+ extqh r21, r18, r21
+ ldq r28, -8(r19)
+ subq r19, 8, r19
+ extql r27, r18, r27
+ mskql r28, r20, r28
+ or r27, r21, r27
+ mskqh r27, r20, r27
+ and r20, 4, r21 # Ending in high LW?
+ bne r21, rdone3 # Only longword store at the end
+rdone2: or r28, r27, r28
+ stq r28, (r19)
+ ret r31, (r26)
+
+rdone3: or r28, r27, r28
+ extql r28, 4, r28
+ stl r28, 4(r19)
+ ret r31, (r26)
+
+rpart: ldq_u r27, 7(r19) # Get dst QW
+ subq r21, 8, r21 # Get negative of bytes not moved
+ subq r18, r21, r18 # From src-8, get src after partial
+ subq r20, r21, r20 # Adjust length for partial move
+ subq r19, r21, r19 # Adjust dst pointer
+ addq r21, 4, r21 # End alignment - 4
+ ble r21, r_lw # Only storing the low longword?
+ and r18, 7, r21 # Src alignment now matching dst?
+ bne r21, rmis # Go back if not
+ mskql r28, r16, r28 # Keep low addresses of src QW
+ mskqh r27, r16, r27 # Keep high address of dst QW
+ralign: subq r20, 8, r20 # How many more whole QW's?
+ or r27, r28, r28 # Combine
+ blt r20, rlast1 # Skip if this is the end
+rloop1: stq r28, (r19) # Store one QW
+rent1: subq r20, 8, r20 # Decrement length
+ ldq r28, -8(r18) # Load preceding QW
+ subq r19, 8, r19 # Decrement dst pointer
+ subq r18, 8, r18 # Decrement src pointer
+ bge r20, rloop1 # Repeat for each whole QW
+rlast1: and r20, 7, r20 # How many odd bytes?
+ beq r20, rdone # Skip if none
+ ldq r27, -8(r18) # Get another source QW
+ subq r31, r20, r20 # Get byte # to end at
+ stq r28, (r19)
+rl_ent: ldq r28, -8(r19)
+ subq r19, 8, r19 # Adjust dst pointer again
+ mskqh r27, r20, r27 # Keep top of src QW
+ and r20, 4, r21 # Ending in high LW?
+ mskql r28, r20, r28 # Keep bottom of dst QW
+ bne r21, rdone4 # Only longword store at the end
+ or r27, r28, r28 # Combine
+rdone: stq r28, (r19) # Store last QW
+ ret r31, (r26)
+
+rdone4: or r27, r28, r28 # Combine
+ extql r28, 4, r28 # Get high part
+ stl r28, 4(r19) # Store last LW
+ ret r31, (r26)
+
+r_lw: and r18, 7, r21 # Src alignment now matching dst?
+ bne r21, rmislw # Go back if not
+ mskql r28, r16, r28 # Keep low addresses of src QW
+ mskqh r27, r16, r27 # Keep high address of dst QW
+ subq r20, 8, r20 # How many more whole QW's?
+ or r27, r28, r28 # Combine
+ blt r20, rlast1_lw # Skip if this is the end
+ stl r28, (r19) # Store one QW
+ br r31, rent1
+
+rlast1_lw:
+ and r20, 7, r20 # How many odd bytes?
+ ldq r27, -8(r18) # Get another source QW
+ subq r31, r20, r20 # Get byte # to end at
+ stl r28, (r19)
+ br rl_ent
+
+rmislw: ldq_u r21, (r18) # Load same or preceding src QW
+ extqh r28, r18, r28 # Get last part of source to store
+ mskqh r27, r16, r27 # Keep high-address part of dst
+ extql r21, r18, r21
+ subq r20, 8, r20 # How many more whole QW's?
+ or r21, r28, r28
+ ldq_u r21, (r18) # Reload source QW
+ mskql r28, r16, r28 # Trim source to length
+ blt r20, rlast2_lw # Skip if no more whole QW's
+ or r28, r27, r28 # Combine pieces
+ stl r28, (r19)
+ br r31, rent2
+
+rlast2_lw:
+ and r20, 7, r20
+ or r28, r27, r28
+ subq r18, r20, r27
+ stl r28, (r19)
+ br r31, rl2ent
+
+ .set at
+ .set reorder
+ .end _OtsMove
diff --git a/private/crt32/misc/alpha/strans.s b/private/crt32/misc/alpha/strans.s
new file mode 100644
index 000000000..9c738dce7
--- /dev/null
+++ b/private/crt32/misc/alpha/strans.s
@@ -0,0 +1,122 @@
+ #++
+ #
+ # Copyright (c) 1993 by
+ # Digital Equipment Corporation, Maynard, MA
+ #
+ # This software is furnished under a license and may be used and copied
+ # only in accordance with the terms of such license and with the
+ # inclusion of the above copyright notice. This software or any other
+ # copies thereof may not be provided or otherwise made available to any
+ # other person. No title to and ownership of the software is hereby
+ # transferred.
+ #
+ # The information in this software is subject to change without notice
+ # and should not be construed as a commitment by Digital Equipment
+ # Corporation.
+ #
+ # Digital assumes no responsibility for the use or reliability of its
+ # software on equipment which is not supplied by Digital.
+ #
+
+ # Facility:
+ #
+ # GEM/OTS - GEM compiler system support library
+ #
+ # Abstract:
+ #
+ # OTS character string support, Alpha version
+ #
+ # Authors:
+ #
+ # Kent Glossop
+ #
+ # void ots_translate(char *dst, long dstlen, char *src, char table[256]);
+ #
+ # Translates a string using a translation table. Handles overlap.
+ #
+ # Special conventions: No stack space, r16-r21 and r26-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # Modification history:
+ #
+ # 006 13 Nov 1992 KDG Initial non-tailored assembly version,
+ # replacing BLISS -005
+ #
+ # 007 26 Jan 1993 KDG Add underscore
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 destination address
+ # r17 length
+ # r18 source address
+ # r19 table address
+ # r20,r21,r27,r28 scratch
+ # r26 return address
+ #
+ .globl _OtsStringTranslate
+ .ent _OtsStringTranslate
+_OtsStringTranslate:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+
+ # sort out which case to use
+ addq r18, r17, r27 # get end address of source + 1 for overlap check
+ cmpult r18, r16, r28 # true if src at lower addr than dest (note trans to self is not a "slow" case)
+ cmpult r16, r27, r27 # true if dst starts before end of src
+ beq r17, done # don't touch memory if length=0
+ and r27, r28, r28 # does dst have bad overlap with src?
+ blbs r28, overlap # go handle poorly overlapping src/dst
+
+ # simple forward loop case (~16 cycles/byte EV4)
+ # (length is presumed to be at least 1)
+ subq r18, 1, r18 # one before the beginning of the source
+ subq r16, 1, r16 # one before the beginning of the destination
+forward_loop:
+ ldq_u r20, 1(r18) # load the qw containing the source
+ lda r18, 1(r18) # bump the source pointer
+ ldq_u r21, 1(r16) # load the qw containing the destination
+ lda r16, 1(r16) # bump the destination pointer
+ extbl r20 ,r18, r20 # get the byte to translate
+ addq r19, r20, r20 # get the address of the translation
+ ldq_u r27, (r20) # load the translation
+ subq r17, 1, r17 # decrement length
+ mskbl r21, r16, r21 # clear the bits in the destination
+ extbl r27, r20, r27 # extract the translation
+ insbl r27, r16, r27 # position for insertion
+ bis r27, r21, r21 # merge into the destination
+ stq_u r21, (r16) # store back
+ bgt r17, forward_loop # do another if there
+
+done: ret r31, (r26)
+ nop #.align 3
+
+ # bad overlap case (~16 cycles/byte EV4, 11c/byte EV5)
+ # (length is presumed to be at least 1)
+overlap:
+ addq r17, r18, r18 # one past the end of the source
+ addq r17, r16, r16 # one past the end of the destination
+backward_loop:
+ ldq_u r20, -1(r18) # load the qw containing the source
+ lda r18, -1(r18) # bump the source pointer
+ ldq_u r21, -1(r16) # load the qw containing the destination
+ lda r16, -1(r16) # bump the destination pointer
+ extbl r20 ,r18, r20 # get the byte to translate
+ addq r19, r20, r20 # get the address of the translation
+ ldq_u r27, (r20) # load the translation
+ subq r17, 1, r17 # decrement length
+ mskbl r21, r16, r21 # clear the bits in the destination
+ extbl r27, r20, r27 # extract the translation
+ insbl r27, r16, r27 # position for insertion
+ bis r27, r21, r21 # merge into the destination
+ stq_u r21, (r16) # store back
+ bgt r17, backward_loop # do another if there
+
+ ret r31, (r26)
+
+ .set at
+ .set reorder
+ .end _OtsStringTranslate
diff --git a/private/crt32/misc/alpha/strcmp_.s b/private/crt32/misc/alpha/strcmp_.s
new file mode 100644
index 000000000..dc25bfebc
--- /dev/null
+++ b/private/crt32/misc/alpha/strcmp_.s
@@ -0,0 +1,357 @@
+ #****************************************************************************
+ #* *
+ #* Copyright (c) 1991 by *
+ #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. *
+ #* All rights reserved. *
+ #* *
+ #* This software is furnished under a license and may be used and copied *
+ #* only in accordance with the terms of such license and with the *
+ #* inclusion of the above copyright notice. This software or any other *
+ #* copies thereof may not be provided or otherwise made available to any *
+ #* other person. No title to and ownership of the software is hereby *
+ #* transferred. *
+ #* *
+ #* The information in this software is subject to change without notice *
+ #* and should not be construed as a commitment by Digital Equipment *
+ #* Corporation. *
+ #* *
+ #* Digital assumes no responsibility for the use or reliability of its *
+ #* software on equipment which is not supplied by Digital. *
+ #* *
+ #* *
+ #****************************************************************************
+ #
+ #++
+ # Facility:
+ # DEC C Run Time Library on the Alpha/WNT Platform
+ #
+ # Abstract:
+ #
+ # Implements the C RTL function strcmp() for the compiler intrinsic.
+ #
+ # Author:
+ # Bill Noyce 9-Aug-1991
+ #
+ # Modified by:
+ #
+ # 001 Kevin Routley 10-Sep-1991
+ # Modified to C RTL Coding standards.
+ #
+ # 002 Chris Bord 30 September 1991
+ # Add decc$ prefixes.
+ #
+ # 003 Chris Bord 24 January 1992
+ # Add second parameter to .procedure_descriptor directive
+ #
+ # 004 John Parks 22 January 1993
+ # Ported to Alpha/NT.
+ #--
+
+//
+// Although the spec says the return value may be <0/0/>0, we now return
+// -1/0/+1 to reduce NT combatibility problems.
+//
+
+ .globl _Otsstrcmp
+ .ent _Otsstrcmp
+
+ # r16 = A
+ # r17 = B
+ # returns r0<0 if A<B, R0=0 if A=B, r0>0 if A>B (unsigned chars)
+ # destroys r16-r21, r27-r28
+ #
+
+_Otsstrcmp:
+ .set noat
+ .set noreorder
+
+ .frame $30, 0, $26
+
+ ldq_u $27, ($16) # Get first A QW
+ and $16, 7, $21 # Alignment of A
+
+ ldq_u $18, ($17) # Get first B QW
+ and $17, 7, $20 # Alignment of B
+
+ subq $20, $21, $0 # B_alignment geq A_alignment?
+
+ cmpbge $31, $27, $19 # Any nulls in A?
+
+ insql $27, $0, $28 # Position A like B if B_align geq
+ bgt $0, more_a # Skip if enough A bytes available
+
+ srl $19, $21, $19 # Discard nulls preceding start of A
+ bne $0, more_b # Go handle opposite mismatch
+
+match: xor $27, $18, $28 # Do A and B differ?
+
+ mskqh $28, $21, $28 # Ignore differences before start
+
+ sll $19, $21, $0 # Line up nulls with differences
+ bne $19, null # Skip out if nulls seen
+
+loop_s: bne $28, diff # Skip out if difference seen
+ ldq_u $27, 8($16) # Get next A QW
+
+ ldq_u $18, 8($17) # Get next B QW
+ addq $16, 8, $16 # Bump A pointer
+
+ addq $17, 8, $17 # Bump B pointer
+
+ cmpbge $31, $27, $0 # Any nulls in A?
+
+ xor $27, $18, $28 # Do A and B differ?
+ beq $0, loop_s # Repeat if no nulls
+
+ # Enter here if null seen.
+ # r0 = mask of nulls
+ # r27= A
+ # r18 = B
+ # r28= xor
+ #
+null: subq $0, 1, $19 # Flip bits up thru first null
+
+ cmpbge $31, $28, $28 # Mask of 1's where A=B
+
+ xor $0, $19, $0 # Mask of 1's thru first null
+
+ andnot $0, $28, $0 # Differences thru first null
+
+ cmpbge $27, $18, $27 # Mask of 1's where A >= B
+ beq $0, done # Exit with R0=0 if no differences
+
+ subq $31, $0, $19 # R19<0, first diff=1, others=0
+
+ and $27, $0, $28 # Mask of A>B thru first null
+
+ and $28, $19, $0 # Keep only first difference
+
+ cmoveq $0, $19, $0 # If A<B, set R0 negative
+
+ cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0
+ cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0
+ subq $20, $21, $0 // set return value to -1/0/+1
+
+done: ret $31, ($26) # All done
+
+ # Enter here if difference seen, but no nulls.
+ # r27= A
+ # r18 = B
+ # R28= xor
+ #
+diff: cmpbge $31, $28, $21 # Where is A = B?
+
+ cmpbge $27, $18, $0 # Where is A >= B?
+
+ subq $21, 255, $19 # R19<0, first diff=1, others=0
+
+ andnot $0, $21, $28 # Mask of A > B
+
+ and $28, $19, $0 # Keep only first difference
+
+ cmoveq $0, $19, $0 # If A<B, set R0 negative
+
+ cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0
+ cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0
+ subq $20, $21, $0 // set return value to -1/0/+1
+
+ ret $31, ($26)
+
+ #.align quad
+
+ # Enter here if A and B alignments differ, and B's is greater (so there are
+ # more A bytes in its first QW than B bytes in its first QW).
+
+more_a: srl $19, $21, $19 # Discard nulls preceding start of A
+
+ xor $28, $18, $21 # Do A and B differ?
+
+ mskqh $21, $20, $21 # Discard diffs preceding start of B
+ bne $19, null_a # Skip if A has nulls
+
+ mov $18, $19 # Put B where common code expects
+
+ bne $21, diff_d # Handle diffs in B
+
+ ldq_u $18, 8($17) # No nulls in A or B, get next QW of B
+ addq $17, 8, $17 # Bump B pointer
+
+ insqh $27, $0, $28 # Position high part of A like B
+
+ #stall
+
+ mskql $18, $0, $19 # Keep low part of B
+
+ # Loop comparing A and B when alignment differs.
+ # Register use:
+ # r16 --> A
+ # r17 --> B
+ # r27 = QW of A
+ # r28 = current piece of A
+ # r18 = QW of B
+ # r19 = current piece of B
+ # r0 = alignment difference (B-A)
+ # r21 = xor of pieces
+ # r20 = mask of null locations
+ #
+ # If a string contains a null, we are careful not to read the following
+ # quadword in that string. But we are willing to read the quadword that
+ # follows the first difference, because this read-ahead improves performance.
+ #
+loop_d: xor $28, $19, $21 # Do A and B pieces differ?
+ ldq_u $27, 8($16) # Get next QW of A
+
+ cmpbge $31, $18, $20 # Any nulls in B?
+ bne $21, diff_d # Skip if difference seen
+
+ent_d: mskqh $18, $0, $19 # Trim B for next compare
+
+ insql $27, $0, $28 # Position A like B
+
+ addq $16, 8, $16 # Bump A pointer
+ bne $20, null_d # Skip if null seen in B
+
+ xor $28, $19, $21 # Do A and B pieces differ?
+ ldq_u $18, 8($17) # Get next QW of B
+
+ cmpbge $31, $27, $20 # Any nulls in A?
+ bne $21, diff_d # Skip if difference seen
+
+ insqh $27, $0, $28 # Position A for next compare
+
+ mskql $18, $0, $19 # Trim B like A
+
+ addq $17, 8, $17 # Bump B pointer
+ beq $20, loop_d # Repeat if no nulls in A
+
+ # We saw a null in A. Since we've already compared the lower part with B,
+ # and B had no nulls, the null is in the upper part of A. We've moved that
+ # part of A to the lower part of r28. Re-compare so the mask of nulls will
+ # be positioned properly for the following code.
+ #
+ cmpbge $31, $28, $20 # Find nulls in repositioned A
+
+ # Null seen and alignments differ.
+ # r28 = positioned A
+ # r19 = positioned B
+ # r20 = mask of nulls
+ # r21 = xor (at entry null_e)
+ #
+ #.odd
+null_d: xor $28, $19, $21 # Where do A and B differ?
+
+null_e: subq $20, 1, $27 # Flip bits up thru first null
+
+ cmpbge $31, $21, $18 # Mask of 1's where A=B
+
+ xor $20, $27, $0 # Mask of 1's thru first null
+
+ andnot $0, $18, $0 # Differences thru first null
+
+ cmpbge $28, $19, $27 # Mask of 1's where A >= B
+ beq $0, done_d # Exit with R0=0 if no differences
+
+ subq $31, $0, $19 # R19<0, first diff=1, others=0
+
+ and $27, $0, $0 # Mask of A>B thru first null
+
+ and $0, $19, $0 # Keep only first difference
+
+ cmoveq $0, $19, $0 # If A<B, set R0 negative
+
+ cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0
+ cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0
+ subq $20, $21, $0 // set return value to -1/0/+1
+
+done_d: ret $31, ($26) # All done
+
+
+ # Null seen in first QW of A, when B alignment greater.
+ # r19 = nulls in A, shifted
+ # r27 = A
+ # r28 = A positioned like B
+ # r18 = B
+ # r21 = xor, masked
+ #
+ #.odd
+null_a: sll $19, $20, $20 # Position nulls like B
+
+ mov $18, $19 # Move B for common code
+ bne $21, null_e # Comparison done if difference seen
+
+ and $20, 255, $18 # Any nulls in first part of A?
+
+ bne $18, null_e # Comparison done if so
+
+ ldq_u $19, 8($17) # Get another B QW
+ insqh $27, $0, $28 # Position A to match
+
+ srl $20, 8, $20 # Shift nulls again to match
+ br $31, null_d # Now we must be at end
+
+
+ # Enter here if A and B alignments differ, and B's is less (so there are more
+ # B bytes in its first QW than A bytes in its first QW).
+
+ #.align quad
+more_b: cmpbge $31, $18, $28 # We'll want to know about nulls in B
+ bne $19, null_b # Skip if null seen in A
+
+ extqh $18, $0, $19 # Position B like A
+
+ srl $28, $20, $28 # Discard nulls preceding start of B
+
+ xor $27, $19, $27 # Do A and B differ?
+
+ mskqh $27, $21, $21 # Discard diffs preceding start of A
+
+ sll $28, $20, $20 # Position null mask for common code
+ ldq_u $27, 8($16) # Get next QW of A
+
+ xor $19, $21, $28 # Recover A for compare
+ beq $21, ent_d # Enter loop if A=B so far
+
+
+ # Enter here if difference seen, but no nulls.
+ # r28 = A piece
+ # r19 = B piece
+ # r21 = xor
+ #
+diff_d: cmpbge $31, $21, $21 # Where is A = B?
+
+ cmpbge $28, $19, $0 # Where is A >= B?
+
+ subq $21, 255, $27 # R27<0, first diff=1, others=0
+
+ andnot $0, $21, $0 # Mask of A > B
+
+ and $0, $27, $0 # Keep only first difference
+
+ cmoveq $0, $27, $0 # If A<B, set R0 negative
+
+ cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0
+ cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0
+ subq $20, $21, $0 // set return value to -1/0/+1
+
+ ret $31, ($26)
+
+ # Null seen in first QW of A, when B alignment less.
+ # r19 = nulls in A, shifted
+ # r27 = A
+ # r18 = original B
+ #
+ nop #.align 8
+null_b: sll $19, $21, $20 # Position null mask like A
+
+ extqh $18, $0, $19 # Position B like A
+
+ mov $27, $28 # Put A where common code expects
+
+ xor $27, $19, $27 # Find differences
+
+ mskqh $27, $21, $21 # Discard diffs preceding A
+ br $31, null_e # Comparison is done
+
+ .set at
+ .set reorder
+ .end _Otsstrcmp
diff --git a/private/crt32/misc/alpha/strcpy_.s b/private/crt32/misc/alpha/strcpy_.s
new file mode 100644
index 000000000..de2057715
--- /dev/null
+++ b/private/crt32/misc/alpha/strcpy_.s
@@ -0,0 +1,257 @@
+ #****************************************************************************
+ #* *
+ #* Copyright (c) 1991 by *
+ #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. *
+ #* All rights reserved. *
+ #* *
+ #* This software is furnished under a license and may be used and copied *
+ #* only in accordance with the terms of such license and with the *
+ #* inclusion of the above copyright notice. This software or any other *
+ #* copies thereof may not be provided or otherwise made available to any *
+ #* other person. No title to and ownership of the software is hereby *
+ #* transferred. *
+ #* *
+ #* The information in this software is subject to change without notice *
+ #* and should not be construed as a commitment by Digital Equipment *
+ #* Corporation. *
+ #* *
+ #* Digital assumes no responsibility for the use or reliability of its *
+ #* software on equipment which is not supplied by Digital. *
+ #* *
+ #* *
+ #****************************************************************************
+ #
+ #++
+ # Facility:
+ # DEC C Run Time Library on the Alpha/WNT Platform
+ #
+ # Abstract:
+ #
+ # Implements the C RTL function strcpy() for the compiler intrinsic.
+ #
+ # Author:
+ # Bill Noyce 9-Aug-1991
+ #
+ # Modified by:
+ #
+ # 001 Kevin Routley 10-Sep-1991
+ # Modified to C RTL Coding standards.
+ #
+ # 002 Chris Bord 30 September 1991
+ # Add decc$ prefixes.
+ #
+ # 003 Chris Bord 24 January 1992
+ # Add second parameter to .procedure_descriptor directive
+ #
+ # 004 John Parks 22 January 1993
+ # Ported to Alpha/NT.
+ #--
+
+ .globl _Otsstrcpy
+ .ent _Otsstrcpy
+
+ # r16 = dst
+ # r17 = src
+ # returns r0 = src
+ # destroys r16-r21, r27-r28
+
+_Otsstrcpy:
+ .set noat
+ .set noreorder
+
+ ldq_u $27, ($17) # Get first src QW
+ and $16, 7, $28 #/ Is dst aligned?
+ lda $18, -1($31) # Get a mask of all 1's
+ bne $28, dst_unaligned #/ Go handle unaligned dst
+ and $17, 7, $19 # Is src aligned too?
+ nop
+ mov $16, $0 # Set up function result
+ bne $19, src_unaligned #/ Go handle aligned dst, unaligned src
+
+a_loop:
+ cmpbge $31, $27, $18 # Any nulls in src QW?
+ bne $18, a_exit_1 # Finish up if so
+ ldq $21, 8($17) # Load next QW if not
+match: # Enter if src matches unaligned dst
+ addq $17, 16, $17 #/ Update src pointer for unrolled loop
+ stq_u $27, ($16) # Store a whole QW
+ addq $16, 16, $16 #/ Update dst pointer for unrolled loop
+ cmpbge $31, $21, $18 # Any nulls in src QW?
+ bne $18, a_exit_2 # Finish up if so
+ ldq $27, ($17) # Load next QW if not
+ stq_u $21, -8($16) # Store a whole QW
+ br $31, a_loop # Repeat during load latency
+
+a_exit_1:
+ ldq_u $21, ($16) # Get dst QW to update
+ subq $18, 1, $17 #/ Use location of null byte...
+ xor $18, $17, $18 # ... to compute mask of what to keep
+ zapnot $27, $18, $27 # Keep src up to & including null
+ zap $21, $18, $21 # Make room for new data
+ nop
+ or $21, $27, $21 # Combine src & dst...
+ stq_u $21, ($16) #/ ... and store
+ ret $31, ($26)
+
+ nop
+a_exit_2:
+ ldq_u $27, -8($16) # Get dst QW to update
+ subq $18, 1, $17 #/ Use location of null byte...
+ xor $18, $17, $18 # ... to compute mask of what to keep
+ zapnot $21, $18, $21 # Keep src up to & including null
+ zap $27, $18, $27 # Make room for new data
+ nop
+ or $27, $21, $27 # Combine src & dst...
+ stq_u $27, -8($16) #/ ... and store
+ ret $31, ($26)
+
+src_unaligned: # dst_unaligned code would work; is this faster?
+ mskqh $18, $17, $18 # Zeros where src to be ignored
+ ornot $27, $18, $19 # Make ignored bytes nonzero
+ cmpbge $31, $19, $21 # Any null bytes in src data?
+ extql $27, $17, $27 # Move src to position of dst
+ bne $21, short_ld #/ Finish up if nulls seen
+ ldq_u $19, 8($17) # Next src QW needed to fill dst
+ br $31, u_entry_2 # Enter loop for mismatched alignment
+
+ # Here's the hard part. Enter with
+ # r16 = dst address
+ # r17 = src address
+ # r18 = -1
+ # r27 = first src QW
+ # r28 = dst alignment (>0)
+ # Check whether the first src QW has any nulls, and load the next one.
+ # Combine these if needed to fill the first dst QW, and enter a loop
+ # that fetches src QWs and checks them, while storing dst QWs.
+
+dst_unaligned:
+ ldq_u $20, ($16) # Load dst to be updated
+ mskqh $18, $17, $18 #/ Zeros where src to be ignored
+ mov $16, $0 # Set up function result
+ ornot $27, $18, $19 # Make ignored bytes of src nonzero
+ cmpbge $31, $19, $21 # Any null bytes in src data?
+ extql $27, $17, $27 # Get only interesting src data
+ bne $21, short # Finish up if nulls seen
+ mskql $20, $16, $20 #/ Make room in dst
+ ldq_u $21, 8($17) # Load next src QW if no nulls
+ mskql $18, $16, $18 #/ Need two src QWs for first dst QW?
+ insql $27, $16, $27 # Move src data to position of dst
+ subq $17, $28, $17 # Adjust src ptr for partial move
+ and $17, 7, $28 # Is src now aligned?
+ bne $18, u_loop #/ Enter loop if one src QW fills dst
+ or $27, $20, $27 # Combine first src QW with dst
+ extqh $21, $17, $20 # Position 2nd src QW in 1st dst QW
+ cmpbge $31, $21, $18 # Any nulls in next src QW?
+ beq $28, match #/ If src aligned, use quick loop
+ mov $21, $19 # Put src QW where loop expects
+ bne $18, short_a #/ Finish up if nulls seen
+
+ # r16 = address of next dst to store
+ # r17 = address-16 of next src to load
+ # r18
+ # r19 = last loaded src QW
+ # r20 = one piece of dst QW
+ # r21
+ # r27 = other piece of dst QW
+ # r28
+
+u_loop:
+ ldq_u $28, 16($17) # Load another src QW
+ addq $17, 16, $17 #/ Update src pointer for unrolled loop
+ or $27, $20, $27 # Combine pieces
+ extql $19, $17, $20 # Get second part of prior src QW
+ stq_u $27, ($16) # Store a dst QW
+ cmpbge $31, $28, $19 #/ Any nulls in this src QW?
+ extqh $28, $17, $27 # Get first part of this src QW
+ bne $19, u_exit_2 #/ Finish up if nulls seen
+ ldq_u $19, 8($17) # Load another src QW
+ addq $16, 16, $16 #/ Update dst pointer for unrolled loop
+ or $27, $20, $20 # Combine pieces
+ extql $28, $17, $27 # Get second piece of prior src QW
+ stq_u $20, -8($16) # Store a dst QW
+u_entry_2:
+ cmpbge $31, $19, $28 #/ Any nulls in this src QW?
+ extqh $19, $17, $20 # Get first part of this src QW
+ beq $28, u_loop #/ Repeat if no nulls seen
+
+ subq $16, 8, $16 # Undo part of pointer update
+ mov $19, $28 # Move src QW to expected place
+u_exit_2:
+ or $27, $20, $27 # Combine pieces
+ ldq_u $18, 8($16) #/ Load dst to update
+ cmpbge $31, $27, $21 # Is null in first dst QW?
+ bne $21, u_exit_3 # Skip if so
+ stq_u $27, 8($16) # Store a whole dst QW
+ extql $28, $17, $27 #/ Get second part of src QW
+ ldq_u $18, 16($16) # We'll update next dst QW
+ cmpbge $31, $27, $21 # Find location of null there
+ addq $16, 8, $16 # Update dst pointer
+u_exit_3:
+ subq $21, 1, $28 # Using position of null byte...
+ xor $21, $28, $21 # ... make mask for desired src data
+ zapnot $27, $21, $27 # Trim src data after null
+ zap $18, $21, $18 # Make room for it in dst
+ nop
+ or $27, $18, $27 # Combine pieces
+ stq_u $27, 8($16) #/ Store dst QW
+ ret $31, ($26)
+short_ld:
+ ldq_u $20, ($16) # Load dst QW to update
+short:
+ cmpbge $31, $27, $17 #/ Get mask showing location of null
+ insql $27, $16, $18 # Move src data to position of dst
+ mskql $20, $16, $19 # Get dst bytes preceding string
+ sll $17, $28, $17 # Move mask in the same way
+ or $18, $19, $18 # Combine src & dst
+ and $17, 255, $28 # Null byte in first dst QW?
+ subq $17, 1, $19 # Using position of null byte...
+ xor $17, $19, $17 # ... make mask for desired src data
+ bne $28, short_2 #/ Skip if null in first dst QW
+ ldq_u $20, 8($16) # Load second dst QW
+ srl $17, 8, $17 #/ Move mask down for use
+ stq_u $18, ($16) # Store first dst QW
+ insqh $27, $16, $18 #/ Move src data to position of dst
+ addq $16, 8, $16 # Advance dst pointer
+short_2:
+ zap $20, $17, $20 # Preserve dst data following null
+ zapnot $18, $17, $18 # Trim src data after null
+ nop
+ or $18, $20, $18 # Combine pieces
+ stq_u $18, ($16) #/ Store dst QW
+ ret $31, ($26)
+
+ # r16 = dst address
+ # r17 = updated src address
+ # r18 = null position
+ # r19 = next src QW
+ # r20 = first part of r19, positioned for dst
+ # r21
+ # r27 = dst QW so far
+ # r28 = low bits of updated src address
+
+short_a:
+ sll $18, 8, $18 # Shift location of null byte...
+ ldq_u $21, ($16) #/ Reload first dst QW
+ or $27, $20, $27 # Combine pieces
+ srl $18, $28, $18 # ... to position in dst QW's
+ nop
+ and $18, 255, $20 # Is null in first dst QW?
+ subq $18, 1, $28 # Using position of null byte...
+ xor $18, $28, $18 # ... make mask for desired src data
+ bne $20, short_a1 #/ Skip if null in first QW
+ stq_u $27, ($16) # Store a whole dst QW
+ extql $19, $17, $27 #/ Prepare next piece of src
+ ldq_u $21, 8($16) # Load second dst QW for update
+ srl $18, 8, $18 #/ Look at next 8 bits of mask
+ addq $16, 8, $16 # Update dst pointer
+short_a1:
+ zapnot $27, $18, $27 # Keep src data
+ zap $21, $18, $21 # Keep end of dst QW
+ nop
+ or $27, $21, $27 # Combine pieces
+ stq_u $27, ($16) # Store last dst QW
+ ret $31, ($26)
+
+ .set at
+ .set reorder
+ .end _Otsstrcpy
diff --git a/private/crt32/misc/alpha/strlen_.s b/private/crt32/misc/alpha/strlen_.s
new file mode 100644
index 000000000..2a7979387
--- /dev/null
+++ b/private/crt32/misc/alpha/strlen_.s
@@ -0,0 +1,95 @@
+ #****************************************************************************
+ #* *
+ #* Copyright (c) 1991 by *
+ #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. *
+ #* All rights reserved. *
+ #* *
+ #* This software is furnished under a license and may be used and copied *
+ #* only in accordance with the terms of such license and with the *
+ #* inclusion of the above copyright notice. This software or any other *
+ #* copies thereof may not be provided or otherwise made available to any *
+ #* other person. No title to and ownership of the software is hereby *
+ #* transferred. *
+ #* *
+ #* The information in this software is subject to change without notice *
+ #* and should not be construed as a commitment by Digital Equipment *
+ #* Corporation. *
+ #* *
+ #* Digital assumes no responsibility for the use or reliability of its *
+ #* software on equipment which is not supplied by Digital. *
+ #* *
+ #* *
+ #****************************************************************************
+ #
+ #++
+ # Facility:
+ # DEC C Run Time Library on the Alpha/WNT Platform
+ #
+ # Abstract:
+ #
+ # Implements the C RTL function strlen() for the compiler intrinsic.
+ #
+ # Author:
+ # Bill Noyce 9-Aug-1991
+ #
+ # Modified by:
+ #
+ # 001 Kevin Routley 10-Sep-1991
+ # Modified to C RTL Coding standards.
+ #
+ # 002 Chris Bord 30 September 1991
+ #
+ # 003 Chris Bord 24 January 1992
+ # Add second parameter to .procedure_descriptor directive
+ #
+ # 004 John Parks 22 January 1993
+ # Ported to Alpha/NT.
+ #--
+
+ .globl _Otsstrlen
+ .ent _Otsstrlen
+
+ # r16 = src pointer
+ # Returns r0 = length
+ # Destroys r16,r27-r28
+
+_Otsstrlen:
+ .set noat
+ .set noreorder
+
+ ldq_u $27, ($16) # Get QW containing start of string
+ lda $28, -1($31) # Mask of all ones
+ mskql $28, $16, $28 # Nonzeros in low bytes to be ignored
+ and $16, 7, $0 # Alignment = bytes not to be counted
+ or $27, $28, $27 # Fill ignored bytes with nonzeros
+ cmpbge $31, $27, $27 # Any null bytes in this QW?
+ subq $31, $0, $0 # Initialize count to -alignment
+ bne $27, bottom # Skip if null byte seen
+
+loop: ldq_u $27, 8($16) # Load next QW of string
+ addq $16, 8, $16 # Advance pointer
+ addq $0, 8, $0 # Increment length
+ cmpbge $31, $27, $27 # Any nulls in this QW?
+ beq $27, loop # Repeat if not
+
+bottom: and $27, 0xF, $28 # Null in low longword?
+ subq $27, 1, $16 # Complement the lowest 1-bit in mask
+ blbs $27, done # Exit if null appears in first byte
+ andnot $27, $16, $27 # Make single-bit mask of null location
+ beq $28, geq_4 # Skip if null is in high longword
+ srl $27, 2, $27 # Map 2/4/8 --> 0/1/2
+ addq $0, 1, $0 # Bump length by one...
+ addq $0, $27, $0 # ... and then by null location
+
+done: ret $31, ($26)
+
+geq_4: srl $27, 5, $28 # Map 10/20/40/80 --> 0/1/2/4
+ srl $27, 7, $27 # Map 10/20/40/80 --> 0/0/0/1
+ addq $0, 4, $0 # Bump length by four
+ subq $28, $27, $28 # Compute location within high LW...
+ addq $0, $28, $0 # ... and add to length
+ ret $31, ($26)
+
+ .set at
+ .set reorder
+ .end _Otsstrlen
diff --git a/private/crt32/misc/alpha/szero.s b/private/crt32/misc/alpha/szero.s
new file mode 100644
index 000000000..c97c31df5
--- /dev/null
+++ b/private/crt32/misc/alpha/szero.s
@@ -0,0 +1,137 @@
+ #++
+ # Copyright 1991, 1994, Digital Equipment Corporation
+ #
+ # ots_zero(char *dstptr, long dstlen)
+ #
+ # Zero dstlen bytes of memory at *dstptr
+ #
+ # Special conventions: No stack space, r16-r17 and r27-r28 ONLY,
+ # no linkage pointer required.
+ # (Warning: The auto-loader potentially takes some regs across
+ # the call if this is being used in a shared lib. environment.)
+ #
+ # This is a GEM support routine for zeroing a region of memory. It is
+ # basically idential to BSD's bzero, though it has limited register
+ # convensions to allow it to work better with compiled code. (Note that
+ # this is just a stripped down version of ots_fill.)
+ #
+ # This is optimized for extremely high performance both for small and
+ # large blocks. In order to reduce overhead for small cases, they are
+ # retired as quickly as possible, more case analysis is reserved
+ # for cases which will do more.
+ #
+ # This version of OTS_ZERO provides longword granularity for Alpha.
+ #
+ # 012 30 Aug 1994 WBN Longword granularity version based on
+ # OTS_ZERO_ALPHA.M64 edit 011.
+ #--
+
+#include "ots_defs.hs"
+
+ # r16 = dst
+ # r17 = len
+ # destroys r16-r17, r27-r28
+
+ .globl _OtsZero
+ .ent _OtsZero
+_OtsZero:
+ .set noat
+ .set noreorder
+ .frame sp,0,r26
+ .prologue 0
+ beq r17, done # No memory refs if len=0
+ subq r17, 4, r28 # Length-4
+ and r16, 3, r27 # Dst alignment (0-3)
+ andnot r16, 3, r16 # LW aligned dst pointer
+ addq r27, r28, r17 # Alignment + length - 4
+ bge r28, geq4 # Lengths >= 4 may not need load
+ ldl r28, (r16) # Load first LW of dst
+ bgt r17, double # Skip if it crosses to next LW
+ addq r17, 4, r17 # Find endpoint within LW
+ mskql r28, r27, r27 # Clear from startpoint thru 7
+ mskqh r28, r17, r28 # Clear from 0 to endpoint
+ or r28, r27, r27 # Combine dest parts
+ stl r27, (r16)
+ ret r31, (r26)
+
+double: mskql r28, r27, r28 # Clear from startpoint in first LW
+ ldl r27, 4(r16) # Load second LW of dst
+ stl r28, (r16)
+ mskqh r27, r17, r27 # Clear up to endpoint in second LW
+ stl r27, 4(r16)
+ ret r31, (r26)
+
+ # Come here if length to be zeroed is >= 4.
+ # r16-> dst aligned to LW
+ # r17 = alignment + length - 4
+ # r27 = dst alignment within LW
+ # r28 = length-4
+
+ #.align quad
+
+geq4: and r16, 4, r28 # Which LW in QW to store first?
+ beq r17, simple # Go handle single aligned LW
+ bne r28, longs # Go use QW stores
+quad: subq r17, 4, r17 # Does dest end in first QW?
+ blt r17, shortq # Ends within first QW
+ beq r27, wh_qw # Store a whole QW
+ ldq r28, (r16) # Load first QW of dest
+ mskql r28, r27, r27 # Clear from startpoint
+wh_qw: stq r27, (r16) # Store first QW of dest
+ br r31, join # Go clear rest of string
+
+simple: stl r31, (r16) # Single aligned LW
+ ret r31, (r26)
+
+shortq: ldq r28, (r16) # Load QW of dest
+ mskql r28, r27, r27 # Clear from startpoint thru 7
+ mskqh r28, r17, r28 # Clear from 0 up to endpoint
+ or r28, r27, r27 # Merge
+ stq r27, (r16) # Store
+ ret r31, (r26)
+
+longs: beq r27, wh_lw # Store a whole LW
+ ldl r28, (r16) # Load first LW of dest
+ mskql r28, r27, r27 # Clear from startpoint
+wh_lw: stl r27, (r16) # Store first LW of dest
+join: subq r17, 32, r17 # At least 4 more quadwords?
+ and r17, 24, r27 # How many after multiple of 4?
+ bge r17, unroll # Taken branch for long strings
+short: and r17, 7, r17 # How many odd bytes?
+ beq r27, last # Skip if no more whole QWs
+ stq_u r31, 8(r16) # Clear one...
+ subq r27, 16, r27 # Map 8/16/24 to -8/0/8
+ addq r16, 8, r16 # Update dest pointer
+ blt r27, last # Skip if no more whole QWs
+ #stall
+ stq_u r31, 8(r16) # Clear two...
+ addq r16, 8, r16 # Update dest pointer
+ nop
+ beq r27, last # Skip if no more whole QWs
+ stq_u r31, 8(r16) # Clear three...
+ addq r16, 8, r16 # Update dest pointer
+last: beq r17, done # Finished if no odd bytes
+ ldq_u r27, 8(r16) # Load last QW of dst
+ subq r17, 4, r28 # More than a LW left?
+ andnot r16, 7, r16 # Clean pointer for STL
+ mskqh r27, r17, r27 # Clear up to endpoint
+ bgt r28, lastq # Go store a QW
+ stl r27, 8(r16) # LW store for last piece
+done: ret r31, (r26)
+
+lastq: stq r27, 8(r16) # QW store for last piece
+ ret r31, (r26)
+
+unroll: stq_u r31, 8(r16) # Store 4 QWs per iteration
+ stq_u r31, 16(r16)
+ stq_u r31, 24(r16)
+ subq r17, 32, r17 # Decrement remaining count
+ stq_u r31, 32(r16)
+ addq r16, 32, r16 # Update dest pointer
+ bge r17, unroll # Repeat until done
+ br r31, short # Then handle leftovers
+
+
+ .set at
+ .set reorder
+ .end _OtsZero
diff --git a/private/crt32/misc/assert.c b/private/crt32/misc/assert.c
new file mode 100644
index 000000000..7f7dc60a0
--- /dev/null
+++ b/private/crt32/misc/assert.c
@@ -0,0 +1,66 @@
+/***
+*assert.c - Display a message and abort
+*
+* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*
+*Revision History:
+* 05-19-88 JCR Module created.
+* 08-10-88 PHG Corrected copyright date
+* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include
+* <cruntime.h>. Also, fixed the copyright.
+* 04-05-90 GJF Added #include <assert.h>
+* 10-04-90 GJF New-style function declarator.
+* 06-19-91 GJF Conditionally use setvbuf() on stderr to prevent
+* the implicit call to malloc() if stderr is being used
+* for the first time (assert() should work even if the
+* heap is trashed).
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <file2.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n";
+
+/***
+*_assert() - Display a message and abort
+*
+*Purpose:
+* The assert macro calls this routine if the assert expression is
+* true. By placing the assert code in a subroutine instead of within
+* the body of the macro, programs that call assert multiple times will
+* save space.
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _assert (
+ void *expr,
+ void *filename,
+ unsigned lineno
+ )
+{
+ if ( !anybuf(stderr) )
+ /*
+ * stderr is unused, hence unbuffered, as yet. set it to
+ * single character buffering (to avoid a malloc() of a
+ * stream buffer).
+ */
+ (void) setvbuf(stderr, NULL, _IONBF, 0);
+
+ fprintf(stderr, _assertstring, expr, filename, lineno);
+ fflush(stderr);
+ abort();
+}
diff --git a/private/crt32/misc/bsearch.c b/private/crt32/misc/bsearch.c
new file mode 100644
index 000000000..5769de6b5
--- /dev/null
+++ b/private/crt32/misc/bsearch.c
@@ -0,0 +1,99 @@
+/***
+*bsearch.c - do a binary search
+*
+* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines bsearch() - do a binary search an an array
+*
+*Revision History:
+* 07-05-84 RN initial version
+* 06-19-85 TC put in ifdefs to handle case of multiplication
+* in large/huge model.
+* 04-13-87 JCR added const to declaration
+* 08-04-87 JCR Added "long" cast to mid= assignment for large/huge
+* model.
+* 11-10-87 SKS Removed IBMC20 switch
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-21-88 JCR Backed out _LOAD_DS...
+* 02-22-88 JCR Added cast to get rid of cl const warning
+* 10-20-89 JCR Added _cdecl to prototype, changed 'char' to 'void'
+* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h> and fixed
+* the copyright. Also, cleaned up the formatting a bit.
+* 04-05-90 GJF Added #include <stdlib.h> and #include <search.h>.
+* Fixed some resulting compiler warnings (at -W3).
+* Also, removed #include <sizeptr.h>.
+* 07-25-90 SBM Removed redundant include (stdio.h), made args match
+* prototype
+* 10-04-90 GJF New-style function declarator.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <search.h>
+
+/***
+*char *bsearch() - do a binary search on an array
+*
+*Purpose:
+* Does a binary search of a sorted array for a key.
+*
+*Entry:
+* const char *key - key to search for
+* const char *base - base of sorted array to search
+* unsigned int num - number of elements in array
+* unsigned int width - number of bytes per element
+* int (*compare)() - pointer to function that compares two array
+* elements, returning neg when #1 < #2, pos when #1 > #2, and
+* 0 when they are equal. Function is passed pointers to two
+* array elements.
+*
+*Exit:
+* if key is found:
+* returns pointer to occurrence of key in array
+* if key is not found:
+* returns NULL
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void * _CALLTYPE1 bsearch (
+ REG4 const void *key,
+ const void *base,
+ size_t num,
+ size_t width,
+ int (_CALLTYPE1 *compare)(const void *, const void *)
+ )
+{
+ REG1 char *lo = (char *)base;
+ REG2 char *hi = (char *)base + (num - 1) * width;
+ REG3 char *mid;
+ unsigned int half;
+ int result;
+
+ while (lo <= hi)
+ if (half = num / 2)
+ {
+ mid = lo + (num & 1 ? half : (half - 1)) * width;
+ if (!(result = (*compare)(key,mid)))
+ return(mid);
+ else if (result < 0)
+ {
+ hi = mid - width;
+ num = num & 1 ? half : half-1;
+ }
+ else {
+ lo = mid + width;
+ num = half;
+ }
+ }
+ else if (num)
+ return((*compare)(key,lo) ? NULL : lo);
+ else
+ break;
+
+ return(NULL);
+}
diff --git a/private/crt32/misc/cmiscdat.c b/private/crt32/misc/cmiscdat.c
new file mode 100644
index 000000000..d1458d8f9
--- /dev/null
+++ b/private/crt32/misc/cmiscdat.c
@@ -0,0 +1,68 @@
+/***
+*cmiscdat.c - miscellaneous C run-time data
+*
+* Copyright (c) 1989-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Includes floating point conversion table (for C float output),
+* a data structure used by signal/exec to tell if a SIGINT handler
+* has been installed, and the public variables _asizeC and _asizeD
+* for conveying memory-model information to the memory-model-independent
+* GRAPHICS.LIB.
+*
+* When floating point i/o conversions are done, but no floating-point
+* variables or expressions are used in the C program, we use the
+* _cfltcvt_tab[] to map these cases to the _fptrap entry point,
+* which prints "floating point not loaded" and dies.
+*
+* This table is initialized to six copies of _fptrap by default.
+* If floating-point is linked in (_fltused), these table entries
+* are reset (see input.c, output.c, fltused.asm, and fltuseda.asm).
+*
+*Revision History:
+* 06-29-89 PHG module created, based on asm version
+* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright
+* and cleaned up the formatting a bit.
+* 07-31-90 SBM Updated comments slightly
+* 08-29-90 SBM Added #include <internal.h> and <fltintrn.h>,
+* removed _fptrap() prototype
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <internal.h>
+#include <fltintrn.h>
+
+/*
+ ... table of (model-dependent) code pointers ...
+
+ Six entries, all point to _fptrap by default,
+ but are changed to point to the appropriate
+ routine if the _fltused initializer (_cfltcvt_init)
+ is linked in.
+
+ this table is used or modified in the following
+ source files:
+
+ \clib\stdio\input.c
+ \clib\stdio\output.c
+ \math\c\fltused.asm
+ \math\c\fltuseda.asm
+
+ if the _fltused modules are linked in, then the
+ _cfltcvt_init initializer sets the 6 entries of
+ _cfltcvt_tab to:
+
+ _cfltcvt
+ _cropzeros
+ _fassign
+ _forcdecpt
+ _positive
+ _cldcvt
+*/
+
+void (*_cfltcvt_tab[6])(void) = {
+ _fptrap, _fptrap, _fptrap, _fptrap, _fptrap, _fptrap
+};
+
+void (*_sigintoff)() = 0; /* SIGINT default signal routine */
diff --git a/private/crt32/misc/ctype.c b/private/crt32/misc/ctype.c
new file mode 100644
index 000000000..382779c6d
--- /dev/null
+++ b/private/crt32/misc/ctype.c
@@ -0,0 +1,161 @@
+/***
+*ctype.c - _ctype definition file
+*
+* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* _ctype definition file of character classification data. This file
+* initializes the array used by the character classification macros
+* in ctype.h.
+*
+*Revision History:
+* 06-08-89 PHG Module created, based on asm version
+* 08-28-89 JCR Corrected _ctype declaration to match ctype.h
+* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright.
+* 10-08-91 ETC _ctype table is unsigned short under _INTL.
+* 11-11-91 ETC Declare _pctype and _pwctype under _INTL.
+* 12-16-91 ETC Make ctype table width independent of _INTL, use
+* _NEWCTYPETABLE for short table, else char.
+* 04-06-92 KRS Remove _INTL switches.
+* 01-19-03 CFW Move to _NEWCTYPETABLE, remove switch.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <ctype.h>
+
+unsigned short *_pctype = _ctype+1; /* pointer to table for char's */
+unsigned short *_pwctype = _ctype+1; /* pointer to table for wchar_t's */
+
+unsigned short _VARTYPE1 _ctype[257] = {
+ 0, /* -1 EOF */
+ _CONTROL, /* 00 (NUL) */
+ _CONTROL, /* 01 (SOH) */
+ _CONTROL, /* 02 (STX) */
+ _CONTROL, /* 03 (ETX) */
+ _CONTROL, /* 04 (EOT) */
+ _CONTROL, /* 05 (ENQ) */
+ _CONTROL, /* 06 (ACK) */
+ _CONTROL, /* 07 (BEL) */
+ _CONTROL, /* 08 (BS) */
+ _SPACE+_CONTROL, /* 09 (HT) */
+ _SPACE+_CONTROL, /* 0A (LF) */
+ _SPACE+_CONTROL, /* 0B (VT) */
+ _SPACE+_CONTROL, /* 0C (FF) */
+ _SPACE+_CONTROL, /* 0D (CR) */
+ _CONTROL, /* 0E (SI) */
+ _CONTROL, /* 0F (SO) */
+ _CONTROL, /* 10 (DLE) */
+ _CONTROL, /* 11 (DC1) */
+ _CONTROL, /* 12 (DC2) */
+ _CONTROL, /* 13 (DC3) */
+ _CONTROL, /* 14 (DC4) */
+ _CONTROL, /* 15 (NAK) */
+ _CONTROL, /* 16 (SYN) */
+ _CONTROL, /* 17 (ETB) */
+ _CONTROL, /* 18 (CAN) */
+ _CONTROL, /* 19 (EM) */
+ _CONTROL, /* 1A (SUB) */
+ _CONTROL, /* 1B (ESC) */
+ _CONTROL, /* 1C (FS) */
+ _CONTROL, /* 1D (GS) */
+ _CONTROL, /* 1E (RS) */
+ _CONTROL, /* 1F (US) */
+ _SPACE+_BLANK, /* 20 SPACE */
+ _PUNCT, /* 21 ! */
+ _PUNCT, /* 22 " */
+ _PUNCT, /* 23 # */
+ _PUNCT, /* 24 $ */
+ _PUNCT, /* 25 % */
+ _PUNCT, /* 26 & */
+ _PUNCT, /* 27 ' */
+ _PUNCT, /* 28 ( */
+ _PUNCT, /* 29 ) */
+ _PUNCT, /* 2A * */
+ _PUNCT, /* 2B + */
+ _PUNCT, /* 2C , */
+ _PUNCT, /* 2D - */
+ _PUNCT, /* 2E . */
+ _PUNCT, /* 2F / */
+ _DIGIT+_HEX, /* 30 0 */
+ _DIGIT+_HEX, /* 31 1 */
+ _DIGIT+_HEX, /* 32 2 */
+ _DIGIT+_HEX, /* 33 3 */
+ _DIGIT+_HEX, /* 34 4 */
+ _DIGIT+_HEX, /* 35 5 */
+ _DIGIT+_HEX, /* 36 6 */
+ _DIGIT+_HEX, /* 37 7 */
+ _DIGIT+_HEX, /* 38 8 */
+ _DIGIT+_HEX, /* 39 9 */
+ _PUNCT, /* 3A : */
+ _PUNCT, /* 3B ; */
+ _PUNCT, /* 3C < */
+ _PUNCT, /* 3D = */
+ _PUNCT, /* 3E > */
+ _PUNCT, /* 3F ? */
+ _PUNCT, /* 40 @ */
+ _UPPER+_HEX, /* 41 A */
+ _UPPER+_HEX, /* 42 B */
+ _UPPER+_HEX, /* 43 C */
+ _UPPER+_HEX, /* 44 D */
+ _UPPER+_HEX, /* 45 E */
+ _UPPER+_HEX, /* 46 F */
+ _UPPER, /* 47 G */
+ _UPPER, /* 48 H */
+ _UPPER, /* 49 I */
+ _UPPER, /* 4A J */
+ _UPPER, /* 4B K */
+ _UPPER, /* 4C L */
+ _UPPER, /* 4D M */
+ _UPPER, /* 4E N */
+ _UPPER, /* 4F O */
+ _UPPER, /* 50 P */
+ _UPPER, /* 51 Q */
+ _UPPER, /* 52 R */
+ _UPPER, /* 53 S */
+ _UPPER, /* 54 T */
+ _UPPER, /* 55 U */
+ _UPPER, /* 56 V */
+ _UPPER, /* 57 W */
+ _UPPER, /* 58 X */
+ _UPPER, /* 59 Y */
+ _UPPER, /* 5A Z */
+ _PUNCT, /* 5B [ */
+ _PUNCT, /* 5C \ */
+ _PUNCT, /* 5D ] */
+ _PUNCT, /* 5E ^ */
+ _PUNCT, /* 5F _ */
+ _PUNCT, /* 60 ` */
+ _LOWER+_HEX, /* 61 a */
+ _LOWER+_HEX, /* 62 b */
+ _LOWER+_HEX, /* 63 c */
+ _LOWER+_HEX, /* 64 d */
+ _LOWER+_HEX, /* 65 e */
+ _LOWER+_HEX, /* 66 f */
+ _LOWER, /* 67 g */
+ _LOWER, /* 68 h */
+ _LOWER, /* 69 i */
+ _LOWER, /* 6A j */
+ _LOWER, /* 6B k */
+ _LOWER, /* 6C l */
+ _LOWER, /* 6D m */
+ _LOWER, /* 6E n */
+ _LOWER, /* 6F o */
+ _LOWER, /* 70 p */
+ _LOWER, /* 71 q */
+ _LOWER, /* 72 r */
+ _LOWER, /* 73 s */
+ _LOWER, /* 74 t */
+ _LOWER, /* 75 u */
+ _LOWER, /* 76 v */
+ _LOWER, /* 77 w */
+ _LOWER, /* 78 x */
+ _LOWER, /* 79 y */
+ _LOWER, /* 7A z */
+ _PUNCT, /* 7B { */
+ _PUNCT, /* 7C | */
+ _PUNCT, /* 7D } */
+ _PUNCT, /* 7E ~ */
+ _CONTROL, /* 7F (DEL) */
+ /* and the rest are 0... */
+};
diff --git a/private/crt32/misc/div.c b/private/crt32/misc/div.c
new file mode 100644
index 000000000..de8cfa3ec
--- /dev/null
+++ b/private/crt32/misc/div.c
@@ -0,0 +1,59 @@
+/***
+*div.c - contains the div routine
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Performs a signed divide and returns quotient
+* and remainder.
+*
+*Revision History:
+* 06-02-89 PHG module created
+* 03-14-90 GJF Made calling type _CALLTYPE1 and added #include
+* <cruntime.h>. Also, fixed the copyright.
+* 10-04-90 GJF New-style function declarator.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+
+/***
+*div_t div(int numer, int denom) - do signed divide
+*
+*Purpose:
+* This routine does an divide and returns the results.
+* Since we don't know how the Intel 860 does division, we'd
+* better make sure that we have done it right.
+*
+*Entry:
+* int numer - Numerator passed in on stack
+* int denom - Denominator passed in on stack
+*
+*Exit:
+* returns quotient and remainder in structure
+*
+*Exceptions:
+* No validation is done on [denom]* thus, if [denom] is 0,
+* this routine will trap.
+*
+*******************************************************************************/
+
+div_t _CALLTYPE1 div (
+ int numer,
+ int denom
+ )
+{
+ div_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ /* did division wrong; must fix up */
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
diff --git a/private/crt32/misc/getenv.c b/private/crt32/misc/getenv.c
new file mode 100644
index 000000000..7d14d2a74
--- /dev/null
+++ b/private/crt32/misc/getenv.c
@@ -0,0 +1,167 @@
+/***
+*getenv.c - get the value of an environment variable
+*
+* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines getenv() - searches the environment for a string variable
+* and returns the value of it.
+*
+*Revision History:
+* 11-22-83 RN initial version
+* 04-13-87 JCR added const to declaration
+* 11-09-87 SKS avoid indexing past end of strings (add strlen check)
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 06-01-88 PHG Merged normal/DLL versions
+* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h> and fixed
+* the copyright. Also, cleaned up the formatting a bit.
+* 04-05-90 GJF Added #include <string.h>.
+* 07-25-90 SBM Removed redundant include (stdio.h)
+* 08-13-90 SBM Compiles cleanly with -W3 (made length unsigned int)
+* 10-04-90 GJF New-style function declarator.
+* 01-18-91 GJF ANSI naming.
+* 02-06-91 SRW Added _WIN32_ conditional for GetEnvironmentVariable
+* 02-18-91 SRW Removed _WIN32_ conditional for GetEnvironmentVariable
+* 01-10-92 GJF Final unlock and return statements shouldn't be in
+* if-block.
+* 03-11-92 GJF Use case-insensitive comparison for Win32.
+* 04-27-92 GJF Repackaged MTHREAD support for Win32 to create a
+* _getenv_lk.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <string.h>
+#include <os2dll.h>
+#include <oscalls.h>
+
+/***
+*char *getenv(option) - search environment for a string
+*
+*Purpose:
+* searches the environment for a string of the form "option=value",
+* if found, return value, otherwise NULL.
+*
+*Entry:
+* const char *option - variable to search for in environment
+*
+*Exit:
+* returns the value part of the environment string if found,
+* otherwise NULL
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _CRUISER_
+
+char * _CALLTYPE1 getenv (
+ REG3 const char *option
+ )
+{
+#ifdef _POSIX_
+ REG1 char **search = environ;
+#else
+ REG1 char **search = _environ;
+#endif
+ REG2 unsigned int length;
+
+ _mlock( _ENV_LOCK );
+
+ if (search && option)
+ {
+
+ length = strlen(option);
+
+ /*
+ ** Make sure `*search' is long enough to be a candidate
+ ** (We must NOT index past the '\0' at the end of `*search'!)
+ ** and that it has an equal sign (`=') in the correct spot.
+ ** If both of these requirements are met, compare the strings.
+ */
+ while (*search)
+ {
+ if (strlen(*search) > length && (*(*search + length)
+ == '=') && (strncmp(*search, option, length) == 0)) {
+ _munlock( _ENV_LOCK );
+ return(*search + length + 1);
+ }
+
+ search++;
+ }
+ }
+
+ _munlock( _ENV_LOCK );
+ return(NULL);
+}
+
+
+#else /* ndef _CRUISER_ */
+#ifdef _WIN32_
+
+
+#ifdef MTHREAD
+
+
+char * _CALLTYPE1 getenv (
+ const char *option
+ )
+{
+ char *retval;
+
+ _mlock(_ENV_LOCK);
+
+ retval = _getenv_lk(option);
+
+ _munlock(_ENV_LOCK);
+
+ return(retval);
+
+}
+
+
+char * _CALLTYPE1 _getenv_lk (
+ const char *option
+ )
+
+#else /* ndef MTHREAD */
+
+char * _CALLTYPE1 getenv (
+ const char *option
+ )
+
+#endif /* MTHREAD */
+{
+ char **search = _environ;
+ unsigned int length;
+
+ if (search && option)
+ {
+
+ length = strlen(option);
+
+ /*
+ ** Make sure `*search' is long enough to be a candidate
+ ** (We must NOT index past the '\0' at the end of `*search'!)
+ ** and that it has an equal sign (`=') in the correct spot.
+ ** If both of these requirements are met, compare the strings.
+ */
+ while (*search)
+ {
+ if (strlen(*search) > length && (*(*search + length)
+ == '=') && (strnicmp(*search, option, length) == 0)) {
+ return(*search + length + 1);
+ }
+
+ search++;
+ }
+ }
+
+ return(NULL);
+}
+
+
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
diff --git a/private/crt32/misc/getpath.c b/private/crt32/misc/getpath.c
new file mode 100644
index 000000000..96782f176
--- /dev/null
+++ b/private/crt32/misc/getpath.c
@@ -0,0 +1,174 @@
+/***
+*getpath.c - extract a pathname from an environment variable
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Extract pathnames from a string of semicolon delimited pathnames
+* (generally the value of an environment variable such as PATH).
+*
+*Revision History:
+* 08-25-89 GJF Module created (taken from SEARCHEN.C and revised)
+* 03-14-90 GJF Replaced near with _CALLTYPE1 and added #include
+* <cruntime.h>
+* 07-25-90 SBM Replaced <stdio.h> by <stddef.h>
+* 10-04-90 GJF New-style function declarator.
+* 04-26-91 SRW Removed level 3 warnings
+* 09-18-91 JCR Strip off leading semi-colons (bug fix)
+* 09-25-91 JCR Changed ifdef "OS2" to "_HPFS_" and defined it
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stddef.h>
+#include <internal.h>
+
+/* support HPFS file system */
+#define _HPFS_ 1
+
+/***
+*_getpath() - extract a pathname from a semicolon-delimited list of pathnames
+*
+*Purpose:
+* To extract the next pathname from a semicolon-delimited list of
+* pathnames (usually the value on an environment variable) and copy
+* it to a caller-specified buffer. No check is done to see if the path
+* is valid. The maximum number of characters copied to the buffer is
+* maxlen - 1 (and then a '\0' is appended).
+*
+#ifdef _HPFS_
+* If we hit a quoted string, then allow any characters inside.
+* For example, to put a semi-colon in a path, the user could have
+* an environment variable that looks like:
+*
+* PATH=C:\BIN;"D:\CRT\TOOLS;B1";C:\BINP
+#endif
+*
+* NOTE: Semi-colons in sequence are skipped over; pointers to 0-length
+* pathnames are NOT returned (this includes leading semi-colons).
+*
+* NOTE: If this routine is made user-callable, the near attribute
+* must be replaced by _LOAD_DS and the prototype moved from INTERNAL.H
+* to STDLIB.H. The source files MISC\SEARCHEN.C and EXEC\SPAWNVPE.C
+* will need to be recompiled, but should not require any changes.
+*
+*Entry:
+* src - Pointer to a string of 0 or more path specificiations,
+* delimited by semicolons (';'), and terminated by a null
+* character
+* dst - Pointer to the buffer where the next path specification is to
+* be copied
+* maxlen - Maximum number of characters to be copied, counting the
+* terminating null character. Note that a value of 0 is treated
+* as UINT_MAX + 1.
+*
+*Exit:
+* If a pathname is successfully extracted and copied, a pointer to the
+* first character of next pathname is returned (intervening semicolons
+* are skipped over). If the pathname is too long, as much as possible
+* is copied to the user-specified buffer and NULL is returned.
+*
+* Note that the no check is made of the validity of the copied pathname.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+char * _CALLTYPE1 _getpath (
+ register const char *src,
+ register char *dst,
+ unsigned maxlen
+ )
+{
+ const char *save_src;
+
+ /*
+ * strip off leading semi colons
+ */
+ while ( *src == ';' )
+ src++;
+
+ /*
+ * Save original src pointer
+ */
+ save_src = src;
+
+ /*
+ * Decrement maxlen to allow for the terminating '\0'
+ */
+ if ( --maxlen == 0 )
+ goto appendnull;
+
+
+ /*
+ * Get the next path in src string
+ */
+ while (*src && (*src != ';')) {
+
+#ifdef _HPFS_
+
+ /*
+ * Check for quote char
+ */
+ if (*src != '"') {
+
+ *dst++ = *src++;
+
+ if ( --maxlen == 0 ) {
+ save_src = src; /* ensure NULL return */
+ goto appendnull;
+ }
+
+ }
+ else {
+
+ /*
+ * Found a quote. Copy all chars until we hit the
+ * final quote or the end of the string.
+ */
+ src++; /* skip over opening quote */
+
+ while (*src && (*src != '"')) {
+
+ *dst++ = *src++;
+
+ if ( --maxlen == 0 ) {
+ save_src = src; /* ensure NULL return */
+ goto appendnull;
+ }
+ }
+
+ if (*src)
+ src++; /* skip over closing quote */
+
+ }
+
+#else
+
+ *dst++ = *src++;
+
+ if ( --maxlen == 0 ) {
+ save_src = src; /* ensure NULL return */
+ goto appendnull;
+ }
+
+#endif
+
+ }
+
+ /*
+ * If we copied something and stopped because of a ';',
+ * skip the ';' before returning
+ */
+ while ( *src == ';' )
+ src++;
+
+ /*
+ * Store a terminating null
+ */
+appendnull:
+
+ *dst = '\0';
+
+ return((save_src != src) ? (char *)src : NULL);
+}
diff --git a/private/crt32/misc/getqloc.c b/private/crt32/misc/getqloc.c
new file mode 100644
index 000000000..b9ab3461f
--- /dev/null
+++ b/private/crt32/misc/getqloc.c
@@ -0,0 +1,736 @@
+/***
+*getqloc.c - get qualified locale
+*
+* Copyright (c) 1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _get_qualified_locale - get complete locale information
+*
+* NOTE: this should be a one-line call to an NT routine, but since NT does
+* not currently support the needed functionality, this will suffice,
+* it MUST be changed when NT supports changes.
+*
+* STAGE 1: convert input to internal LC_ID
+*
+* STAGE 2: qualify internal LC_ID
+* Locales in NT version 1 are really just a language and a sublanguage;
+* the language info is not useful. We therefore do not return a true
+* country code, but rather return the language for that country.
+*
+* STAGE 3: convert to proper output format
+* If output is an Id, no conversion necessary. If output is a string, call
+* NT routines to get English strings for qualified locale.
+**
+*Revision History:
+* 12-11-92 CFW initial version
+* 01-08-93 CFW cleaned up file
+* 02-02-93 CFW Added test for NULL input string fields
+* 02-08-93 CFW Casts to remove warnings.
+* 02-18-93 CFW Removed debugging support routines, changed copyright.
+* 02-18-93 CFW Removed debugging support routines, changed copyright.
+* 03-01-93 CFW Test code page validity, use ANSI comments.
+* 03-02-93 CFW Add ISO 3166 3-letter country codes, verify country table.
+* 03-04-93 CFW Call IsValidCodePage to test code page vailidity.
+* 03-10-93 CFW Protect table testing code.
+* 03-17-93 CFW Add __ to lang & ctry info tables, move defs to setlocal.h.
+* 03-23-93 CFW Make internal functions static, add _ to GetQualifiedLocale.
+* 03-24-93 CFW Change to _get_qualified_locale, support ".codepage".
+* 04-20-93 CFW Enable all strange countries.
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <setlocal.h>
+
+#define iAslpStr(i) ((LPLC_STRINGS)i)
+#define iAslpId(i) ((LPLC_ID)i)
+
+#define MAX_TEMP_STR_LEN (max(MAX_LANG_LEN, max(MAX_CTRY_LEN, MAX_CP_LEN)))
+
+static WORD trans_lang_lang(const PSZ pszLang);
+static WORD trans_ctry_ctry(const PSZ pszCtry);
+static WORD trans_ctry_lang(WORD wCtry);
+static BOOL match_ctry_lang(WORD *pwCtry, WORD *pwLang);
+static VOID pszcpywcs(PSZ pszStr, PWSTR pwStr);
+
+/* Languages supported are according to "Win32 NLSAPI Functional */
+/* Specification" of 15 September, 1992 */
+
+#define LANG_STR_NUM 92 /* number of language strings + 1 for algorithm */
+
+LANGREC __rg_lang_rec[] =
+{
+ {"", MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)},
+ {"american", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"american english", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"american-english", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"australian", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)},
+ {"belgian", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)},
+ {"canadian", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)},
+ {"chinese", MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT)},
+ {"chinese-simplified", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)},
+ {"chinese-traditional", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)},
+ {"chs", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)},
+ {"cht", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)},
+ {"csy", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)},
+ {"czech", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)},
+ {"dan", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)},
+ {"danish", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)},
+ {"dea", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN)},
+ {"des", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)},
+ {"deu", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)},
+ {"dutch", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)},
+ {"dutch-belgian", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)},
+ {"ell", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)},
+ {"ena", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)},
+ {"enc", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)},
+ {"eng", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)},
+ {"english", MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)},
+ {"english-american", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"english-aus", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)},
+ {"english-can", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)},
+ {"english-nz", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_NZ)},
+ {"english-uk", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)},
+ {"english-us", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"english-usa", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"enu", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"enz", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_NZ)},
+ {"esm", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MEXICAN)},
+ {"esn", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN)},
+ {"esp", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT)},
+ {"fin", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)},
+ {"finnish", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)},
+ {"fra", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)},
+ {"frb", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN)},
+ {"frc", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_CANADIAN)},
+ {"french", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)},
+ {"french-belgian", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN)},
+ {"french-canadian", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_CANADIAN)},
+ {"french-swiss", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_SWISS)},
+ {"frs", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_SWISS)},
+ {"german", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)},
+ {"german-austrian", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN)},
+ {"german-swiss", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)},
+ {"greek", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)},
+ {"hun", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)},
+ {"hungarian", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)},
+ {"icelandic", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT)},
+ {"isl", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT)},
+ {"ita", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)},
+ {"italian", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)},
+ {"italian-swiss", MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN_SWISS)},
+ {"its", MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN_SWISS)},
+ {"japanese", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)},
+ {"jpn", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)},
+ {"kor", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)},
+ {"korean", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)},
+ {"nlb", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)},
+ {"nld", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)},
+ {"non", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)},
+ {"nor", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL)},
+ {"norwegian", MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT)},
+ {"norwegian-bokmal", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL)},
+ {"norwegian-nynorsk", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)},
+ {"plk", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)},
+ {"polish", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)},
+ {"portuguese", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE)},
+ {"portuguese-brazilian", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN)},
+ {"ptb", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN)},
+ {"ptg", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE)},
+ {"rus", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)},
+ {"russian", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)},
+ {"sky", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)},
+ {"slovak", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)},
+ {"spanish", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT)},
+ {"spanish-mexican", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MEXICAN)},
+ {"spanish-modern", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN)},
+ {"sve", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)},
+ {"swedish", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)},
+ {"swiss", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)},
+ {"trk", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)},
+ {"turkish", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)},
+ {"uk", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)},
+ {"us", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)},
+ {"usa", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}
+};
+
+/* Countries supported are according to "Win32 NLSAPI Functional */
+/* Specification" of 15 September, 1992 */
+
+#define CTRY_STR_NUM 68 /* number of country strings + 1 for algorithm */
+
+CTRYREC __rg_ctry_rec[] =
+{
+ {"", 0},
+ {"america", CTRY_UNITED_STATES},
+ {"aus", CTRY_AUSTRALIA},
+ {"australia", CTRY_AUSTRALIA},
+ {"austria", CTRY_AUSTRIA},
+ {"aut", CTRY_AUSTRIA},
+ {"bel", CTRY_BELGIUM},
+ {"belgium", CTRY_BELGIUM},
+ {"bra", CTRY_BRAZIL},
+ {"brazil", CTRY_BRAZIL},
+ {"britain", CTRY_UNITED_KINGDOM},
+ {"can", CTRY_CANADA},
+ {"canada", CTRY_CANADA},
+ {"che", CTRY_SWITZERLAND},
+ {"china", CTRY_PRCHINA},
+ {"chn", CTRY_PRCHINA},
+ {"denmark", CTRY_DENMARK},
+ {"deu", CTRY_GERMANY},
+ {"dnk", CTRY_DENMARK},
+ {"england", CTRY_UNITED_KINGDOM},
+ {"esp", CTRY_SPAIN},
+ {"fin", CTRY_FINLAND},
+ {"finland", CTRY_FINLAND},
+ {"fra", CTRY_FRANCE},
+ {"france", CTRY_FRANCE},
+ {"gbr", CTRY_UNITED_KINGDOM},
+ {"germany", CTRY_GERMANY},
+ {"great britain", CTRY_UNITED_KINGDOM},
+ {"holland", CTRY_NETHERLANDS},
+ {"iceland", CTRY_ICELAND},
+ {"ireland", CTRY_IRELAND},
+ {"irl", CTRY_IRELAND},
+ {"isl", CTRY_ICELAND},
+ {"ita", CTRY_ITALY},
+ {"italy", CTRY_ITALY},
+ {"japan", CTRY_JAPAN},
+ {"jpn", CTRY_JAPAN},
+ {"kor", CTRY_SOUTH_KOREA},
+ {"korea", CTRY_SOUTH_KOREA},
+ {"mex", CTRY_MEXICO},
+ {"mexico", CTRY_MEXICO},
+ {"netherlands", CTRY_NETHERLANDS},
+ {"new zealand", CTRY_NEW_ZEALAND},
+ {"new-zealand", CTRY_NEW_ZEALAND},
+ {"nld", CTRY_NETHERLANDS},
+ {"nor", CTRY_NORWAY},
+ {"norway", CTRY_NORWAY},
+ {"nz", CTRY_NEW_ZEALAND},
+ {"nzl", CTRY_NEW_ZEALAND},
+ {"portugal", CTRY_PORTUGAL},
+ {"pr china", CTRY_PRCHINA},
+ {"pr-china", CTRY_PRCHINA},
+ {"prt", CTRY_PORTUGAL},
+ {"south korea", CTRY_SOUTH_KOREA},
+ {"south-korea", CTRY_SOUTH_KOREA},
+ {"spain", CTRY_SPAIN},
+ {"swe", CTRY_SWEDEN},
+ {"sweden", CTRY_SWEDEN},
+ {"switzerland", CTRY_SWITZERLAND},
+ {"taiwan", CTRY_TAIWAN},
+ {"twn", CTRY_TAIWAN},
+ {"uk", CTRY_UNITED_KINGDOM},
+ {"united kingdom", CTRY_UNITED_KINGDOM},
+ {"united states", CTRY_UNITED_STATES},
+ {"united-kingdom", CTRY_UNITED_KINGDOM},
+ {"united-states", CTRY_UNITED_STATES},
+ {"us", CTRY_UNITED_STATES},
+ {"usa", CTRY_UNITED_STATES},
+};
+
+#define MAX_LANG_PER_CTRY 3 /* Switzerland has three languages*/
+#define MAX_CTRY_NUM 86 /* Ignore high digit (Max=China[86]=Taiwan[886])*/
+WORD __rgrgwlang[MAX_CTRY_NUM + 1][MAX_LANG_PER_CTRY] =
+{
+/* 0*/
+ {0,0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_CAN),
+ MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_CANADIAN),0},
+ {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MEXICAN),
+ MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN),0},
+ {0,0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+/* 10*/
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+/* 20*/
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+/* 30*/
+ {0,0,0},
+ {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH),0,0},
+ {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN),
+ MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_BELGIAN),0},
+ {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH),0,0},
+ {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH),0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN),0,0},
+/* 40*/
+ {0,0,0},
+ {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_SWISS),
+ MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_SWISS),
+ MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN_SWISS)},
+ {0,0,0},
+ {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_AUSTRIAN),0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK),0,0},
+
+ {MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT),0,0},
+ {MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT),0,0},
+ {MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT),0,0},
+ {0,0,0},
+ {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN),0,0},
+/* 50*/
+ {0,0,0},
+ {MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE),0,0},
+ {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MEXICAN),0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK),0,0},
+ {MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT),0,0},
+
+ {MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN),0,0},
+ {0,0,0},
+ {0,0,0},
+ {MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT),0,0},
+ {0,0,0},
+/* 60*/
+ {0,0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_AUS),0,0},
+ {0,0,0},
+ {0,0,0},
+ {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_NZ),0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+/* 70*/
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+/* 80*/
+ {0,0,0},
+ {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT),0,0},
+ {MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT),0,0},
+ {0,0,0},
+ {0,0,0},
+ {0,0,0},
+ {MAKELANGID(LANG_CHINESE,SUBLANG_DEFAULT),0,0}
+};
+
+/***
+*void pszcpywcs - strcpy, wide char string to char string
+*
+*Purpose:
+* Copies and converts string
+*
+*Entry:
+* psz pszStr - pointer to destination char string
+* pwstr pwStr - pointer to source wide char string
+*
+*Exit:
+* None.
+*
+*Exceptions:
+*
+*******************************************************************************/
+static VOID pszcpywcs(PSZ pszStr, PWSTR pwStr)
+{
+ while (*pwStr)
+ *pszStr++ = (char)(*pwStr++);
+ *pszStr = 0;
+}
+
+/***
+*WORD trans_lang_lang - translate language string to language id
+*
+*Purpose:
+* convert string to id
+*
+*Entry:
+* pszLang - pointer to language string
+*
+*Exit:
+* translated language id
+*
+*Exceptions:
+*
+*******************************************************************************/
+static WORD trans_lang_lang(const PSZ pszLang)
+{
+ INT i, cmp, low = 0, high = LANG_STR_NUM + 1;
+
+ while (1)
+ {
+ i = (low + high) / 2;
+
+ if (!(cmp = stricmp(pszLang, (const char *)__rg_lang_rec[i].szLanguage)))
+ return __rg_lang_rec[i].wLanguage; /* found the string*/
+ else if (cmp < 0)
+ high = i; /* less than pivot*/
+ else
+ low = i; /* more than pivot*/
+ if (low + 1 == high)
+ return 0; /* not found*/
+ }
+}
+
+/***
+*WORD trans_ctry_ctry - translate country string to country id
+*
+*Purpose:
+* convert string to id
+*
+*Entry:
+* pszCtry - pointer to country string
+*
+*Exit:
+* translated country id
+*
+*Exceptions:
+*
+*******************************************************************************/
+static WORD trans_ctry_ctry(const PSZ pszCtry)
+{
+ INT i, cmp, low = 0, high = CTRY_STR_NUM + 1;
+
+ while (1)
+ {
+ i = (low + high) / 2;
+
+ if (!(cmp = stricmp(pszCtry, (const char *)__rg_ctry_rec[i].szCountry)))
+ return __rg_ctry_rec[i].wCountry; /* found the string*/
+ else if (cmp < 0)
+ high = i; /* less than pivot*/
+ else
+ low = i; /* more than pivot*/
+ if (low + 1 == high)
+ return 0; /* not found*/
+ }
+}
+
+/***
+*WORD trans_ctry_lang - get default language for a country
+*
+*Purpose:
+* convert country id to language id
+*
+*Entry:
+* wCtry - country id
+*
+*Exit:
+* translated language id
+*
+*Exceptions:
+*
+*******************************************************************************/
+static WORD trans_ctry_lang(WORD wCtry)
+{
+ wCtry %= 100;
+ if (wCtry > MAX_CTRY_NUM)
+ return 0;
+
+ return __rgrgwlang[wCtry][0];
+}
+
+/***
+*BOOL match_ctry_lang - match country with language
+*
+*Purpose:
+* ensure language and country match, choose proper values for language
+* and country when matching, country ids converted to proper language id
+*
+*Entry:
+* pwCtry - pointer to country id to match and set
+* pwLang - pointer to language id to match and set
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+static BOOL match_ctry_lang(WORD *pwCtry, WORD *pwLang)
+{
+ UINT i;
+ WORD wCtry = *pwCtry;
+ WORD wLang = *pwLang;
+ WORD wLangT;
+
+ /* only use base 10 two least significant places*/
+ wCtry = wCtry % 100;
+
+ if (wCtry > MAX_CTRY_NUM)
+ return FALSE;
+
+ /* see if any of the sublanguages for this country match*/
+ for (i = 0; i < MAX_LANG_PER_CTRY; i++)
+ {
+ if (!(wLangT = __rgrgwlang[wCtry][i]))
+ break;
+ if (PRIMARYLANGID(wLangT) == PRIMARYLANGID(wLang))
+ {
+ /* they match*/
+ if (!SUBLANGID(wLang))
+ /* don't override sublanguage*/
+ *pwLang = wLangT;
+ *pwCtry = wLangT;
+ return TRUE;
+ }
+ }
+ /* get the default language for this country*/
+ if (!(*pwCtry = __rgrgwlang[wCtry][0]))
+ /* bad country number*/
+ return FALSE;
+ return TRUE;
+}
+
+/***
+*BOOL _get_qualified_locale - return fully qualified locale
+*
+*Purpose:
+* get default locale, qualify partially complete locales
+*
+*Entry:
+* dwType - indicates type of lpInput, either QF_STRINGS or QF_LCID
+* lpInput - input string/id to be qualified
+* lpOutId - pointer to output id, may be NULL if lpOutStr is !NULL
+* lpOutStr - pointer to output string, may be NULL if lpOutId is !NULL
+*
+*Exit:
+* TRUE if success, qualified locale is valid
+* FALSE if failure
+*
+*Exceptions:
+*
+*******************************************************************************/
+BOOL _CRTAPI1 _get_qualified_locale(
+ const DWORD dwType,
+ const LPVOID lpInput,
+ LPLC_ID lpOutId,
+ LPLC_STRINGS lpOutStr
+ )
+{
+#if defined _POSIX_
+ return FALSE;
+#else /* _POSIX_ */
+
+ LC_ID Id;
+ WCHAR wcsTemp[MAX_TEMP_STR_LEN];
+
+ if (!lpOutId && !lpOutStr)
+ return FALSE;
+
+ /* -----------------------------------------------------------------------
+ stage 1: convert input to internal LC_ID.
+ -----------------------------------------------------------------------*/
+
+ if (dwType == QF_STRINGS)
+ {
+ Id.wLanguage = (WORD)0;
+ Id.wCountry = (WORD)0;
+ Id.wCodePage = (WORD)0;
+
+ if (iAslpStr(lpInput)->szLanguage
+ && *(iAslpStr(lpInput)->szLanguage)
+ && (!(Id.wLanguage =
+ trans_lang_lang((const PSZ)iAslpStr(lpInput)->szLanguage))))
+ return FALSE;
+
+ if (iAslpStr(lpInput)->szCountry
+ && *(iAslpStr(lpInput)->szCountry)
+ && (!(Id.wCountry =
+ trans_ctry_ctry((const PSZ)iAslpStr(lpInput)->szCountry))))
+ return FALSE;
+
+ if (iAslpStr(lpInput)->szCodePage
+ && *(iAslpStr(lpInput)->szCodePage)
+ && (!(Id.wCodePage = atoi((const char *)iAslpStr(lpInput)->szCodePage))))
+ return FALSE;
+ }
+ else if (dwType == QF_LCID)
+ {
+ Id = *iAslpId(lpInput);
+ }
+
+ /* -----------------------------------------------------------------------
+ stage 2: qualify internal LC_ID
+ -----------------------------------------------------------------------*/
+
+ if (!Id.wLanguage)
+ {
+ /* language undefined*/
+ if (!Id.wCountry)
+ {
+ /* language undefined, country undefined*/
+ Id.wLanguage = Id.wCountry = LANGIDFROMLCID(GetUserDefaultLCID());
+ if (Id.wCodePage)
+ {
+ /* language undefined, country undefined and code page defined*/
+ if (IsValidCodePage(Id.wCodePage) == FALSE)
+ return FALSE;
+ }
+ else {
+ /* language, country and code page undefined*/
+ Id.wCodePage = (WORD)GetOEMCP();
+ }
+ }
+ else
+ {
+ /* language undefined, country defined*/
+ Id.wCountry = Id.wLanguage = trans_ctry_lang(Id.wCountry);
+
+ if (Id.wCodePage)
+ {
+ /* language undefined, country defined and code page defined*/
+ if (IsValidCodePage(Id.wCodePage) == FALSE)
+ return FALSE;
+ }
+ else {
+ /* language undefined, country defined and code page undefined*/
+ if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN))
+ return FALSE;
+ Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10);
+ }
+ }
+ }
+ else
+ {
+ /* language defined*/
+ if (!Id.wCountry)
+ {
+ /* language defined, country undefined*/
+ Id.wCountry = Id.wLanguage;
+
+ if (Id.wCodePage)
+ {
+ /* language defined, country undefined and code page defined*/
+ if (IsValidCodePage(Id.wCodePage) == FALSE)
+ return FALSE;
+ }
+ else {
+ /* language undefined, country undefined and code page undefined*/
+ if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN))
+ return FALSE;
+ Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10);
+ }
+ }
+ else
+ {
+ /* language defined, country defined*/
+
+ /* match and set country and language*/
+ if (!match_ctry_lang((WORD *)&Id.wCountry, (WORD *)&Id.wLanguage))
+ return FALSE;
+
+ if (Id.wCodePage)
+ {
+ /* language defined, country defined and code page defined*/
+ if (IsValidCodePage(Id.wCodePage) == FALSE)
+ return FALSE;
+ }
+ else {
+ /* language defined, country defined and code page undefined*/
+ if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN))
+ return FALSE;
+ Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10);
+ }
+ }
+ }
+
+ /* -----------------------------------------------------------------------
+ stage 3: convert to proper output format
+ -----------------------------------------------------------------------*/
+
+ if (lpOutId)
+ {
+ *lpOutId = Id;
+ }
+
+ if (lpOutStr)
+ {
+ if (!GetLocaleInfoW(MAKELCID(Id.wLanguage, SORT_DEFAULT), LOCALE_SENGLANGUAGE, wcsTemp, MAX_LANG_LEN))
+ return FALSE;
+ pszcpywcs((PSZ)lpOutStr->szLanguage, (PWSTR)wcsTemp);
+
+ if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_SENGCOUNTRY, wcsTemp, MAX_CTRY_LEN))
+ return FALSE;
+ pszcpywcs((PSZ)lpOutStr->szCountry, (PWSTR)wcsTemp);
+
+ _itoa((int)Id.wCodePage, (char *)lpOutStr->szCodePage, 10);
+ }
+ return TRUE;
+#endif /* _POSIX_ */
+}
+
+
+/* for testing when new items added to tables */
+
+#if 0
+
+VOID _CRTAPI1 test_lang_table(VOID)
+{
+ UINT i;
+
+ printf("Testing Language Table\n");
+ printf("Real Table Size = %d entries, defined size=%d entries\n",
+ sizeof(__rg_lang_rec) / sizeof(LANGREC), LANG_STR_NUM);
+ for (i = 0; i < LANG_STR_NUM-1; i++)
+ {
+ printf("language name[%d] = '%s' number=%d\n", i, __rg_lang_rec[i].szLanguage, __rg_lang_rec[i].wLanguage);
+ if ((stricmp(__rg_lang_rec[i].szLanguage,__rg_lang_rec[i+1].szLanguage) >= 0))
+ printf("\n*********\nBad Lang Table Lang[%d]=%s Lang[%d]=%s\n\n",
+ i, __rg_lang_rec[i].szLanguage, i+1, __rg_lang_rec[i+1].szLanguage);
+ }
+ printf("language name[%d] = '%s' number=%d\n", i, __rg_lang_rec[i].szLanguage, __rg_lang_rec[i].wLanguage);
+}
+
+VOID _CRTAPI1 test_ctry_table(VOID)
+{
+ UINT i;
+
+ printf("Testing Country Table\n");
+ printf("Real Table Size = %d entries, defined size=%d entries\n",
+ sizeof(__rg_ctry_rec) / sizeof(CTRYREC), CTRY_STR_NUM);
+ for (i = 0; i < CTRY_STR_NUM-1; i++)
+ {
+ printf("country name[%d] = '%s' number=%d\n", i, __rg_ctry_rec[i].szCountry, __rg_ctry_rec[i].wCountry);
+ if ((stricmp(__rg_ctry_rec[i].szCountry,__rg_ctry_rec[i+1].szCountry) >= 0))
+ printf("\n**********\nBad Ctry Table Ctry[%d]=%s Ctry[%d]=%s\n\n",
+ i, __rg_ctry_rec[i].szCountry, i+1, __rg_ctry_rec[i+1].szCountry);
+ }
+ printf("country name[%d] = '%s' number=%d\n", i, __rg_ctry_rec[i].szCountry, __rg_ctry_rec[i].wCountry);
+}
+
+#endif
diff --git a/private/crt32/misc/i386/_initone.asm b/private/crt32/misc/i386/_initone.asm
new file mode 100644
index 000000000..90d901904
--- /dev/null
+++ b/private/crt32/misc/i386/_initone.asm
@@ -0,0 +1,17 @@
+ page ,132
+
+;*******
+;
+; Alternate form of CINITONE.ASM
+;
+; The MIPS C Compiler does not prepend underscores to C
+; variables and functions like the I386 C Compiler does.
+;
+; The EQUate below will yield an object file
+; which will be appropriate for MIPS COFF format.
+;
+;*******
+
+NO_UNDERSCORE equ 1
+
+include i386\cinitone.asm
diff --git a/private/crt32/misc/i386/cinitone.asm b/private/crt32/misc/i386/cinitone.asm
new file mode 100644
index 000000000..e4bf0ef39
--- /dev/null
+++ b/private/crt32/misc/i386/cinitone.asm
@@ -0,0 +1,78 @@
+ page ,132
+ title cinitone - C Run-Time Initialization for _onexit/atexit
+;***
+;cinitone.asm - WIN32 C Run-Time Initialization for _onexit()/atexit() routines
+;
+; Copyright (c) 1992, Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Initialization entry for the _onexit()/atexit() functions.
+; This module adds an entry for _onexitinit() to the initializer table.
+; ONEXIT.C references the dummy variable __c_onexit in order to force
+; the loading of this module.
+;
+;Notes:
+;
+;Revision History:
+; 03-19-92 SKS Module created.
+; 03-24-92 SKS Added MIPS support (NO_UNDERSCORE)
+; 04-30-92 SKS Add "offset FLAT:" to get correct fixups for OMF objs
+; 08-06-92 SKS Revised to use new section names and macros
+;
+;*******************************************************************************
+
+.xlist
+include cruntime.inc
+include defsects.inc
+.list
+
+ifndef _WIN32_
+.err
+%out _WIN32_ MUST be defined!
+endif
+
+
+ifndef NO_UNDERSCORE ; I386 VERSION *************************
+
+
+ extrn _onexitinit:NEAR
+
+
+beginSection XIC
+
+ dd offset FLAT: _onexitinit
+
+endSection XIC
+
+
+ .DATA
+
+ public __c_onexit
+
+__c_onexit dd 0
+
+
+else ; NO_UNDERSCORE ; MIPS VERSION *************************
+
+
+ extrn onexitinit:NEAR
+
+
+beginSection XIC
+
+ dd offset FLAT: onexitinit
+
+endSection XIC
+
+
+ .DATA
+
+ public _c_onexit
+
+_c_onexit dd 0
+
+
+endif ; NO_UNDERSCORE ; **** VERSION *************************
+
+
+ end
diff --git a/private/crt32/misc/i386/exsup.asm b/private/crt32/misc/i386/exsup.asm
new file mode 100644
index 000000000..8e7043eca
--- /dev/null
+++ b/private/crt32/misc/i386/exsup.asm
@@ -0,0 +1,299 @@
+;***
+;exsup.asm
+;
+; Copyright (c) 1993-1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Exception handling for i386. This file contains those routines
+; common to both C8.0 and C9.0.
+;
+;Notes:
+;
+;Revision History:
+; 04-13-93 JWM setjmp(), longjmp() & raisex() moved to setjmp.asm;
+; common data definitions moved to exsup.inc.
+; 10-18-93 GJF Ensure direction flag is clear in _except_handler2
+; 12-16-93 PML Accept <0,0,>0 from except filter, not just -1,0,+1
+; 01-10-94 PML Moved C8-specific __except_handler2 to exsup2.inc.
+; Only C8/C9 common routines left here.
+; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not
+; 0.
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+ifdef _WIN32_
+_WIN32_OR_POSIX_ equ 1
+endif
+ifdef _POSIX_
+_WIN32_OR_POSIX_ equ 1
+endif
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+;REVIEW: can we get rid of _global_unwind2, and just use
+; the C runtimes version, _global_unwind?
+
+ifdef _WIN32_OR_POSIX_
+extrn _RtlUnwind@16:near
+endif
+
+;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION;
+;struct _EXCEPTION_REGISTRATION{
+; struct _EXCEPTION_REGISTRATION *prev;
+; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
+; struct scopetable_entry *scopetable;
+; int trylevel;
+;};
+_EXCEPTION_REGISTRATION_COMMON struc ; C8.0/C9.0 common only
+ dd ? ; prev (OS-req, def'd in exsup.inc)
+ dd ? ; handler (ditto)
+scopetable dd ? ; C8/C9 common
+trylevel dd ? ; C8/C9 common
+_EXCEPTION_REGISTRATION_COMMON ends
+
+;#define EXCEPTION_MAXIMUM_PARAMETERS 4
+;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
+;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
+;struct _EXCEPTION_RECORD{
+; NTSTATUS ExceptionCode;
+; ULONG ExceptionFlags;
+; struct _EXCEPTION_RECORD *ExceptionRecord;
+; PVOID ExceptionAddress;
+; ULONG NumberParameters;
+; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+;};
+_EXCEPTION_RECORD struc
+ exception_number dd ?
+ exception_flags dd ?
+ exception_record dd ?
+ exception_address dd ?
+ number_parameters dd ?
+ exception_information dd 4 dup(?)
+_EXCEPTION_RECORD ends
+SIZEOF_EXCEPTION_RECORD equ 36
+
+assumes DS,DATA
+assumes FS,DATA
+
+public __except_list
+__except_list equ 0
+
+;struct _SCOPETABLE_ENTRY{
+; int enclosing_level; /* lexical level of enclosing scope */
+; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */
+; void (*specific_handler)(void); /* xcpt or termination handler */
+;};
+;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS];
+_SCOPETABLE_ENTRY struc
+ enclosing_level dd ?
+ filter dd ?
+ specific_handler dd ?
+_SCOPETABLE_ENTRY ends
+
+BeginCODE
+if @Version LT 600
+ifdef _WIN32_OR_POSIX_
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+else
+assumes CS,CODE
+endif
+endif
+
+ifdef _WIN32_OR_POSIX_ ;{
+
+;NB: call to RtlUnwind appears to trash ebx! and possibly others so just
+; to be save, we save all callee save regs.
+cProc _global_unwind2,<C,PUBLIC>,<IBX,ISI,IDI,IBP>
+ parmDP stop
+cBegin
+ push 0 ; ReturnValue
+ push 0 ; ExceptionRecord
+ push offset flat:_gu_return ; TargetIp
+ push stop ; TargetFrame
+
+ call _RtlUnwind@16
+_gu_return:
+cEnd
+
+else ;}{
+
+;/* _GLOBAL_UNWIND2 - */
+;void _global_unwind2(PEXCEPTION_REGISTRATION *stop)
+;{
+; for(xr=__except_list; xr!=stop; xr=xr->prev){
+; assert(xr!=NULL);
+; /* NOTE: must set ebp to this scopes frame before call */
+; _local_unwind2(xr, -1);
+; }
+;}
+cProc _global_unwind2,<C,PUBLIC>,<ISI,IDI>
+ parmDP stop
+ localV xr,SIZEOF_EXCEPTION_RECORD
+cBegin
+ ;build an EXCEPTION_RECORD to pass to language handler for unwinding
+ lea esi, xr
+ mov [esi.exception_number], 0
+ mov [esi.exception_flags], EXCEPTION_UNWIND_CONTEXT
+ ;REVIEW: fill in the rest of the struct?
+
+ mov edi, dword ptr fs:__except_list
+_gu_top:
+ cmp edi, stop
+ je short _gu_done
+ cmp edi, -1 ; -1 means no higher-level handler
+ je short _gu_error
+
+ push edi
+ push esi
+ call [edi.handler]
+ add esp, 8
+
+ mov edi, [edi.prev]
+ mov dword ptr fs:__except_list, edi
+ jmp short _gu_top
+
+_gu_error:
+ ;assert(0);
+
+_gu_done:
+cEnd
+
+endif ;}
+
+;_unwind_handler(
+; PEXCEPTION_RECORD xr,
+; PREGISTRATION_RECORD establisher,
+; PCONTEXT context,
+; PREGISTRATION_RECORD dispatcher);
+;
+;this is a special purpose handler used to guard our local unwinder.
+; its job is to catch collided unwinds.
+;
+;NB: this code is basically stolen from the NT routine xcptmisc.asm
+; and is basically the same method used by the system unwinder (RtlUnwind).
+;
+cProc _unwind_handler,<C>
+cBegin
+ mov ecx, dword ptr [esp+4]
+ test dword ptr [ecx.exception_flags], EXCEPTION_UNWIND_CONTEXT
+ mov eax, DISPOSITION_CONTINUE_SEARCH
+ jz short _uh_return
+
+ ; We collide in a _local_unwind. We set the dispatched to the
+ ; establisher just before the local handler so we can unwind
+ ; any future local handlers.
+
+ mov eax, [esp+8] ; Our establisher is the one
+ ; in front of the local one
+
+ mov edx, [esp+16]
+ mov [edx], eax ; set dispatcher to local_unwind2
+
+ mov eax, DISPOSITION_COLLIDED_UNWIND
+_uh_return:
+cEnd
+
+;/* _LOCAL_UNWIND2 - run all termination handlers listed in the scope table
+; * associated with the given registration record, from the current lexical
+; * level through enclosing levels up to, but not including the given 'stop'
+; * level.
+; */
+;void _local_unwind2(PEXCEPTION_REGISTRATION xr, int stop)
+;{
+; int ix;
+;
+; for(ix=xr->trylevel; ix!=-1 && ix!=stop; ix=xr->xscope[i].enclosing_level){
+; /* NULL indicates that this entry is for a termination handler */
+; if(xr->xscope[i].filter==NULL){
+; /* NB: call to the termination handler may trash callee save regs */
+; (*xr->xscope[i].specific_handler)();
+; }
+; }
+; xr->trylevel=stop;
+;}
+;/* NOTE: frame (ebp) is setup by caller of __local_unwind2 */
+cProc _local_unwind2,<C,PUBLIC>
+cBegin
+ push ebx
+ push esi
+ push edi ;call to the handler may trash, so we must save it
+
+ mov eax, [esp+16] ; (eax) = PEXCEPTION_REGISTRATION
+
+ ;link in a handler to guard our unwind
+ push eax
+ push TRYLEVEL_INVALID
+ push OFFSET FLAT:__unwind_handler
+ push fs:__except_list
+ mov fs:__except_list, esp
+
+_lu_top:
+ mov eax, [esp+32] ; (eax) = PEXCEPTION_REGISTRATION
+ mov ebx, [eax.scopetable]
+ mov esi, [eax.trylevel]
+
+ cmp esi, -1 ; REVIEW: do we need this extra check?
+ je short _lu_done
+ cmp esi, [esp+36]
+ je short _lu_done
+
+ lea esi, [esi+esi*2] ; esi*= 3
+
+ mov ecx, [(ebx+esi*4).enclosing_level]
+ mov [esp+8], ecx ; save enclosing level
+ mov [eax.trylevel], ecx
+
+ cmp dword ptr [(ebx+esi*4).filter], 0
+ jnz short _lu_continue
+
+ call [(ebx+esi*4).specific_handler]
+
+_lu_continue:
+ jmp short _lu_top
+
+_lu_done:
+ pop fs:__except_list
+ add esp, 4*3 ; cleanup stack
+
+ pop edi ; restore c-runtime registers
+ pop esi
+ pop ebx
+cEnd
+
+;/* _ABNORMAL_TERMINATION - return TRUE if __finally clause entered via
+; * _local_unwind2.
+; */
+;BOOLEAN _abnormal_termination(void);
+cProc _abnormal_termination,<C,PUBLIC>
+cBegin
+ xor eax, eax ; assume FALSE
+
+ mov ecx, fs:__except_list
+ cmp [ecx.handler], offset FLAT:__unwind_handler
+ jne short _at_done ; UnwindHandler first?
+
+ mov edx, [ecx+12] ; establisher of local_unwind2
+ mov edx, [edx.trylevel] ; is trylevel the same as the
+ cmp [ecx+8], edx ; local_unwind level?
+ jne short _at_done ; no - then FALSE
+
+ mov eax, 1 ; currently in _abnormal_termination
+_at_done:
+cEnd
+
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/exsup2.asm b/private/crt32/misc/i386/exsup2.asm
new file mode 100644
index 000000000..ead56f5af
--- /dev/null
+++ b/private/crt32/misc/i386/exsup2.asm
@@ -0,0 +1,271 @@
+;***
+;exsup2.asm
+;
+; Copyright (c) 1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Exception handling for i386. This is just the C8.0 version of
+; the language-specific exception handler. The C9.0 version is
+; found in exsup3.asm, and the routines common to both C8 and C9
+; are found in exsup.asm.
+;
+;Notes:
+;
+;Revision History:
+; 01-10-94 PML Created with __except_handler2 from exsup.asm
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+ifdef _WIN32_
+_WIN32_OR_POSIX_ equ 1
+endif
+ifdef _POSIX_
+_WIN32_OR_POSIX_ equ 1
+endif
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+;REVIEW: can we get rid of _global_unwind2, and just use
+; the C runtimes version, _global_unwind?
+
+extrn __global_unwind2:near
+extrn __local_unwind2:near
+
+;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION;
+;struct _EXCEPTION_REGISTRATION{
+; struct _EXCEPTION_REGISTRATION *prev;
+; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
+; struct scopetable_entry *scopetable;
+; int trylevel;
+; int _ebp;
+; PEXCEPTION_POINTERS xpointers;
+;};
+_C8_EXCEPTION_REGISTRATION struc ; C8.0 version
+ dd ? ; prev (common)
+ dd ? ; handler (common)
+;private:
+ scopetable dd ?
+ trylevel dd ?
+ _ebp dd ?
+ xpointers dd ?
+_C8_EXCEPTION_REGISTRATION ends
+
+;#define EXCEPTION_MAXIMUM_PARAMETERS 4
+;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
+;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
+;struct _EXCEPTION_RECORD{
+; NTSTATUS ExceptionCode;
+; ULONG ExceptionFlags;
+; struct _EXCEPTION_RECORD *ExceptionRecord;
+; PVOID ExceptionAddress;
+; ULONG NumberParameters;
+; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+;};
+_EXCEPTION_RECORD struc
+ exception_number dd ?
+ exception_flags dd ?
+ exception_record dd ?
+ exception_address dd ?
+ number_parameters dd ?
+ exception_information dd 4 dup(?)
+_EXCEPTION_RECORD ends
+SIZEOF_EXCEPTION_RECORD equ 36
+
+;/* following is the structure returned by the _exception_info() intrinsic. */
+;typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS;
+;typedef struct EXCEPTION_POINTERS *PEXCEPTION_POINTERS;
+;struct _EXCEPTION_POINTERS{
+; PEXCEPTION_RECORD ExceptionRecord;
+; PCONTEXT Context;
+;};
+_EXCEPTION_POINTERS struc
+ ep_xrecord dd ?
+ ep_context dd ?
+_EXCEPTION_POINTERS ends
+SIZEOF_EXCEPTION_POINTERS equ 8
+
+assumes DS,DATA
+assumes FS,DATA
+
+__except_list equ 0
+
+;struct _SCOPETABLE_ENTRY{
+; int enclosing_level; /* lexical level of enclosing scope */
+; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */
+; void (*specific_handler)(void); /* xcpt or termination handler */
+;};
+;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS];
+_SCOPETABLE_ENTRY struc
+ enclosing_level dd ?
+ filter dd ?
+ specific_handler dd ?
+_SCOPETABLE_ENTRY ends
+
+BeginCODE
+if @Version LT 600
+ifdef _WIN32_OR_POSIX_
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+else
+assumes CS,CODE
+endif
+endif
+
+;/* _EXCEPT_HANDLER2 - Try to find an exception handler listed in the scope
+; * table associated with the given registration record, that wants to accept
+; * the current exception. If we find one, run it (and never return).
+; * RETURNS: (*if* it returns)
+; * DISPOSITION_DISMISS - dismiss the exception.
+; * DISPOSITION_CONTINUE_SEARCH - pass the exception up to enclosing handlers
+; */
+;int _except_handler2(
+; PEXCEPTION_RECORD exception_record,
+; PEXCEPTION_REGISTRATION registration,
+; PCONTEXT context,
+; PEXCEPTION_REGISTRATION dispatcher)
+;{
+; int ix, filter_result;
+;
+; for(ix=registration->trylevel; ix!=-1; ix=registration->xscope[ix].enclosing_level){
+; /* if filter==NULL, then this is an entry for a termination handler */
+; if(registration->xscope[ix].filter){
+; /* NB: call to the filter may trash the callee save
+; registers. (this is *not* a standard cdecl function) */
+; filter_result=(*registration->xscope[ix].filter)(xinfo);
+; if(filter_result==FILTER_DISMISS)
+; return(-1); /* dismiss */
+; if(filter_result==FILTER_ACCEPT){
+; _global_unwind2(registration);
+; _local_unwind2(registration, ix);
+; (*registration->xscope[ix].specific_handler)(void);
+; assert(UNREACHED); /*should never return from handler*/
+; }
+; assert(filter_result==FILTER_CONTINUE_SEARCH);
+; }
+; }
+; return(0); /* didnt find one */
+;}
+ db 'VC10' ;; VC/C++ 1.0/32-bit (C8.0) version
+ db 'XC00' ;; so debugger can recognize this proc (cuda:3936)
+cProc _except_handler2,<C,PUBLIC>,<IBX,ISI,IDI,IBP>
+ parmDP xrecord
+ parmDP registration
+ parmDP context
+ parmDP dispatcher
+ localV xp,SIZEOF_EXCEPTION_POINTERS
+cBegin
+ ;4*4b for callee saves + 4b return address + 4b param = 24
+
+ ;DF in indeterminate state at time of exception, so clear it
+ cld
+
+ mov ebx, registration ;ebx= PEXCEPTION_REGISTRATION
+ mov eax, xrecord
+
+ test [eax.exception_flags], EXCEPTION_UNWIND_CONTEXT
+ jnz short _lh_unwinding
+
+ ;build the EXCEPTION_POINTERS locally store its address in the
+ ; registration record. this is the pointer that is returned by
+ ; the _eception_info intrinsic.
+ mov xp.ep_xrecord, eax
+ mov eax, context
+ mov xp.ep_context, eax
+ lea eax, xp
+ mov [ebx.xpointers], eax
+
+ mov esi, [ebx.trylevel] ;esi= try level
+ mov edi, [ebx.scopetable] ;edi= scope table base
+_lh_top:
+ cmp esi, -1
+ je short _lh_bagit
+ lea ecx, [esi+esi*2] ;ecx= trylevel*3
+ cmp dword ptr [(edi+ecx*4).filter], 0
+ je short _lh_continue ;term handler, so keep looking
+
+ ;filter may trash *all* registers, so save ebp and scopetable offset
+ push esi
+ push ebp
+
+ mov ebp, [ebx._ebp]
+ call [(edi+ecx*4).filter] ;call the filter
+
+ pop ebp
+ pop esi
+ ;ebx may have been trashed by the filter, so we must reload
+ mov ebx, registration
+
+ ; Accept <0, 0, >0 instead of just -1, 0, +1
+ or eax, eax
+ jz short _lh_continue
+ js short _lh_dismiss
+ ;assert(eax==FILTER_ACCEPT)
+
+ ;reload xscope base, cuz it was trashed by the filter call
+ mov edi, [ebx.scopetable]
+ ;load handler address before we loose components of address mode
+ push ebx ;registration*
+ call __global_unwind2 ;run term handlers
+ add esp, 4
+
+ ;setup ebp for the local unwinder and the specific handler
+ mov ebp, [ebx._ebp]
+
+ ;the stop try level == accepting except level
+ push esi ;stop try level
+ push ebx ;registration*
+ call __local_unwind2
+ add esp, 8
+
+ lea ecx, [esi+esi*2] ;ecx=trylevel*3
+; set the current trylevel to our enclosing level immediately
+; before giving control to the handler. it is the enclosing
+; level, if any, that guards the handler.
+ mov eax, [(edi+ecx*4).enclosing_level]
+ mov [ebx.trylevel], eax
+ call [(edi+ecx*4).specific_handler] ;call the except handler
+ ;assert(0) ;(NB! should not return)
+
+_lh_continue:
+ ;reload the scope table base, possibly trashed by call to filter
+ mov edi, [ebx.scopetable]
+ lea ecx, [esi+esi*2]
+ mov esi, [edi+ecx*4+0] ;load the enclosing trylevel
+ jmp short _lh_top
+
+_lh_dismiss:
+ mov eax, DISPOSITION_DISMISS ;dismiss the exception
+ jmp short _lh_return
+
+_lh_bagit:
+ mov eax, DISPOSITION_CONTINUE_SEARCH
+ jmp short _lh_return
+
+_lh_unwinding:
+ push ebp
+ mov ebp, [ebx._ebp]
+ push -1
+ push ebx
+ call __local_unwind2
+ add esp, 8
+ pop ebp
+ ;the return value is not really relevent in an unwind context
+ mov eax, DISPOSITION_CONTINUE_SEARCH
+
+_lh_return:
+cEnd
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/exsup3.asm b/private/crt32/misc/i386/exsup3.asm
new file mode 100644
index 000000000..ff8a91dfa
--- /dev/null
+++ b/private/crt32/misc/i386/exsup3.asm
@@ -0,0 +1,290 @@
+;***
+;exsup3.asm
+;
+; Copyright (c) 1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Exception handling for i386. This is just the C9.0 version of
+; the language-specific exception handler. The C8.0 version is
+; found in exsup2.asm, and the routines common to both C8 and C9
+; are found in exsup.asm.
+;
+;Notes:
+;
+;Revision History:
+; 01-10-94 PML Create VC/C++ 2.0 (C9.0) version from C8.0 original
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+ifdef _WIN32_
+_WIN32_OR_POSIX_ equ 1
+endif
+ifdef _POSIX_
+_WIN32_OR_POSIX_ equ 1
+endif
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+;REVIEW: can we get rid of _global_unwind2, and just use
+; the C runtimes version, _global_unwind?
+
+extrn __global_unwind2:near
+extrn __local_unwind2:near
+
+;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION;
+;struct _EXCEPTION_REGISTRATION{
+;/* _esp, xpointers at negative offset */
+; int _esp;
+; PEXCEPTION_POINTERS xpointers;
+; struct _EXCEPTION_REGISTRATION *prev;
+; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
+; struct scopetable_entry *scopetable;
+; int trylevel;
+;};
+;private (at negative offsets from node ptr)
+ _esp = -8
+ xpointers = -4
+_C9_EXCEPTION_REGISTRATION struc ; C9.0 version
+;public:
+ dd ? ; prev (common)
+ dd ? ; handler (common)
+;private:
+ scopetable dd ?
+ trylevel dd ?
+_C9_EXCEPTION_REGISTRATION ends
+FRAME_EBP_OFFSET equ 16
+
+;#define EXCEPTION_MAXIMUM_PARAMETERS 4
+;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
+;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
+;struct _EXCEPTION_RECORD{
+; NTSTATUS ExceptionCode;
+; ULONG ExceptionFlags;
+; struct _EXCEPTION_RECORD *ExceptionRecord;
+; PVOID ExceptionAddress;
+; ULONG NumberParameters;
+; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+;};
+_EXCEPTION_RECORD struc
+ exception_number dd ?
+ exception_flags dd ?
+ exception_record dd ?
+ exception_address dd ?
+ number_parameters dd ?
+ exception_information dd 4 dup(?)
+_EXCEPTION_RECORD ends
+SIZEOF_EXCEPTION_RECORD equ 36
+
+;/* following is the structure returned by the _exception_info() intrinsic. */
+;typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS;
+;typedef struct EXCEPTION_POINTERS *PEXCEPTION_POINTERS;
+;struct _EXCEPTION_POINTERS{
+; PEXCEPTION_RECORD ExceptionRecord;
+; PCONTEXT Context;
+;};
+_EXCEPTION_POINTERS struc
+ ep_xrecord dd ?
+ ep_context dd ?
+_EXCEPTION_POINTERS ends
+SIZEOF_EXCEPTION_POINTERS equ 8
+
+assumes DS,DATA
+assumes FS,DATA
+
+__except_list equ 0
+
+;struct _SCOPETABLE_ENTRY{
+; int enclosing_level; /* lexical level of enclosing scope */
+; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */
+; void (*specific_handler)(void); /* xcpt or termination handler */
+;};
+;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS];
+_SCOPETABLE_ENTRY struc
+ enclosing_level dd ?
+ filter dd ?
+ specific_handler dd ?
+_SCOPETABLE_ENTRY ends
+
+BeginCODE
+if @Version LT 600
+ifdef _WIN32_OR_POSIX_
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+else
+assumes CS,CODE
+endif
+endif
+
+;/* _EXCEPT_HANDLER3 - Try to find an exception handler listed in the scope
+; * table associated with the given registration record, that wants to accept
+; * the current exception. If we find one, run it (and never return).
+; * RETURNS: (*if* it returns)
+; * DISPOSITION_DISMISS - dismiss the exception.
+; * DISPOSITION_CONTINUE_SEARCH - pass the exception up to enclosing handlers
+; */
+;int _except_handler3(
+; PEXCEPTION_RECORD exception_record,
+; PEXCEPTION_REGISTRATION registration,
+; PCONTEXT context,
+; PEXCEPTION_REGISTRATION dispatcher)
+;{
+; int ix, filter_result;
+;
+; for(ix=registration->trylevel; ix!=-1; ix=registration->xscope[ix].enclosing_level){
+; /* if filter==NULL, then this is an entry for a termination handler */
+; if(registration->xscope[ix].filter){
+; /* NB: call to the filter may trash the callee save
+; registers. (this is *not* a standard cdecl function) */
+; filter_result=(*registration->xscope[ix].filter)(xinfo);
+; if(filter_result==FILTER_DISMISS)
+; return(-1); /* dismiss */
+; if(filter_result==FILTER_ACCEPT){
+; _global_unwind2(registration);
+; _local_unwind2(registration, ix);
+; (*registration->xscope[ix].specific_handler)(void);
+; assert(UNREACHED); /*should never return from handler*/
+; }
+; assert(filter_result==FILTER_CONTINUE_SEARCH);
+; }
+; }
+; return(0); /* didnt find one */
+;}
+ db 'VC20' ;; VC/C++ 2.0/32-bit (C9.0) version
+ db 'XC00' ;; so debugger can recognize this proc (cuda:3936)
+cProc _except_handler3,<C,PUBLIC>,<IBX,ISI,IDI,IBP>
+ parmDP xrecord
+ parmDP registration
+ parmDP context
+ parmDP dispatcher
+ localV xp,SIZEOF_EXCEPTION_POINTERS
+cBegin
+ ;4*4b for callee saves + 4b return address + 4b param = 24
+
+ ;DF in indeterminate state at time of exception, so clear it
+ cld
+
+ mov ebx, registration ;ebx= PEXCEPTION_REGISTRATION
+ mov eax, xrecord
+
+ test [eax.exception_flags], EXCEPTION_UNWIND_CONTEXT
+ jnz short _lh_unwinding
+
+ ;build the EXCEPTION_POINTERS locally store its address in the
+ ; registration record. this is the pointer that is returned by
+ ; the _eception_info intrinsic.
+ mov xp.ep_xrecord, eax
+ mov eax, context
+ mov xp.ep_context, eax
+ lea eax, xp
+ mov [ebx.xpointers], eax
+
+ mov esi, [ebx.trylevel] ;esi= try level
+ mov edi, [ebx.scopetable] ;edi= scope table base
+_lh_top:
+ cmp esi, -1
+ je short _lh_bagit
+ lea ecx, [esi+esi*2] ;ecx= trylevel*3
+ cmp dword ptr [(edi+ecx*4).filter], 0
+ je short _lh_continue ;term handler, so keep looking
+
+ ;filter may trash *all* registers, so save ebp and scopetable offset
+ push esi
+ push ebp
+
+ lea ebp, FRAME_EBP_OFFSET[ebx]
+ call [(edi+ecx*4).filter] ;call the filter
+
+ pop ebp
+ pop esi
+ ;ebx may have been trashed by the filter, so we must reload
+ mov ebx, registration
+
+ ; Accept <0, 0, >0 instead of just -1, 0, +1
+ or eax, eax
+ jz short _lh_continue
+ js short _lh_dismiss
+ ;assert(eax==FILTER_ACCEPT)
+
+ ;reload xscope base, cuz it was trashed by the filter call
+ mov edi, [ebx.scopetable]
+ ;load handler address before we loose components of address mode
+ push ebx ;registration*
+ call __global_unwind2 ;run term handlers
+ add esp, 4
+
+ ;setup ebp for the local unwinder and the specific handler
+ lea ebp, FRAME_EBP_OFFSET[ebx]
+
+ ;the stop try level == accepting except level
+ push esi ;stop try level
+ push ebx ;registration*
+ call __local_unwind2
+ add esp, 8
+
+ lea ecx, [esi+esi*2] ;ecx=trylevel*3
+; set the current trylevel to our enclosing level immediately
+; before giving control to the handler. it is the enclosing
+; level, if any, that guards the handler.
+ mov eax, [(edi+ecx*4).enclosing_level]
+ mov [ebx.trylevel], eax
+ call [(edi+ecx*4).specific_handler] ;call the except handler
+ ;assert(0) ;(NB! should not return)
+
+_lh_continue:
+ ;reload the scope table base, possibly trashed by call to filter
+ mov edi, [ebx.scopetable]
+ lea ecx, [esi+esi*2]
+ mov esi, [edi+ecx*4+0] ;load the enclosing trylevel
+ jmp short _lh_top
+
+_lh_dismiss:
+ mov eax, DISPOSITION_DISMISS ;dismiss the exception
+ jmp short _lh_return
+
+_lh_bagit:
+ mov eax, DISPOSITION_CONTINUE_SEARCH
+ jmp short _lh_return
+
+_lh_unwinding:
+ push ebp
+ lea ebp, FRAME_EBP_OFFSET[ebx]
+ push -1
+ push ebx
+ call __local_unwind2
+ add esp, 8
+ pop ebp
+ ;the return value is not really relevent in an unwind context
+ mov eax, DISPOSITION_CONTINUE_SEARCH
+
+_lh_return:
+cEnd
+
+public __seh_longjmp_unwind@4
+__seh_longjmp_unwind@4 proc near
+ push ebp
+ mov ecx, 8[esp]
+ mov ebp, [ecx.saved_ebp]
+ mov eax, [ecx.saved_trylevel]
+ push eax
+ mov eax, [ecx.saved_xregistration]
+ push eax
+ call __local_unwind2
+ add esp, 8
+ pop ebp
+ ret 4
+__seh_longjmp_unwind@4 endp
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/longjmp.asm b/private/crt32/misc/i386/longjmp.asm
new file mode 100644
index 000000000..ae236afff
--- /dev/null
+++ b/private/crt32/misc/i386/longjmp.asm
@@ -0,0 +1,150 @@
+;***
+;longjmp.asm
+;
+; Copyright (C) 1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Contains setjmp(), longjmp() & raisex() routines;
+; split from exsup.asm for granularity purposes.
+;
+;Notes:
+;
+;Revision History:
+; 01-12-94 PML Split from setjmp.asm, added C9.0 generic EH
+; callback for unwind.
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+BeginDATA
+
+COMM __setjmpexused:dword
+
+EndDATA
+
+assumes DS,DATA
+assumes FS,DATA
+
+BeginCODE
+if @Version LT 600
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+endif
+
+; Following symbols defined in exsup.asm, sehsupp.c
+extrn __except_list:near
+extrn __global_unwind2:near
+extrn __local_unwind2:near
+extrn __rt_probe_read4@4:near
+
+; int
+; longjmp (
+; IN jmp_buf env
+; IN int val)
+;
+; Routine Description:
+;
+; Restore the stack and register environment saved by _setjmp.
+; Reloads callee-save registers and stack pointer to that saved in
+; the jmp_buf, then returns to the point of the _setjmp call.
+;
+; If exception unwinding is enabled, also reload the exception state
+; from the jmp_buf by doing an unwind (both global and local) back
+; to the old state. Do so by checking for a new-format (C9.0)
+; jmp_buf, and call the EH longjmp unwinder saved therein if
+; found, else assume a C8.0-vintage jmp_buf and SEH.
+;
+; Arguments:
+;
+; env - Address of the buffer holding the reload state
+; val - Value to return from the _setjmp callsite (if nonzero)
+;
+; Return Value:
+;
+; None. longjmp does not return directly, but instead continues
+; execution from the point of the _setjmp used to initialize the
+; jmp_buf. That call will return the 'val' parameter if nonzero,
+; else a one.
+
+cProc longjmp,<C,PUBLIC>
+cBegin
+ mov ebx, [esp+4] ;get jmp_buf
+
+ ;restore ebp before possible call to local_unwind-er
+ ; the call to global/local unwind will preserve this (callee save).
+ mov ebp, [ebx.saved_ebp] ;set up bp
+ifdef _NTSDK
+ cmp __setjmpexused, 0
+ je short _lj_no_unwind
+endif
+ mov esi, [ebx.saved_xregistration]
+ cmp esi, dword ptr fs:__except_list
+ je short _lj_local_unwind
+
+ push esi
+ call __global_unwind2
+ add esp,4
+
+_lj_local_unwind:
+ cmp esi, 0
+ je short _lj_no_unwind
+
+ ; Check if called with old or new format jmp_buf. Look for the
+ ; version cookie that's only present in the new format.
+ lea eax, [ebx.version_cookie]
+ push eax
+ call __rt_probe_read4@4
+ or eax, eax
+ jz short _lj_old_unwind
+ mov eax, [ebx.version_cookie]
+ cmp eax, JMPBUF_COOKIE
+ jnz short _lj_old_unwind
+
+ ; Called with a new-format jmp_buf. Call unwind function supplied
+ ; to the jmp_buf at setjmp time.
+ mov eax, [ebx.unwind_func]
+ or eax, eax
+ jz short _lj_no_unwind ;no local unwind necessary
+ push ebx
+ call eax
+ jmp short _lj_no_unwind
+
+ ; Called with an old-format jmp_buf. Duplicate old longjmp behavior,
+ ; assuming there's a C8.0 SEH node at top.
+_lj_old_unwind:
+ mov eax, [ebx.saved_trylevel]
+ push eax
+ push esi
+ call __local_unwind2
+ add esp, 8
+
+_lj_no_unwind:
+ mov edx, ebx
+ mov ebx, [edx.saved_ebx] ;recover registers...
+ mov edi, [edx.saved_edi]
+ mov esi, [edx.saved_esi]
+
+ mov eax, [esp+8] ;load the return value
+ cmp eax, 1 ;make sure it's not 0
+ adc eax, 0
+
+ mov esp, [edx.saved_esp] ;here, sp gets scorched
+ add esp, 4 ;punt the (old) return address
+ jmp [edx.saved_return] ;return
+cEnd
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/sehsupp.c b/private/crt32/misc/i386/sehsupp.c
new file mode 100644
index 000000000..1dbce51bb
--- /dev/null
+++ b/private/crt32/misc/i386/sehsupp.c
@@ -0,0 +1,59 @@
+/***
+*sehsupp.c - helper functions for Structured Exception Handling support
+*
+* Copyright (C) 1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains _rt_probe_read. Helper for the SEH runtime support
+* routines (longjmp in particular). Much of the SEH code is written
+* in asm, so these routines are available when probing memory in ways
+* that must be guarded with __try/__except in case of access violation.
+*
+*Revision History:
+* 12-05-93 PML Module created.
+* 12-22-93 GJF Made #define WIN32_LEAN_AND_MEAN conditional.
+* 01-12-94 PML Rewritten - still need helpers, just different ones
+*
+*******************************************************************************/
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+
+#include <windows.h>
+
+/***
+*BOOL __stdcall _rt_probe_read4 - Check if a DWORD is readable
+*
+*Purpose:
+* Internal support function called by longjmp. Check if a DWORD is
+* readable under a __try/__except.
+*
+*Entry:
+* DWORD * p - Pointer to DWORD to be probed
+*
+*Exit:
+* Success: TRUE - Able to read
+* Failure: FALSE - Access violation while reading
+*
+******************************************************************************/
+
+BOOL __stdcall _rt_probe_read4(
+ DWORD * ptr)
+{
+ BOOL readable;
+
+ __try
+ {
+ *(volatile DWORD *)ptr;
+ readable = TRUE;
+ }
+ __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH)
+ {
+ readable = FALSE;
+ }
+
+ return readable;
+}
diff --git a/private/crt32/misc/i386/setjmp.asm b/private/crt32/misc/i386/setjmp.asm
new file mode 100644
index 000000000..f4015572e
--- /dev/null
+++ b/private/crt32/misc/i386/setjmp.asm
@@ -0,0 +1,151 @@
+;***
+;setjmp.asm
+;
+; Copyright (C) 1993 - 1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Contains setjmp() & raisex() routines;
+; split from exsup.asm for granularity purposes.
+;
+;Notes:
+;
+;Revision History:
+; 04-13-93 JWM Module created.
+; 10-14-93 GJF Merged in NT verson.
+; 01-12-94 PML Added C9.0 generic EH callback for unwind. Split
+; into setjmp.asm, setjmp3.asm, and longjmp.asm.
+; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not
+; 0.
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+assumes DS,DATA
+assumes FS,DATA
+
+BeginCODE
+if @Version LT 600
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+endif
+
+; Following symbol defined in exsup.asm
+extrn __except_list:near
+
+; int
+; _setjmp (
+; OUT jmp_buf env)
+;
+; Routine Description:
+;
+; (Old) implementation of setjmp intrinsic. Saves the current
+; nonvolatile register state in the specified jump buffer and returns
+; a function value of zero.
+;
+; Saves the callee-save registers, stack pointer and return address.
+; Also saves the exception registration list head.
+;
+; This code is only present for old apps that link to the DLL runtimes,
+; or old object files compiles with C8.0. It intentionally duplicates
+; the old setjmp bugs, blindly assuming that the topmost EH node is a
+; C8.0 SEH node.
+;
+; Arguments:
+;
+; env - Address of the buffer for storing the state information
+;
+; Return Value:
+;
+; A value of zero is returned.
+
+public __setjmp
+__setjmp PROC NEAR
+ mov edx, [esp+4]
+ mov [edx.saved_ebp], ebp ; old bp and the rest
+ mov [edx.saved_ebx], ebx
+ mov [edx.saved_edi], edi
+ mov [edx.saved_esi], esi
+ mov [edx.saved_esp], esp
+
+ mov eax, [esp] ; return address
+ mov [edx.saved_return], eax
+
+ mov eax, dword ptr fs:__except_list
+ mov [edx.saved_xregistration], eax
+
+ cmp eax, -1 ; -1 means no higher-level handler
+ jnz short _sj_save_trylevel
+ mov dword ptr [edx.saved_trylevel], -1 ;something invalid
+ jmp short _sj_done
+
+_sj_save_trylevel:
+ mov eax, [eax + C8_TRYLEVEL]
+ mov [edx.saved_trylevel], eax
+
+_sj_done:
+ sub eax, eax
+ ret
+__setjmp ENDP
+
+; void
+; raisex (
+; IN PEXCEPTION_RECORD pxr)
+;
+; Routine Description:
+;
+; Unknown. This seems to duplicate the RaiseException API (sort of),
+; but I'm not sure what it's doing here. It's not documented, but
+; it's in the reserved ANSI namespace. Here it stays, in case someone
+; really counts on it.
+;
+; Arguments:
+;
+; pxr - Pointer to EXCEPTION_RECORD buffer
+;
+; Return Value:
+;
+; None.
+
+cProc raisex,<C,PUBLIC>
+ parmDP pxr
+cBegin
+ pushfd
+ pushad
+
+ mov esi, dword ptr pxr
+ mov ebx, dword ptr fs:__except_list
+_r_top:
+ or ebx, ebx
+ je short _r_error
+ push ebx ;pass address of the registration record
+ push esi ;pass the exception record
+ call [ebx.handler] ;execute language handler for this proc
+ add esp, 8
+ cmp eax, DISPOSITION_DISMISS
+ je short _r_dismiss
+ cmp eax, DISPOSITION_CONTINUE_SEARCH
+ jne short _r_error
+ mov ebx, [ebx.prev]
+ jmp short _r_top
+_r_error:
+ ;assert(UNREACHED); exit(-1);
+_r_dismiss:
+ popad
+ popfd
+cEnd
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/setjmp3.asm b/private/crt32/misc/i386/setjmp3.asm
new file mode 100644
index 000000000..9c03e9a8c
--- /dev/null
+++ b/private/crt32/misc/i386/setjmp3.asm
@@ -0,0 +1,148 @@
+;***
+;setjmp3.asm
+;
+; Copyright (C) 1994 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Contains setjmp(), longjmp() & raisex() routines;
+; split from exsup.asm for granularity purposes.
+;
+;Notes:
+;
+;Revision History:
+; 01-12-94 PML Split from setjmp.asm, added C9.0 generic EH
+; callback for unwind.
+; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not
+; 0.
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+include exsup.inc
+.list
+
+assumes DS,DATA
+assumes FS,DATA
+
+BeginCODE
+if @Version LT 600
+;this needs to go here to work around a masm5 bug. (emits wrong fixup)
+assumes CS,FLAT
+endif
+
+; Following symbol defined in exsup.asm
+extrn __except_list:near
+
+; int
+; _setjmp3 (
+; OUT jmp_buf env,
+; int count,
+; ...)
+;
+; Routine Description:
+;
+; (New) implementation of setjmp intrinsic. Saves the current
+; nonvolatile register state in the specified jump buffer and returns
+; a function value of zero.
+;
+; Saves the callee-save registers, stack pointer and return address.
+; Also saves the exception registration list head. If setjmp is
+; called from a function using any form of exception handling, then
+; additional data is also saved allowing some form of local unwind
+; at longjmp time to restore the proper exception handling state.
+;
+; Arguments:
+;
+; env - Address of the buffer for storing the state information
+; count - count of additional DWORDs of information. Zero if setjmp
+; not called from a function with any form of EH.
+; ... Additional data pushed by the setjmp intrinsic if called
+; from a function with any form of EH. The first DWORD is
+; a function ptr which will be called at longjmp time to do
+; the local unwind. The second DWORD is the try level to be
+; restored (if applicable). Any further data is saved in the
+; generic data array in the jmp_buf for use by the local
+; unwind function.
+;
+; Return Value:
+;
+; A value of zero is returned.
+
+public __setjmp3
+__setjmp3 PROC NEAR
+ mov edx, [esp+4]
+ mov [edx.saved_ebp], ebp ; old bp and the rest
+ mov [edx.saved_ebx], ebx
+ mov [edx.saved_edi], edi
+ mov [edx.saved_esi], esi
+ mov [edx.saved_esp], esp
+
+ mov eax, [esp] ; return address
+ mov [edx.saved_return], eax
+
+ mov dword ptr [edx.version_cookie], JMPBUF_COOKIE
+ mov dword ptr [edx.unwind_func], 0
+
+ mov eax, dword ptr fs:__except_list
+ mov [edx.saved_xregistration], eax
+
+ cmp eax, -1 ; -1 means no higher-level handler
+ jnz short _s3_get_count
+ mov dword ptr [edx.saved_trylevel], -1 ;something invalid
+ jmp short _s3_done
+
+_s3_get_count:
+ mov ecx, [esp+8] ; count of additional data
+ or ecx, ecx
+ jz short _s3_default_trylevel
+
+ mov eax, [esp+12] ; func to do local unwind at longjmp
+ mov [edx.unwind_func], eax
+ dec ecx
+ jnz _s3_save_trylevel
+
+ ; Not called from a function with any form of EH, or no trylevel
+ ; passed. Save the TryLevel from the topmost EH node anyway,
+ ; assuming a C8.0 SEH node. If we're linked to an obsolete CRTDLL
+ ; and call the old longjmp, then we'll still do the right thing.
+_s3_default_trylevel:
+ mov eax, [eax + C8_TRYLEVEL]
+ mov [edx.saved_trylevel], eax
+ jmp short _s3_done
+
+_s3_save_trylevel:
+ mov eax, [esp+16] ; try level to unwind to
+ mov [edx.saved_trylevel], eax
+ dec ecx
+ jz short _s3_done
+
+ push esi
+ push edi
+ lea esi, [esp+20+8]
+ lea edi, [edx.unwind_data]
+ cmp ecx, 6 ; save up to 6 more DWORDs in jmp_buf
+ jbe _s3_save_data
+ mov ecx, 6
+
+_s3_save_data:
+ rep movsd
+ pop edi
+ pop esi
+
+_s3_done:
+ sub eax, eax
+ ret
+__setjmp3 ENDP
+
+EndCODE
+END
diff --git a/private/crt32/misc/i386/setjmpex.asm b/private/crt32/misc/i386/setjmpex.asm
new file mode 100644
index 000000000..dfe444b7c
--- /dev/null
+++ b/private/crt32/misc/i386/setjmpex.asm
@@ -0,0 +1,55 @@
+;***
+;setjmpex.asm
+;
+; Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Contains setjmpex().
+;
+;Notes:
+;
+;Revision History:
+; 10-14-93 GJF Grabbed from NT SDK tree, cleaned up a bit and this
+; header was added.
+; 01-13-94 PML Trigger off __longjmpex instead of __setjmpex, since
+; _setjmp is an intrinsic, but longjmp isn't.
+;
+;*******************************************************************************
+
+;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this;
+
+;Define small32 and flat32 since these are not defined in the NT build process
+small32 equ 1
+flat32 equ 1
+
+.xlist
+include pversion.inc
+?DFDATA = 1
+?NODATA = 1
+include cmacros.mas
+.list
+
+
+extrn _longjmp:near
+
+;
+; If setjmpex is included then set __setjmpexused = 1.
+;
+
+BeginDATA
+ public __setjmpexused
+__setjmpexused dd 1
+EndDATA
+
+BeginCODE
+if @Version LT 600
+assumes CS,FLAT
+endif
+
+public __longjmpex
+__longjmpex PROC NEAR
+ jmp _longjmp
+__longjmpex ENDP
+
+EndCODE
+END
diff --git a/private/crt32/misc/initcoll.c b/private/crt32/misc/initcoll.c
new file mode 100644
index 000000000..d2e2985a7
--- /dev/null
+++ b/private/crt32/misc/initcoll.c
@@ -0,0 +1,51 @@
+/***
+*initcoll.c - contains _init_collate
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the locale-category initialization function: _init_collate().
+*
+* Each initialization function sets up locale-specific information
+* for their category, for use by functions which are affected by
+* their locale category.
+*
+* *** For internal use by setlocale() only ***
+*
+*Revision History:
+* 12-08-91 ETC Created.
+* 12-20-91 ETC Minor beautification for consistency.
+* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+*
+*******************************************************************************/
+
+#ifdef _INTL
+#include <windows.h>
+#include <locale.h>
+#include <setlocal.h>
+
+/***
+*int _init_collate() - initialization for LC_COLLATE locale category.
+*
+*Purpose:
+* The LC_COLLATE category currently requires no initialization.
+*
+*Entry:
+* None.
+*
+*Exit:
+* 0 success
+* 1 fail
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI3 _init_collate (
+ void
+ )
+{
+ return 0;
+}
+#endif /* _INTL */
diff --git a/private/crt32/misc/initctyp.c b/private/crt32/misc/initctyp.c
new file mode 100644
index 000000000..02382a1b2
--- /dev/null
+++ b/private/crt32/misc/initctyp.c
@@ -0,0 +1,212 @@
+/***
+*initctyp.c - contains _init_ctype
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the locale-category initialization function: _init_ctype().
+*
+* Each initialization function sets up locale-specific information
+* for their category, for use by functions which are affected by
+* their locale category.
+*
+* *** For internal use by setlocale() only ***
+*
+*Revision History:
+* 12-08-91 ETC Created.
+* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo.
+* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
+* 01-19-03 CFW Move to _NEWCTYPETABLE, remove switch.
+* 02-08-93 CFW Bug fixes under _INTL switch.
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+* 06-11-93 CFW Now inithelp takes void *.
+*
+*******************************************************************************/
+
+#ifdef _INTL
+
+#include <stdlib.h>
+#include <windows.h>
+#include <locale.h>
+#include <setlocal.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <limits.h>
+
+#define _CTABSIZE 257 /* size of ctype tables */
+
+/***
+*int _init_ctype() - initialization for LC_CTYPE locale category.
+*
+*Purpose:
+* In non-C locales, preread ctype tables for chars and wide-chars.
+* Old tables are freed when new tables are fully established, else
+* the old tables remain intact (as if original state unaltered).
+* The leadbyte table is implemented as the high bit in ctype1.
+*
+* In the C locale, ctype tables are freed, and pointers point to
+* the static ctype table.
+*
+* Tables contain 257 entries: -1 to 256.
+* Table pointers point to entry 0 (to allow index -1).
+*
+*Entry:
+* None.
+*
+*Exit:
+* 0 success
+* 1 fail
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI3 _init_ctype (
+ void
+ )
+{
+#if defined _POSIX_
+ return 0;
+
+#else /* _POSIX_ */
+ /* non-C locale table for char's */
+ static unsigned short *ctype1 = NULL; /* keep around until next time */
+ unsigned short *newctype1; /* temp new table */
+
+ /* non-C locale table for wchar_t's */
+ static unsigned short *wctype1 = NULL; /* keep around until next time */
+ unsigned short *newwctype1; /* temp new table */
+
+ int size; // char buffer sizes
+ int wcsize; // wide char buffer sizes
+ unsigned char *cbuffer = NULL; // char working buffer
+ wchar_t *wbuffer = NULL; // wchar_t working buffer
+
+ int i; // general purpose counter
+ unsigned char *cp; // char pointer
+ wchar_t *wcp; // wide char pointer
+ CPINFO CPInfo; // struct for use with GetCPInfo
+
+ /* allocate and set up buffers before destroying old ones */
+ /* codepage will be restored by setlocale if error */
+
+ if (_lc_handle[LC_CTYPE] != _CLOCALEHANDLE)
+ {
+ if (_lc_codepage == 0)
+ { /* code page was not specified */
+ if (_getlocaleinfo(LC_INT_TYPE, MAKELCID(_lc_id[LC_CTYPE].wLanguage, SORT_DEFAULT),
+ LOCALE_IDEFAULTCODEPAGE,
+ (void *)&_lc_codepage) == -1)
+ goto error_cleanup;
+ }
+
+ /* allocate new buffers for tables */
+ newctype1 = (unsigned short *) malloc
+ (_CTABSIZE * sizeof(unsigned short));
+ newwctype1 = (unsigned short *) malloc
+ (_CTABSIZE * sizeof(unsigned short));
+ cbuffer = (unsigned char *) malloc (_CTABSIZE * sizeof(char));
+ wbuffer = (wchar_t *) malloc (_CTABSIZE * sizeof(wchar_t));
+
+ if (!newctype1 || !newwctype1 || !cbuffer || !wbuffer)
+ goto error_cleanup;
+
+ /* construct string composed of first 256 chars in sequence */
+ for (cp=cbuffer, i=0; i<_CTABSIZE-1; i++)
+ *cp++ = (unsigned char)i;
+
+ if (GetCPInfo( _lc_codepage, &CPInfo) == FALSE)
+ goto error_cleanup;
+
+ if (CPInfo.MaxCharSize > MB_LEN_MAX)
+ goto error_cleanup;
+
+ __mb_cur_max = (unsigned short) CPInfo.MaxCharSize;
+
+ /* zero out leadbytes so MBtoWC doesn't interpret as multi-byte chars */
+ if (__mb_cur_max > 1)
+ {
+ for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2)
+ {
+ for (i = cp[0]; i <= cp[1]; i++)
+ cbuffer[i] = 0;
+ }
+ }
+
+ /* convert to wide character string */
+ size = (_CTABSIZE-1) * sizeof(char);
+ wcsize = (_CTABSIZE-1) * sizeof(wchar_t);
+ if (MultiByteToWideChar (_lc_codepage, 0, (char *)cbuffer, size,
+ wbuffer, wcsize) == 0)
+ goto error_cleanup;
+
+ /* convert to newctype1 table */
+ if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newctype1+1)
+ == FALSE)
+ goto error_cleanup;
+ *newctype1 = 0; /* entry for EOF */
+
+ /* construct wide char string composed of first 256 chars in sequence */
+ for (wcp=wbuffer, i=0; i<_CTABSIZE-1; i++)
+ *wcp++ = (wchar_t)i;
+
+ /* convert to newctype1 table */
+ if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newwctype1+1)
+ == FALSE)
+ goto error_cleanup;
+ *newwctype1 = 0; /* entry for EOF */
+
+ /* ignore DefaultChar */
+
+ /* mark lead-byte entries in newctype1 table */
+ if (__mb_cur_max > 1)
+ {
+ for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2)
+ {
+ for (i = cp[0]; i <= cp[1]; i++)
+ newctype1[i+1] = _LEADBYTE;
+ }
+ }
+
+ /* set pointers to point to entry 0 of tables */
+ _pctype = newctype1 + 1;
+ _pwctype = newwctype1 + 1;
+
+ /* free old tables */
+ if (ctype1)
+ free (ctype1);
+ ctype1 = newctype1;
+
+ if (wctype1)
+ free (wctype1);
+ wctype1 = newwctype1;
+
+ /* cleanup and return success */
+ free (cbuffer);
+ free (wbuffer);
+ return 0;
+
+error_cleanup:
+ free (newctype1);
+ free (newwctype1);
+ free (cbuffer);
+ free (wbuffer);
+ return 1;
+
+ } else {
+
+ /* set pointers to static C-locale table */
+ _pctype = _ctype + 1;
+ _pwctype = _ctype + 1;
+
+ /* free dynamic locale-specific tables */
+ free (ctype1);
+ free (wctype1);
+ ctype1 = NULL;
+ wctype1 = NULL;
+
+ return 0;
+ }
+#endif /* _POSIX_ */
+}
+#endif /* _INTL */
diff --git a/private/crt32/misc/inithelp.c b/private/crt32/misc/inithelp.c
new file mode 100644
index 000000000..a372b595a
--- /dev/null
+++ b/private/crt32/misc/inithelp.c
@@ -0,0 +1,143 @@
+/***
+*inithelp.c - Contains the _getlocaleinfo helper routine
+*
+* Copyright (c) 1992-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the _getlocaleinfo helper routine.
+*
+*Revision History:
+* 12-28-92 CFW Module created, _getlocaleinfo ported to Cuda tree.
+* 12-29-92 CFW Update for new GetLocaleInfoW, add LC_*_TYPE handling.
+* 01-25-93 KRS Change category argument to LCID.
+* 02-02-93 CFW Optimized INT case, bug fix in STR case.
+* 02-08-93 CFW Optimized GetQualifiedLocale call, cast to remove warnings.
+* 04-22-93 CFW Fixed cast bug.
+* 06-11-93 CFW Now inithelp takes void *, use wcstod().
+*
+*******************************************************************************/
+
+#ifdef _INTL
+
+#include <stdlib.h>
+#include <cruntime.h>
+#include <locale.h>
+#include <setlocal.h>
+
+/***
+*_getlocaleinfo - return locale data
+*
+*Purpose:
+* Return locale data appropriate for the setlocale init functions.
+* In particular, wide locale strings are converted to char strings
+* or numeric depending on the value of the first parameter.
+*
+* Memory is allocated for the char version of the data, and the
+* calling function's pointer is set to it. This pointer should later
+* be used to free the data. The wide-char data is fetched using
+* GetLocaleInfo and converted to multibyte using WideCharToMultiByte.
+*
+* *** For internal use by the _init_* functions only ***
+*
+* *** Future optimization ***
+* When converting a large number of wide-strings to multibyte, do
+* not query the size of the result, but convert them one after
+* another into a large character buffer. The entire buffer can
+* also be freed with one pointer.
+*
+*Entry:
+* int lc_type - LC_STR_TYPE for string data, LC_INT_TYPE for numeric data
+* LCID localehandle - LCID based on category and lang or ctry of _lc_id
+ LCTYPE fieldtype - int or string value
+*
+*Exit:
+* void *address - pointer to pointer to storage
+* 0 success
+* -1 failure
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#if NO_ERROR == -1
+#error Need to use another error return code in _getlocaleinfo
+#endif
+
+#define STR_CHAR_CNT 128
+#define INT_CHAR_CNT 4
+
+int _CRTAPI3 _getlocaleinfo (
+ int lc_type,
+ LCID localehandle,
+ LCTYPE fieldtype,
+ void *address
+ )
+{
+#if defined _POSIX_
+ return -1;
+#else /* _POSIX_ */
+ if (lc_type == LC_STR_TYPE)
+ {
+ char **straddress = (char **)address;
+
+ static wchar_t staticwcbuffer[STR_CHAR_CNT];
+ wchar_t *wcbuffer = staticwcbuffer;
+ int bufferused = 0; /* 1 indicates buffer points to malloc'ed memory */
+ int buffersize = STR_CHAR_CNT * sizeof(wchar_t);
+ int outsize;
+
+ if (GetLocaleInfoW (localehandle, fieldtype, wcbuffer, buffersize) == 0)
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto error;
+ /* buffersize too small, get required size and malloc new buffer */
+ if ((buffersize = GetLocaleInfoW (localehandle, fieldtype, NULL, 0))
+ == 0)
+ goto error;
+ if ((wcbuffer = (wchar_t *) malloc (buffersize)) == NULL)
+ goto error;
+ bufferused = 1;
+ if (GetLocaleInfoW (localehandle, fieldtype, wcbuffer, buffersize) == 0)
+ goto error;
+ }
+
+ if ((outsize = WideCharToMultiByte (_lc_codepage, 0, wcbuffer, -1,
+ NULL, 0, NULL, NULL)) == 0)
+ goto error;
+
+ if ((*straddress = (char *) malloc (outsize)) == NULL)
+ goto error;
+
+ if (WideCharToMultiByte (_lc_codepage, 0, wcbuffer, -1,
+ *straddress, outsize, NULL, NULL) == 0)
+ goto error;
+
+ if (bufferused)
+ free (wcbuffer);
+
+ return 0;
+
+error:
+ if (bufferused)
+ free (wcbuffer);
+ return -1;
+
+ } else if (lc_type == LC_INT_TYPE)
+ {
+ char *charaddress = (char *)address;
+ wchar_t wcbuffer[INT_CHAR_CNT];
+
+ if (GetLocaleInfoW (localehandle, fieldtype, (LPWSTR)wcbuffer, INT_CHAR_CNT) == 0)
+ return -1;
+
+ /* GetLocaleInfoW returns integer in wcstr format */
+
+ *(char *)charaddress = (char)wcstol(wcbuffer, NULL, 10);
+
+ return 0;
+ }
+ return -1;
+#endif /* _POSIX_ */
+}
+
+#endif /*_INTL*/
diff --git a/private/crt32/misc/initmon.c b/private/crt32/misc/initmon.c
new file mode 100644
index 000000000..c2b9cd3fe
--- /dev/null
+++ b/private/crt32/misc/initmon.c
@@ -0,0 +1,191 @@
+/***
+*initmon.c - contains _init_monetary
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the locale-category initialization function: _init_monetary().
+*
+* Each initialization function sets up locale-specific information
+* for their category, for use by functions which are affected by
+* their locale category.
+*
+* *** For internal use by setlocale() only ***
+*
+*Revision History:
+* 12-08-91 ETC Created.
+* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo.
+* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
+* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function.
+* 01-25-93 KRS Changed _getlocaleinfo interface again.
+* 02-08-93 CFW Added _lconv_static_*.
+* 02-17-93 CFW Removed debugging print statement.
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+* 06-11-93 CFW Now inithelp takes void *.
+*
+*******************************************************************************/
+
+#ifdef _INTL
+
+#include <stdlib.h>
+#include <windows.h>
+#include <locale.h>
+#include <setlocal.h>
+#include <malloc.h>
+#include <limits.h>
+
+static int _CRTAPI3 _get_lc_lconv(struct lconv *l);
+static void _CRTAPI3 _free_lc_lconv(struct lconv *l);
+
+/* Pointer to current lconv */
+extern struct lconv *_lconv;
+
+/* C locale lconv structure */
+extern struct lconv _lconv_c;
+
+/* Pointer to non-C locale lconv */
+static struct lconv *_lconv_intl = NULL;
+
+/*
+ * Note that _lconv_c is used when the monetary category is in the C locale
+ * but the numeric category may not necessarily be in the C locale.
+ */
+
+
+/***
+*int _init_monetary() - initialization for LC_MONETARY locale category.
+*
+*Purpose:
+* In non-C locales, read the localized monetary strings into
+* _lconv_intl, and also copy the numeric strings from _lconv into
+* _lconv_intl. Set _lconv to point to _lconv_intl. The old
+* _lconv_intl is not freed until the new one is fully established.
+*
+* In the C locale, the monetary fields in lconv are filled with
+* contain C locale values. Any allocated _lconv_intl fields are freed.
+*
+* At startup, _lconv points to a static lconv structure containing
+* C locale strings. This structure is never used again if
+* _init_monetary is called.
+*
+*Entry:
+* None.
+*
+*Exit:
+* 0 success
+* 1 fail
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI3 _init_monetary (
+ void
+ )
+{
+ struct lconv *lc;
+
+ if (_lc_handle[LC_MONETARY] != _CLOCALEHANDLE) {
+
+ /* Allocate structure filled with NULL pointers */
+ if ((lc = (struct lconv *)
+ calloc (1, sizeof(struct lconv))) == NULL)
+ return 1;
+
+ if (_get_lc_lconv (lc) == -1) {
+ _free_lc_lconv (lc);
+ free ((void *)lc);
+ return 1;
+ }
+
+ /* Copy numeric locale fields */
+ lc->decimal_point = _lconv->decimal_point;
+ lc->thousands_sep = _lconv->thousands_sep;
+ lc->grouping = _lconv->grouping;
+
+ _lconv = lc; /* point to new one */
+ _free_lc_lconv (_lconv_intl); /* free the old one */
+ free ((void *)_lconv_intl);
+ _lconv_intl = lc;
+ return 0;
+
+ } else {
+ /*
+ * Copy numeric locale fields (not necessarily C locale)
+ * to static structure. Note that _lconv_c numeric locale
+ * fields may contain non-C locale information, but
+ * monetary locale fields always contain C locale info.
+ */
+ _lconv_c.decimal_point = _lconv->decimal_point;
+ _lconv_c.thousands_sep = _lconv->thousands_sep;
+ _lconv_c.grouping = _lconv->grouping;
+
+ _lconv = &_lconv_c; /* point to new one */
+
+ _free_lc_lconv (_lconv_intl); /* free the old one */
+ free ((void *)_lconv_intl);
+ _lconv_intl = NULL;
+ return 0;
+ }
+}
+
+/*
+ * Get the lconv fields.
+ */
+static int _CRTAPI3 _get_lc_lconv (
+ struct lconv *l
+ )
+{
+ int ret = 0;
+
+ /* Currency is country--not language--dependent. NT work-around. */
+ LCID ctryid=MAKELCID(_lc_id[LC_MONETARY].wCountry, SORT_DEFAULT);
+
+ if (l == NULL)
+ return -1;
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SINTLSYMBOL, (void *)&l->int_curr_symbol);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SCURRENCY, (void *)&l->currency_symbol);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONDECIMALSEP, (void *)&l->mon_decimal_point);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONTHOUSANDSEP, (void *)&l->mon_thousands_sep);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONGROUPING, (void *)&l->mon_grouping);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SPOSITIVESIGN, (void *)&l->positive_sign);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SNEGATIVESIGN, (void *)&l->negative_sign);
+
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IINTLCURRDIGITS, (void *)&l->int_frac_digits);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ICURRDIGITS, (void *)&l->frac_digits);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSYMPRECEDES, (void *)&l->p_cs_precedes);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSEPBYSPACE, (void *)&l->p_sep_by_space);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSYMPRECEDES, (void *)&l->n_cs_precedes);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSEPBYSPACE, (void *)&l->n_sep_by_space);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSIGNPOSN, (void *)&l->p_sign_posn);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSIGNPOSN, (void *)&l->n_sign_posn);
+
+ return ret;
+}
+
+/*
+ * Free the lconv strings.
+ * Numeric values do not need to be freed.
+ */
+static void _CRTAPI3 _free_lc_lconv (
+ struct lconv *l
+ )
+{
+ if (l == NULL)
+ return;
+
+ if (l->int_curr_symbol != _lconv_static_null)
+ {
+ free (l->int_curr_symbol);
+ free (l->currency_symbol);
+ free (l->mon_decimal_point);
+ free (l->mon_thousands_sep);
+ free (l->mon_grouping);
+ free (l->positive_sign);
+ free (l->negative_sign);
+ }
+ /* Don't need to make these pointers NULL */
+}
+
+#endif /* _INTL */
diff --git a/private/crt32/misc/initnum.c b/private/crt32/misc/initnum.c
new file mode 100644
index 000000000..dea832aad
--- /dev/null
+++ b/private/crt32/misc/initnum.c
@@ -0,0 +1,129 @@
+/***
+*initnum.c - contains _init_numeric
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the locale-category initialization function: _init_numeric().
+*
+* Each initialization function sets up locale-specific information
+* for their category, for use by functions which are affected by
+* their locale category.
+*
+* *** For internal use by setlocale() only ***
+*
+*Revision History:
+* 12-08-91 ETC Created.
+* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo.
+* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
+* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function.
+* 01-25-93 KRS Change interface to _getlocaleinfo again.
+* 02-08-93 CFW Added _lconv_static_*.
+* 02-17-93 CFW Removed debugging print statement.
+* 03-17-93 CFW C locale thousands sep is "", not ",".
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+* 06-11-93 CFW Now inithelp takes void *.
+*
+*******************************************************************************/
+
+#ifdef _INTL
+
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <locale.h>
+#include <setlocal.h>
+#include <malloc.h>
+#include <assert.h>
+#include <nlsint.h>
+
+/* Pointer to current lconv */
+extern struct lconv *_lconv;
+
+/***
+*int _init_numeric() - initialization for LC_NUMERIC locale category.
+*
+*Purpose:
+*
+*Entry:
+* None.
+*
+*Exit:
+* 0 success
+* 1 fail
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI3 _init_numeric (
+ void
+ )
+{
+ static char *decimal_point = NULL;
+ static char *thousands_sep = NULL;
+ static char *grouping = NULL;
+ int ret = 0;
+
+ /* Numeric data is country--not language--dependent. NT work-around. */
+ LCID ctryid = MAKELCID(_lc_id[LC_NUMERIC].wCountry, SORT_DEFAULT);
+
+ if (_lc_handle[LC_NUMERIC] != _CLOCALEHANDLE)
+ {
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SDECIMAL, (void *)&decimal_point);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_STHOUSAND, (void *)&thousands_sep);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SGROUPING, (void *)&grouping);
+
+ if (ret == -1)
+ {
+ free (decimal_point);
+ free (thousands_sep);
+ free (grouping);
+ decimal_point = NULL;
+ thousands_sep = NULL;
+ grouping = NULL;
+ return -1;
+ }
+
+ if (_lconv->decimal_point != _lconv_static_decimal)
+ {
+ free(_lconv->decimal_point);
+ free(_lconv->thousands_sep);
+ free(_lconv->grouping);
+ }
+
+ _lconv->decimal_point = decimal_point;
+ _lconv->thousands_sep = thousands_sep;
+ _lconv->grouping = grouping;
+
+
+#ifdef _DEBUG
+ assert (strlen(_lconv->decimal_point) == 1);
+#endif
+ /* set global decimal point character */
+ *_decimal_point = *_lconv->decimal_point;
+ _decimal_point_length = 1;
+
+ return 0;
+
+ } else {
+ free (decimal_point);
+ free (thousands_sep);
+ free (grouping);
+ decimal_point = NULL;
+ thousands_sep = NULL;
+ grouping = NULL;
+
+ // strdup them so we can free them
+ _lconv->decimal_point = _strdup(".");
+ _lconv->thousands_sep = _strdup("");
+ _lconv->grouping = strdup("");
+
+ /* set global decimal point character */
+ *_decimal_point = *_lconv->decimal_point;
+ _decimal_point_length = 1;
+
+ return 0;
+ }
+}
+#endif /* _INTL */
diff --git a/private/crt32/misc/inittime.c b/private/crt32/misc/inittime.c
new file mode 100644
index 000000000..7ce1dd8e7
--- /dev/null
+++ b/private/crt32/misc/inittime.c
@@ -0,0 +1,301 @@
+/***
+*inittime.c - contains _init_time
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the locale-category initialization function: _init_time().
+*
+* Each initialization function sets up locale-specific information
+* for their category, for use by functions which are affected by
+* their locale category.
+*
+* *** For internal use by setlocale() only ***
+*
+*Revision History:
+* 12-08-91 ETC Created.
+* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo.
+* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
+* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function.
+* 01-25-93 KRS Adapted to use ctry or lang dependent data, as approp.
+* 02-08-93 CFW Casts to remove warnings.
+* 02-16-93 CFW Added support for date and time strings.
+* 03-09-93 CFW Use char* time_sep in storeTimeFmt.
+* 05-20-93 GJF Include windows.h, not individual win*.h files
+* 06-11-93 CFW Now inithelp takes void *.
+*
+*******************************************************************************/
+
+#ifdef _INTL
+
+#include <stdlib.h>
+#include <windows.h>
+#include <locale.h>
+#include <setlocal.h>
+#include <malloc.h>
+
+static int _CRTAPI3 _get_lc_time(struct _lc_time_data *lc_time);
+static void _CRTAPI3 _free_lc_time(struct _lc_time_data *lc_time);
+
+/* Pointer to current time strings */
+extern struct _lc_time_data *_lc_time_curr;
+
+/* C locale time strings */
+extern struct _lc_time_data _lc_time_c;
+
+/* Pointer to non-C locale time strings */
+struct _lc_time_data *_lc_time_intl = NULL;
+
+int storeTimeFmt(
+ int ctryid,
+ struct _lc_time_data *lc_time
+);
+
+/***
+*int _init_time() - initialization for LC_TIME locale category.
+*
+*Purpose:
+* In non-C locales, read the localized time/date strings into
+* _lc_time_intl, and set _lc_time_curr to point to it. The old
+* _lc_time_intl is not freed until the new one is fully established.
+*
+* In the C locale, _lc_time_curr is made to point to _lc_time_c.
+* Any allocated _lc_time_intl structures are freed.
+*
+*Entry:
+* None.
+*
+*Exit:
+* 0 success
+* 1 fail
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI3 _init_time (
+ void
+ )
+{
+ /* Temporary date/time strings */
+ struct _lc_time_data *lc_time;
+
+ if (_lc_handle[LC_TIME] != _CLOCALEHANDLE)
+ {
+ /* Allocate structure filled with NULL pointers */
+ if ((lc_time = (struct _lc_time_data *)
+ calloc (1, sizeof(struct _lc_time_data))) == NULL)
+ return 1;
+
+ if (_get_lc_time (lc_time))
+ {
+ _free_lc_time (lc_time);
+ free ((void *)lc_time);
+ return 1;
+ }
+
+ _lc_time_curr = lc_time; /* point to new one */
+ _free_lc_time (_lc_time_intl); /* free the old one */
+ free ((void *)_lc_time_intl);
+ _lc_time_intl = lc_time;
+ return 0;
+
+ } else {
+ _lc_time_curr = &_lc_time_c; /* point to new one */
+ _free_lc_time (_lc_time_intl); /* free the old one */
+ free ((void *)_lc_time_intl);
+ _lc_time_intl = NULL;
+ return 0;
+ }
+}
+
+/*
+ * Get the localized time strings.
+ * Of course, this can be beautified with some loops!
+ */
+static int _CRTAPI3 _get_lc_time (
+ struct _lc_time_data *lc_time
+ )
+{
+ int ret = 0;
+
+/* Some things are language-dependent and some are country-dependent.
+ This works around an NT limitation and lets us distinguish the two. */
+
+ LCID langid = MAKELCID(_lc_id[LC_TIME].wLanguage, SORT_DEFAULT);
+ LCID ctryid = MAKELCID(_lc_id[LC_TIME].wCountry, SORT_DEFAULT);
+
+ if (lc_time == NULL)
+ return -1;
+
+/* All the text-strings are Language-dependent: */
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME1, (void *)&lc_time->wday_abbr[1]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME2, (void *)&lc_time->wday_abbr[2]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME3, (void *)&lc_time->wday_abbr[3]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME4, (void *)&lc_time->wday_abbr[4]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME5, (void *)&lc_time->wday_abbr[5]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME6, (void *)&lc_time->wday_abbr[6]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME7, (void *)&lc_time->wday_abbr[0]);
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME1, (void *)&lc_time->wday[1]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME2, (void *)&lc_time->wday[2]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME3, (void *)&lc_time->wday[3]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME4, (void *)&lc_time->wday[4]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME5, (void *)&lc_time->wday[5]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME6, (void *)&lc_time->wday[6]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME7, (void *)&lc_time->wday[0]);
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME1, (void *)&lc_time->month_abbr[0]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME2, (void *)&lc_time->month_abbr[1]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME3, (void *)&lc_time->month_abbr[2]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME4, (void *)&lc_time->month_abbr[3]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME5, (void *)&lc_time->month_abbr[4]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME6, (void *)&lc_time->month_abbr[5]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME7, (void *)&lc_time->month_abbr[6]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME8, (void *)&lc_time->month_abbr[7]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME9, (void *)&lc_time->month_abbr[8]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME10, (void *)&lc_time->month_abbr[9]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME11, (void *)&lc_time->month_abbr[10]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME12, (void *)&lc_time->month_abbr[11]);
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME1, (void *)&lc_time->month[0]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME2, (void *)&lc_time->month[1]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME3, (void *)&lc_time->month[2]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME4, (void *)&lc_time->month[3]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME5, (void *)&lc_time->month[4]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME6, (void *)&lc_time->month[5]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME7, (void *)&lc_time->month[6]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME8, (void *)&lc_time->month[7]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME9, (void *)&lc_time->month[8]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME10, (void *)&lc_time->month[9]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME11, (void *)&lc_time->month[10]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME12, (void *)&lc_time->month[11]);
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_S1159, (void *)&lc_time->ampm[0]);
+ ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_S2359, (void *)&lc_time->ampm[1]);
+
+
+/* The following relate to time format and are Country-dependent: */
+
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SSHORTDATE, (void *)&lc_time->ww_sdatefmt);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SLONGDATE, (void *)&lc_time->ww_ldatefmt);
+
+/* NLS API dropped time format strings, we have to make up our own */
+ ret |= storeTimeFmt(ctryid, lc_time);
+
+ return ret;
+}
+
+/*
+ * Free the localized time strings.
+ * Of course, this can be beautified with some loops!
+ */
+static void _CRTAPI3 _free_lc_time (
+ struct _lc_time_data *lc_time
+ )
+{
+ if (lc_time == NULL)
+ return;
+
+ free ((void *)lc_time->wday_abbr[1]);
+ free ((void *)lc_time->wday_abbr[2]);
+ free ((void *)lc_time->wday_abbr[3]);
+ free ((void *)lc_time->wday_abbr[4]);
+ free ((void *)lc_time->wday_abbr[5]);
+ free ((void *)lc_time->wday_abbr[6]);
+ free ((void *)lc_time->wday_abbr[0]);
+
+ free ((void *)lc_time->wday[1]);
+ free ((void *)lc_time->wday[2]);
+ free ((void *)lc_time->wday[3]);
+ free ((void *)lc_time->wday[4]);
+ free ((void *)lc_time->wday[5]);
+ free ((void *)lc_time->wday[6]);
+ free ((void *)lc_time->wday[0]);
+
+ free ((void *)lc_time->month_abbr[0]);
+ free ((void *)lc_time->month_abbr[1]);
+ free ((void *)lc_time->month_abbr[2]);
+ free ((void *)lc_time->month_abbr[3]);
+ free ((void *)lc_time->month_abbr[4]);
+ free ((void *)lc_time->month_abbr[5]);
+ free ((void *)lc_time->month_abbr[6]);
+ free ((void *)lc_time->month_abbr[7]);
+ free ((void *)lc_time->month_abbr[8]);
+ free ((void *)lc_time->month_abbr[9]);
+ free ((void *)lc_time->month_abbr[10]);
+ free ((void *)lc_time->month_abbr[11]);
+
+ free ((void *)lc_time->month[0]);
+ free ((void *)lc_time->month[1]);
+ free ((void *)lc_time->month[2]);
+ free ((void *)lc_time->month[3]);
+ free ((void *)lc_time->month[4]);
+ free ((void *)lc_time->month[5]);
+ free ((void *)lc_time->month[6]);
+ free ((void *)lc_time->month[7]);
+ free ((void *)lc_time->month[8]);
+ free ((void *)lc_time->month[9]);
+ free ((void *)lc_time->month[10]);
+ free ((void *)lc_time->month[11]);
+
+ free ((void *)lc_time->ampm[0]);
+ free ((void *)lc_time->ampm[1]);
+
+ free ((void *)lc_time->ww_sdatefmt);
+ free ((void *)lc_time->ww_ldatefmt);
+ free ((void *)lc_time->ww_timefmt);
+/* Don't need to make these pointers NULL */
+}
+
+
+/* NLS API dropped time format strings, we have to make up our own */
+int storeTimeFmt(
+ int ctryid,
+ struct _lc_time_data *lc_time
+)
+{
+ int ret = 0;
+ char *pfmt, *psep;
+ char *time_sep;
+ unsigned clock24 = 0;
+ unsigned leadzero = 0;
+
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ITIME, (void *)&clock24);
+ ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ITLZERO, (void *)&leadzero);
+ ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_STIME, (void *)&time_sep);
+
+ if (ret)
+ return ret;
+
+ /* 13 = 6 chars for hhmmss + up to three for each separator + NULL */
+
+ pfmt = lc_time->ww_timefmt = (char *)malloc(13);
+
+ if (clock24)
+ {
+ *pfmt++ = 'H';
+ if (leadzero)
+ *pfmt++ = 'H';
+ }
+ else {
+ *pfmt++ = 'h';
+ if (leadzero)
+ *pfmt++ = 'h';
+ }
+ for(psep = time_sep; *psep; *pfmt++ = *psep++) ;
+ *pfmt++ = 'm';
+ if (leadzero)
+ *pfmt++ = 'm';
+ for(psep = time_sep; *psep; *pfmt++ = *psep++) ;
+ *pfmt++ = 's';
+ *pfmt++ = 's';
+ *pfmt = '\0';
+
+ free(time_sep);
+
+ return ret;
+}
+
+#endif /* _INTL */
diff --git a/private/crt32/misc/labs.c b/private/crt32/misc/labs.c
new file mode 100644
index 000000000..e26a75115
--- /dev/null
+++ b/private/crt32/misc/labs.c
@@ -0,0 +1,52 @@
+/***
+*labs.c - find absolute value of a long integer
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines labs() - find absolute value of a long integer.
+*
+*Revision History:
+* 03-15-84 RN initial version
+* 04-22-87 JMB added function pragma for conversion to C 5.0 compiler
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 10-04-90 GJF New-style function declarator.
+* 12-28-90 SRW Added _CRUISER_ conditional around function pragma
+* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too.
+* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+#pragma function(labs)
+#endif
+
+/***
+*long labs(lnumber) - find absolute value of long.
+*
+*Purpose:
+* Find the absolute value of a long integer (lnumber if lnumber >= 0),
+* -lnumber if lnumber < 0).
+*
+*Entry:
+* long lnumber - number to find absolute value of
+*
+*Exit:
+* returns the absolute value of lnumber
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+long _CALLTYPE1 labs (
+ long lnumber
+ )
+{
+ return( lnumber>=0L ? lnumber : -lnumber );
+}
diff --git a/private/crt32/misc/lconv.c b/private/crt32/misc/lconv.c
new file mode 100644
index 000000000..a7d18aac6
--- /dev/null
+++ b/private/crt32/misc/lconv.c
@@ -0,0 +1,86 @@
+/***
+*lconv.c - Contains the localeconv function
+*
+* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the localeconv() function.
+*
+*Revision History:
+* 03-21-89 JCR Module created.
+* 06-20-89 JCR Removed _LOAD_DGROUP code
+* 03-14-90 GJF Replaced _cdecl _LOAD_DS with _CALLTYPE1 and added
+* #include <cruntime.h>. Also, fixed the copyright.
+* 10-04-90 GJF New-style function declarator.
+* 10-04-91 ETC Changed _c_lconv to _lconv (locale support).
+* _lconv no longer static.
+* 12-20-91 ETC Changed _lconv to _lconv_c (C locale structure).
+* Created _lconv pointer to point to current lconv.
+* 02-08-93 CFW Added _lconv_static_*.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <limits.h>
+#include <locale.h>
+
+
+
+/* pointer to original static to avoid freeing */
+char _lconv_static_decimal[] = ".";
+char _lconv_static_null[] = "";
+
+/* lconv settings for "C" locale */
+struct lconv _lconv_c = {
+ _lconv_static_decimal, /* decimal_point */
+ _lconv_static_null, /* thousands_sep */
+ _lconv_static_null, /* grouping */
+ _lconv_static_null, /* int_curr_symbol */
+ _lconv_static_null, /* currency_symbol */
+ _lconv_static_null, /* mon_decimal_point */
+ _lconv_static_null, /* mon_thousands_sep */
+ _lconv_static_null, /* mon_grouping */
+ _lconv_static_null, /* positive_sign */
+ _lconv_static_null, /* negative_sign */
+ CHAR_MAX, /* int_frac_digits */
+ CHAR_MAX, /* frac_digits */
+ CHAR_MAX, /* p_cs_precedes */
+ CHAR_MAX, /* p_sep_by_space */
+ CHAR_MAX, /* n_cs_precedes */
+ CHAR_MAX, /* n_sep_by_space */
+ CHAR_MAX, /* p_sign_posn */
+ CHAR_MAX /* n_sign_posn */
+ };
+
+
+/* pointer to current lconv structure */
+
+struct lconv *_lconv = &_lconv_c;
+
+
+/***
+*struct lconv *localeconv(void) - Return the numeric formatting convention
+*
+*Purpose:
+* The localeconv() routine returns the numeric formatting conventions
+* for the current locale setting. [ANSI]
+*
+*Entry:
+* void
+*
+*Exit:
+* struct lconv * = pointer to struct indicating current numeric
+* formatting conventions.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+struct lconv * _CALLTYPE1 localeconv (
+ void
+ )
+{
+ /* the work is done by setlocale() */
+
+ return(_lconv);
+}
diff --git a/private/crt32/misc/ldiv.c b/private/crt32/misc/ldiv.c
new file mode 100644
index 000000000..05c92f2da
--- /dev/null
+++ b/private/crt32/misc/ldiv.c
@@ -0,0 +1,59 @@
+/***
+*ldiv.c - contains the ldiv routine
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Performs a signed divide on longs and returns quotient
+* and remainder.
+*
+*Revision History:
+* 06-02-89 PHG module created
+* 03-14-90 GJF Made calling type _CALLTYPE1 and added #include
+* <cruntime.h>. Also, fixed the copyright.
+* 10-04-90 GJF New-style function declarator.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+
+/***
+*ldiv_t div(long numer, long denom) - do signed divide
+*
+*Purpose:
+* This routine does an long divide and returns the results.
+* Since we don't know how the Intel 860 does division, we'd
+* better make sure that we have done it right.
+*
+*Entry:
+* long numer - Numerator passed in on stack
+* long denom - Denominator passed in on stack
+*
+*Exit:
+* returns quotient and remainder in structure
+*
+*Exceptions:
+* No validation is done on [denom]* thus, if [denom] is 0,
+* this routine will trap.
+*
+*******************************************************************************/
+
+ldiv_t _CALLTYPE1 ldiv (
+ long numer,
+ long denom
+ )
+{
+ ldiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ /* did division wrong; must fix up */
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
diff --git a/private/crt32/misc/lfind.c b/private/crt32/misc/lfind.c
new file mode 100644
index 000000000..7b7443cbd
--- /dev/null
+++ b/private/crt32/misc/lfind.c
@@ -0,0 +1,79 @@
+/***
+*lfind.c - do a linear search
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _lfind() - do a linear search of an array.
+*
+*Revision History:
+* 06-19-85 TC initial version
+* 02-05-87 BM changed <= to < in while condition to fix bug
+* of looking one element too far
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-21-88 JCR Backed out _LOAD_DS...
+* 10-30-89 JCR Added _cdecl to prototypes
+* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h> and
+* fixed the copyright. Also, cleaned up the formatting
+* a bit.
+* 04-05-90 GJF Added #include <search.h> and fixed the resulting
+* compilation errors and warnings. Also, removed an
+* unreferenced local variable.
+* 07-25-90 SBM Replaced <stdio.h> by <stddef.h>
+* 10-04-90 GJF New-style function declarator.
+* 01-17-91 GJF ANSI naming.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <search.h>
+#include <stddef.h>
+
+/***
+*char *_lfind(key, base, num, width, compare) - do a linear search
+*
+*Purpose:
+* Performs a linear search on the array, looking for the value key
+* in an array of num elements of width bytes in size. Returns
+* a pointer to the array value if found, NULL if not found.
+*
+*Entry:
+* char *key - key to search for
+* char *base - base of array to search
+* unsigned *num - number of elements in array
+* int width - number of bytes in each array element
+* int (*compare)() - pointer to function that compares two
+* array values, returning 0 if they are equal and non-0
+* if they are different. Two pointers to array elements
+* are passed to this function.
+*
+*Exit:
+* if key found:
+* returns pointer to array element
+* if key not found:
+* returns NULL
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void * _CALLTYPE1 _lfind (
+ REG2 const void *key,
+ REG1 const void *base,
+ REG3 unsigned int *num,
+ unsigned int width,
+ int (_CALLTYPE1 *compare)(const void *, const void *)
+ )
+{
+ unsigned int place = 0;
+ while (place < *num )
+ if (!(*compare)(key,base))
+ return( (void *)base );
+ else
+ {
+ base = (char *)base + width;
+ place++;
+ }
+ return( NULL );
+}
diff --git a/private/crt32/misc/lsearch.c b/private/crt32/misc/lsearch.c
new file mode 100644
index 000000000..42b870764
--- /dev/null
+++ b/private/crt32/misc/lsearch.c
@@ -0,0 +1,87 @@
+/***
+*lsearch.c - linear search of an array
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* contains the _lsearch() function - linear search of an array
+*
+*Revision History:
+* 06-19-85 TC initial version
+* 05-14-87 JMB added function pragma for memcpy in compact/large mode
+* for huge pointer support
+* include sizeptr.h for SIZED definition
+* 08-01-87 SKS Add include file for prototype of memcpy()
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-21-88 JCR Backed out _LOAD_DS...
+* 10-30-89 JCR Added _cdecl to prototypes
+* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h> and
+* fixed the copyright. Also, cleaned up the formatting
+* a bit.
+* 04-05-90 GJF Added #include <search.h> and fixed the resulting
+* compiler errors and warnings. Removed unreferenced
+* local variable. Also, removed #include <sizeptr.h>.
+* 07-25-90 SBM Replaced <stdio.h> by <stddef.h>
+* 10-04-90 GJF New-style function declarator.
+* 01-17-91 GJF ANSI naming.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stddef.h>
+#include <search.h>
+#include <memory.h>
+
+/***
+*char *_lsearch(key, base, num, width, compare) - do a linear search
+*
+*Purpose:
+* Performs a linear search on the array, looking for the value key
+* in an array of num elements of width bytes in size. Returns
+* a pointer to the array value if found; otherwise adds the
+* key to the end of the list.
+*
+*Entry:
+* char *key - key to search for
+* char *base - base of array to search
+* unsigned *num - number of elements in array
+* int width - number of bytes in each array element
+* int (*compare)() - pointer to function that compares two
+* array values, returning 0 if they are equal and non-0
+* if they are different. Two pointers to array elements
+* are passed to this function.
+*
+*Exit:
+* if key found:
+* returns pointer to array element
+* if key not found:
+* adds the key to the end of the list, and increments
+* *num.
+* returns pointer to new element.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void * _CALLTYPE1 _lsearch (
+ REG2 const void *key,
+ REG1 void *base,
+ REG3 unsigned int *num,
+ unsigned int width,
+ int (_CALLTYPE1 *compare)(const void *, const void *)
+ )
+{
+ unsigned int place = 0;
+ while (place < *num )
+ if (!(*compare)(key,base))
+ return(base);
+ else
+ {
+ base = (char *)base + width;
+ place++;
+ }
+ (void) memcpy( base, key, width );
+ (*num)++;
+ return( base );
+}
diff --git a/private/crt32/misc/makefile b/private/crt32/misc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/crt32/misc/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/misc/makepath.c b/private/crt32/misc/makepath.c
new file mode 100644
index 000000000..6cf245500
--- /dev/null
+++ b/private/crt32/misc/makepath.c
@@ -0,0 +1,128 @@
+/***
+*makepath.c - create path name from components
+*
+* Copyright (c) 1987-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* To provide support for creation of full path names from components
+*
+*Revision History:
+* 06-13-87 DFW initial version
+* 08-05-87 JCR Changed appended directory delimeter from '/' to '\'.
+* 09-24-87 JCR Removed 'const' from declarations (caused cl warnings).
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 11-20-89 GJF Fixed copyright, indents. Added const to types of
+* appropriate args.
+* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include
+* <cruntime.h>.
+* 10-04-90 GJF New-style function declarator.
+* 06-09-93 KRS Add _MBCS support.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#ifdef _MBCS
+#include <mbdata.h>
+#include <mbstring.h>
+#endif
+
+/***
+*void _makepath() - build path name from components
+*
+*Purpose:
+* create a path name from its individual components
+*
+*Entry:
+* char *path - pointer to buffer for constructed path
+* char *drive - pointer to drive component, may or may not contain
+* trailing ':'
+* char *dir - pointer to subdirectory component, may or may not include
+* leading and/or trailing '/' or '\' characters
+* char *fname - pointer to file base name component
+* char *ext - pointer to extension component, may or may not contain
+* a leading '.'.
+*
+*Exit:
+* path - pointer to constructed path name
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _makepath (
+ register char *path,
+ const char *drive,
+ const char *dir,
+ const char *fname,
+ const char *ext
+ )
+{
+ register const char *p;
+
+ /* we assume that the arguments are in the following form (although we
+ * do not diagnose invalid arguments or illegal filenames (such as
+ * names longer than 8.3 or with illegal characters in them)
+ *
+ * drive:
+ * A ; or
+ * A:
+ * dir:
+ * \top\next\last\ ; or
+ * /top/next/last/ ; or
+ * either of the above forms with either/both the leading
+ * and trailing / or \ removed. Mixed use of '/' and '\' is
+ * also tolerated
+ * fname:
+ * any valid file name
+ * ext:
+ * any valid extension (none if empty or null )
+ */
+
+ /* copy drive */
+
+ if (drive && *drive) {
+ *path++ = *drive;
+ *path++ = ':';
+ }
+
+ /* copy dir */
+
+ if ((p = dir) && *p) {
+ do {
+ *path++ = *p++;
+ }
+ while (*p);
+#ifdef _MBCS
+ if (*(p=_mbsdec(dir,p)) != '/' && *p != '\\') {
+#else
+ if (*(p-1) != '/' && *(p-1) != '\\') {
+#endif
+ *path++ = '\\';
+ }
+ }
+
+ /* copy fname */
+
+ if (p = fname) {
+ while (*p) {
+ *path++ = *p++;
+ }
+ }
+
+ /* copy ext, including 0-terminator - check to see if a '.' needs
+ * to be inserted.
+ */
+
+ if (p = ext) {
+ if (*p && *p != '.') {
+ *path++ = '.';
+ }
+ while (*path++ = *p++)
+ ;
+ }
+ else {
+ /* better add the 0-terminator */
+ *path = '\0';
+ }
+}
diff --git a/private/crt32/misc/mbval.c b/private/crt32/misc/mbval.c
new file mode 100644
index 000000000..aa3ad3a16
--- /dev/null
+++ b/private/crt32/misc/mbval.c
@@ -0,0 +1,22 @@
+/***
+*mbval.c - definition of __invalid_mb_chars variable
+*
+* Copyright (c) 1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines __invalid_mb_chars and adds a pointer to __set_invalid_mb_chars
+* to be called at runtime startup.
+*
+**
+*Revision History:
+* 10-22-93 CFW Module created.
+*
+*******************************************************************************/
+
+void __set_invalid_mb_chars(void);
+
+int __invalid_mb_chars = 0;
+
+#pragma data_seg(".CRT$XIC")
+void (*__pfn_set_invalid_mb_chars) = __set_invalid_mb_chars;
+
diff --git a/private/crt32/misc/mips/chandler.c b/private/crt32/misc/mips/chandler.c
new file mode 100644
index 000000000..4721f82b1
--- /dev/null
+++ b/private/crt32/misc/mips/chandler.c
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ chandler.c
+
+Abstract:
+
+ This module implements the C specific exception handler that provides
+ structured condition handling for the C language.
+
+Author:
+
+ David N. Cutler (davec) 11-Sep-1990
+
+Environment:
+
+ Any mode.
+
+Revision History:
+
+--*/
+
+#include "nt.h"
+
+
+//
+// Define procedure prototypes for exception filter and termination handler
+// execution routines defined in jmpunwnd.s
+//
+
+LONG
+__C_ExecuteExceptionFilter (
+ PEXCEPTION_POINTERS ExceptionPointers,
+ EXCEPTION_FILTER ExceptionFilter,
+ ULONG EstablisherFrame
+ );
+
+VOID
+__C_ExecuteTerminationHandler (
+ BOOLEAN AbnormalTermination,
+ TERMINATION_HANDLER TerminationHandler,
+ ULONG EstablisherFrame
+ );
+
+EXCEPTION_DISPOSITION
+__C_specific_handler (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PVOID EstablisherFrame,
+ IN OUT PCONTEXT ContextRecord,
+ IN OUT PDISPATCHER_CONTEXT DispatcherContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function scans the scope tables associated with the specified
+ procedure and calls exception and termination handlers as necessary.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to an exception record.
+
+ EstablisherFrame - Supplies a pointer to frame of the establisher function.
+
+ ContextRecord - Supplies a pointer to a context record.
+
+ DispatcherContext - Supplies a pointer to the exception dispatcher or
+ unwind dispatcher context.
+
+Return Value:
+
+ If the exception is handled by one of the exception filter routines, then
+ there is no return from this routine and RtlUnwind is called. Otherwise,
+ an exception disposition value of continue execution or continue search is
+ returned.
+
+--*/
+
+{
+
+ ULONG ControlPc;
+ EXCEPTION_FILTER ExceptionFilter;
+ EXCEPTION_POINTERS ExceptionPointers;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG Index;
+ PSCOPE_TABLE ScopeTable;
+ ULONG TargetPc;
+ TERMINATION_HANDLER TerminationHandler;
+ LONG Value;
+
+ //
+ // Get address of where control left the establisher, the address of the
+ // function table entry that describes the function, and the address of
+ // the scope table.
+ //
+
+ ControlPc = DispatcherContext->ControlPc;
+ FunctionEntry = DispatcherContext->FunctionEntry;
+ ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData);
+
+ //
+ // If an unwind is not in progress, then scan the scope table and call
+ // the appropriate exception filter routines. Otherwise, scan the scope
+ // table and call the appropriate termination handlers using the target
+ // PC obtained from the context record.
+ // are called.
+ //
+
+ if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // Scan the scope table and call the appropriate exception filter
+ // routines.
+ //
+
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) &&
+ (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) {
+
+ //
+ // Call the exception filter routine.
+ //
+
+ ExceptionFilter =
+ (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ Value = __C_ExecuteExceptionFilter(&ExceptionPointers,
+ ExceptionFilter,
+ (ULONG)EstablisherFrame);
+
+ //
+ // If the return value is less than zero, then dismiss the
+ // exception. Otherwise, if the value is greater than zero,
+ // then unwind to the target exception handler. Otherwise,
+ // continue the search for an exception filter.
+ //
+
+ if (Value < 0) {
+ return ExceptionContinueExecution;
+
+ } else if (Value > 0) {
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget,
+ ExceptionRecord,
+ (PVOID)ExceptionRecord->ExceptionCode);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // Scan the scope table and call the appropriate termination handler
+ // routines.
+ //
+
+ TargetPc = ContextRecord->Fir;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) {
+
+ //
+ // If the target PC is within the same scope the control PC
+ // is within, then this is an uplevel goto out of an inner try
+ // scope or a long jump back into a try scope. Terminate the
+ // scan termination handlers.
+ //
+ // N.B. The target PC can be just beyond the end of the scope,
+ // in which case it is a leave from the scope.
+ //
+
+
+ if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) {
+ break;
+
+ } else {
+
+ //
+ // If the scope table entry describes an exception filter
+ // and the associated exception handler is the target of
+ // the unwind, then terminate the scan for termination
+ // handlers. Otherwise, if the scope table entry describes
+ // a termination handler, then record the address of the
+ // end of the scope as the new control PC address and call
+ // the termination handler.
+ //
+
+ if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) {
+ if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) {
+ break;
+ }
+
+ } else {
+ DispatcherContext->ControlPc =
+ ScopeTable->ScopeRecord[Index].EndAddress + 4;
+ TerminationHandler =
+ (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ (ULONG)EstablisherFrame);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Continue search for exception or termination handlers.
+ //
+
+ return ExceptionContinueSearch;
+}
diff --git a/private/crt32/misc/mips/jmpuwind.s b/private/crt32/misc/mips/jmpuwind.s
new file mode 100644
index 000000000..8e99fcc4c
--- /dev/null
+++ b/private/crt32/misc/mips/jmpuwind.s
@@ -0,0 +1,138 @@
+// TITLE("Jump to Unwind")
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+//
+// Module Name:
+//
+// jmpuwind.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to jump to the runtime
+// time library unwind routine.
+//
+// Author:
+//
+// David N. Cutler (davec) 12-Sep-1990
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+ SBTTL("Execute Exception Filter")
+//++
+//
+// ULONG
+// __C_ExecuteExceptionFilter (
+// PEXCEPTION_POINTERS ExceptionPointers,
+// EXCEPTION_FILTER ExceptionFilter,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// exception filter routine.
+//
+// Arguments:
+//
+// ExceptionPointers (a0) - Supplies a pointer to the exception pointers
+// structure.
+//
+// ExceptionFilter (a1) - Supplies the address of the exception filter
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// The value returned by the exception filter routine.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteExceptionFilter)
+
+ move v0,a2 // set static link
+ j a1 // transfer control to exception filter
+
+ .end __C_ExecuteExceptionFilter
+
+ SBTTL("Execute Termination Handler")
+//++
+//
+// VOID
+// __C_ExecuteTerminationHandler (
+// BOOLEAN AbnormalTermination,
+// TERMINATION_HANDLER TerminationHandler,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function sets the static link and transfers control to the specified
+// termination handler routine.
+//
+// Arguments:
+//
+// AbnormalTermination (a0) - Supplies a boolean value that determines
+// whether the termination is abnormal.
+//
+// TerminationHandler (a1) - Supplies the address of the termination handler
+// routine.
+//
+// EstablisherFrame (a2) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(__C_ExecuteTerminationHandler)
+
+ move v0,a2 // set static link
+ j a1 // transfer control to termination handler
+
+ .end __C_ExecuteTerminationHandler
+
+ SBTTL("Jump to Unwind")
+//++
+//
+// VOID
+// __jump_unwind (
+// IN PVOID EstablishFrame,
+// IN PVOID TargetPc
+// )
+//
+// Routine Description:
+//
+// This function transfer control to unwind. It is used by the MIPS
+// compiler when a goto out of the body or a try statement occurs.
+//
+// Arguments:
+//
+// EstablishFrame (a0) - Supplies the establisher frame point of the
+// target of the unwind.
+//
+// TargetPc (a1) - Supplies the target instruction address where control
+// is to be transfered to after the unwind operation is complete.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(__jump_unwind)
+
+ move a2,zero // set NULL exception record address
+ move a3,zero // set destination return value
+ j RtlUnwind // unwind to specified target
+
+ .end __jump_unwind
diff --git a/private/crt32/misc/mips/longjmp.s b/private/crt32/misc/mips/longjmp.s
new file mode 100644
index 000000000..04e886570
--- /dev/null
+++ b/private/crt32/misc/mips/longjmp.s
@@ -0,0 +1,128 @@
+// TITLE("Long Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// longjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a long
+// jump operation.
+//
+// N.B. This routine conditionally provides UNSAFE handling of longjmp
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an unitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Long Jump")
+//++
+//
+// int
+// longjmp (
+// IN jmp_buf JumpBuffer,
+// IN int ReturnValue
+// )
+//
+// Routine Description:
+//
+// This function performs a long jump to the context specified by the
+// jump buffer.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer that contains
+// jump information.
+//
+// ReturnValue (a1) - Supplies the value that is to be returned to the
+// caller of set jump.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 4 * 4 // argument save area
+LjEr: .space ExceptionRecordLength // exception record
+ .space 4 * 3 // fill
+LjRa: .space 4 // saved return address
+LongjmpFrameLength:
+
+ NESTED_ENTRY(longjmp, LongjmpFrameLength, zero)
+
+ subu sp,sp,LongjmpFrameLength // allocate stack frame
+ sw ra,LjRa(sp) // save return address
+
+ PROLOGUE_END
+
+ bne zero,a1,10f // if ne, return value specified
+ li a1,1 // set return value to nonzero value
+10: lw v0,JbType(a0) // get safe setjmp/longjmp flag
+ bne zero,v0,20f // if ne, provide safe longjmp
+
+//
+// Provide unsafe handling of longjmp.
+//
+
+ move v0,a1 // set return value
+ ldc1 f20,JbFltF20(a0) // restore floating registers f20 - f31
+ ldc1 f22,JbFltF22(a0) //
+ ldc1 f24,JbFltF24(a0) //
+ ldc1 f26,JbFltF26(a0) //
+ ldc1 f28,JbFltF28(a0) //
+ ldc1 f30,JbFltF30(a0) //
+ lw s0,JbIntS0(a0) // restore integer registers s0 - s8
+ lw s1,JbIntS1(a0) //
+ lw s2,JbIntS2(a0) //
+ lw s3,JbIntS3(a0) //
+ lw s4,JbIntS4(a0) //
+ lw s5,JbIntS5(a0) //
+ lw s6,JbIntS6(a0) //
+ lw s7,JbIntS7(a0) //
+ lw s8,JbIntS8(a0) //
+ lw a1,JbFir(a0) // get setjmp return address
+ lw sp,JbIntSp(a0) // restore stack pointer
+ j a1 // jump back to setjmp site
+
+//
+// Provide safe handling of longjmp.
+//
+// An exception record is constructed that contains a log jump status
+// code and the first exception information parameter is a pointer to
+// the jump buffer.
+//
+
+20: li v0,STATUS_LONGJUMP // get long jump status code
+ sw v0,LjEr + ErExceptionCode(sp) // set exception code
+ sw zero,LjEr + ErExceptionFlags(sp) // clear exception flags
+ sw zero,LjEr + ErExceptionRecord(sp) // clear associate record
+ sw zero,LjEr + ErExceptionAddress(sp) // clear exception address
+ li v0,1 // set number of parameters
+ sw v0,LjEr + ErNumberParameters(sp) //
+ sw a0,LjEr + ErExceptionInformation(sp) // set jump buffer address
+ move a3,a1 // set return value
+ addu a2,sp,LjEr // compute exception record address
+ lw a1,JbFir(a0) // set target instruction address
+ lw a0,JbType(a0) // set target virtual frame address
+ jal RtlUnwind // finish in common code
+ b 20b
+
+ .end longjmp
diff --git a/private/crt32/misc/mips/setjmp.s b/private/crt32/misc/mips/setjmp.s
new file mode 100644
index 000000000..245cd4b37
--- /dev/null
+++ b/private/crt32/misc/mips/setjmp.s
@@ -0,0 +1,101 @@
+// TITLE("Set Jump")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// setjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a setjmp.
+//
+// N.B. This module conditionally provides UNSAFE handling of setjmp and
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an uninitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// David N. Cutler (davec) 7-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe or unsafe with
+// respect to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .comm _setjmpexused , 4
+
+ SBTTL("Set Jump")
+//++
+//
+// int
+// setjmp (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function saved the current nonvolatile register state in the
+// specified jump buffer and returns a function vlaue of zero.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY(setjmp)
+
+ lw v0,_setjmpexused // get value of switch variable
+ bne zero,v0,10f // if ne, provide safe setjmp
+
+//
+// Provide unsafe handling of setjmp.
+//
+
+ sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31
+ sdc1 f22,JbFltF22(a0) //
+ sdc1 f24,JbFltF24(a0) //
+ sdc1 f26,JbFltF26(a0) //
+ sdc1 f28,JbFltF28(a0) //
+ sdc1 f30,JbFltF30(a0) //
+ sw s0,JbIntS0(a0) // save integer registers s0 - s8
+ sw s1,JbIntS1(a0) //
+ sw s2,JbIntS2(a0) //
+ sw s3,JbIntS3(a0) //
+ sw s4,JbIntS4(a0) //
+ sw s5,JbIntS5(a0) //
+ sw s6,JbIntS6(a0) //
+ sw s7,JbIntS7(a0) //
+ sw s8,JbIntS8(a0) //
+ sw ra,JbFir(a0) // get setjmp return address
+ sw sp,JbIntSp(a0) // save stack pointer
+ sw zero,JbType(a0) // clean safe setjmp flag
+ move v0,zero // set return value
+ j ra // return
+
+//
+// Provide safe handling of setjmp.
+//
+
+10: j v0 // finish in common code
+
+ .end setjmp
diff --git a/private/crt32/misc/mips/setjmpex.s b/private/crt32/misc/mips/setjmpex.s
new file mode 100644
index 000000000..31385e394
--- /dev/null
+++ b/private/crt32/misc/mips/setjmpex.s
@@ -0,0 +1,156 @@
+// TITLE("Set Jump Extended")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// setjmpex.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to provide SAFE
+// handling of setjmp/longjmp with respect to structured exception
+// handling.
+//
+// Author:
+//
+// David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+//
+// Define variable that will cause setjmp/longjmp to be safe with respect
+// to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .data
+_setjmpexused:
+ .word _setjmpex // set address of safe setjmp routine
+
+ SBTTL("Set Jump Extended")
+//++
+//
+// int
+// _setjmpex (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function transfers control to the actual setjmp routine.
+//
+// Arguments:
+//
+// JumpBuffer (a0) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ .struct 0
+ .space 4 * 4 // argument save area
+SjS0: .space 4 // saved integer register s0
+SjFl: .space 4 // in function flag variable
+ .space 4 // fill
+SjRa: .space 4 // saved return address
+SetjmpFrameLength:
+
+ NESTED_ENTRY(_setjmpex, SetjmpFrameLength, zero)
+
+ subu sp,sp,SetjmpFrameLength // allocate stack frame
+ sw s0,SjS0(sp) // save integer register s0
+ sw ra,SjRa(sp) // save return address
+ move s0,sp // set frame pointer
+
+ PROLOGUE_END
+
+ subu sp,sp,ContextFrameLength + 16 // allocate a context frame
+
+//
+// Save the nonvolatile machine state in both the jump buffer and a context
+// record that will be used to compute the virtual frame pointer.
+//
+
+ sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31
+ sdc1 f22,JbFltF22(a0) //
+ sdc1 f24,JbFltF24(a0) //
+ sdc1 f26,JbFltF26(a0) //
+ sdc1 f28,JbFltF28(a0) //
+ sdc1 f30,JbFltF30(a0) //
+ lw v0,SjS0(s0) // get saved integer register s0
+ sw v0,JbIntS0(a0) // save integer registers s0 - s8
+ sw s1,JbIntS1(a0) //
+ sw s2,JbIntS2(a0) //
+ sw s3,JbIntS3(a0) //
+ sw s4,JbIntS4(a0) //
+ sw s5,JbIntS5(a0) //
+ sw s6,JbIntS6(a0) //
+ sw s7,JbIntS7(a0) //
+ sw s8,JbIntS8(a0) //
+ sw ra,JbFir(a0) // get setjmp return address
+ addu v0,s0,SetjmpFrameLength // compute stack pointer address
+ sw v0,JbIntSp(a0) // save stack pointer
+
+ sdc1 f20,CxFltF20 + 16(sp) // save floating registers f20 - f31
+ sdc1 f22,CxFltF22 + 16(sp) //
+ sdc1 f24,CxFltF24 + 16(sp) //
+ sdc1 f26,CxFltF26 + 16(sp) //
+ sdc1 f28,CxFltF28 + 16(sp) //
+ sdc1 f30,CxFltF30 + 16(sp) //
+ lw v0,SjS0(s0) // get saved integer register s0
+ sw v0,CxIntS0 + 16(sp) // save integer registers s0 - s8
+ sw s1,CxIntS1 + 16(sp) //
+ sw s2,CxIntS2 + 16(sp) //
+ sw s3,CxIntS3 + 16(sp) //
+ sw s4,CxIntS4 + 16(sp) //
+ sw s5,CxIntS5 + 16(sp) //
+ sw s6,CxIntS6 + 16(sp) //
+ sw s7,CxIntS7 + 16(sp) //
+ sw s8,CxIntS8 + 16(sp) // save integer register s8
+ sw gp,CxIntGp + 16(sp) // save integer register gp
+ addu v0,s0,SetjmpFrameLength // compute stack pointer address
+ sw v0,CxIntSp + 16(sp) // save stack pointer
+ sw ra,CxIntRa + 16(sp) // save return address
+ sw ra,CxFir + 16(sp) // save return address
+
+//
+// Perform unwind to determine the virtual frame pointer of the caller.
+//
+
+ addu a0,a0,JbType // set virtual frame address argument
+ sw a0,4 * 4(sp) //
+ subu a0,ra,4 // compute control PC address
+ jal RtlLookupFunctionEntry // lookup function table address
+ lw a0,SjRa(s0) // get return address
+ subu a0,a0,4 // compute control PC address
+ move a1,v0 // set address of function entry
+ addu a2,sp,16 // compute address of context record
+ addu a3,s0,SjFl // set address of in function variable
+ sw zero,4 * 5(sp) // set context pointer array address
+ jal RtlVirtualUnwind // compute virtual frame pointer value
+
+//
+// Set return value, restore registers, deallocate stack frame, and return.
+//
+
+ move v0,zero // set return value
+ move sp,s0 // reset stack pointer
+ lw s0,SjS0(sp) // restore integer register s0
+ lw ra,SjRa(sp) // restore return address
+ addu sp,sp,SetjmpFrameLength // deallocate stack frame
+ j ra // return
+
+ .end _setjmpex
diff --git a/private/crt32/misc/mtest.c b/private/crt32/misc/mtest.c
new file mode 100644
index 000000000..0e95bcee1
--- /dev/null
+++ b/private/crt32/misc/mtest.c
@@ -0,0 +1,530 @@
+/***
+* mtest.c - Multi-thread debug testing module
+*
+* Copyright (c) 19xx-1988, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This source contains a group of routines used for multi-thread
+* testing. In order to use the debug flavor of these routines, you
+* MUST link special debug versions of multi-thread crt0dat.obj and
+* mlock.obj into your program.
+*
+* [NOTE: This source module is NOT included in the C runtime library;
+* it is used only for testing and must be explicitly linked into the
+* test program.]
+*
+*Revision History:
+* 12-??-87 JCR Module created.
+* 06-17-88 JCR Misc. bug fixes.
+* 08-03-88 JCR Use the stdio.h value of _NFILE
+* 10-03-88 JCR 386: Use SYS calls, not DOS calls
+* 10-04-88 JCR 386: Removed 'far' keyword
+* 10-10-88 GJF Made API names match DOSCALLS.H
+* 06-08-89 JCR New 386 _beginthread interface; also brought
+* lots of new options across from the C600 tree.
+* 07-11-89 JCR Added _POPEN_LOCK to _locknames[] array
+* 07-14-89 JCR Added _LOCKTAB_LOCK support
+* 07-24-90 SBM Removed '32' from API names
+*
+*******************************************************************************/
+
+#ifdef M_I386
+#ifdef STACKALLOC
+#error Can't define STACKALLOC in 386 mode
+#endif
+#endif
+
+#ifdef M_I386
+#ifdef _DOSCREATETHREAD_
+#error Currently can't define _DOSCREATETHREAD_ in 386 mode
+#endif
+#endif
+
+#ifdef _DOSCREATETHREAD_
+#ifndef STACKALLOC
+#error Can't define _DOSCREATETHREAD_ without STACKALLOC
+#endif
+#endif
+
+/*
+Multi-thread core tester module.
+*/
+#include <malloc.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <io.h>
+#include <mtest.h>
+#ifdef DEBUG
+#include <os2dll.h>
+#include <file2.h>
+#endif
+
+/* Define FAR to be blank for the 386 and far otherwise. */
+
+#undef FAR
+#ifdef M_I386
+#define FAR
+#else
+#define FAR far
+#endif
+
+/* define stack size */
+#ifdef M_I386
+#define _STACKSIZE_ 8192
+#else
+#define _STACKSIZE_ 2048
+#endif
+
+
+/* routines */
+#ifdef M_I386
+unsigned _syscall DOSSLEEP (unsigned long) ;
+#else
+unsigned FAR pascal DOSSLEEP (unsigned long) ;
+#endif
+int main ( int argc , char * * argv ) ;
+int minit(void);
+void childcode ( void FAR * arg ) ;
+#ifdef _DOSCREATETHREAD_
+#ifndef M_I386
+void childcode ( void ) ;
+unsigned FAR pascal DOSCREATETHREAD (void FAR *, void FAR *, void FAR *);
+#endif
+#else
+void childcode ( void FAR * arg ) ;
+#endif
+int mterm(void);
+
+/* global data */
+char Result [ _THREADMAX_ ] ;
+unsigned Synchronize ;
+
+#ifdef DEBUG
+/* Array of lock names. This order must match the declarations in
+ os2dll.h and os2dll.inc. */
+
+char *_locknames[] = {
+ "** NO LOCK 0 ** ", /* lock values are 1-based */
+ "_SIGNAL_LOCK ",
+ "_IOB_SCAN_LOCK ",
+ "_TMPNAM_LOCK ",
+ "_INPUT_LOCK ",
+ "_OUTPUT_LOCK ",
+ "_CSCANF_LOCK ",
+ "_CPRINTF_LOCK ",
+ "_CONIO_LOCK ",
+ "_HEAP_LOCK ",
+ "_BHEAP_LOCK ",
+ "_TIME_LOCK ",
+ "_ENV_LOCK ",
+ "_EXIT_LOCK1 ",
+ "_EXIT_LOCK2 ",
+ "_THREADDATA_LOCK",
+ "_POPEN_LOCK ",
+ "_SSCANF_LOCK ",
+ "_SPRINTF_LOCK ",
+#ifdef M_I386
+ "_VSPRINTF_LOCK ",
+ "_LOCKTAB_LOCK "
+#else
+ "_VSPRINTF_LOCK "
+#endif
+ };
+
+/* Minimal sanity check on above array. */
+#ifdef M_I386
+
+#if ((_LOCKTAB_LOCK+1)-_STREAM_LOCKS)
+#error *** _locknames[] does agree with lock values ***
+#endif
+
+#else /* !M_I386 */
+
+#if ((_VSPRINTF_LOCK+1)-_STREAM_LOCKS)
+#error *** _locknames[] does agree with lock values ***
+#endif
+
+#endif /* M_I386 */
+
+#endif /* DEBUG */
+
+
+/***
+* main() - Main mthread testing shell
+*
+*Purpose:
+* Provides a general purpose shell for mthread testing.
+* The module does the following:
+*
+* (1) Call minit() to perform test initialization operations.
+*
+* (2) Begins one thread for each argument passed to the
+* program. Each thread is passed the corresponding argument.
+* Thread begin location is assumed to be at routine childcode();
+*
+* (3) Waits for all threads to terminate.
+*
+* (4) Calls mterm() to perform termination operations.
+*
+* Note that minit(), childcode(), and mterm() are routines that
+* are external to this source. Again, this source doesn't care
+* what their purpose or operation is.
+*
+* Also, childcode() is expected to conform to the following rules:
+*
+* (1) The childcode should not start running until
+* the variable 'Synchronize' becomes non-zero.
+*
+* (2) When the thread is done executing, it should set
+* the value Result[threadid] to a non-zero value so the
+* parent (i.e., this routine) knows it has completed.
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int main ( int argc , char * * argv )
+{
+ int rc ;
+ unsigned result = 0 ;
+ long ChildCount ;
+ int NumThreads ;
+ int t ;
+ int r ;
+ int MaxThread = 0 ;
+ long LoopCount ;
+#ifdef THREADLOOP
+ char **argvsave;
+#endif
+#ifndef M_I386
+ char * stackbottom ;
+#endif
+
+#ifdef DEBUG
+ if ( argc > MAXTHREADID) {
+ printf("*** ERROR: Mthread debugging only supports %u threads ***\n", MAXTHREADID);
+ return(-1);
+ }
+#endif
+
+ if ( -- argc > (_THREADMAX_-1) )
+ {
+ printf ( "*** Error: Too many arguments***\n" ) ;
+ return (-1) ;
+ }
+
+ /* Call the initiation routine */
+
+ if (minit() != 0) {
+ printf("*** Error: From minit() routine ***\n");
+ return(-1);
+ }
+
+ /* Bring up the threads */
+
+ printf ( "Process ID = %u, Thread ID = %d, ArgCount= %d\r\n" ,
+ getpid ( ) , * _threadid , argc ) ;
+
+#ifndef M_I386
+#ifdef STACKALLOC
+ printf( "(thread stacks allocated explicilty by mtest suite)\r\n");
+#else
+ printf( "(thread stacks allocated implicitly via _beginthread)\r\n");
+#endif
+#endif
+
+#ifdef THREADLOOP
+ /* Bring up all the threads several times (so tids get re-used) */
+ argvsave=argv;
+ for (threadloop=1;threadloop<=_THREADLOOPCNT_;threadloop++) {
+ printf("\nThreadloop = %i\n", threadloop);
+ argv=argvsave;
+#endif
+
+ NumThreads = 0 ;
+
+ while ( * ++ argv )
+ {
+
+ ChildCount = atol ( * argv ) ;
+
+#ifdef M_I386
+
+ rc = _beginthread ( (void FAR *) childcode , _STACKSIZE_ ,
+ (void FAR *) ChildCount ) ;
+
+ if ( rc == -1 )
+
+#else /* !M_I386 */
+
+#ifdef STACKALLOC
+ if ( ! ( stackbottom = _fmalloc ( _STACKSIZE_ ) ) )
+ {
+ printf ( "*** Error: Could not allocate a stack ***\n" ) ;
+ break ;
+ }
+#else
+ stackbottom = (void FAR *) NULL;
+#endif
+
+#ifdef _DOSCREATETHREAD_
+ stackbottom+=_STACKSIZE_-16; /* point to end of malloc'd block */
+ rc1 = DOSCREATETHREAD( (void FAR *) childcode, &rc,
+ (void FAR *) stackbottom);
+
+ if (rc1 != 0)
+#else
+ rc = _beginthread ( (void FAR *) childcode , (void FAR *) stackbottom ,
+ _STACKSIZE_ , (void FAR *) ChildCount ) ;
+
+ if ( rc == -1 )
+#endif
+
+#endif /* M_I386 */
+
+ {
+ printf ("*** Error: Could not Spawn %d-th Thread (argument=%ld) ***\n" ,
+ NumThreads + 1 , ChildCount ) ;
+ break ;
+ }
+
+ if ( rc > MaxThread )
+ MaxThread = rc ;
+
+ printf ( "Spawning %d-th Thread %d with argument=%ld\r\n" ,
+ ++ NumThreads , rc , ChildCount ) ;
+ }
+
+ printf ( "NumThreads = %d, MaxThread = %d\r\n" ,
+ NumThreads, MaxThread ) ;
+
+ /* Let the threads begin and wait for them to term. */
+
+ LoopCount = 0L ;
+
+ Synchronize = 1 ;
+
+ for ( t = 0 ; t < NumThreads ; ++ t )
+ {
+ r = 0 ;
+ while ( ! Result [ r ] )
+ {
+ DOSSLEEP ( 0L ) ;
+ if ( ++ r > MaxThread )
+ {
+ r = 0 ;
+ printf ( "%ld\r" , LoopCount ++ ) ;
+ }
+ }
+
+ printf ( "%d: Thread %d Done.\r\n" , t , r) ;
+
+ Result [ r ] = '\0' ;
+ }
+#ifdef THREADLOOP
+ }
+#endif
+
+ /* All the threads have completed. Call the term routine and return. */
+
+ if (mterm() != 0) {
+ printf("*** Error: From mterm() routine ***\n");
+ return(-1);
+ }
+
+ printf("\nDone!\n");
+ return 0 ;
+}
+
+
+#ifdef DEBUG
+
+/***
+* Debug Print Routines - Display useful mthread lock data
+*
+*Purpose:
+* The following routines extract information from the multi-thread
+* debug data bases and print them out in various formats.
+* In order to use these routines, you MUST link special debug
+* versions of multi-thread crt0dat.obj and mlock.obj into your program.
+*
+*Entry:
+*
+*Exit:
+* 0 = success
+* 0! = failure
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+/*--- Print lock routine ---*/
+int printlock(int locknum)
+{
+ int retval;
+
+#ifdef _INIT_LOCKS
+ if (locknum >= _STREAM_LOCKS)
+ printf("\nValidating lock #%i (%s):\n",locknum, "not a 'single lock'");
+ else
+ printf("\nValidating lock #%i: %s\n",locknum, _locknames[locknum]);
+#else
+ printf("\nValidating lock #%i (%s, %s):\n",
+ locknum,
+ (locknum >= _STREAM_LOCKS ?
+ "not a 'single' lock" : _locknames[locknum]),
+ (_lock_exist(locknum) ?
+ "initialized" : "NOT initialized")
+ );
+#endif
+
+ retval = _check_lock(locknum);
+ printf("\tLock count = %u\r\n", _lock_cnt(locknum));
+ printf("\tCollision count = %u\r\n", _collide_cnt(locknum));
+
+ if (retval != 0)
+ printf("\t*** ERROR: Checking lock ***\n");
+
+ return(retval);
+}
+
+
+/*--- Printf single locks ---*/
+int print_single_locks(void)
+{
+ int locknum;
+ int retval=0;
+ int lockval;
+
+ printf("\n--- Single Locks ---\n");
+
+#ifdef _INIT_LOCKS
+ printf("\t\t\t\tlock count\tcollide count\n");
+ for (locknum=1;locknum<_STREAM_LOCKS;locknum++) {
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("#%i / %s\t\t%u\t\t%u\t%s\n",
+ locknum, _locknames[locknum], _lock_cnt(locknum),
+ _collide_cnt(locknum), (lockval ? "*LOCK ERROR*" : "") );
+ }
+#else
+ printf("\t\t\t\tlock count\tcollide count\texists?\n");
+ for (locknum=1;locknum<_STREAM_LOCKS;locknum++) {
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("#%i / %s\t\t%u\t\t%u\t\t%s\t%s\n",
+ locknum, _locknames[locknum], _lock_cnt(locknum),
+ _collide_cnt(locknum),
+ (_lock_exist(locknum) ? "YES" : "NO"),
+ (lockval ? "*LOCK ERROR*" : "") );
+ }
+#endif
+
+ return(retval);
+}
+
+
+/*--- Print all stdio locks ---*/
+int print_stdio_locks(void)
+{
+ int i;
+ int locknum;
+ int retval=0;
+ int lockval;
+
+ printf("\n--- Stdio Locks ---\n");
+
+#ifdef _INIT_LOCKS
+ printf("stream\t\tlock count\tcollide count\n");
+ for (i=0;i<_NFILE;i++) {
+ locknum = _stream_locknum(i);
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("%i\t\t%u\t\t%u\t%s\n",
+ i, _lock_cnt(locknum), _collide_cnt(locknum),
+ (lockval ? "*LOCK ERROR*" : "") );
+ }
+#else
+ printf("stream\t\tlock count\tcollide count\texists?\n");
+ for (i=0;i<_NFILE;i++) {
+ locknum = _stream_locknum(i);
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("%i\t\t%u\t\t%u\t\t%s\t%s\n",
+ i, _lock_cnt(locknum), _collide_cnt(locknum),
+ (_lock_exist(locknum) ? "YES" : "NO"),
+ (lockval ? "*LOCK ERROR*" : "") );
+ }
+#endif
+
+ return(retval);
+}
+
+
+/*--- Print all lowio locks ---*/
+int print_lowio_locks(void)
+{
+ int i;
+ int locknum;
+ int retval=0;
+ int lockval;
+
+ printf("\n--- Lowio locks ---\n");
+
+#ifdef _INIT_LOCKS
+ printf("fh\t\tlock count\tcollide count\n");
+ for (i=0;i<_NFILE;i++) {
+ locknum = _fh_locknum(i);
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("%i\t\t%u\t\t%u\t%s\n",
+ i, _lock_cnt(locknum), _collide_cnt(locknum),
+ (lockval ? "*LOCK ERROR*" : "") );
+ }
+#else
+ printf("fh\t\tlock count\tcollide count\texists?\n");
+ for (i=0;i<_NFILE;i++) {
+ locknum = _fh_locknum(i);
+ if (lockval = (_check_lock(locknum) != 0))
+ retval++;
+ printf("%i\t\t%u\t\t%u\t\t%s\t%s\n",
+ i, _lock_cnt(locknum), _collide_cnt(locknum),
+ (_lock_exist(locknum) ? "YES" : "NO"),
+ (lockval ? "*LOCK ERROR*" : "") );
+ }
+#endif
+
+ return(retval);
+}
+
+
+/*--- Print all I/O locks ---*/
+int print_iolocks(void)
+{
+ int retval=0;
+
+ retval += print_stdio_locks();
+ retval += print_lowio_locks();
+
+ return(retval);
+}
+
+
+/*--- Print all Locks ---*/
+int print_locks(void)
+{
+ int retval=0;
+
+ retval += print_single_locks();
+ retval += print_iolocks();
+
+ return(retval);
+}
+
+#endif
diff --git a/private/crt32/misc/nlsdata1.c b/private/crt32/misc/nlsdata1.c
new file mode 100644
index 000000000..6b5a9b2b7
--- /dev/null
+++ b/private/crt32/misc/nlsdata1.c
@@ -0,0 +1,38 @@
+/***
+*nlsdata1.c - globals for international library - small globals
+*
+* Copyright (c) 1991-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains the globals: __mb_cur_max, _decimal_point,
+* _decimal_point_length. This module is always required.
+* This module is separated from nlsdatax.c for granularity.
+*
+*Revision History:
+* 12-01-91 ETC Created.
+* 04-03-92 PLM Changes tdef.h to tchar.h
+* 08-18-92 KRS Rip out _tflag--not used.
+*
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <nlsint.h>
+
+/*
+ * Value of MB_CUR_MAX macro.
+ */
+unsigned short __mb_cur_max = 1;
+
+/*
+ * Localized decimal point string.
+ */
+char _decimal_point[] = ".";
+
+#ifdef _INTL
+
+/*
+ * Decimal point length, not including terminating null.
+ */
+size_t _decimal_point_length = 1;
+
+#endif /* _INTL */
diff --git a/private/crt32/misc/nlsdata2.c b/private/crt32/misc/nlsdata2.c
new file mode 100644
index 000000000..7cbca2a2f
--- /dev/null
+++ b/private/crt32/misc/nlsdata2.c
@@ -0,0 +1,34 @@
+/***
+*nlsdata2.c - globals for international library - locale handles and code page
+*
+* Copyright (c) 1991-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module defines the locale handles and code page. The handles are
+* required by almost all locale dependent functions. This module is
+* separated from nlsdatax.c for granularity.
+*
+*Revision History:
+* 12-01-91 ETC Created.
+*
+*******************************************************************************/
+
+#include <locale.h>
+#include <setlocal.h>
+
+/*
+ * Locale handles.
+ */
+LCID _lc_handle[LC_MAX-LC_MIN+1] = {
+ _CLOCALEHANDLE,
+ _CLOCALEHANDLE,
+ _CLOCALEHANDLE,
+ _CLOCALEHANDLE,
+ _CLOCALEHANDLE,
+ _CLOCALEHANDLE
+};
+
+/*
+ * Code page.
+ */
+UINT _lc_codepage = _CLOCALECP; /* CP_ACP */
diff --git a/private/crt32/misc/nlsdata3.c b/private/crt32/misc/nlsdata3.c
new file mode 100644
index 000000000..5e57d2111
--- /dev/null
+++ b/private/crt32/misc/nlsdata3.c
@@ -0,0 +1,34 @@
+/***
+*nlsdata3.c - globals for international library - locale id's
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains the definition of locale id's. These id's and
+* this file should only be visible to the _init_(locale category)
+* functions. This module is separated from nlsdatax.c for granularity.
+*
+*Revision History:
+* 12-01-91 ETC Created.
+* 01-25-93 KRS Updated.
+*
+*******************************************************************************/
+
+#ifdef _INTL
+#include <locale.h>
+#include <setlocal.h>
+
+/*
+ * Locale id's.
+ */
+/* UNDONE: define struct consisting of LCID/LANGID, CTRY ID, and CP. */
+LC_ID _lc_id[LC_MAX-LC_MIN+1] = {
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 }
+};
+
+#endif /* _INTL */
diff --git a/private/crt32/misc/onexit.c b/private/crt32/misc/onexit.c
new file mode 100644
index 000000000..13806f41a
--- /dev/null
+++ b/private/crt32/misc/onexit.c
@@ -0,0 +1,286 @@
+/***
+*onexit.c - save function for execution on exit
+*
+* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _onexit(), atexit() - save function for execution at exit
+*
+* In order to save space, the table is allocated via malloc/realloc,
+* and only consumes as much space as needed. __onexittable is
+* set to point to the table if onexit() is ever called.
+*
+*Revision History:
+* 06-30-89 PHG module created, based on asm version
+* 03-15-90 GJF Replace _cdecl with _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also,
+* cleaned up the formatting a bit.
+* 05-21-90 GJF Fixed compiler warning.
+* 10-04-90 GJF New-style function declarators.
+* 12-28-90 SRW Added casts of func for Mips C Compiler
+* 01-21-91 GJF ANSI naming.
+* 09-09-91 GJF Revised for C++ needs.
+* 03-20-92 SKS Revamped for new initialization model
+* 04-23-92 DJM POSIX support.
+* 12-02-93 SKS Add __dllonexit for DLLs using CRTDLL.DLL
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <os2dll.h>
+#include <stdlib.h>
+#include <internal.h>
+
+void __cdecl _onexitinit(void);
+
+#ifdef _MSC_VER
+
+#pragma data_seg(".CRT$XIC")
+static void (__cdecl *pinit)(void) = _onexitinit;
+#pragma data_seg()
+
+#endif /* _MSC_VER */
+
+#include <malloc.h>
+#include <rterr.h>
+
+typedef void (_CALLTYPE1 *PF)(void); /* pointer to function */
+
+/*
+ * Define pointers to beginning and end of the table of function pointers
+ * manipulated by _onexit()/atexit().
+ */
+extern PF *__onexitbegin;
+extern PF *__onexitend;
+
+/*
+ * Define increment (in entries) for growing the _onexit/atexit table
+ */
+#define ONEXITTBLINCR 4
+
+/***
+*_onexit(func), atexit(func) - add function to be executed upon exit
+*
+*Purpose:
+* The _onexit/atexit functions are passed a pointer to a function
+* to be called when the program terminate normally. Successive
+* calls create a register of functions that are executed last in,
+* first out.
+*
+*Entry:
+* void (*func)() - pointer to function to be executed upon exit
+*
+*Exit:
+* onexit:
+* Success - return pointer to user's function.
+* Error - return NULL pointer.
+* atexit:
+* Success - return 0.
+* Error - return non-zero value.
+*
+*Notes:
+* This routine depends on the behavior of _initterm() in CRT0DAT.C.
+* Specifically, _initterm() must not skip the address pointed to by
+* its first parameter, and must also stop before the address pointed
+* to by its second parameter. This is because _onexitbegin will point
+* to a valid address, and _onexitend will point at an invalid address.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+
+_onexit_t _CALLTYPE1 _onexit (
+ _onexit_t func
+ )
+{
+ PF *p;
+
+#ifdef MTHREAD
+ _lockexit(); /* lock the exit code */
+#endif
+
+ /*
+ * First, make sure the table has room for a new entry
+ */
+ if ( _msize(__onexitbegin) <= (unsigned)((char *)__onexitend -
+ (char *)__onexitbegin) ) {
+ /*
+ * not enough room, try to grow the table
+ */
+ if ( (p = (PF *) realloc(__onexitbegin, _msize(__onexitbegin) +
+ ONEXITTBLINCR * sizeof(PF))) == NULL ) {
+ /*
+ * didn't work. don't do anything rash, just fail
+ */
+#ifdef MTHREAD
+ _unlockexit();
+#endif
+
+ return NULL;
+ }
+
+ /*
+ * update __onexitend and __onexitbegin
+ */
+ __onexitend = p + (__onexitend - __onexitbegin);
+ __onexitbegin = p;
+ }
+
+ /*
+ * Put the new entry into the table and update the end-of-table
+ * pointer.
+ */
+ *(__onexitend++) = (PF)func;
+
+#ifdef MTHREAD
+ _unlockexit();
+#endif
+
+ return func;
+
+}
+
+int _CALLTYPE1 atexit (
+ PF func
+ )
+{
+ return (_onexit((_onexit_t)func) == NULL) ? -1 : 0;
+}
+
+/***
+* void _onexitinit(void) - initialization routine for the function table
+* used by _onexit() and _atexit().
+*
+*Purpose:
+* Allocate the table with room for 32 entries (minimum required by
+* ANSI). Also, initialize the pointers to the beginning and end of
+* the table.
+*
+*Entry:
+* None.
+*
+*Exit:
+* No return value. A fatal runtime error is generated if the table
+* cannot be allocated.
+*
+*Notes:
+* This routine depends on the behavior of doexit() in CRT0DAT.C.
+* Specifically, doexit() must not skip the address pointed to by
+* __onexitbegin, and it must also stop before the address pointed
+* to by __onexitend. This is because _onexitbegin will point
+* to a valid address, and _onexitend will point at an invalid address.
+*
+* Since the table of onexit routines is built in forward order, it
+* must be traversed by doexit() in CRT0DAT.C in reverse order. This
+* is because these routines must be called in last-in, first-out order.
+*
+* If __onexitbegin == __onexitend, then the onexit table is empty!
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _onexitinit (
+ void
+ )
+{
+ if ( (__onexitbegin = (PF *)malloc(32 * sizeof(PF))) == NULL )
+ /*
+ * cannot allocate minimal required size. generate
+ * fatal runtime error.
+ */
+ _amsg_exit(_RT_ONEXIT);
+
+ *(__onexitbegin) = (PF) NULL;
+ __onexitend = __onexitbegin;
+}
+
+#ifdef CRTDLL
+
+/***
+*__dllonexit(func, pbegin, pend) - add function to be executed upon DLL detach
+*
+*Purpose:
+* The _onexit/atexit functions in a DLL linked with CRTDLL.LIB
+* must maintain their own atexit/_onexit list. This routine is
+* the worker that gets called by such DLLs. It is analogous to
+* the regular _onexit above except that the __onexitbegin and
+* __onexitend variables are not global variables visible to this
+* routine but rather must be passed as parameters.
+*
+*Entry:
+* void (*func)() - pointer to function to be executed upon exit
+* void (***pbegin)() - pointer to variable pointing to the beginning
+* of list of functions to execute on detach
+* void (***pend)() - pointer to variable pointing to the end of list
+* of functions to execute on detach
+*
+*Exit:
+* Success - return pointer to user's function.
+* Error - return NULL pointer.
+*
+*Notes:
+* This routine depends on the behavior of _initterm() in CRT0DAT.C.
+* Specifically, _initterm() must not skip the address pointed to by
+* its first parameter, and must also stop before the address pointed
+* to by its second parameter. This is because *pbegin will point
+* to a valid address, and *pend will point at an invalid address.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_onexit_t _CALLTYPE1 __dllonexit (
+ _onexit_t func,
+ PF ** pbegin,
+ PF ** pend
+ )
+{
+ PF *p;
+
+#ifdef MTHREAD
+ _lockexit(); /* lock the exit code */
+#endif
+
+ /*
+ * First, make sure the table has room for a new entry
+ */
+ if ( _msize((*pbegin)) <= (unsigned)((char *)(*pend) -
+ (char *)(*pbegin)) ) {
+ /*
+ * not enough room, try to grow the table
+ */
+ if ( (p = (PF *) realloc((*pbegin), _msize((*pbegin)) +
+ ONEXITTBLINCR * sizeof(PF))) == NULL ) {
+ /*
+ * didn't work. don't do anything rash, just fail
+ */
+#ifdef MTHREAD
+ _unlockexit();
+#endif
+
+ return NULL;
+ }
+
+ /*
+ * update (*pend) and (*pbegin)
+ */
+ (*pend) = p + ((*pend) - (*pbegin));
+ (*pbegin) = p;
+ }
+
+ /*
+ * Put the new entry into the table and update the end-of-table
+ * pointer.
+ */
+ *((*pend)++) = (PF)func;
+
+#ifdef MTHREAD
+ _unlockexit();
+#endif
+
+ return func;
+
+}
+#endif /* CRTDLL */
diff --git a/private/crt32/misc/perror.c b/private/crt32/misc/perror.c
new file mode 100644
index 000000000..9e41b1c7a
--- /dev/null
+++ b/private/crt32/misc/perror.c
@@ -0,0 +1,78 @@
+/***
+*perror.c - print system error message
+*
+* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines perror() - print system error message
+* System error message are indexed by errno; conforms to XENIX
+* standard, with much compatability with 1983 uniforum draft standard.
+*
+*Revision History:
+* 09-02-83 RN initial version
+* 04-13-87 JCR added const to declaration
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 12-29-87 JCR Multi-thread support
+* 05-31-88 PHG Merged DLL and normal versions
+* 06-03-88 JCR Added <io.h> to so _write_lk evaluates correctly and
+* added (char *)message casts to get rid of warnings
+* 03-15-90 GJF Replace _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h>, removed #include <register.h> and fixed
+* the copyright. Also, cleaned up the formatting a bit.
+* 04-05-90 GJF Added #include <string.h>.
+* 08-14-90 SBM Removed unneeded #include <errmsg.h>
+* 10-04-90 GJF New-style function declarator.
+* 08-26-92 GJF Include unistd.h for POSIX build.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#ifdef _POSIX_
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syserr.h>
+#include <os2dll.h>
+#include <io.h>
+
+/***
+*void perror(message) - print system error message
+*
+*Purpose:
+* prints user's error message, then follows it with ": ", then the system
+* error message, then a newline. All output goes to stderr. If user's
+* message is NULL or a null string, only the system error message is
+* printer. If errno is weird, prints "Unknown error".
+*
+*Entry:
+* const char *message - users message to prefix system error message
+*
+*Exit:
+* Prints message; no return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 perror (
+ REG1 const char *message
+ )
+{
+ REG2 int fh = 2;
+
+ _lock_fh(fh); /* acquire file handle lock */
+
+ if (message && *message)
+ {
+ _write_lk(fh,(char *)message,strlen(message));
+ _write_lk(fh,": ",2);
+ }
+
+ message = _sys_err_msg( errno );
+ _write_lk(fh,(char *)message,strlen(message));
+ _write_lk(fh,"\n",1);
+
+ _unlock_fh(fh); /* release file handle lock */
+}
diff --git a/private/crt32/misc/ppc/chandler.c b/private/crt32/misc/ppc/chandler.c
new file mode 100644
index 000000000..4badd7a1d
--- /dev/null
+++ b/private/crt32/misc/ppc/chandler.c
@@ -0,0 +1,222 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ chandler.c
+
+Abstract:
+
+ This module implements the C specific exception handler that provides
+ structured condition handling for the C language.
+
+Author:
+
+ Modified for PowerPC by Rick Simpson 27-Sep-1993
+
+
+ from MIPS version by David N. Cutler (davec) 11-Sep-1990
+
+Environment:
+
+ Any mode.
+
+Revision History:
+
+ Tom Wood (twood) 1-Nov-1993
+ Use __C_ExecuteExceptionFilter and __C_ExecuteTerminationHandler
+ previously deleted from the MIPS version.
+--*/
+
+#include "nt.h"
+
+
+//
+// Define procedure prototypes for exception filter and termination handler
+// execution routines defined in jmpunwnd.s
+//
+LONG
+__C_ExecuteExceptionFilter (
+ PEXCEPTION_POINTERS ExceptionPointers,
+ EXCEPTION_FILTER ExceptionFilter,
+ ULONG EstablisherFrame
+ );
+VOID
+__C_ExecuteTerminationHandler (
+ BOOLEAN AbnormalTermination,
+ TERMINATION_HANDLER TerminationHandler,
+ ULONG EstablisherFrame
+ );
+
+EXCEPTION_DISPOSITION
+__C_specific_handler (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PVOID EstablisherFrame,
+ IN OUT PCONTEXT ContextRecord,
+ IN OUT PDISPATCHER_CONTEXT DispatcherContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function scans the scope tables associated with the specified
+ procedure and calls exception and termination handlers as necessary.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to an exception record.
+
+ EstablisherFrame - Supplies a pointer to frame of the establisher function.
+
+ ContextRecord - Supplies a pointer to a context record.
+
+ DispatcherContext - Supplies a pointer to the exception dispatcher or
+ unwind dispatcher context.
+
+Return Value:
+
+ If the exception is handled by one of the exception filter routines, then
+ there is no return from this routine and RtlUnwind is called. Otherwise,
+ an exception disposition value of continue execution or continue search is
+ returned.
+
+--*/
+
+{
+
+ ULONG ControlPc;
+ EXCEPTION_FILTER ExceptionFilter;
+ EXCEPTION_POINTERS ExceptionPointers;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG Index;
+ PSCOPE_TABLE ScopeTable;
+ ULONG TargetPc;
+ TERMINATION_HANDLER TerminationHandler;
+ LONG Value;
+
+ //
+ // Get address of where control left the establisher, the address of the
+ // function table entry that describes the function, and the address of
+ // the scope table.
+ //
+
+ ControlPc = DispatcherContext->ControlPc;
+ FunctionEntry = DispatcherContext->FunctionEntry;
+ ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData);
+
+ //
+ // If an unwind is not in progress, then scan the scope table and call
+ // the appropriate exception filter routines. Otherwise, scan the scope
+ // table and call the appropriate termination handlers using the target
+ // PC obtained from the context record.
+ // are called.
+ //
+
+ if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
+
+ //
+ // Scan the scope table and call the appropriate exception filter
+ // routines.
+ //
+
+ ExceptionPointers.ExceptionRecord = ExceptionRecord;
+ ExceptionPointers.ContextRecord = ContextRecord;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) &&
+ (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) {
+
+ //
+ // Call the exception filter routine.
+ //
+
+ ExceptionFilter =
+ (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ Value = __C_ExecuteExceptionFilter(&ExceptionPointers,
+ ExceptionFilter,
+ (ULONG)EstablisherFrame);
+
+ //
+ // If the return value is less than zero, then dismiss the
+ // exception. Otherwise, if the value is greater than zero,
+ // then unwind to the target exception handler. Otherwise,
+ // continue the search for an exception filter.
+ //
+
+ if (Value < 0) {
+ return ExceptionContinueExecution;
+ } else if (Value > 0) {
+ RtlUnwind(EstablisherFrame,
+ (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget,
+ ExceptionRecord,
+ (PVOID)ExceptionRecord->ExceptionCode);
+ }
+ }
+ }
+
+ } else {
+
+ //
+ // Scan the scope table and call the appropriate termination handler
+ // routines.
+ //
+
+ TargetPc = ContextRecord->Iar;
+ for (Index = 0; Index < ScopeTable->Count; Index += 1) {
+ if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) {
+
+ //
+ // If the target PC is within the same scope the control PC
+ // is within, then this is an uplevel goto out of an inner try
+ // scope or a long jump back into a try scope. Terminate the
+ // scan termination handlers.
+ //
+ // N.B. The target PC can be just beyond the end of the scope,
+ // in which case it is a leave from the scope.
+ //
+
+
+ if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
+ (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) {
+ break;
+
+ } else {
+
+ //
+ // If the scope table entry describes an exception filter
+ // and the associated exception handler is the target of
+ // the unwind, then terminate the scan for termination
+ // handlers. Otherwise, if the scope table entry describes
+ // a termination handler, then record the address of the
+ // end of the scope as the new control PC address and call
+ // the termination handler.
+ //
+
+ if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) {
+ if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) {
+ break;
+ }
+
+ } else {
+ DispatcherContext->ControlPc =
+ ScopeTable->ScopeRecord[Index].EndAddress + 4;
+ TerminationHandler =
+ (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress;
+ __C_ExecuteTerminationHandler(TRUE,
+ TerminationHandler,
+ (ULONG)EstablisherFrame);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Continue search for exception or termination handlers.
+ //
+
+ return ExceptionContinueSearch;
+}
diff --git a/private/crt32/misc/ppc/cinitone.s b/private/crt32/misc/ppc/cinitone.s
new file mode 100644
index 000000000..f412234e0
--- /dev/null
+++ b/private/crt32/misc/ppc/cinitone.s
@@ -0,0 +1,41 @@
+// page ,132
+// title cinitone - C Run-Time Initialization for _onexit/atexit
+//
+// cinitone.asm - WIN32 C Run-Time Init for _onexit()/atexit() routines
+//
+// Copyright (c) 1992, Microsoft Corporation. All rights reserved.
+//
+// Purpose:
+// Initialization entry for the _onexit()/atexit() functions.
+// This module adds an entry for _onexitinit() to the initializer table.
+// ONEXIT.C references the dummy variable __c_onexit in order to force
+// the loading of this module.
+//
+// Notes:
+//
+// Revision History:
+// 03-19-92 SKS Module created.
+// 03-24-92 SKS Added MIPS support (NO_UNDERSCORE)
+// 04-30-92 SKS Add "offset FLAT:" to get correct fixups for OMF objs
+// 08-06-92 SKS Revised to use new section names and macros
+//
+// *****************************************************************************
+
+#include "kxppc.h"
+
+ .extern _onexitinit
+
+beginSection(XIC)
+
+ .long _onexitinit
+
+endSection(XIC)
+
+
+ .data
+ .align 2
+
+ .globl __c_onexit
+
+__c_onexit: .long 0
+
diff --git a/private/crt32/misc/ppc/jmpuwind.s b/private/crt32/misc/ppc/jmpuwind.s
new file mode 100644
index 000000000..dcd129f29
--- /dev/null
+++ b/private/crt32/misc/ppc/jmpuwind.s
@@ -0,0 +1,162 @@
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+//
+// Module Name:
+//
+// jmpuwind.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to jump to the runtime
+// time library unwind routine.
+//
+// Author:
+//
+// David N. Cutler (davec) 12-Sep-1990
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Tom Wood (twood) 1-Nov-1993
+// Added __C_ExecuteExceptionFilter and __C_ExecuteTerminationHandler
+// previously deleted from the MIPS version.
+//--
+
+//list(off)
+#include "ksppc.h"
+//list(on)
+ .extern ..RtlUnwind
+
+//
+// Define the call frame for calling the exception filter and termination
+// handler.
+//
+ .struct 0
+CfBackChain: .space 4 // chain to previous call frame
+CfSavedR31: .space 4 // glue-saved register
+CfSavedRtoc: .space 4 // glue-saved register
+ .space 3*4 // remaining part of the frame header
+//++
+//
+// ULONG
+// __C_ExecuteExceptionFilter (
+// PEXCEPTION_POINTERS ExceptionPointers,
+// EXCEPTION_FILTER ExceptionFilter,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function calls the specified exception filter routine with the
+// establisher environment passed in the TOC register.
+//
+// Arguments:
+//
+// ExceptionPointers (r.3) - Supplies a pointer to the exception pointers
+// structure.
+//
+// ExceptionFilter (r.4) - Supplies the address of the exception filter
+// routine.
+//
+// EstablisherFrame (r.5) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// The value returned by the exception filter routine.
+//
+//--
+ SPECIAL_ENTRY(__C_ExecuteExceptionFilter)
+ stw r.31, CfSavedR31 (r.sp) // save r.31 before using it.
+ mtctr r.4 // get ready to call the filter.
+ mflr r.31 // save the link register in r.31.
+ stw r.toc, CfSavedRtoc (r.sp) // save r.toc
+ PROLOGUE_END(__C_ExecuteExceptionFilter)
+ or r.toc,r.5,r.5 // pass the establisher environment in r.toc
+ bctrl // branch and link to the filter.
+ mtlr r.31 // get ready to return
+ lwz r.31, CfSavedR31 (r.sp) // restore r.31
+ lwz r.toc, CfSavedRtoc (r.sp) // restore r.toc
+ SPECIAL_EXIT(__C_ExecuteExceptionFilter)
+
+//++
+//
+// VOID
+// __C_ExecuteTerminationHandler (
+// BOOLEAN AbnormalTermination,
+// TERMINATION_HANDLER TerminationHandler,
+// ULONG EstablisherFrame
+// )
+//
+// Routine Description:
+//
+// This function calls the specified termination handler routine with the
+// establisher environment passed in the TOC register.
+//
+// Arguments:
+//
+// AbnormalTermination (r.3) - Supplies a boolean value that determines
+// whether the termination is abnormal.
+//
+// TerminationHandler (r.4) - Supplies the address of the termination
+// handler routine.
+//
+// EstablisherFrame (r.5) - Supplies the establisher frame pointer.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ SPECIAL_ENTRY(__C_ExecuteTerminationHandler)
+ stw r.31, CfSavedR31 (r.sp) // save r.31 before using it.
+ mtctr r.4 // get ready to call the filter.
+ mflr r.31 // save the link register in r.31.
+ stw r.toc, CfSavedRtoc (r.sp) // save r.toc
+ PROLOGUE_END(__C_ExecuteTerminationHandler)
+ or r.toc,r.5,r.5 // pass the establisher environment in r.toc
+ bctrl // branch and link to the filter.
+ mtlr r.31 // get ready to return
+ lwz r.31, CfSavedR31 (r.sp) // restore r.31
+ lwz r.toc, CfSavedRtoc (r.sp) // restore r.toc
+ SPECIAL_EXIT(__C_ExecuteTerminationHandler)
+
+//++
+//
+// VOID
+// __jump_unwind (
+// IN PVOID EstablishFrame,
+// IN PVOID TargetPc
+// )
+//
+// Routine Description:
+//
+// This function transfer control to unwind. It is used by the MIPS
+// compiler when a goto out of the body or a try statement occurs.
+//
+// Arguments:
+//
+// EstablishFrame (r.3) - Supplies the establisher frame pointer of the
+// target of the unwind.
+//
+// TargetPc (r.4) - Supplies the target instruction address where control
+// is to be transfered to after the unwind operation is complete.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ NESTED_ENTRY (__jump_unwind, STK_MIN_FRAME+8, 0, 0)
+ PROLOGUE_END(__jump_unwind)
+
+ li r.5, 0 // set NULL exception record address
+ li r.6, 0 // set destination return value
+ bl ..RtlUnwind // unwind to specified target
+ .znop ..RtlUnwind
+
+ NESTED_EXIT (__jump_unwind, STK_MIN_FRAME+8, 0, 0)
diff --git a/private/crt32/misc/ppc/longjmp.s b/private/crt32/misc/ppc/longjmp.s
new file mode 100644
index 000000000..d5149f869
--- /dev/null
+++ b/private/crt32/misc/ppc/longjmp.s
@@ -0,0 +1,143 @@
+//++
+//
+// Copyright (c) 1993 IBM Corporation and Microsoft Corporation
+//
+// Module Name:
+//
+// longjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a long
+// jump operation.
+//
+// N.B. This routine conditionally provides UNSAFE handling of longjmp
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an unitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// Rick Simpson 13-Oct-1993
+//
+// based on MIPS version by David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+//list(off)
+#include "ksppc.h"
+//list(on)
+ .extern ..RtlUnwind
+
+//++
+//
+// int
+// longjmp (
+// IN jmp_buf JumpBuffer,
+// IN int ReturnValue
+// )
+//
+// Routine Description:
+//
+// This function performs a long jump to the context specified by the
+// jump buffer.
+//
+// Arguments:
+//
+// JumpBuffer (r.3) - Supplies the address of a jump buffer that contains
+// jump information.
+//
+// ReturnValue (r.4) - Supplies the value that is to be returned to the
+// caller of setjmp().
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY (longjmp)
+
+ cmpwi cr.0, r.4, 0 // check return value for 0
+ lwz r.0, JbType (r.3) // load safe/unsafe switch
+ cmpwi cr.1, r.0, 0 // check for unsafe
+ bne cr.0, Lj10 // branch if not trying to return 0
+ li r.4, 1 // force return value to be non-zero
+Lj10: bne cr.1, ...Lj20 // branch if safe form of setjmp/longjmp
+
+//
+// Provide unsafe handling of longjmp.
+//
+
+ lfd f.14, JbFpr14 (r.3) // reload n-v floating point regs
+ lfd f.15, JbFpr15 (r.3)
+ lfd f.16, JbFpr16 (r.3)
+ lfd f.17, JbFpr17 (r.3)
+ lfd f.18, JbFpr18 (r.3)
+ lfd f.19, JbFpr19 (r.3)
+ lfd f.20, JbFpr20 (r.3)
+ lfd f.21, JbFpr21 (r.3)
+ lfd f.22, JbFpr22 (r.3)
+ lfd f.23, JbFpr23 (r.3)
+ lfd f.24, JbFpr24 (r.3)
+ lfd f.25, JbFpr25 (r.3)
+ lfd f.26, JbFpr26 (r.3)
+ lfd f.27, JbFpr27 (r.3)
+ lfd f.28, JbFpr28 (r.3)
+ lfd f.29, JbFpr29 (r.3)
+ lfd f.30, JbFpr30 (r.3)
+ lfd f.31, JbFpr31 (r.3)
+
+ lwz r.13, JbGpr13 (r.3) // reload n-v general regs
+ lwz r.14, JbGpr14 (r.3)
+ lwz r.15, JbGpr15 (r.3)
+ lwz r.16, JbGpr16 (r.3)
+ lwz r.17, JbGpr17 (r.3)
+ lwz r.18, JbGpr18 (r.3)
+ lwz r.19, JbGpr19 (r.3)
+ lwz r.20, JbGpr20 (r.3)
+ lwz r.21, JbGpr21 (r.3)
+ lwz r.22, JbGpr22 (r.3)
+ lwz r.23, JbGpr23 (r.3)
+ lwz r.24, JbGpr24 (r.3)
+ lwz r.25, JbGpr25 (r.3)
+ lwz r.26, JbGpr26 (r.3)
+ lwz r.27, JbGpr27 (r.3)
+ lwz r.28, JbGpr28 (r.3)
+ lwz r.29, JbGpr29 (r.3)
+ lwz r.30, JbGpr30 (r.3)
+ lwz r.31, JbGpr31 (r.3)
+
+ lwz r.5, JbIar (r.3) // get setjmp return address
+ lwz r.6, JbCr (r.3) // get saved CR
+ mtlr r.5 // return addr -> LR
+ lwz r.1, JbGpr1 (r.3) // restore stack pointer
+ lwz r.2, JbGpr2 (r.3) // restore TOC pointer
+ mtcrf 0xff,r.6 // saved CR -> CR
+ mr r.3, r.4 // return value from longjmp()
+ blr // jump back to setjmp() site
+
+ DUMMY_EXIT (longjmp)
+
+
+//
+// Provide safe handling of longjmp.
+//
+
+ NESTED_ENTRY(.Lj20, STK_MIN_FRAME+8, 0, 0)
+ PROLOGUE_END(.Lj20)
+
+ mr r.6, r.4 // set return value (4th arg)
+ li r.5, 0 // set exception record address (3rd arg)
+ lwz r.4, 4 (r.3) // set target instr address (2nd arg)
+ lwz r.3, 0 (r.3) // set target frame address (1st arg)
+ bl ..RtlUnwind // finish in common code
+ .znop ..RtlUnwind
+
+ NESTED_EXIT(.Lj20, STK_MIN_FRAME+8, 0, 0)
diff --git a/private/crt32/misc/ppc/miscasm.s b/private/crt32/misc/ppc/miscasm.s
new file mode 100644
index 000000000..8fab2f64e
--- /dev/null
+++ b/private/crt32/misc/ppc/miscasm.s
@@ -0,0 +1,273 @@
+//
+// Miscellaneous assembly-language routines and data for
+// PowerPC RTL
+//
+#include "ksppc.h"
+//
+// Copyright 1993 IBM Corporation
+//
+// By Rick Simpson, 17 August 1993
+//
+//-----------------------------------------------------------------------------
+//
+// These routines save and restore only the GPRs and FPRs.
+//
+// Saving and restoring of other non-volatile registers (LR, certain
+// fields of CR) is the responsibility of in-line prologue and epilogue
+// code.
+//
+//-----------------------------------------------------------------------------
+//
+// _savegpr_<n>
+// Inputs:
+// r12 = pointer to END of GPR save area
+// LR = return address to invoking prologue
+// Saves GPR<n> through GPR31 in area preceeding where r12 points
+//
+// _savefpr_<n>
+// Inputs:
+// r1 = pointer to stack frame header
+// LR = return address to invoking prologue
+// Saves FPR<m> through FPR31 in area preceeding stack frame header
+//
+//-----------------------------------------------------------------------------
+//
+// _restgpr_<n>
+// Inputs:
+// r12 = pointer to END of GPR save area
+// LR = return address to invoking prologue
+// Restores GPR<n> through GPR31 from area preceeding where r12 points
+//
+// _restfpr_<m>
+// Inputs:
+// r1 = pointer to stack frame header
+// LR = return address to invoking prologue
+// Restores FPR<m> through FPR31 from area preceeding stack frame header
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+//
+// _savegpr_<n> -- Save GPRs when FPRs are also saved
+//
+// On entry:
+// r12 = address of END of GPR save area
+// LR = return address to prologue
+//
+// Saves GPR<n> through GPR31 in area preceeding where r12 points
+//
+//-----------------------------------------------------------------------------
+
+ FN_TABLE(_savegpr_13,0,1)
+ DUMMY_ENTRY(_savegpr_13)
+ .set _savegpr_13.body,.._savegpr_13-1
+ stw r13, -4*(32-13)(r12)
+ DUMMY_ENTRY(_savegpr_14)
+ stw r14, -4*(32-14)(r12)
+ DUMMY_ENTRY(_savegpr_15)
+ stw r15, -4*(32-15)(r12)
+ DUMMY_ENTRY(_savegpr_16)
+ stw r16, -4*(32-16)(r12)
+ DUMMY_ENTRY(_savegpr_17)
+ stw r17, -4*(32-17)(r12)
+ DUMMY_ENTRY(_savegpr_18)
+ stw r18, -4*(32-18)(r12)
+ DUMMY_ENTRY(_savegpr_19)
+ stw r19, -4*(32-19)(r12)
+ DUMMY_ENTRY(_savegpr_20)
+ stw r20, -4*(32-20)(r12)
+ DUMMY_ENTRY(_savegpr_21)
+ stw r21, -4*(32-21)(r12)
+ DUMMY_ENTRY(_savegpr_22)
+ stw r22, -4*(32-22)(r12)
+ DUMMY_ENTRY(_savegpr_23)
+ stw r23, -4*(32-23)(r12)
+ DUMMY_ENTRY(_savegpr_24)
+ stw r24, -4*(32-24)(r12)
+ DUMMY_ENTRY(_savegpr_25)
+ stw r25, -4*(32-25)(r12)
+ DUMMY_ENTRY(_savegpr_26)
+ stw r26, -4*(32-26)(r12)
+ DUMMY_ENTRY(_savegpr_27)
+ stw r27, -4*(32-27)(r12)
+ DUMMY_ENTRY(_savegpr_28)
+ stw r28, -4*(32-28)(r12)
+ DUMMY_ENTRY(_savegpr_29)
+ stw r29, -4*(32-29)(r12)
+ DUMMY_ENTRY(_savegpr_30)
+ stw r30, -4*(32-30)(r12)
+ DUMMY_ENTRY(_savegpr_31)
+ stw r31, -4*(32-31)(r12)
+ SPECIAL_EXIT(_savegpr_13)
+
+//-----------------------------------------------------------------------------
+//
+// _savefpr_<n> -- Saves FPRs
+//
+// On entry:
+// r1 = pointer to stack frame header
+// LR = return address to prologue
+//
+// Saves FPR<n> through FPR31 in area preceeding stack frame header
+//
+//-----------------------------------------------------------------------------
+
+ FN_TABLE(_savefpr_14,0,1)
+ DUMMY_ENTRY(_savefpr_14)
+ .set _savefpr_14.body,.._savefpr_14-1
+ stfd f14, -8*(32-14)(r1)
+ DUMMY_ENTRY(_savefpr_15)
+ stfd f15, -8*(32-15)(r1)
+ DUMMY_ENTRY(_savefpr_16)
+ stfd f16, -8*(32-16)(r1)
+ DUMMY_ENTRY(_savefpr_17)
+ stfd f17, -8*(32-17)(r1)
+ DUMMY_ENTRY(_savefpr_18)
+ stfd f18, -8*(32-18)(r1)
+ DUMMY_ENTRY(_savefpr_19)
+ stfd f19, -8*(32-19)(r1)
+ DUMMY_ENTRY(_savefpr_20)
+ stfd f20, -8*(32-20)(r1)
+ DUMMY_ENTRY(_savefpr_21)
+ stfd f21, -8*(32-21)(r1)
+ DUMMY_ENTRY(_savefpr_22)
+ stfd f22, -8*(32-22)(r1)
+ DUMMY_ENTRY(_savefpr_23)
+ stfd f23, -8*(32-23)(r1)
+ DUMMY_ENTRY(_savefpr_24)
+ stfd f24, -8*(32-24)(r1)
+ DUMMY_ENTRY(_savefpr_25)
+ stfd f25, -8*(32-25)(r1)
+ DUMMY_ENTRY(_savefpr_26)
+ stfd f26, -8*(32-26)(r1)
+ DUMMY_ENTRY(_savefpr_27)
+ stfd f27, -8*(32-27)(r1)
+ DUMMY_ENTRY(_savefpr_28)
+ stfd f28, -8*(32-28)(r1)
+ DUMMY_ENTRY(_savefpr_29)
+ stfd f29, -8*(32-29)(r1)
+ DUMMY_ENTRY(_savefpr_30)
+ stfd f30, -8*(32-30)(r1)
+ DUMMY_ENTRY(_savefpr_31)
+ stfd f31, -8*(32-31)(r1)
+ SPECIAL_EXIT(_savefpr_14)
+
+//-----------------------------------------------------------------------------
+//
+// _restgpr_<n> -- Restore GPRs when FPRs are also restored
+//
+// On entry:
+// r12 = address of END of GPR save area
+// LR = return address
+//
+// Restores GPR<n> through GPR31 from area preceeding where r12 points
+//
+//-----------------------------------------------------------------------------
+
+ FN_TABLE(_restgpr_13,0,2)
+ DUMMY_ENTRY(_restgpr_13)
+ .set _restgpr_13.body,.._restgpr_13-2
+ lwz r13, -4*(32-13)(r12)
+ DUMMY_ENTRY(_restgpr_14)
+ lwz r14, -4*(32-14)(r12)
+ DUMMY_ENTRY(_restgpr_15)
+ lwz r15, -4*(32-15)(r12)
+ DUMMY_ENTRY(_restgpr_16)
+ lwz r16, -4*(32-16)(r12)
+ DUMMY_ENTRY(_restgpr_17)
+ lwz r17, -4*(32-17)(r12)
+ DUMMY_ENTRY(_restgpr_18)
+ lwz r18, -4*(32-18)(r12)
+ DUMMY_ENTRY(_restgpr_19)
+ lwz r19, -4*(32-19)(r12)
+ DUMMY_ENTRY(_restgpr_20)
+ lwz r20, -4*(32-20)(r12)
+ DUMMY_ENTRY(_restgpr_21)
+ lwz r21, -4*(32-21)(r12)
+ DUMMY_ENTRY(_restgpr_22)
+ lwz r22, -4*(32-22)(r12)
+ DUMMY_ENTRY(_restgpr_23)
+ lwz r23, -4*(32-23)(r12)
+ DUMMY_ENTRY(_restgpr_24)
+ lwz r24, -4*(32-24)(r12)
+ DUMMY_ENTRY(_restgpr_25)
+ lwz r25, -4*(32-25)(r12)
+ DUMMY_ENTRY(_restgpr_26)
+ lwz r26, -4*(32-26)(r12)
+ DUMMY_ENTRY(_restgpr_27)
+ lwz r27, -4*(32-27)(r12)
+ DUMMY_ENTRY(_restgpr_28)
+ lwz r28, -4*(32-28)(r12)
+ DUMMY_ENTRY(_restgpr_29)
+ lwz r29, -4*(32-29)(r12)
+ DUMMY_ENTRY(_restgpr_30)
+ lwz r30, -4*(32-30)(r12)
+ DUMMY_ENTRY(_restgpr_31)
+ lwz r31, -4*(32-31)(r12)
+ SPECIAL_EXIT(_restgpr_13)
+
+//-----------------------------------------------------------------------------
+//
+// _restfpr_<n> -- Restores FPRs
+//
+// On entry:
+// r1 = pointer to stack frame header
+// LR = return address
+//
+// Restores FPR<n> through FPR31 from area preceeding stack frame header
+//
+//-----------------------------------------------------------------------------
+
+ FN_TABLE(_restfpr_14,0,2)
+ DUMMY_ENTRY(_restfpr_14)
+ .set _restfpr_14.body,.._restfpr_14-2
+ lfd f14, -8*(32-14)(r1)
+ DUMMY_ENTRY(_restfpr_15)
+ lfd f15, -8*(32-15)(r1)
+ DUMMY_ENTRY(_restfpr_16)
+ lfd f16, -8*(32-16)(r1)
+ DUMMY_ENTRY(_restfpr_17)
+ lfd f17, -8*(32-17)(r1)
+ DUMMY_ENTRY(_restfpr_18)
+ lfd f18, -8*(32-18)(r1)
+ DUMMY_ENTRY(_restfpr_19)
+ lfd f19, -8*(32-19)(r1)
+ DUMMY_ENTRY(_restfpr_20)
+ lfd f20, -8*(32-20)(r1)
+ DUMMY_ENTRY(_restfpr_21)
+ lfd f21, -8*(32-21)(r1)
+ DUMMY_ENTRY(_restfpr_22)
+ lfd f22, -8*(32-22)(r1)
+ DUMMY_ENTRY(_restfpr_23)
+ lfd f23, -8*(32-23)(r1)
+ DUMMY_ENTRY(_restfpr_24)
+ lfd f24, -8*(32-24)(r1)
+ DUMMY_ENTRY(_restfpr_25)
+ lfd f25, -8*(32-25)(r1)
+ DUMMY_ENTRY(_restfpr_26)
+ lfd f26, -8*(32-26)(r1)
+ DUMMY_ENTRY(_restfpr_27)
+ lfd f27, -8*(32-27)(r1)
+ DUMMY_ENTRY(_restfpr_28)
+ lfd f28, -8*(32-28)(r1)
+ DUMMY_ENTRY(_restfpr_29)
+ lfd f29, -8*(32-29)(r1)
+ DUMMY_ENTRY(_restfpr_30)
+ lfd f30, -8*(32-30)(r1)
+ DUMMY_ENTRY(_restfpr_31)
+ lfd f31, -8*(32-31)(r1)
+ SPECIAL_EXIT(_restfpr_14)
+
+//
+// This is a copy of the function table entries for the millicode. It's
+// used with the PPCKD_SYMBOL_SEARCH mechanism in vunwind.c to allow
+// for older versions of miscasm.obj.
+//
+
+ .reldata
+ .globl _millicode_table
+_millicode_table:
+ .long .._savegpr_13, _savegpr_13.end, 0, 1, .._savegpr_13
+ .long .._savefpr_14, _savefpr_14.end, 0, 1, .._savefpr_14
+ .long .._restgpr_13, _restgpr_13.end, 0, 2, .._restgpr_13
+ .long .._restfpr_14, _restfpr_14.end, 0, 2, .._restfpr_14
diff --git a/private/crt32/misc/ppc/setjmp.s b/private/crt32/misc/ppc/setjmp.s
new file mode 100644
index 000000000..65b58adf5
--- /dev/null
+++ b/private/crt32/misc/ppc/setjmp.s
@@ -0,0 +1,138 @@
+//++
+//
+// Copyright (c) 1993 IBM Corporation and Microsoft Corporation
+//
+// Module Name:
+//
+// setjmp.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to perform a setjmp.
+//
+// N.B. This module conditionally provides UNSAFE handling of setjmp and
+// which is NOT integrated with structured exception handling. The
+// determination is made based on whether an uninitialized variable
+// has been set to a nonzero value.
+//
+// Author:
+//
+// Rick Simpson 13-Oct-1993
+//
+// based on MIPS version by David N. Cutler (davec) 7-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+//list(off)
+#include "ksppc.h"
+//list(on)
+
+//
+// Define variable that will cause setjmp/longjmp to be safe or unsafe with
+// respect to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .comm _setjmpexused , 4
+
+//++
+//
+// int
+// setjmp (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function saved the current nonvolatile register state in the
+// specified jump buffer and returns a function vlaue of zero.
+//
+// Arguments:
+//
+// JumpBuffer (r.3) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+ LEAF_ENTRY (setjmp)
+
+//
+// If _setjmpexused is non-NULL, it contains the entry point address
+// of the safe version of setjmp, ..setjmpex. We branch thru the CTR
+// using this variable rather than branching directly to the entry point
+// to avoid assembling a hard reference to ..setjmpex into this code.
+// CTR is used to avoid killing caller's LR.
+//
+
+ lwz r.4, [toc] _setjmpexused (r.toc) // get address of switch variable
+ lwz r.0, 0 (r.4) // get value of switch variable
+ cmpwi r.0, 0 // see if switch is NULL
+ mtctr r.0 // if switch is non-NULL,
+ bnectr // branch to safe setjmp() routine
+
+//
+// Provide unsafe handling of setjmp.
+//
+
+ mflr r.0 // fetch incoming LR
+ mfcr r.4 // fetch incoming CR
+
+ stfd f.14, JbFpr14 (r.3) // save n-v floating point regs
+ stfd f.15, JbFpr15 (r.3)
+ stfd f.16, JbFpr16 (r.3)
+ stfd f.17, JbFpr17 (r.3)
+ stfd f.18, JbFpr18 (r.3)
+ stfd f.19, JbFpr19 (r.3)
+ stfd f.20, JbFpr20 (r.3)
+ stfd f.21, JbFpr21 (r.3)
+ stfd f.22, JbFpr22 (r.3)
+ stfd f.23, JbFpr23 (r.3)
+ stfd f.24, JbFpr24 (r.3)
+ stfd f.25, JbFpr25 (r.3)
+ stfd f.26, JbFpr26 (r.3)
+ stfd f.27, JbFpr27 (r.3)
+ stfd f.28, JbFpr28 (r.3)
+ stfd f.29, JbFpr29 (r.3)
+ stfd f.30, JbFpr30 (r.3)
+ stfd f.31, JbFpr31 (r.3)
+
+ stw r.13, JbGpr13 (r.3) // save n-v general regs
+ stw r.14, JbGpr14 (r.3)
+ stw r.15, JbGpr15 (r.3)
+ stw r.16, JbGpr16 (r.3)
+ stw r.17, JbGpr17 (r.3)
+ stw r.18, JbGpr18 (r.3)
+ stw r.19, JbGpr19 (r.3)
+ stw r.20, JbGpr20 (r.3)
+ stw r.21, JbGpr21 (r.3)
+ stw r.22, JbGpr22 (r.3)
+ stw r.23, JbGpr23 (r.3)
+ stw r.24, JbGpr24 (r.3)
+ stw r.25, JbGpr25 (r.3)
+ stw r.26, JbGpr26 (r.3)
+ stw r.27, JbGpr27 (r.3)
+ stw r.28, JbGpr28 (r.3)
+ stw r.29, JbGpr29 (r.3)
+ stw r.30, JbGpr30 (r.3)
+ stw r.31, JbGpr31 (r.3)
+
+ stw r.0, JbIar (r.3) // setjmp return address
+ stw r.4, JbCr (r.3) // save CR (n-v part)
+ stw r.sp, JbGpr1 (r.3) // save stack pointer
+ stw r.toc, JbGpr2 (r.3) // save TOC pointer
+ li r.0, 0
+ stw r.0, JbType (r.3) // clean safe setjmp flag
+
+ li r.3, 0 // set return value
+ LEAF_EXIT (setjmp) // return
+
diff --git a/private/crt32/misc/ppc/setjmpex.s b/private/crt32/misc/ppc/setjmpex.s
new file mode 100644
index 000000000..063f8fa68
--- /dev/null
+++ b/private/crt32/misc/ppc/setjmpex.s
@@ -0,0 +1,194 @@
+//++
+//
+// Copyright (c) 1993 IBM Corporation and Microsoft Corporation
+//
+// Module Name:
+//
+// setjmpex.s
+//
+// Abstract:
+//
+// This module implements the MIPS specific routine to provide SAFE
+// handling of setjmp/longjmp with respect to structured exception
+// handling.
+//
+// Author:
+//
+// Rick Simpson 13-Oct-1993
+//
+// based on MIPS version by David N. Cutler (davec) 2-Apr-1993
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+// Tom Wood 23-Aug-1994
+// Add stack limit parameters to RtlVirtualUnwind.
+//--
+
+//list(off)
+#include "ksppc.h"
+//list(on)
+ .extern ..RtlLookupFunctionEntry
+ .extern ..RtlVirtualUnwind
+
+//
+// Define variable that will cause setjmp/longjmp to be safe with respect
+// to structured exception handling.
+//
+
+ .globl _setjmpexused
+ .data
+_setjmpexused:
+ .long .._setjmpex // set address of safe setjmp routine
+
+//++
+//
+// int
+// _setjmpex (
+// IN jmp_buf JumpBuffer
+// )
+//
+// Routine Description:
+//
+// This function transfers control to the actual setjmp routine.
+//
+// Arguments:
+//
+// JumpBuffer (r.3) - Supplies the address of a jump buffer to store the
+// jump information.
+//
+// Return Value:
+//
+// A value of zero is returned.
+//
+//--
+
+// Stack frame definition:
+
+ .struct 0
+SjBackChain: .space 4 // chain to previous stack frame
+ .space 5*4 // rest of standard stack frame header
+
+ .space 8*4 // standard outgoing arg area
+
+ .align 3 // ensure 8-byte boundary
+SjCtxt: .space ContextFrameLength // context frame
+
+SjFl: .space 4 // in function flag variable
+
+ .align 3 // ensure that overall length
+ // will be a multiple of 8
+SjReturnAddr: .space 4 // space for saved LR (prologue will
+ // store it here)
+ .space 4 // space for saved r.31
+SetjmpFrameLength:
+
+
+
+ NESTED_ENTRY (_setjmpex,SetjmpFrameLength,1,0)
+
+ PROLOGUE_END (_setjmpex)
+
+//
+// Save the nonvolatile machine state in the context record
+//
+
+ // skip Fprs as all we are really trying to do here is prime the
+ // pump for RtlVirtualUnwind.
+
+ stw r.13, CxGpr13 + SjCtxt (r.sp) // save n-v general regs
+ stw r.14, CxGpr14 + SjCtxt (r.sp)
+ stw r.15, CxGpr15 + SjCtxt (r.sp)
+ stw r.16, CxGpr16 + SjCtxt (r.sp)
+ stw r.17, CxGpr17 + SjCtxt (r.sp)
+ stw r.18, CxGpr18 + SjCtxt (r.sp)
+ stw r.19, CxGpr19 + SjCtxt (r.sp)
+ stw r.20, CxGpr20 + SjCtxt (r.sp)
+ stw r.21, CxGpr21 + SjCtxt (r.sp)
+ stw r.22, CxGpr22 + SjCtxt (r.sp)
+ stw r.23, CxGpr23 + SjCtxt (r.sp)
+ stw r.24, CxGpr24 + SjCtxt (r.sp)
+ stw r.25, CxGpr25 + SjCtxt (r.sp)
+ stw r.26, CxGpr26 + SjCtxt (r.sp)
+ stw r.27, CxGpr27 + SjCtxt (r.sp)
+ stw r.28, CxGpr28 + SjCtxt (r.sp)
+ stw r.29, CxGpr29 + SjCtxt (r.sp)
+ stw r.30, CxGpr30 + SjCtxt (r.sp)
+ stw r.31, CxGpr31 + SjCtxt (r.sp)
+
+ mr r.31, r.3 // save incoming jump buffer pointer
+
+ lwz r.3, SjReturnAddr (r.sp) // pick up return addr to caller
+ la r.0, SetjmpFrameLength (r.sp) // save caller's stack frame pointer
+ stw r.0, CxGpr1 + SjCtxt (r.sp)
+ stw r.3, CxIar + SjCtxt (r.sp) // save resume addr in context
+ stw r.3, 4 (r.31) // save resume addr in 2nd word of jmpbuf
+ stw r.sp, JbType (r.31) // set "safe setjmp" flag in jump buffer
+
+//
+// Perform unwind to determine the virtual frame pointer of the caller.
+//
+ subi r.3, r.3, 4 // compute control PC address
+ bl ..RtlLookupFunctionEntry // lookup function table address
+ .znop ..RtlLookupFunctionEntry
+
+ mr r.4, r.3 // set returned value as 2nd arg
+ lwz r.3, SjReturnAddr (r.sp) // pick up return address again
+ la r.5, SjCtxt (r.sp) // context record addr is 3rd arg
+ la r.6, SjFl (r.sp) // addr of in-func flag is 4th arg
+ subi r.3, r.3, 4 // compute control PC address as 1st arg
+ mr r.7, r.31 // addr of 1st word of jmpbuf is 5th arg
+ // (virt frame pointer will be stored here)
+ li r.8, 0 // ctxt pointers (NULL) is 6th arg
+ li r.9, 0 // low stack limit is 7th arg
+ li r.10, -1 // high stack limit is 8th arg
+ bl ..RtlVirtualUnwind // compute virtual frame pointer value
+ .znop ..RtlVirtualUnwind
+
+//
+// If we were called via a thunk the Establisher Frame derived by
+// RtlVirtualUnwind will be equal to the current stack frame. If
+// this is the case we need to unwind one more level, also, the
+// ControlPc returned by RtlVirtualUnwind (+4) should be used as
+// the resume address.
+//
+// Note: this requirement will go away if we adopt the glue proposal
+// that returns directly to the caller (caller reloades toc).
+// (plj 3/26/94)
+
+ lwz r.7, 0(r.31) // Establisher Frame
+ addi r.8, r.sp, SetjmpFrameLength // caller's sp
+ cmplw r.7, r.8
+ bne SjDone
+
+ // Save returned value (+4) as resume address in jump buffer
+
+ addi r.8, r.3, 4
+ stw r.8, 4(r.31)
+
+ // Unwind one more level to get the "real" establisher frame.
+
+ bl ..RtlLookupFunctionEntry // lookup function table address
+ .znop ..RtlLookupFunctionEntry
+
+ mr r.4, r.3 // set returned value as 2nd arg
+ lwz r.3, 4(r.31) // pick up ControlPc again
+ la r.5, SjCtxt(r.sp) // &context record
+ la r.6, SjFl(r.sp) // addr of in-func flag
+ mr r.7, r.31 // & 1st word of jmpbuf
+ li r.8, 0 // ctxt pointers (NULL)
+ li r.9, 0 // low stack limit
+ li r.10, -1 // high stack limit
+ subi r.3, r.3, 4 // unadjust ControlPc
+ bl ..RtlVirtualUnwind // compute & frame pointer
+ .znop ..RtlVirtualUnwind
+//
+// Set return value, restore registers, deallocate stack frame, and return.
+//
+
+SjDone:
+ li r.3, 0 // set return value of 0
+ NESTED_EXIT (_setjmpex,SetjmpFrameLength,1,0)
diff --git a/private/crt32/misc/ppc/sources b/private/crt32/misc/ppc/sources
new file mode 100644
index 000000000..520ce611c
--- /dev/null
+++ b/private/crt32/misc/ppc/sources
@@ -0,0 +1,6 @@
+PPC_SOURCES=ppc\chandler.c \
+ ppc\setjmp.s \
+ ppc\setjmpex.s \
+ ppc\longjmp.s \
+ ppc\jmpuwind.s \
+ ppc\miscasm.s
diff --git a/private/crt32/misc/purevirt.c b/private/crt32/misc/purevirt.c
new file mode 100644
index 000000000..14743f517
--- /dev/null
+++ b/private/crt32/misc/purevirt.c
@@ -0,0 +1,42 @@
+/***
+*purevirt.c - stub to trap pure virtual function calls
+*
+* Copyright (c) 1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _purecall() -
+*
+*Revision History:
+* 09-30-92 GJF Module created
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <internal.h>
+#include <rterr.h>
+
+/***
+*void _purecall(void) -
+*
+*Purpose:
+*
+*Entry:
+* No arguments
+*
+*Exit:
+* Never returns
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 _purecall(
+ void
+ )
+{
+ _amsg_exit(_RT_PUREVIRT);
+}
+
+#endif
diff --git a/private/crt32/misc/putenv.c b/private/crt32/misc/putenv.c
new file mode 100644
index 000000000..0e74fcbb5
--- /dev/null
+++ b/private/crt32/misc/putenv.c
@@ -0,0 +1,453 @@
+/***
+*putenv.c - put an environment variable into the environment
+*
+* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _putenv() - adds a new variable to environment; does not
+* change global environment, only the process' environment.
+*
+*Revision History:
+* 08-08-84 RN initial version
+* 02-23-88 SKS check for environment containing only the NULL string
+* 05-31-88 PHG Merged DLL and normal versions
+* 07-14-88 JCR Much simplified since (1) __setenvp always uses heap, and
+* (2) envp array and env strings are in seperate heap blocks
+* 07-03-89 PHG Now "option=" string removes string from environment
+* 08-17-89 GJF Removed _NEAR_, _LOAD_DS and fixed indents.
+* 09-14-89 KRS Don't give error if 'option' not defined in "option=".
+* 11-20-89 GJF Added const to arg type. Also, fixed copyright.
+* 03-15-90 GJF Made the calling type _CALLTYPE1, added #include
+* <cruntime.h> and removed #include <register.h>.
+* 04-05-90 GJF Made findenv() _CALLTYPE4.
+* 04-26-90 JCR Bug fix if environ is NULL (stubbed out _setenvp)
+* 07-25-90 SBM Removed redundant include (stdio.h)
+* 10-04-90 GJF New-style function declarators.
+* 01-21-91 GJF ANSI naming.
+* 02-06-91 SRW Added _WIN32_ conditional for SetEnvironmentVariable
+* 02-18-91 SRW Changed _WIN32_ conditional for SetEnvironmentVariable
+* to be in addition to old logic instead of replacement
+* 04-23-92 GJF Made findenv insensitive to the case of name for Win32.
+* Also added support for 'current drive' environment
+* strings in Win32.
+* 04-29-92 GJF Repackaged so that _putenv_lk could be easily added for
+* for Win32.
+* 05-05-92 DJM POSIX not supported.
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <internal.h>
+#include <os2dll.h>
+#include <memory.h>
+#include <oscalls.h>
+
+static int _CALLTYPE4 findenv(const char *name, int len);
+
+
+#ifdef _CRUISER_
+
+/***
+*int _putenv(option) - add/replace/remove variable in environment
+*
+*Purpose:
+* option should be of the form "option=value". If a string with the
+* given option part already exists, it is replaced with the given
+* string; otherwise the given string is added to the environment.
+* If the string is of the form "option=", then the string is
+* removed from the environment, if it exists. If the string has
+* no equals sign, error is returned.
+*
+*Entry:
+* char *option - option string to set in the environment list.
+* should be of the form "option=value".
+*
+*Exit:
+* returns 0 if OK, -1 if fails.
+*
+*Exceptions:
+*
+*Warning:
+* This code will not work if variables are removed from the
+* environment by deleting them from environ[]. Use _putenv("option=")
+* to remove a variable.
+*
+*******************************************************************************/
+
+int _CALLTYPE1 _putenv (
+ REG3 const char *option
+ )
+{
+ REG1 char **env;
+ REG4 const char *equal;
+ REG2 int ix;
+ int remove; /* 1 means remove string from environment */
+
+ if (!option)
+ return(-1);
+
+ _mlock( _ENV_LOCK );
+
+ /* find the equal sign to delimit the name being searched for.
+ * If no equal sign, then return error
+ */
+
+ for (equal = option; *equal != '='; equal++)
+ if (*equal == '\0')
+ goto unlock_error;
+
+ /* see if removing or adding */
+ remove = (equal[1] == '\0');
+
+ /* see if _environ array exists */
+ if (_environ == NULL) {
+ if (remove)
+ goto unlock_good;
+ else {
+ /* get an array and init it to NULL */
+ if ( (_environ = malloc(sizeof(void *))) == NULL)
+ goto unlock_error;
+ *_environ = NULL;
+ }
+ }
+
+ /* init env pointer */
+
+ env = _environ;
+
+ /* See if the string is already in the environment */
+
+ ix = findenv(option, equal - option);
+
+ if ((ix >= 0) && (*env != NULL)) {
+ /* String is already in the environment -- overwrite/remove it.
+ */
+ if (remove) {
+ /* removing -- move all the later strings up */
+ for ( ; env[ix] != NULL; ++ix) {
+ env[ix] = env[ix+1];
+ }
+
+ /* shrink the environment memory block
+ (ix now has number of strings, including NULL) --
+ this realloc probably can't fail, since we're
+ shrinking a mem block, but we're careful anyway. */
+ if (env = (char **) realloc(env, ix * sizeof(char *)))
+ _environ = env;
+ }
+ else {
+ /* replace the option */
+ env[ix] = (char *) option;
+ }
+ }
+ else {
+ /* String is NOT in the environment */
+
+ if (!remove) { /* can't remove something that's not there */
+
+ /* Grow vector table by one */
+ if (ix < 0)
+ ix = -ix; /* ix = length of environ table */
+
+ if (!(env = (char **)realloc(env, sizeof(char *) * (ix + 2))))
+ goto unlock_error;
+
+ env[ix] = (char *)option;
+ env[ix + 1] = NULL;
+ _environ = env;
+ }
+ }
+
+unlock_good:
+ _munlock( _ENV_LOCK );
+ return(0);
+
+unlock_error:
+ _munlock( _ENV_LOCK );
+ return -1;
+}
+
+
+/***
+*int findenv(name, len) - [STATIC]
+*
+*Purpose:
+* Scan for the given string within the environment
+*
+*Entry:
+*
+*Exit:
+* Returns the offset in "environ[]" of the given variable
+* Returns the negative of the length of environ[] if not found.
+* Returns 0 if the environment is empty.
+*
+* [NOTE: That a 0 return can mean that the environment is empty
+* or that the string was found as the first entry in the array.]
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static int _CALLTYPE4 findenv (
+ const char *name,
+ int len
+ )
+{
+ REG4 char **env = _environ;
+ REG2 const char *nm;
+ REG1 char *envname;
+ REG3 int l;
+
+
+ while (envname = *env) {
+ nm = name;
+ l = len;
+ while (l && *envname++ == *nm++)
+ l--;
+
+ if (l == 0 && ( *envname == '=' || !*envname ) )
+ return(env - _environ);
+ env++;
+ }
+
+ return(-(env - _environ));
+
+}
+
+#else /* _CRUISER_ */
+
+#ifdef _WIN32_
+
+/***
+*int _putenv(option) - add/replace/remove variable in environment
+*
+*Purpose:
+* option should be of the form "option=value". If a string with the
+* given option part already exists, it is replaced with the given
+* string; otherwise the given string is added to the environment.
+* If the string is of the form "option=", then the string is
+* removed from the environment, if it exists. If the string has
+* no equals sign, error is returned.
+*
+*Entry:
+* char *option - option string to set in the environment list.
+* should be of the form "option=value".
+*
+*Exit:
+* returns 0 if OK, -1 if fails.
+*
+*Exceptions:
+*
+*Warning:
+* This code will not work if variables are removed from the
+* environment by deleting them from environ[]. Use _putenv("option=")
+* to remove a variable.
+*
+*******************************************************************************/
+
+#ifdef MTHREAD
+
+int _CALLTYPE1 _putenv (
+ const char *option
+ )
+{
+ int retval;
+
+ _mlock(_ENV_LOCK);
+
+ retval = _putenv_lk(option);
+
+ _munlock(_ENV_LOCK);
+
+ return retval;
+}
+
+int _CALLTYPE1 _putenv_lk (
+ const char *option
+ )
+
+#else /* ndef MTHREAD */
+
+int _CALLTYPE1 _putenv (
+ const char *option
+ )
+
+#endif /* MTHREAD */
+
+{
+ char **env;
+ const char *equal;
+ char *name, *value;
+ int ix;
+ int remove; /* 1 means remove string from environment */
+
+ /* check that the option string is valid and find the equal sign
+ */
+ if ( (option == NULL) || ((equal = strchr(option, '=')) == NULL) )
+ return(-1);
+
+ /* check for the special case of '=' being the very first character
+ * of option. though the use of '=' in an environment variable name
+ * is documented as being illegal, the 'current directory' strings
+ * all look like this:
+ *
+ * =<Drive Letter>:=<Drive Letter><fully qualified path>
+ *
+ * handle this by setting the equal pointer to point to the second
+ * '=' if it exists. Otherwise, handle as before.
+ */
+ if ( option == equal )
+ if ( (equal = strchr(option + 1, '=')) == NULL )
+ equal = option;
+
+ /* if the character following '=' is null, we are removing the
+ * the environment variable. Otherwise, we are adding or updating
+ * an environment variable.
+ */
+ remove = (*(equal + 1) == '\0');
+
+ /* see if _environ array exists */
+ if (_environ == NULL) {
+ if ( remove )
+ return 0;
+ else {
+ /* get an array and init it to NULL */
+ if ( (_environ = malloc(sizeof(void *))) == NULL)
+ return -1;
+ *_environ = NULL;
+ }
+ }
+
+ /* init env pointer */
+
+ env = _environ;
+
+ /* See if the string is already in the environment */
+
+ ix = findenv(option, equal - option);
+
+ if ((ix >= 0) && (*env != NULL)) {
+ /* String is already in the environment -- overwrite/remove it.
+ */
+ if (remove) {
+ /* removing -- move all the later strings up */
+ for ( ; env[ix] != NULL; ++ix) {
+ env[ix] = env[ix+1];
+ }
+
+ /* shrink the environment memory block
+ (ix now has number of strings, including NULL) --
+ this realloc probably can't fail, since we're
+ shrinking a mem block, but we're careful anyway. */
+ if (env = (char **) realloc(env, ix * sizeof(char *)))
+ _environ = env;
+ }
+ else {
+ /* replace the option */
+ env[ix] = (char *) option;
+ }
+ }
+ else {
+ /*
+ * String is NOT in the environment
+ */
+ if ( !remove ) {
+
+ /*
+ * Append the string to the environ table. Note that
+ * table must be grown to do this.
+ */
+ if (ix < 0)
+ ix = -ix; /* ix = length of environ table */
+
+ if ( (env = (char **)realloc(env, sizeof(char *) *
+ (ix + 2))) == NULL )
+ return -1;
+
+ env[ix] = (char *)option;
+ env[ix + 1] = NULL;
+ _environ = env;
+ }
+ else
+ /*
+ * We are asked to remove an environment var that
+ * isn't there...just return success
+ */
+ return 0;
+ }
+
+ /*
+ * Update the real environment. Don't give an error if this fails
+ * since the failure will not affect the user unless he/she is making
+ * direct API calls.
+ */
+ if ( (name = malloc(strlen(option) + 2)) != NULL ) {
+ strcpy(name, option);
+ value = name + (equal - option);
+ *value++ = '\0';
+ SetEnvironmentVariable(name, remove ? NULL : value);
+ free(name);
+ }
+
+ return 0;
+}
+
+
+/***
+*int findenv(name, len) - [STATIC]
+*
+*Purpose:
+* Scan for the given string within the environment
+*
+*Entry:
+*
+*Exit:
+* Returns the offset in "environ[]" of the given variable
+* Returns the negative of the length of environ[] if not found.
+* Returns 0 if the environment is empty.
+*
+* [NOTE: That a 0 return can mean that the environment is empty
+* or that the string was found as the first entry in the array.]
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static int _CALLTYPE4 findenv (
+ const char *name,
+ int len
+ )
+{
+ char **env;
+
+ for ( env = _environ ; *env != NULL ; env++ ) {
+ /*
+ * See if first len characters match, up to case
+ */
+ if ( _strnicmp(name, *env, len) == 0 )
+ /*
+ * the next character of the environment string must
+ * be an '=' or a '\0'
+ */
+ if ( (*env)[len] == '=' || (*env)[len] == '\0' )
+ return(env - _environ);
+//
+// We cannot break here since findenv must report the total number of strings.
+// else
+// break;
+ }
+
+ return(-(env - _environ));
+}
+
+
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
+
+#endif /* _POSIX_ */
diff --git a/private/crt32/misc/qsort.c b/private/crt32/misc/qsort.c
new file mode 100644
index 000000000..30e15e6fd
--- /dev/null
+++ b/private/crt32/misc/qsort.c
@@ -0,0 +1,329 @@
+/***
+*qsort.c - quicksort algorithm; qsort() library function for sorting arrays
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* To implement the qsort() routine for sorting arrays.
+*
+*Revision History:
+* 06-22-84 RN author
+* 03-25-85 RN added pre-check for elements already in order to
+* eliminate worst-case behavior.
+* 05-18-86 TC changed to recurse on the smallest piece to avoid
+* piece. unneccesary stack usage, and to iterate on
+* largest
+* 01-09-87 BCM fixed huge-array case where (num-1) * wid computation
+* was overflowing (large/compact models only)
+* 06-13-89 PHG made more efficient, many more comments, removed
+* recursion
+* 10-30-89 JCR Added _cdecl to prototypes
+* 03-15-90 GJF Replaced _cdecl with _CALLTYPE1 and added #include
+* <cruntime.h>. Also, fixed the copyright.
+* 04-05-90 GJF Made shortsort() and swap() _CALLTYPE4. Also, added
+* #include <search.h>.
+* 10-04-90 GJF New-style function declarators.
+* 12-28-90 SRW Added _CRUISER_ conditional around check_stack pragmas
+* 01-24-91 SRW Added missing close comment in swap procedure
+* 11-19-91 GJF Do the swap one character at a time to avoid alignment
+* woes.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <search.h>
+
+/* prototypes for local routines */
+static void _CALLTYPE4 shortsort(char *lo, char *hi, unsigned width,
+ int (_CALLTYPE1 *comp)(const void *, const void *));
+static void _CALLTYPE4 swap(char *p, char *q, unsigned int width);
+
+/* this parameter defines the cutoff between using quick sort and
+ insertion sort for arrays; arrays with lengths shorter or equal to the
+ below value use insertion sort */
+
+#define CUTOFF 8 /* testing shows that this is good value */
+
+
+/***
+*qsort(base, num, wid, comp) - quicksort function for sorting arrays
+*
+*Purpose:
+* quicksort the array of elements
+* side effects: sorts in place
+*
+*Entry:
+* char *base = pointer to base of array
+* unsigned num = number of elements in the array
+* unsigned width = width in bytes of each array element
+* int (*comp)() = pointer to function returning analog of strcmp for
+* strings, but supplied by user for comparing the array elements.
+* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
+* 1=2, pos if 1>2.
+*
+*Exit:
+* returns void
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _CRUISER_
+#pragma check_stack(on) /* lots of locals */
+#endif /* ndef _CRUISER_ */
+
+/* sort the array between lo and hi (inclusive) */
+
+void _CALLTYPE1 qsort (
+ void *base,
+ unsigned num,
+ unsigned width,
+ int (_CALLTYPE1 *comp)(const void *, const void *)
+ )
+{
+ char *lo, *hi; /* ends of sub-array currently sorting */
+ char *mid; /* points to middle of subarray */
+ char *loguy, *higuy; /* traveling pointers for partition step */
+ unsigned size; /* size of the sub-array */
+ char *lostk[30], *histk[30];
+ int stkptr; /* stack for saving sub-array to be processed */
+
+ /* Note: the number of stack entries required is no more than
+ 1 + log2(size), so 30 is sufficient for any array */
+
+ if (num < 2 || width == 0)
+ return; /* nothing to do */
+
+ stkptr = 0; /* initialize stack */
+
+ lo = base;
+ hi = (char *)base + width * (num-1); /* initialize limits */
+
+ /* this entry point is for pseudo-recursion calling: setting
+ lo and hi and jumping to here is like recursion, but stkptr is
+ prserved, locals aren't, so we preserve stuff on the stack */
+recurse:
+
+ size = (hi - lo) / width + 1; /* number of el's to sort */
+
+ /* below a certain size, it is faster to use a O(n^2) sorting method */
+ if (size <= CUTOFF) {
+ shortsort(lo, hi, width, comp);
+ }
+ else {
+ /* First we pick a partititioning element. The efficiency of the
+ algorithm demands that we find one that is approximately the
+ median of the values, but also that we select one fast. Using
+ the first one produces bad performace if the array is already
+ sorted, so we use the middle one, which would require a very
+ wierdly arranged array for worst case performance. Testing shows
+ that a median-of-three algorithm does not, in general, increase
+ performance. */
+
+ mid = lo + (size / 2) * width; /* find middle element */
+ swap(mid, lo, width); /* swap it to beginning of array */
+
+ /* We now wish to partition the array into three pieces, one
+ consisiting of elements <= partition element, one of elements
+ equal to the parition element, and one of element >= to it. This
+ is done below; comments indicate conditions established at every
+ step. */
+
+ loguy = lo;
+ higuy = hi + width;
+
+ /* Note that higuy decreases and loguy increases on every iteration,
+ so loop must terminate. */
+ for (;;) {
+ /* lo <= loguy < hi, lo < higuy <= hi + 1,
+ A[i] <= A[lo] for lo <= i <= loguy,
+ A[i] >= A[lo] for higuy <= i <= hi */
+
+ do {
+ loguy += width;
+ } while (loguy <= hi && comp(loguy, lo) <= 0);
+
+ /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
+ either loguy > hi or A[loguy] > A[lo] */
+
+ do {
+ higuy -= width;
+ } while (higuy > lo && comp(higuy, lo) >= 0);
+
+ /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
+ either higuy <= lo or A[higuy] < A[lo] */
+
+ if (higuy < loguy)
+ break;
+
+ /* if loguy > hi or higuy <= lo, then we would have exited, so
+ A[loguy] > A[lo], A[higuy] < A[lo],
+ loguy < hi, highy > lo */
+
+ swap(loguy, higuy, width);
+
+ /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
+ of loop is re-established */
+ }
+
+ /* A[i] >= A[lo] for higuy < i <= hi,
+ A[i] <= A[lo] for lo <= i < loguy,
+ higuy < loguy, lo <= higuy <= hi
+ implying:
+ A[i] >= A[lo] for loguy <= i <= hi,
+ A[i] <= A[lo] for lo <= i <= higuy,
+ A[i] = A[lo] for higuy < i < loguy */
+
+ swap(lo, higuy, width); /* put partition element in place */
+
+ /* OK, now we have the following:
+ A[i] >= A[higuy] for loguy <= i <= hi,
+ A[i] <= A[higuy] for lo <= i < higuy
+ A[i] = A[lo] for higuy <= i < loguy */
+
+ /* We've finished the partition, now we want to sort the subarrays
+ [lo, higuy-1] and [loguy, hi].
+ We do the smaller one first to minimize stack usage.
+ We only sort arrays of length 2 or more.*/
+
+ if ( higuy - 1 - lo >= hi - loguy ) {
+ if (lo + width < higuy) {
+ lostk[stkptr] = lo;
+ histk[stkptr] = higuy - width;
+ ++stkptr;
+ } /* save big recursion for later */
+
+ if (loguy < hi) {
+ lo = loguy;
+ goto recurse; /* do small recursion */
+ }
+ }
+ else {
+ if (loguy < hi) {
+ lostk[stkptr] = loguy;
+ histk[stkptr] = hi;
+ ++stkptr; /* save big recursion for later */
+ }
+
+ if (lo + width < higuy) {
+ hi = higuy - width;
+ goto recurse; /* do small recursion */
+ }
+ }
+ }
+
+ /* We have sorted the array, except for any pending sorts on the stack.
+ Check if there are any, and do them. */
+
+ --stkptr;
+ if (stkptr >= 0) {
+ lo = lostk[stkptr];
+ hi = histk[stkptr];
+ goto recurse; /* pop subarray from stack */
+ }
+ else
+ return; /* all subarrays done */
+}
+
+#ifdef _CRUISER_
+#pragma check_stack() /* revert to command line behaviour */
+#endif /* ndef _CRUISER_ */
+
+
+/***
+*shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays
+*
+*Purpose:
+* sorts the sub-array of elements between lo and hi (inclusive)
+* side effects: sorts in place
+* assumes that lo < hi
+*
+*Entry:
+* char *lo = pointer to low element to sort
+* char *hi = pointer to high element to sort
+* unsigned width = width in bytes of each array element
+* int (*comp)() = pointer to function returning analog of strcmp for
+* strings, but supplied by user for comparing the array elements.
+* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
+* 1=2, pos if 1>2.
+*
+*Exit:
+* returns void
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static void _CALLTYPE4 shortsort (
+ char *lo,
+ char *hi,
+ unsigned width,
+ int (_CALLTYPE1 *comp)(const void *, const void *)
+ )
+{
+ char *p, *max;
+
+ /* Note: in assertions below, i and j are alway inside original bound of
+ array to sort. */
+
+ while (hi > lo) {
+ /* A[i] <= A[j] for i <= j, j > hi */
+ max = lo;
+ for (p = lo+width; p <= hi; p += width) {
+ /* A[i] <= A[max] for lo <= i < p */
+ if (comp(p, max) > 0) {
+ max = p;
+ }
+ /* A[i] <= A[max] for lo <= i <= p */
+ }
+
+ /* A[i] <= A[max] for lo <= i <= hi */
+
+ swap(max, hi, width);
+
+ /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
+
+ hi -= width;
+
+ /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
+ }
+ /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
+ so array is sorted */
+}
+
+
+/***
+*swap(a, b, width) - swap two elements
+*
+*Purpose:
+* swaps the two array elements of size width
+*
+*Entry:
+* char *a, *b = pointer to two elements to swap
+* unsigned width = width in bytes of each array element
+*
+*Exit:
+* returns void
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static void _CALLTYPE4 swap (
+ char *a,
+ char *b,
+ unsigned width
+ )
+{
+ char tmp;
+
+ if ( a != b )
+ /* Do the swap one character at a time to avoid potential alignment
+ problems. */
+ while ( width-- ) {
+ tmp = *a;
+ *a++ = *b;
+ *b++ = tmp;
+ }
+}
diff --git a/private/crt32/misc/rand.c b/private/crt32/misc/rand.c
new file mode 100644
index 000000000..b5df0798f
--- /dev/null
+++ b/private/crt32/misc/rand.c
@@ -0,0 +1,133 @@
+/***
+*rand.c - random number generator
+*
+* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines rand(), srand() - random number generator
+*
+*Revision History:
+* 03-16-84 RN initial version
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 05-31-88 PHG Merged DLL and normal versions
+* 06-06-89 JCR 386 mthread support
+* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 04-05-90 GJF Added #include <stdlib.h>.
+* 10-04-90 GJF New-style function declarators.
+* 07-17-91 GJF Multi-thread support for Win32 [_WIN32_].
+* 02-17-93 GJF Changed for new _getptd().
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <os2dll.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifndef MTHREAD
+static long holdrand = 1L;
+#endif
+
+/***
+*void srand(seed) - seed the random number generator
+*
+*Purpose:
+* Seeds the random number generator with the int given. Adapted from the
+* BASIC random number generator.
+*
+*Entry:
+* unsigned seed - seed to seed rand # generator with
+*
+*Exit:
+* None.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CRTAPI1 srand (
+ unsigned int seed
+ )
+{
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ struct _tiddata * tdata;
+
+ tdata = _gettidtab(); /* get tid's data address */
+ tdata->_holdrand = (long)seed;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ _getptd()->_holdrand = (unsigned long)seed;
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+#else
+ holdrand = (long)seed;
+#endif
+}
+
+
+/***
+*int rand() - returns a random number
+*
+*Purpose:
+* returns a pseudo-random number 0 through 32767.
+*
+*Entry:
+* None.
+*
+*Exit:
+* Returns a pseudo-random number 0 through 32767.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 rand (
+ void
+ )
+{
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ struct _tiddata * tdata;
+
+ tdata = _gettidtab(); /* get tid's data address */
+ return(((tdata->_holdrand = tdata->_holdrand * 214013L + 2531011L) >>
+ 16) & 0x7fff);
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ _ptiddata ptd = _getptd();
+
+ return( ((ptd->_holdrand = ptd->_holdrand * 214013L
+ + 2531011L) >> 16) & 0x7fff );
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+#else
+ return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
+#endif
+}
diff --git a/private/crt32/misc/rotl.c b/private/crt32/misc/rotl.c
new file mode 100644
index 000000000..79af5779f
--- /dev/null
+++ b/private/crt32/misc/rotl.c
@@ -0,0 +1,90 @@
+/***
+*rotl.c - rotate an unsigned integer left
+*
+* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _rotl() - performs a rotate left on an unsigned integer.
+*
+*Revision History:
+* 06-02-89 PHG Module created
+* 11-03-89 JCR Added _lrotl
+* 03-15-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 10-04-90 GJF New-style function declarators.
+* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too.
+* 09-02-92 GJF Don't build for POSIX.
+* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too.
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifdef _MSC_VER
+#pragma function(_lrotl,_rotl)
+#endif
+
+#if UINT_MAX != 0xffffffff
+#error This module assumes 32-bit integers
+#endif
+
+#if (UINT_MAX != ULONG_MAX)
+#error This module assumes sizeof(int) == sizeof(long)
+#endif
+
+/***
+*unsigned _rotl(val, shift) - int rotate left
+*
+*Purpose:
+* Performs a rotate left on an unsigned integer.
+*
+* [Note: The _lrotl entry is based on the assumption
+* that sizeof(int) == sizeof(long).]
+*Entry:
+* unsigned val: value to rotate
+* int shift: number of bits to shift by
+*
+*Exit:
+* returns rotated value
+*
+*Exceptions:
+* None.
+*
+*******************************************************************************/
+
+unsigned long _CALLTYPE1 _lrotl (
+ unsigned long val,
+ int shift
+ )
+{
+ return( (unsigned long) _rotl((unsigned) val, shift) );
+}
+
+unsigned _CALLTYPE1 _rotl (
+ unsigned val,
+ int shift
+ )
+{
+ register unsigned hibit; /* non-zero means hi bit set */
+ register unsigned num = val; /* number to rotate */
+
+ shift &= 0x1f; /* modulo 32 -- this will also make
+ negative shifts work */
+
+ while (shift--) {
+ hibit = num & 0x80000000; /* get high bit */
+ num <<= 1; /* shift left one bit */
+ if (hibit)
+ num |= 1; /* set lo bit if hi bit was set */
+ }
+
+ return num;
+}
+
+
+#endif
diff --git a/private/crt32/misc/rotr.c b/private/crt32/misc/rotr.c
new file mode 100644
index 000000000..5abe91f23
--- /dev/null
+++ b/private/crt32/misc/rotr.c
@@ -0,0 +1,90 @@
+/***
+*rotr.c - rotate an unsigned integer right
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _rotr() - performs a rotate right on an unsigned integer.
+*
+*Revision History:
+* 06-02-89 PHG Module created
+* 11-03-89 JCR Added _lrotl
+* 03-15-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 10-04-90 GJF New-style function declarators.
+* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too.
+* 09-02-92 GJF Don't build for POSIX.
+* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too.
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifdef _MSC_VER
+#pragma function(_lrotr,_rotr)
+#endif
+
+#if UINT_MAX != 0xffffffff
+#error This module assumes 32-bit integers
+#endif
+
+#if (UINT_MAX != ULONG_MAX)
+#error This module assumes sizeof(int) == sizeof(long)
+#endif
+
+/***
+*unsigned _rotr(val, shift) - int rotate right
+*
+*Purpose:
+* Performs a rotate right on an unsigned integer.
+*
+* [Note: The _lrotl entry is based on the assumption
+* that sizeof(int) == sizeof(long).]
+*Entry:
+* unsigned val: value to rotate
+* int shift: number of bits to shift by
+*
+*Exit:
+* returns rotated values
+*
+*Exceptions:
+* None.
+*
+*******************************************************************************/
+
+unsigned long _CALLTYPE1 _lrotr (
+ unsigned long val,
+ int shift
+ )
+{
+ return( (unsigned long) _rotr((unsigned) val, shift) );
+}
+
+unsigned _CALLTYPE1 _rotr (
+ unsigned val,
+ int shift
+ )
+{
+ register unsigned lobit; /* non-zero means lo bit set */
+ register unsigned num = val; /* number to rotate */
+
+ shift &= 0x1f; /* modulo 32 -- this will also make
+ negative shifts work */
+
+ while (shift--) {
+ lobit = num & 1; /* get high bit */
+ num >>= 1; /* shift right one bit */
+ if (lobit)
+ num |= 0x80000000; /* set hi bit if lo bit was set */
+ }
+
+ return num;
+}
+
+
+#endif
diff --git a/private/crt32/misc/searchen.c b/private/crt32/misc/searchen.c
new file mode 100644
index 000000000..8b92e476f
--- /dev/null
+++ b/private/crt32/misc/searchen.c
@@ -0,0 +1,114 @@
+/***
+*searchenv.c - find a file using paths from an environment variable
+*
+* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* to search a set a directories specified by an environment variable
+* for a specified file name. If found the full path name is returned.
+*
+*Revision History:
+* 06-15-87 DFW initial implementation
+* 08-06-87 JCR Changed directory delimeter from '/' to '\'.
+* 09-24-87 JCR Removed 'const' from declarations (caused cl warnings).
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 02-17-88 JCR Added 'const' copy_path local to get rid of cl warning.
+* 07-19-88 SKS Fixed bug if root directory is current directory
+* 08-03-89 JCR Allow quoted strings in file/path names
+* 08-29-89 GJF Changed copy_path() to _getpath() and moved it to it's
+* own source file. Also fixed handling of multiple semi-
+* colons.
+* 11-20-89 GJF Added const attribute to types of fname and env_var.
+* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include
+* <cruntime.h>. Also, cleaned up the formatting a bit.
+* 07-25-90 SBM Removed redundant include (stdio.h)
+* 10-04-90 GJF New-style function declarator.
+* 01-22-91 GJF ANSI naming.
+* 08-26-92 GJF Include unistd.h for POSIX build.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#ifdef _POSIX_
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <direct.h>
+#include <io.h>
+#include <internal.h>
+
+/***
+*_searchenv() - search for file along paths from environment variable
+*
+*Purpose:
+* to search for a specified file in the directory(ies) specified by
+* a given environment variable, and, if found, to return the full
+* path name of the file. The file is first looked for in the current
+* working directory, prior to looking in the paths specified by env_var.
+*
+*Entry:
+* fname - name of file to search for
+* env_var - name of environment variable to use for paths
+* path - pointer to storage for the constructed path name
+*
+*Exit:
+* path - pointer to constructed path name, if the file is found, otherwise
+* it points to the empty string.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _searchenv (
+ const char *fname,
+ const char *env_var,
+ register char *path
+ )
+{
+ register char *p;
+ register int c;
+ char *env_p;
+
+#ifdef _POSIX_
+ if (access(fname, 0) == 0) {
+#else
+ if (_access(fname, 0) == 0) {
+#endif
+ /* exists in this directory - get cwd and concatenate file
+ name */
+ _getcwd(path, _MAX_PATH);
+ if(path[3]) /* Do NOT add `\' to root directory */
+ strcat(path, "\\");
+ strcat(path, fname);
+ return;
+ }
+ if ((env_p = getenv(env_var)) == NULL) {
+ /* no such environment var. and not in cwd, so return empty
+ string */
+ *path = '\0';
+ return;
+ }
+ while ( (env_p = _getpath(env_p, path, 0)) && *path ) {
+ /* path now holds nonempty pathname from env_p, concatenate
+ the file name and go */
+ p = path + strlen(path);
+ if (((c = *(p - 1)) != '/') && (c != '\\') && (c != ':')) {
+ /* add a trailing '\' */
+ *p++ = '\\';
+ }
+ /* p now points to character following trailing '/', '\'
+ or ':' */
+ strcpy(p, fname);
+#ifdef _POSIX_
+ if (access(path, 0) == 0) {
+#else
+ if (_access(path, 0) == 0) {
+#endif
+ /* found a match, we're done */
+ return;
+ }
+ }
+ /* if we get here, we never found it, return empty string */
+ *path = '\0';
+}
diff --git a/private/crt32/misc/setlocal.c b/private/crt32/misc/setlocal.c
new file mode 100644
index 000000000..4fa3bbc05
--- /dev/null
+++ b/private/crt32/misc/setlocal.c
@@ -0,0 +1,620 @@
+/***
+*setlocal.c - Contains the setlocale function
+*
+* Copyright (c) 1988-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the setlocale() function.
+*
+*Revision History:
+* 03-21-89 JCR Module created.
+* 09-25-89 GJF Fixed copyright. Checked for compatibility with Win 3.0
+* 09-25-90 KRS Major rewrite--support more than "C" locale if _INTL.
+* 11-05-91 ETC Get 09-25-90 working for C and "" locales; separate
+* setlocal.h; add Init functions.
+* 12-05-91 ETC Separate nlsdata.c; add mt support; remove calls to
+* itself.
+* 12-20-91 ETC Added _getlocaleinfo api interface function.
+* 09-25-92 KRS Fix for latest NLSAPI changes, etc.
+* 01-25-93 KRS Fix for latest changes, clean up code, etc.
+* 02-02-93 CFW Many modifications and bug fixes (all under _INTL).
+* 02-08-93 CFW Bug fixes and casts to avoid warnings (all under _INTL).
+* 02-17-93 CFW Removed re-call of init() functions in case of failure.
+* 03-01-93 CFW Check GetQualifiedLocale return value.
+* 03-02-93 CFW Added POSIX conformance, check environment variables.
+* 03-09-93 CFW Set CP to CP_ACP when changing to C locale.
+* 03-17-93 CFW Change expand to expandlocale, prepend _ to internal functions,
+* lots of POSIX fixup.
+* 03-23-93 CFW Add _ to GetQualifiedLocale call.
+* 03-24-93 CFW Change to _get_qualified_locale, support ".codepage".
+* 05-10-93 CFW Disallow setlocale(LC_*, ".").
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <locale.h>
+#ifdef _INTL
+#include <os2dll.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h> /* for strtol */
+#include <setlocal.h>
+
+#ifdef MTHREAD
+/*
+ * Check order of locale category multithread locks.
+ * (needed by _setlocale_set_cat)
+ */
+#if _LC_COLLATE_LOCK != _SETLOCALE_LOCK + LC_COLLATE || \
+ _LC_CTYPE_LOCK != _SETLOCALE_LOCK + LC_CTYPE || \
+ _LC_MONETARY_LOCK != _SETLOCALE_LOCK + LC_MONETARY || \
+ _LC_NUMERIC_LOCK != _SETLOCALE_LOCK + LC_NUMERIC || \
+ _LC_TIME_LOCK != _SETLOCALE_LOCK + LC_TIME
+
+#error Locale category multithread locks are disordered
+#endif
+#endif /* MTHREAD */
+
+#endif /* _INTL */
+
+/* C locale */
+static char _clocalestr[] = "C";
+#ifdef _POSIX_
+static char _posixlocalestr[] = "POSIX";
+#endif
+
+
+#ifdef _INTL
+/* CONSIDER: for granularity, reference from approp component (lconv.c, etc.) */
+int _CRTAPI3 _init_collate(void);
+int _CRTAPI3 _init_ctype(void);
+int _CRTAPI3 _init_monetary(void);
+int _CRTAPI3 _init_numeric(void);
+int _CRTAPI3 _init_time(void);
+int _CRTAPI3 _init_dummy(void);
+
+static struct {
+ const char * catname;
+ char * locale;
+ int (* init)(void);
+} _lc_category[LC_MAX-LC_MIN+1] = {
+ /* code assumes locale initialization is "_clocalestr" */
+ { "LC_ALL", NULL, _init_dummy /* never called */ },
+ { "LC_COLLATE", _clocalestr, _init_collate },
+ { "LC_CTYPE", _clocalestr, _init_ctype },
+ { "LC_MONETARY", _clocalestr, _init_monetary },
+ { "LC_NUMERIC", _clocalestr, _init_numeric },
+ { "LC_TIME", _clocalestr, _init_time }
+};
+/* CONSIDER: _init_* functions should map to _init_dummy when not linked in */
+
+/* helper function prototypes */
+char * _expandlocale(char *, char *, LC_ID *, UINT *, int);
+void _strcats(char *, int, ...);
+void _lc_lctostr(char *, const LC_STRINGS *);
+int _lc_strtolc(LC_STRINGS *, const char *);
+static char * _CRTAPI3 _setlocale_set_cat(int, const char *);
+static char * _CRTAPI3 _setlocale_get_all(void);
+#endif /* _INTL */
+
+/***
+*char * setlocale(int category, char *locale) - Set one or all locale categories
+*
+*Purpose:
+* The setlocale() routine allows the user to set one or more of
+* the locale categories to the specific locale selected by the
+* user. [ANSI]
+*
+* NOTE: Under !_INTL, the C libraries only support the "C" locale.
+* Attempts to change the locale will fail.
+*
+*Entry:
+* int category = One of the locale categories defined in locale.h
+* char *locale = String identifying a specific locale or NULL to
+* query the current locale.
+*
+*Exit:
+* If supplied locale pointer == NULL:
+*
+* Return pointer to current locale string and do NOT change
+* the current locale.
+*
+* If supplied locale pointer != NULL:
+*
+* If locale string is '\0', set locale to default.
+*
+* If desired setting can be honored, return a pointer to the
+* locale string for the appropriate category.
+*
+* If desired setting can NOT be honored, return NULL.
+*
+*Exceptions:
+* Compound locale strings of the form "LC_COLLATE=xxx;LC_CTYPE=xxx;..."
+* are allowed for the LC_ALL category. This is to support the ability
+* to restore locales with the returned string, as specified by ANSI.
+* Setting the locale with a compound locale string will succeed unless
+* *all* categories failed. The returned string will reflect the current
+* locale. For example, if LC_CTYPE fails in the above string, setlocale
+* will return "LC_COLLATE=xxx;LC_CTYPE=yyy;..." where yyy is the
+* previous locale (or the C locale if restoring the previous locale
+* also failed). Unrecognized LC_* categories are ignored.
+*
+*******************************************************************************/
+char * _CRTAPI1 setlocale (
+ int _category,
+ const char *_locale
+ )
+{
+#ifdef _INTL
+char * retval;
+#endif
+
+ /* Validate category */
+ if ((_category < LC_MIN) || (_category > LC_MAX))
+ return NULL;
+
+ /* Interpret locale */
+
+#ifndef _INTL /* trivial ANSI support */
+ if ( (_locale == NULL) ||
+ (_locale[0] == '\0') ||
+ ( (_locale[0]=='C') && (_locale[1]=='\0'))
+#ifdef _POSIX_
+ || (!strcmp(_locale,"POSIX"))
+#endif
+ )
+#ifdef _POSIX_
+ return _posixlocalestr;
+#else
+ return _clocalestr;
+#endif
+ else
+ return NULL;
+
+#else /* _INTL */
+
+_mlock (_SETLOCALE_LOCK);
+
+ if (_category != LC_ALL)
+ {
+ retval = (_locale) ? _setlocale_set_cat(_category,_locale) :
+ _lc_category[_category].locale;
+
+ } else { /* LC_ALL */
+
+ char lctemp[MAX_LC_LEN];
+ int i;
+ int same = 1;
+ int fLocaleSet = 0; /* flag to indicate if anything successfully set */
+
+ if (_locale != NULL)
+ {
+ if ( (_locale[0]=='L') && (_locale[1]=='C') && (_locale[2]=='_') )
+ {
+ /* parse compound locale string */
+ size_t len;
+ const char * p = _locale; /* start of string to parse */
+ const char * s;
+
+ do {
+ s = strpbrk(p,"=;");
+ if ((s==(char *)NULL) || (!(len=s-p)) || (*s==';'))
+ {
+ _munlock (_SETLOCALE_LOCK);
+ return NULL; /* syntax error */
+ }
+
+ /* match with known LC_ strings, if possible, else ignore */
+ for (i=LC_ALL+1; i<=LC_MAX; i++)
+ {
+ if ((!strncmp(_lc_category[i].catname,p,len))
+ && (len==strlen(_lc_category[i].catname)))
+ {
+ break; /* matched i */
+ }
+ } /* no match if (i>LC_MAX) -- just ignore */
+
+ if ((!(len = strcspn(++s,";"))) && (*s!=';'))
+ {
+ _munlock (_SETLOCALE_LOCK);
+ return NULL; /* syntax error */
+ }
+
+ if (i<=LC_MAX)
+ {
+ /* CONSIDER: check for repeated categories? */
+ strncpy(lctemp, s, len);
+ lctemp[len]='\0'; /* null terminate string */
+
+ /* don't fail unless all categories fail */
+ if (_setlocale_set_cat(i,lctemp))
+ fLocaleSet++; /* record a success */
+ }
+ if (*(p = s+len)!='\0')
+ p++; /* skip ';', if present */
+
+ } while (*p);
+
+ retval = (fLocaleSet) ? _setlocale_get_all() : NULL;
+
+ /* CONSIDER: LC_CTYPE should be done first. _init_monetary for example
+ will convert wide strings to multibyte (dependent on ctype).
+ This is currently not a problem; ctype is done second; collate is done
+ first, but it does not require ctype. */
+ /* Not necessarily true when a compound locale string is used, but WE always
+ put it in the right order. */
+
+ } else { /* simple LC_ALL locale string */
+
+ /* confirm locale is supported, get expanded locale */
+ if (retval = _expandlocale((char *)_locale, lctemp, NULL, NULL, _category))
+ {
+ for (i=LC_MIN; i<=LC_MAX; i++)
+ {
+ if (i!=LC_ALL)
+ {
+ if (strcmp(lctemp, _lc_category[i].locale))
+ {
+ if (_setlocale_set_cat(i, lctemp))
+ {
+ fLocaleSet++; /* record a success */
+ }
+ else
+ {
+ same = 0; /* record a failure */
+ }
+ }
+ else
+ fLocaleSet++; /* trivial succcess */
+ }
+ }
+#ifdef _POSIX_
+ /* special case for POSIX - since LC_ALL expands,
+ one LC_ALL call may set many different categories,
+ must assume not same, get full string */
+ same = 0;
+#endif
+ if (same) /* needn't call setlocale_get_all() if all the same */
+ {
+ retval = _setlocale_get_all();
+ /* retval set above */
+ free(_lc_category[LC_ALL].locale);
+ _lc_category[LC_ALL].locale = NULL;
+ }
+ else
+ retval = (fLocaleSet) ? _setlocale_get_all() : NULL;
+ }
+ }
+ } else { /* LC_ALL & NULL */
+ retval = _setlocale_get_all ();
+ }
+ }
+
+ /* common exit point */
+ _munlock (_SETLOCALE_LOCK);
+ return retval;
+
+#endif /* _INTL */
+
+} /* setlocale */
+
+
+#ifdef _INTL /* rest are international helpers */
+static char * _CRTAPI3 _setlocale_set_cat (
+ int category,
+ const char * locale
+ )
+{
+ char * oldlocale;
+ LCID oldhandle;
+ UINT oldcodepage;
+ LC_ID oldid;
+
+ LC_ID idtemp;
+ UINT cptemp;
+ char lctemp[MAX_LC_LEN];
+ char * pch;
+
+ /* lock this category to keep other library functions */
+ /* from using locale handles, information, etc. */
+
+ _mlock (_SETLOCALE_LOCK + category);
+
+ if (!_expandlocale((char *)locale, lctemp, &idtemp, &cptemp, category))
+ {
+ _munlock (_SETLOCALE_LOCK + category);
+ return NULL; /* unrecognized locale */
+ }
+
+ if (!(pch = (char *)malloc(strlen(lctemp)+1)))
+ {
+ _munlock (_SETLOCALE_LOCK + category);
+ return NULL; /* error if malloc fails */
+ }
+
+ oldlocale = _lc_category[category].locale; /* save for possible restore*/
+ oldhandle = _lc_handle[category];
+ memcpy((void *)&oldid, (void *)&_lc_id[category], sizeof(oldid));
+ oldcodepage = _lc_codepage;
+
+ /* update locale string */
+ _lc_category[category].locale = strcpy(pch,lctemp);
+ _lc_handle[category] = MAKELCID(idtemp.wLanguage, SORT_DEFAULT);
+ memcpy((void *)&_lc_id[category], (void *)&idtemp, sizeof(idtemp));
+
+ if (category==LC_CTYPE)
+ _lc_codepage = cptemp;
+
+ if (_lc_category[category].init())
+ {
+ /* restore previous state! */
+ _lc_category[category].locale = oldlocale;
+ free(pch);
+ _lc_handle[category] = oldhandle;
+ _lc_codepage = oldcodepage;
+
+ _munlock (_SETLOCALE_LOCK + category);
+ return NULL; /* error if non-zero return */
+ }
+
+ /* locale set up successfully */
+ /* Cleanup */
+ if ((oldlocale != _clocalestr)
+#ifdef _POSIX_
+ && (oldlocale!=_posixlocalestr)
+#endif
+ )
+ free(oldlocale);
+
+ _munlock (_SETLOCALE_LOCK + category);
+
+ return _lc_category[category].locale;
+
+} /* _setlocale_set_cat */
+
+
+
+static char * _CRTAPI3 _setlocale_get_all (
+ void
+ )
+{
+ int i;
+ int same = 1;
+ /* allocate memory if necessary */
+ if (!_lc_category[LC_ALL].locale)
+ _lc_category[LC_ALL].locale = malloc((MAX_LC_LEN+1) * (LC_MAX-LC_MIN+1) + CATNAMES_LEN);
+
+ _lc_category[LC_ALL].locale[0] = '\0';
+ for (i=LC_MIN+1; ; i++)
+ {
+ _strcats(_lc_category[LC_ALL].locale, 3, _lc_category[i].catname,"=",_lc_category[i].locale);
+ if (i<LC_MAX)
+ {
+ strcat(_lc_category[LC_ALL].locale,";");
+ if (strcmp(_lc_category[i].locale, _lc_category[i+1].locale))
+ same=0;
+ }
+ else
+ {
+ if (!same)
+ return _lc_category[LC_ALL].locale;
+ else
+ {
+ free(_lc_category[LC_ALL].locale); /* free */
+ _lc_category[LC_ALL].locale = (char *)NULL;
+ return _lc_category[LC_CTYPE].locale;
+ }
+ }
+ }
+} /* _setlocale_get_all */
+
+
+char * _expandlocale (
+ char *expr,
+ char * output,
+ LC_ID * id,
+ UINT * cp,
+ int category
+ )
+{
+ static LC_ID cacheid = {0, 0, 0};
+ static UINT cachecp = 0;
+ static char cachein[MAX_LC_LEN] = "C";
+ static char cacheout[MAX_LC_LEN] = "C";
+
+ if (!expr)
+ return NULL; /* error if no input */
+
+#ifdef _POSIX_
+ if (!*expr)
+ {
+ /* POSIX: when locale=="", look first at the environment variables:
+ 1) use LC_ALL EV if defined and not null (LC_ALL expands to LC_*)
+ 2) use EV that matches category and is not null
+ 3) use LANG EV if defined and not null
+ otherwise, we fall through to get system default */
+
+ char *envar;
+
+ if (category == LC_ALL && (envar = getenv("LC_ALL")))
+ {
+ if (!*envar)
+ {
+ /* LC_ALL expands to LC_*, set output to "", each category will be
+ expanded individually */
+ *output = '\0';
+ return output;
+ }
+ else {
+ expr = envar;
+ }
+ }
+ else {
+ if ((envar = getenv(_lc_category[category].catname)) && *envar ||
+ (envar = getenv("LANG")) && *envar)
+ {
+ expr = envar;
+ }
+ }
+ }
+#endif /* _POSIX_ */
+
+ if (((*expr=='C') && (!expr[1]))
+#ifdef _POSIX_
+ || (!strcmp(expr, _posixlocalestr))
+#endif
+ ) /* for "C" locale, just return */
+ {
+#ifdef _POSIX_
+ strcpy(output, _posixlocalestr);
+#else
+ *output = 'C';
+ output[1] = '\0';
+#endif
+ if (id)
+ {
+ id->wLanguage = 0;
+ id->wCountry = 0;
+ id->wCodePage = 0;
+ }
+ if (cp)
+ {
+ *cp = CP_ACP; /* return to ANSI code page */
+ }
+ return output; /* "C" */
+ }
+
+ /* first, make sure we didn't just do this one */
+ if (strcmp(cacheout,expr) && strcmp(cachein,expr))
+ {
+ /* do some real work */
+ const LC_STRINGS names;
+
+ if (_lc_strtolc((LC_STRINGS *)&names, (const char *)expr))
+ return NULL; /* syntax error */
+
+ if (!_get_qualified_locale((const DWORD)QF_STRINGS, (const LPVOID)&names,
+ (LPLC_ID)&cacheid, (LPLC_STRINGS)&names))
+ return NULL; /* locale not recognized/supported */
+
+ /* begin: cache atomic section */
+
+ cachecp = cacheid.wCodePage;
+
+ _lc_lctostr((char *)cacheout, &names);
+
+ /* Don't cache "" empty string */
+ if (*expr)
+ strcpy(cachein, expr);
+ else
+ strcpy(cachein, cacheout);
+
+ /* end: cache atomic section */
+ }
+ if (id)
+ memcpy((void *)id, (void *)&cacheid, sizeof(cacheid)); /* possibly return LC_ID */
+ if (cp)
+ memcpy((void *)cp, (void *)&cachecp, sizeof(cachecp)); /* possibly return cp */
+
+ strcpy(output,cacheout);
+ return cacheout; /* return fully expanded locale string */
+}
+
+/* helpers */
+
+int _CRTAPI3 _init_dummy(void) /* default routine for locale initializer */
+{
+ return 0;
+}
+
+void _strcats
+ (
+ char *outstr,
+ int n,
+ ...
+ )
+{
+ int i;
+ va_list substr;
+
+ va_start (substr, n);
+
+ for (i =0; i<n; i++)
+ {
+ strcat(outstr, va_arg(substr, char *));
+ }
+ va_end(substr);
+}
+
+int _lc_strtolc
+ (
+ LC_STRINGS *names,
+ const char *locale
+ )
+{
+ int i, len;
+ char ch;
+
+ memset((void *)names, '\0', sizeof(LC_STRINGS)); /* clear out result */
+
+ if (*locale=='\0')
+ return 0; /* trivial case */
+
+ // only code page is given
+ if (locale[0] == '.' && locale[1] != '\0')
+ {
+ strcpy((char *)names->szCodePage, &locale[1]);
+ return 0;
+ }
+
+ for (i=0; ; i++)
+ {
+ if (!(len=strcspn(locale,"_.,")))
+ return -1; /* syntax error */
+
+ ch = locale[len];
+
+ if ((i==0) && (len<MAX_LANG_LEN) && (ch!='.'))
+ strncpy((char *)names->szLanguage, locale, len);
+
+ else if ((i==1) && (len<MAX_CTRY_LEN) && (ch!='_'))
+ strncpy((char *)names->szCountry, locale, len);
+
+ else if ((i==2) && (ch=='\0' || ch==','))
+ strncpy((char *)names->szCodePage, locale, len);
+
+ else
+ return -1; /* error parsing locale string */
+
+ if (ch==',')
+ {
+ /* modifier not used in current implementation, but it
+ must be parsed to for POSIX/XOpen conformance */
+ /* strncpy(names->szModifier, locale, MAX_MODIFIER_LEN-1); */
+ break;
+ }
+
+ if (!ch)
+ break;
+ locale+=(len+1);
+ }
+ return 0;
+}
+
+void _lc_lctostr
+ (
+ char *locale,
+ const LC_STRINGS *names
+ )
+{
+ strcpy(locale, (char *)names->szLanguage);
+ if (*(names->szCountry))
+ _strcats(locale, 2, "_", names->szCountry);
+ if (*(names->szCodePage))
+ _strcats(locale, 2, ".", names->szCodePage);
+ /* if (names->szModifier)
+ _strcats(locale, 2, ",", names->szModifier); */
+}
+
+#endif /* _INTL */
diff --git a/private/crt32/misc/setmbval.c b/private/crt32/misc/setmbval.c
new file mode 100644
index 000000000..bbbf48f3f
--- /dev/null
+++ b/private/crt32/misc/setmbval.c
@@ -0,0 +1,35 @@
+/***
+*setmbval.c - sets __invalid_mb_chars variable
+*
+* Copyright (c) 1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* sets __invalid_mb_chars flag to value apppropriate to the NLS API
+* call support. Older versions of NT do not support this flag.
+*
+**
+*Revision History:
+* 10-22-93 CFW Module created.
+*
+*******************************************************************************/
+
+#include <windows.h>
+#include <internal.h>
+
+
+void __set_invalid_mb_chars(void)
+{
+ char *astring = "a"; /* test string */
+
+ /*
+ * Determine whether API supports this flag by making a dummy call.
+ *
+ */
+
+ if (0 != MultiByteToWideChar(0, MB_ERR_INVALID_CHARS, astring, -1, NULL, 0))
+ __invalid_mb_chars = MB_ERR_INVALID_CHARS;
+ else
+ __invalid_mb_chars = 0;
+}
+
+
diff --git a/private/crt32/misc/sources b/private/crt32/misc/sources
new file mode 100644
index 000000000..cd3f28bea
--- /dev/null
+++ b/private/crt32/misc/sources
@@ -0,0 +1,129 @@
+!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=misc
+
+TARGETNAME=misc
+TARGETPATH=..\obj
+TARGETTYPE=LIBRARY
+386_STDCALL=0
+
+!INCLUDE ..\crt32.def
+
+SOURCES=abort.c \
+ abs.c \
+ assert.c \
+ bsearch.c \
+ cmiscdat.c \
+ ctype.c \
+ div.c \
+ ldiv.c \
+ getenv.c \
+ getpath.c \
+ getqloc.c \
+ initcoll.c \
+ initctyp.c \
+ inithelp.c \
+ initmon.c \
+ initnum.c \
+ inittime.c \
+ labs.c \
+ lconv.c \
+ lfind.c \
+ lsearch.c \
+ makepath.c \
+ mbval.c \
+ onexit.c \
+ nlsdata1.c \
+ nlsdata2.c \
+ nlsdata3.c \
+ perror.c \
+ purevirt.c \
+ putenv.c \
+ qsort.c \
+ rand.c \
+ rotl.c \
+ rotr.c \
+ searchen.c \
+ setlocal.c \
+ setmbval.c \
+ splitpat.c \
+ _strerr.c \
+ strerror.c \
+ syserr.c \
+ umask.c \
+ winsig.c \
+ winxfltr.c \
+ wrt2err.c
+
+i386_SOURCES=i386\setjmpex.asm \
+ i386\setjmp.asm \
+ i386\setjmp3.asm \
+ i386\longjmp.asm \
+ i386\sehsupp.c \
+ i386\exsup.asm \
+ i386\exsup2.asm \
+ i386\exsup3.asm
+
+MIPS_SOURCES=mips\chandler.c \
+ mips\setjmp.s \
+ mips\setjmpex.s \
+ mips\longjmp.s \
+ mips\jmpuwind.s
+
+ALPHA_SOURCES=alpha\chandler.c \
+ alpha\divdat.s \
+ alpha\divide2.s \
+ alpha\extv.s \
+ alpha\extvvol.s \
+ alpha\extzv.s \
+ alpha\extzvvol.s \
+ alpha\ghandler.c \
+ alpha\insv.s \
+ alpha\insvvol.s \
+ alpha\jmpuwind.s \
+ alpha\longjmp.s \
+ alpha\otsdiv.s \
+ alpha\otsjmp.s \
+ alpha\otsjmpex.s \
+ alpha\otsuwind.s \
+ alpha\scmpeql.s \
+ alpha\scmpeqlp.s \
+ alpha\scmpleq.s \
+ alpha\scmpleqp.s \
+ alpha\scmplss.s \
+ alpha\scmplssp.s \
+ alpha\setjmp.s \
+ alpha\setjmpex.s \
+ alpha\sfill.s \
+ alpha\sloc.s \
+ alpha\smove.s \
+ alpha\smovem.s \
+ alpha\strans.s \
+ alpha\strcmp_.s \
+ alpha\strcpy_.s \
+ alpha\strlen_.s \
+ alpha\szero.s
diff --git a/private/crt32/misc/splitpat.c b/private/crt32/misc/splitpat.c
new file mode 100644
index 000000000..f85b26b1e
--- /dev/null
+++ b/private/crt32/misc/splitpat.c
@@ -0,0 +1,201 @@
+/***
+*splitpath.c - break down path name into components
+*
+* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* To provide support for accessing the individual components of an
+* arbitrary path name
+*
+*Revision History:
+* 06-14-87 DFW initial implementation
+* 09-23-87 JCR Removed 'const' from declarations (fixed cl warnings)
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 11-20-89 GJF Fixed indents, copyright. Added const attribute to
+* type of path.
+* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include
+* <cruntime.h>.
+* 07-25-90 SBM Removed redundant include (stdio.h), replaced local
+* MIN macro with standard min macro
+* 10-04-90 GJF New-style function declarator.
+* 01-22-91 GJF ANSI naming.
+* 11-20-92 KRS Port _MBCS support from 16-bit tree.
+* 05-12-93 KRS Add fix for MBCS max path handling.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MBCS
+#include <mbstring.h>
+#include <mbctype.h>
+#include <mbdata.h>
+#endif
+
+#ifdef _MBCS
+#define STRNCPY _mbsnbcpy
+#else
+#define STRNCPY strncpy
+#endif
+
+/***
+*_splitpath() - split a path name into its individual components
+*
+*Purpose:
+* to split a path name into its individual components
+*
+*Entry:
+* path - pointer to path name to be parsed
+* drive - pointer to buffer for drive component, if any
+* dir - pointer to buffer for subdirectory component, if any
+* fname - pointer to buffer for file base name component, if any
+* ext - pointer to buffer for file name extension component, if any
+*
+*Exit:
+* drive - pointer to drive string. Includes ':' if a drive was given.
+* dir - pointer to subdirectory string. Includes leading and trailing
+* '/' or '\', if any.
+* fname - pointer to file base name
+* ext - pointer to file extension, if any. Includes leading '.'.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _splitpath (
+ register const char *path,
+ char *drive,
+ char *dir,
+ char *fname,
+ char *ext
+ )
+{
+ register char *p;
+ char *last_slash = NULL, *dot = NULL;
+ unsigned len;
+
+ /* we assume that the path argument has the following form, where any
+ * or all of the components may be missing.
+ *
+ * <drive><dir><fname><ext>
+ *
+ * and each of the components has the following expected form(s)
+ *
+ * drive:
+ * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
+ * ':'
+ * dir:
+ * 0 to _MAX_DIR-1 characters in the form of an absolute path
+ * (leading '/' or '\') or relative path, the last of which, if
+ * any, must be a '/' or '\'. E.g -
+ * absolute path:
+ * \top\next\last\ ; or
+ * /top/next/last/
+ * relative path:
+ * top\next\last\ ; or
+ * top/next/last/
+ * Mixed use of '/' and '\' within a path is also tolerated
+ * fname:
+ * 0 to _MAX_FNAME-1 characters not including the '.' character
+ * ext:
+ * 0 to _MAX_EXT-1 characters where, if any, the first must be a
+ * '.'
+ *
+ */
+
+ /* extract drive letter and :, if any */
+
+ if (*(path + _MAX_DRIVE - 2) == ':') {
+ if (drive) {
+ strncpy(drive, path, _MAX_DRIVE - 1);
+ *(drive + _MAX_DRIVE-1) = '\0';
+ }
+ path += _MAX_DRIVE - 1;
+ }
+ else if (drive) {
+ *drive = '\0';
+ }
+
+ /* extract path string, if any. Path now points to the first character
+ * of the path, if any, or the filename or extension, if no path was
+ * specified. Scan ahead for the last occurence, if any, of a '/' or
+ * '\' path separator character. If none is found, there is no path.
+ * We will also note the last '.' character found, if any, to aid in
+ * handling the extension.
+ */
+
+ for (last_slash = NULL, p = (char *)path; *p; p++) {
+#ifdef _MBCS
+ if (_ISLEADBYTE (*p))
+ p++;
+ else {
+#endif
+ if (*p == '/' || *p == '\\')
+ /* point to one beyond for later copy */
+ last_slash = p + 1;
+ else if (*p == '.')
+ dot = p;
+#ifdef _MBCS
+ }
+#endif
+ }
+
+ if (last_slash) {
+
+ /* found a path - copy up through last_slash or max. characters
+ * allowed, whichever is smaller
+ */
+
+ if (dir) {
+ len = __min((last_slash - path), (_MAX_DIR - 1));
+ STRNCPY(dir, path, len);
+ *(dir + len) = '\0';
+ }
+ path = last_slash;
+ }
+ else if (dir) {
+
+ /* no path found */
+
+ *dir = '\0';
+ }
+
+ /* extract file name and extension, if any. Path now points to the
+ * first character of the file name, if any, or the extension if no
+ * file name was given. Dot points to the '.' beginning the extension,
+ * if any.
+ */
+
+ if (dot && (dot >= path)) {
+ /* found the marker for an extension - copy the file name up to
+ * the '.'.
+ */
+ if (fname) {
+ len = __min((dot - path), (_MAX_FNAME - 1));
+ STRNCPY(fname, path, len);
+ *(fname + len) = '\0';
+ }
+ /* now we can get the extension - remember that p still points
+ * to the terminating nul character of path.
+ */
+ if (ext) {
+ len = __min((p - dot), (_MAX_EXT - 1));
+ STRNCPY(ext, dot, len);
+ *(ext + len) = '\0';
+ }
+ }
+ else {
+ /* found no extension, give empty extension and copy rest of
+ * string into fname.
+ */
+ if (fname) {
+ len = __min((p - path), (_MAX_FNAME - 1));
+ STRNCPY(fname, path, len);
+ *(fname + len) = '\0';
+ }
+ if (ext) {
+ *ext = '\0';
+ }
+ }
+}
diff --git a/private/crt32/misc/strerror.c b/private/crt32/misc/strerror.c
new file mode 100644
index 000000000..ec8c7dd41
--- /dev/null
+++ b/private/crt32/misc/strerror.c
@@ -0,0 +1,142 @@
+/***
+*strerror.c - Contains the strerror C runtime.
+*
+* Copyright (c) 1987-1993, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* The strerror runtime accepts an error number as input
+* and returns the corresponding error string.
+*
+* NOTE: The "old" strerror C runtime resides in file _strerr.c
+* and is now called _strerror. The new strerror runtime
+* conforms to the ANSI standard.
+*
+*Revision History:
+* 02-24-87 JCR Module created.
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 01-04-87 JCR Improved code.
+* 01-05-87 JCR Multi-thread support
+* 05-31-88 PHG Merge DLL and normal versions
+* 06-06-89 JCR 386 mthread support
+* 03-16-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 10-04-90 GJF New-style function declarator.
+* 07-18-91 GJF Multi-thread support for Win32 [_WIN32_].
+* 02-17-93 GJF Changed for new _getptd().
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <errmsg.h>
+#include <stdlib.h>
+#include <syserr.h>
+#include <string.h>
+#include <os2dll.h>
+#ifdef MTHREAD
+#include <malloc.h>
+#include <stddef.h>
+#endif
+
+/* [NOTE: The mthread error message buffer is shared by both strerror
+ and _strerror so must be the max length of both. */
+#ifdef MTHREAD
+/* Max length of message = user_string(94)+system_string+2 */
+#define _ERRMSGLEN_ 94+_SYS_MSGMAX+2
+#else
+/* Max length of message = system_string+2 */
+#define _ERRMSGLEN_ _SYS_MSGMAX+2
+#endif
+
+
+/***
+*char *strerror(errnum) - Map error number to error message string.
+*
+*Purpose:
+* The strerror runtime takes an error number for input and
+* returns the corresponding error message string. This routine
+* conforms to the ANSI standard interface.
+*
+*Entry:
+* int errnum - Integer error number (corresponding to an errno value).
+*
+*Exit:
+* char * - Strerror returns a pointer to the error message string.
+* This string is internal to the strerror routine (i.e., not supplied
+* by the user).
+*
+*Exceptions:
+* None.
+*
+*******************************************************************************/
+
+char * _CRTAPI1 strerror (
+ int errnum
+ )
+{
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ struct _tiddata * tdata;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ _ptiddata ptd = _getptd();
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+ char *errmsg;
+ static char errmsg_backup[_SYS_MSGMAX+2];
+
+#else
+
+ static char errmsg[_ERRMSGLEN_]; /* Longest errmsg + \0 */
+
+#endif
+
+#ifdef MTHREAD
+
+#ifdef _CRUISER_
+
+ tdata = _gettidtab(); /* get tid's data address */
+ if (tdata->_errmsg == NULL) {
+ if ( (tdata->_errmsg = malloc(_ERRMSGLEN_)) == NULL)
+ errmsg = errmsg_backup; /* error: use backup */
+ else
+ errmsg = tdata->_errmsg;
+ }
+ else
+ errmsg = tdata->_errmsg;
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ if ( (ptd->_errmsg == NULL) && ((ptd->_errmsg = malloc(_ERRMSGLEN_))
+ == NULL) )
+ errmsg = errmsg_backup; /* error: use backup */
+ else
+ errmsg = ptd->_errmsg;
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+#endif
+
+ strcpy(errmsg, _sys_err_msg(errnum));
+ return(errmsg);
+}
diff --git a/private/crt32/misc/syserr.c b/private/crt32/misc/syserr.c
new file mode 100644
index 000000000..ef5ee29ed
--- /dev/null
+++ b/private/crt32/misc/syserr.c
@@ -0,0 +1,85 @@
+/***
+*syserr.c - system error list
+*
+* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Defines the System Error List, containing the full messages for
+* all errno values set by the library routines.
+* Defines sys_errlist, sys_nerr.
+*
+*Revision History:
+* 08-07-87 PHG removed obsolete definition of sys_msgmax.
+* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright.
+* 01-21-91 GJF ANSI naming.
+* 07-11-91 JCR Changed "core" to "memory" in ENOMEM message
+* 01-23-92 GJF Added #include <stdlib.h> (contains decl of sys_nerr).
+* 09-30-92 GJF Made POSIX compatible. Non-POSIX errno values are
+* mapped to "Unknown error" for now. Next step is to
+* delete these and renumber to eliminate the gaps, after
+* the beta release.
+* 04-08-93 CFW Added EILSEQ (42) message.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <stdlib.h>
+
+char *_sys_errlist[] =
+{
+ /* 0 */ "No error",
+ /* 1 EPERM */ "Operation not permitted",
+ /* 2 ENOENT */ "No such file or directory",
+ /* 3 ESRCH */ "No such process",
+ /* 4 EINTR */ "Interrupted function call",
+ /* 5 EIO */ "Input/output error",
+ /* 6 ENXIO */ "No such device or address",
+ /* 7 E2BIG */ "Arg list too long",
+ /* 8 ENOEXEC */ "Exec format error",
+ /* 9 EBADF */ "Bad file descriptor",
+ /* 10 ECHILD */ "No child processes",
+ /* 11 EAGAIN */ "Resource temporarily unavailable",
+ /* 12 ENOMEM */ "Not enough space",
+ /* 13 EACCES */ "Permission denied",
+ /* 14 EFAULT */ "Bad address",
+ /* 15 ENOTBLK */ "Unknown error", /* not POSIX */
+ /* 16 EBUSY */ "Resource device",
+ /* 17 EEXIST */ "File exists",
+ /* 18 EXDEV */ "Improper link",
+ /* 19 ENODEV */ "No such device",
+ /* 20 ENOTDIR */ "Not a directory",
+ /* 21 EISDIR */ "Is a directory",
+ /* 22 EINVAL */ "Invalid argument",
+ /* 23 ENFILE */ "Too many open files in system",
+ /* 24 EMFILE */ "Too many open files",
+ /* 25 ENOTTY */ "Inappropriate I/O control operation",
+ /* 26 ETXTBSY */ "Unknown error", /* not POSIX */
+ /* 27 EFBIG */ "File too large",
+ /* 28 ENOSPC */ "No space left on device",
+ /* 29 ESPIPE */ "Invalid seek",
+ /* 30 EROFS */ "Read-only file system",
+ /* 31 EMLINK */ "Too many links",
+ /* 32 EPIPE */ "Broken pipe",
+ /* 33 EDOM */ "Domain error",
+ /* 34 ERANGE */ "Result too large",
+ /* 35 EUCLEAN */ "Unknown error", /* not POSIX */
+ /* 36 EDEADLK */ "Resource deadlock avoided",
+ /* 37 UNKNOWN */ "Unknown error",
+ /* 38 ENAMETOOLONG */ "Filename too long",
+ /* 39 ENOLCK */ "No locks available",
+ /* 40 ENOSYS */ "Function not implemented",
+ /* 41 ENOTEMPTY */ "Directory not empty",
+ /* 42 EILSEQ */ "Illegal byte sequence",
+ /* 43 */ "Unknown error"
+
+};
+
+int _sys_nerr = sizeof( _sys_errlist ) / sizeof( _sys_errlist[ 0 ] ) - 1;
+
+/* The above array contains all the errors including unknown error # 37
+ which is used if msg_num is unknown */
+
+
+/* ***NOTE: Parameter _SYS_MSGMAX (in file syserr.h) indicates the length of
+ the longest systerm error message in the above table. When you add or
+ modify a message, you must update the value _SYS_MSGMAX, if appropriate. */
diff --git a/private/crt32/misc/umask.c b/private/crt32/misc/umask.c
new file mode 100644
index 000000000..9ca63a876
--- /dev/null
+++ b/private/crt32/misc/umask.c
@@ -0,0 +1,55 @@
+/***
+*umask.c - set file permission mask
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines _umask() - sets file permission mask of current process*
+* affecting files created by creat, open, or sopen.
+*
+*Revision History:
+* 06-02-89 PHG module created
+* 03-16-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 04-05-90 GJF Added #include <io.h>.
+* 10-04-90 GJF New-style function declarator.
+* 01-17-91 GJF ANSI naming.
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#include <internal.h>
+#include <io.h>
+
+/***
+*int _umask(mode) - set the file mode mask
+*
+*Purpose:
+* Sets the file-permission mask of the current process* which
+* modifies the permission setting of new files created by creat,
+* open, or sopen.
+*
+*Entry:
+* int mode - new file permission mask
+* may contain S_IWRITE, S_IREAD, S_IWRITE | S_IREAD.
+* The S_IREAD bit has no effect under OS/2.
+*
+*Exit:
+* returns the previous setting of the file permission mask.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CALLTYPE1 _umask (
+ int mode
+ )
+{
+ register int oldmode; /* old umask value */
+
+ mode &= 0x180; /* only user read/write permitted */
+ oldmode = _umaskval; /* remember old value */
+ _umaskval = mode; /* set new value */
+ return oldmode; /* return old value */
+}
diff --git a/private/crt32/misc/winsig.c b/private/crt32/misc/winsig.c
new file mode 100644
index 000000000..310f1c62f
--- /dev/null
+++ b/private/crt32/misc/winsig.c
@@ -0,0 +1,709 @@
+/***
+*winsig.c - C signal support
+*
+* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved
+*
+*Purpose:
+* Defines signal(), raise() and supporting functions.
+*
+*Revision History:
+* 10-21-91 GJF Signal for Win32 and Dosx32. Copied from old signal.c
+* (the Cruiser implementation with some revisions for
+* Win32), then extensively rewritten.
+* 11-08-91 GJF Cleaned up header files usage.
+* 12-13-91 GJF Fixed multi-thread build.
+* 09-30-92 SRW Add WINAPI keyword to CtrlC handler
+* 02-17-93 GJF Changed for new _getptd().
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <errno.h>
+#include <float.h>
+#include <malloc.h>
+#include <os2dll.h>
+#include <oscalls.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * look up the first entry in the exception-action table corresponding to
+ * the given signal
+ */
+#ifdef MTHREAD
+static struct _XCPT_ACTION * _CRTAPI3 siglookup(int, struct _XCPT_ACTION *);
+#else /* not MTHREAD */
+static struct _XCPT_ACTION * _CRTAPI3 siglookup(int);
+#endif /* MTHREAD */
+
+/*
+ * variables holding action codes (and code pointers) for SIGINT, SIGBRK,
+ * SIGABRT and SIGTERM.
+ *
+ * note that the disposition (i.e., action to be taken upon receipt) of
+ * these signals is defined on a per-process basis (not per-thread)!!
+ */
+
+static _PHNDLR ctrlc_action = SIG_DFL; /* SIGINT */
+static _PHNDLR ctrlbreak_action = SIG_DFL; /* SIGBREAK */
+static _PHNDLR abort_action = SIG_DFL; /* SIGABRT */
+static _PHNDLR term_action = SIG_DFL; /* SIGTERM */
+
+/*
+ * flag indicated whether or not a handler has been installed to capture
+ * ^C and ^Break events.
+ */
+static int ConsoleCtrlHandler_Installed = 0;
+
+
+/***
+*static BOOL WINAPI ctrlevent_capture(DWORD CtrlType) - capture ^C and ^Break events
+*
+*Purpose:
+* Capture ^C and ^Break events from the console and dispose of them
+* according the values in ctrlc_action and ctrlbreak_action, resp.
+* This is the routine that evokes the user-defined action for SIGINT
+* (^C) or SIGBREAK (^Break) installed by a call to signal().
+*
+*Entry:
+* DWORD CtrlType - indicates type of event, two values:
+* CTRL_C_EVENT
+* CTRL_BREAK_EVENT
+*
+*Exit:
+* Returns TRUE to indicate the event (signal) has been handled.
+* Otherwise, returns FALSE.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+static BOOL WINAPI ctrlevent_capture (
+ DWORD CtrlType
+ )
+{
+ _PHNDLR ctrl_action;
+ _PHNDLR *pctrl_action;
+ int sigcode;
+
+ _mlock(_SIGNAL_LOCK);
+
+ /*
+ * Identify the type of event and fetch the corresponding action
+ * description.
+ */
+
+ if ( CtrlType == CTRL_C_EVENT ) {
+ ctrl_action = *(pctrl_action = &ctrlc_action);
+ sigcode = SIGINT;
+ }
+ else {
+ ctrl_action = *(pctrl_action = &ctrlbreak_action);
+ sigcode = SIGBREAK;
+ }
+
+ if ( ctrl_action == SIG_DFL ) {
+ /*
+ * return FALSE, indicating the event has NOT been handled
+ */
+ _munlock(_SIGNAL_LOCK);
+ return FALSE;
+ }
+
+ if ( ctrl_action != SIG_IGN ) {
+ /*
+ * Reset the action to be SIG_DFL and call the user's handler.
+ */
+ *pctrl_action = SIG_DFL;
+ _munlock(_SIGNAL_LOCK);
+ (*ctrl_action)(sigcode);
+ }
+ else
+ /*
+ * SIG_IGN - nothing special to do except release the lock
+ */
+ _munlock(_SIGNAL_LOCK);
+
+ /*
+ * Return TRUE, indicating the event has been handled (which may
+ * mean it's being ignored)
+ */
+ return TRUE;
+}
+
+
+
+/***
+*_PHNDLR signal(signum, sigact) - Define a signal handler
+*
+*Purpose:
+* The signal routine allows the user to define what action should
+* be taken when various signals occur. The Win32/Dosx32 implementation
+* supports seven signals, divided up into three general groups
+*
+* 1. Signals corresponding to OS exceptions. These are:
+* SIGFPE
+* SIGILL
+* SIGSEGV
+* Signal actions for these signals are installed by altering the
+* XcptAction and SigAction fields for the appropriate entry in the
+* exception-action table (XcptActTab[]).
+*
+* 2. Signals corresponding to ^C and ^Break. These are:
+* SIGINT
+* SIGBREAK
+* Signal actions for these signals are installed by altering the
+* _ctrlc_action and _ctrlbreak_action variables.
+*
+* 3. Signals which are implemented only in the runtime. That is, they
+* occur only as the result of a call to raise().
+* SIGABRT
+* SIGTERM
+*
+*
+*Entry:
+* int signum signal type. recognized signal types are:
+*
+* SIGABRT (ANSI)
+* SIGBREAK
+* SIGFPE (ANSI)
+* SIGILL (ANSI)
+* SIGINT (ANSI)
+* SIGSEGV (ANSI)
+* SIGTERM (ANSI)
+*
+* _PHNDLR sigact signal handling function or action code. the action
+* codes are:
+*
+* SIG_DFL - take the default action, whatever that may
+* be, upon receipt of this type type of signal.
+*
+* SIG_DIE - *** ILLEGAL ***
+* special code used in the XcptAction field of an
+* XcptActTab[] entry to indicate that the runtime is
+* to terminate the process upon receipt of the exception.
+* not accepted as a value for sigact.
+*
+* SIG_IGN - ignore this type of signal
+*
+* [function address] - transfer control to this address
+* when a signal of this type occurs.
+*
+*Exit:
+* Good return:
+* Signal returns the previous value of the signal handling function
+* (e.g., SIG_DFL, SIG_IGN, etc., or [function address]). This value is
+* returned in DX:AX.
+*
+* Error return:
+* Signal returns -1 and errno is set to EINVAL. The error return is
+* generally taken if the user submits bogus input values.
+*
+*Exceptions:
+* None.
+*
+*******************************************************************************/
+
+_PHNDLR _CRTAPI1 signal(
+ int signum,
+ _PHNDLR sigact
+ )
+{
+ struct _XCPT_ACTION *pxcptact;
+ _PHNDLR oldsigact;
+#ifdef MTHREAD
+ _ptiddata ptd;
+#endif
+
+ /*
+ * Check for values of sigact supported on other platforms but not
+ * on this one. Also, make sure sigact is not SIG_DIE
+ */
+ if ( (sigact == SIG_ACK) || (sigact == SIG_SGE) )
+ goto sigreterror;
+
+ /*
+ * Take care of all signals which do not correspond to exceptions
+ * in the host OS. Those are:
+ *
+ * SIGINT
+ * SIGBREAK
+ * SIGABRT
+ * SIGTERM
+ *
+ */
+ if ( (signum == SIGINT) || (signum == SIGBREAK) || (signum == SIGABRT)
+ || (signum == SIGTERM) ) {
+
+ _mlock(_SIGNAL_LOCK);
+
+ /*
+ * if SIGINT or SIGBREAK, make sure the handler is installed
+ * to capture ^C and ^Break events.
+ */
+ if ( ((signum == SIGINT) || (signum == SIGBREAK)) &&
+ !ConsoleCtrlHandler_Installed )
+ if ( SetConsoleCtrlHandler(ctrlevent_capture, TRUE)
+ == TRUE )
+ ConsoleCtrlHandler_Installed = TRUE;
+ else {
+ _doserrno = GetLastError();
+ _munlock(_SIGNAL_LOCK);
+ goto sigreterror;
+ }
+
+ switch (signum) {
+
+ case SIGINT:
+ oldsigact = ctrlc_action;
+ ctrlc_action = sigact;
+ break;
+
+ case SIGBREAK:
+ oldsigact = ctrlbreak_action;
+ ctrlbreak_action = sigact;
+ break;
+
+ case SIGABRT:
+ oldsigact = abort_action;
+ abort_action = sigact;
+ break;
+
+ case SIGTERM:
+ oldsigact = term_action;
+ term_action = sigact;
+ break;
+ }
+
+ _munlock(_SIGNAL_LOCK);
+ goto sigretok;
+ }
+
+ /*
+ * If we reach here, signum is supposed to be one the signals which
+ * correspond to exceptions in the host OS. Those are:
+ *
+ * SIGFPE
+ * SIGILL
+ * SIGSEGV
+ */
+
+ /*
+ * Make sure signum is one of the remaining supported signals.
+ */
+ if ( (signum != SIGFPE) && (signum != SIGILL) && (signum != SIGSEGV) )
+ goto sigreterror;
+
+
+#ifdef MTHREAD
+ /*
+ * Fetch the tid data table entry for this thread
+ */
+ ptd = _getptd();
+
+ /*
+ * Check that there a per-thread instance of the exception-action
+ * table for this thread. if there isn't, create one.
+ */
+ if ( ptd->_pxcptacttab == _XcptActTab )
+ /*
+ * allocate space for an exception-action table
+ */
+ if ( (ptd->_pxcptacttab = malloc(_XcptActTabSize))
+ != NULL )
+ /*
+ * initialize the table by copying over the contents
+ * of _XcptActTab[]
+ */
+ (void) memcpy(ptd->_pxcptacttab, _XcptActTab,
+ _XcptActTabSize);
+ else
+ /*
+ * cannot create exception-action table, return
+ * error to caller
+ */
+ goto sigreterror;
+
+#endif /* MTHREAD */
+
+ /*
+ * look up the proper entry in the exception-action table. note that
+ * if several exceptions are mapped to the same signal, this returns
+ * the pointer to first such entry in the exception action table. it
+ * is assumed that the other entries immediately follow this one.
+ */
+#ifdef MTHREAD
+ if ( (pxcptact = siglookup(signum, ptd->_pxcptacttab)) == NULL )
+#else /* not MTHREAD */
+ if ( (pxcptact = siglookup(signum)) == NULL )
+#endif /* MTHREAD */
+ goto sigreterror;
+
+ /*
+ * SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped
+ * to them. the code below depends on the exceptions corresponding to
+ * the same signal being grouped together in the exception-action
+ * table.
+ */
+
+ /*
+ * store old signal action code for return value
+ */
+ oldsigact = pxcptact->XcptAction;
+
+ /*
+ * loop through all entries corresponding to the
+ * given signal and update the SigAction and XcptAction
+ * fields as appropriate
+ *
+ * should add a test to make sure pxcptact never runs
+ * off the end of the table (works okay for now because
+ * of the order of the entries).
+ */
+ while ( pxcptact->SigNum == signum ) {
+ /*
+ * take care of the SIG_IGN and SIG_DFL action
+ * codes
+ */
+ pxcptact->XcptAction = sigact;
+ pxcptact++;
+ }
+
+sigretok:
+ return(oldsigact);
+
+sigreterror:
+ errno = EINVAL;
+ return(SIG_ERR);
+}
+
+/***
+*int raise(signum) - Raise a signal
+*
+*Purpose:
+* This routine raises a signal (i.e., performs the action currently
+* defined for this signal). The action associated with the signal is
+* evoked directly without going through intermediate dispatching or
+* handling.
+*
+*Entry:
+* int signum - signal type (e.g., SIGINT)
+*
+*Exit:
+* returns 0 on good return, -1 on bad return.
+*
+*Exceptions:
+* May not return. Raise has no control over the action
+* routines defined for the various signals. Those routines may
+* abort, terminate, etc. In particular, the default actions for
+* certain signals will terminate the program.
+*
+*******************************************************************************/
+
+
+int _CRTAPI1 raise (
+ int signum
+ )
+{
+ _PHNDLR sigact;
+ _PHNDLR *psigact;
+ PEXCEPTION_POINTERS oldpxcptinfoptrs;
+ int oldfpecode;
+
+#ifdef MTHREAD
+ int siglock = 0;
+ _ptiddata ptd;
+#endif
+
+ switch (signum) {
+
+ case SIGINT:
+ sigact = *(psigact = &ctrlc_action);
+#ifdef MTHREAD
+ siglock++;
+#endif
+ break;
+
+ case SIGBREAK:
+ sigact = *(psigact = &ctrlbreak_action);
+#ifdef MTHREAD
+ siglock++;
+#endif
+ break;
+
+ case SIGABRT:
+ sigact = *(psigact = &abort_action);
+#ifdef MTHREAD
+ siglock++;
+#endif
+ break;
+
+ case SIGTERM:
+ sigact = *(psigact = &term_action);
+#ifdef MTHREAD
+ siglock++;
+#endif
+ break;
+
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
+#ifdef MTHREAD
+ ptd = _getptd();
+ sigact = *(psigact = &(siglookup( signum,
+ ptd->_pxcptacttab )->XcptAction));
+#else
+ sigact = *(psigact = &(siglookup( signum )->
+ XcptAction));
+#endif
+ break;
+
+ default:
+ /*
+ * unsupported signal, return an error
+ */
+ return (-1);
+ }
+
+#ifdef MTHREAD
+ /*
+ * if signum is one of the 'process-wide' signals (i.e., SIGINT,
+ * SIGBREAK, SIGABRT or SIGTERM), assert _SIGNAL_LOCK.
+ */
+ if ( siglock )
+ _mlock(_SIGNAL_LOCK);
+#endif
+
+ /*
+ * If the current action is SIG_IGN, just return
+ */
+ if ( sigact == SIG_IGN ) {
+
+#ifdef MTHREAD
+ if ( siglock )
+ _munlock(_SIGNAL_LOCK);
+#endif
+ return(0);
+ }
+
+ /*
+ * If the current action is SIG_DFL, take the default action
+ */
+ if ( sigact == SIG_DFL ) {
+
+#ifdef MTHREAD
+ if ( siglock )
+ _munlock(_SIGNAL_LOCK);
+#endif
+ /*
+ * The current default action for all of the supported
+ * signals is to terminate with an exit code of 3.
+ *
+ * BUG, BUG!!!! THIS IS ALMOST CERTAINLY THE WRONG EXIT
+ * CODE FOR SOME OF THE SIGNALS IN NT!
+ */
+ _exit(3);
+ }
+
+ /*
+ * From here on, sigact is assumed to be a pointer to a user-supplied
+ * handler.
+ */
+
+ /*
+ * For signals which correspond to exceptions, set the pointer
+ * to the EXCEPTION_POINTERS structure to NULL
+ */
+ if ( (signum == SIGFPE) || (signum == SIGSEGV) ||
+ (signum == SIGILL) ) {
+#ifdef MTHREAD
+ oldpxcptinfoptrs = ptd->_tpxcptinfoptrs;
+ ptd->_tpxcptinfoptrs = NULL;
+#else
+ oldpxcptinfoptrs = _pxcptinfoptrs;
+ _pxcptinfoptrs = NULL;
+#endif
+
+ /*
+ * If signum is SIGFPE, also set _fpecode to
+ * _FPE_EXPLICITGEN
+ */
+ if ( signum == SIGFPE ) {
+#ifdef MTHREAD
+ oldfpecode = ptd->_tfpecode;
+ ptd->_tfpecode = _FPE_EXPLICITGEN;
+#else
+ oldfpecode = _fpecode;
+ _fpecode = _FPE_EXPLICITGEN;
+#endif
+ }
+ }
+
+ /*
+ * Reset the action to SIG_DFL and call the user specified handler
+ * routine.
+ */
+ *psigact = SIG_DFL;
+
+#ifdef MTHREAD
+ if ( siglock )
+ _munlock(_SIGNAL_LOCK);
+#endif
+
+ if ( signum == SIGFPE )
+ /*
+ * Special hack to support old SIGFPE handlers which
+ * expect the value of _fpecode as the second argument.
+ */
+#ifdef MTHREAD
+ (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE,
+ ptd->_tfpecode);
+#else
+ (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE, _fpecode);
+#endif
+ else
+ (*sigact)(signum);
+
+ /*
+ * For signals which correspond to exceptions, restore the pointer
+ * to the EXCEPTION_POINTERS structure.
+ */
+ if ( (signum == SIGFPE) || (signum == SIGSEGV) ||
+ (signum == SIGILL) ) {
+#ifdef MTHREAD
+ ptd->_tpxcptinfoptrs = oldpxcptinfoptrs;
+#else
+ _pxcptinfoptrs = oldpxcptinfoptrs;
+#endif
+
+ /*
+ * If signum is SIGFPE, also restore _fpecode
+ */
+ if ( signum == SIGFPE )
+#ifdef MTHREAD
+ ptd->_tfpecode = oldfpecode;
+#else
+ _fpecode = oldfpecode;
+#endif
+ }
+
+ return(0);
+}
+
+
+/***
+*struct _XCPT_ACTION *siglookup(int signum) - look up exception-action table
+* entry for signal.
+*
+*Purpose:
+* Find the first entry int _XcptActTab[] whose SigNum field is signum.
+*
+*Entry:
+* int signum - C signal type (e.g., SIGINT)
+*
+*Exit:
+* If successful, pointer to the table entry. If no such entry, NULL is
+* returned.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef MTHREAD
+
+static struct _XCPT_ACTION * _CRTAPI3 siglookup (
+ int signum,
+ struct _XCPT_ACTION *pxcptacttab
+ )
+{
+ struct _XCPT_ACTION *pxcptact = pxcptacttab;
+
+#else /* not MTHREAD */
+
+static struct _XCPT_ACTION * _CRTAPI3 siglookup(int signum)
+{
+ struct _XCPT_ACTION *pxcptact = _XcptActTab;
+
+#endif /* MTHREAD */
+ /*
+ * walk thru the _xcptactab table looking for the proper entry. note
+ * that in the case where more than one exception corresponds to the
+ * same signal, the first such instance in the table is the one
+ * returned.
+ */
+#ifdef MTHREAD
+
+ while ( (pxcptact->SigNum != signum) && (++pxcptact <
+ pxcptacttab + _XcptActTabCount) ) ;
+
+#else /* not MTHREAD */
+
+ while ( (pxcptact->SigNum != signum) && (++pxcptact <
+ _XcptActTab + _XcptActTabCount) ) ;
+
+#endif /* MTHREAD */
+
+ if ( pxcptact->SigNum == signum )
+ /*
+ * found a table entry corresponding to the signal
+ */
+ return(pxcptact);
+ else
+ /*
+ * found no table entry corresponding to the signal
+ */
+ return(NULL);
+}
+
+#ifdef MTHREAD
+
+/***
+*int *__fpecode(void) - return pointer to _fpecode field of the tidtable entry
+* for the current thread
+*
+*Purpose:
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int * _CRTAPI1 __fpecode (
+ void
+ )
+{
+ return( &(_getptd()->_tfpecode) );
+}
+
+
+/***
+*void **__pxcptinfoptrs(void) - return pointer to _pxcptinfoptrs field of the
+* tidtable entry for the current thread
+*
+*Purpose:
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void ** _CRTAPI1 __pxcptinfoptrs (
+ void
+ )
+{
+ return( &(_getptd()->_tpxcptinfoptrs) );
+}
+
+#endif
+
+#endif /* _POSIX_ */
diff --git a/private/crt32/misc/winxfltr.c b/private/crt32/misc/winxfltr.c
new file mode 100644
index 000000000..22b4f08f4
--- /dev/null
+++ b/private/crt32/misc/winxfltr.c
@@ -0,0 +1,618 @@
+/***
+*winxfltr.c - startup exception filter
+*
+* Copyright (c) 1990-1993, Microsoft Corporation. All rights reserved
+*
+*Purpose:
+* Defines _XcptFilter(), the function called by the exception filter
+* expression in the startup code.
+*
+*Revision History:
+* 10-31-91 GJF Module created. Copied from the original xcptfltr.c
+* then extensively revised.
+* 11-08-91 GJF Cleaned up header files usage.
+* 12-13-91 GJF Fixed multi-thread build.
+* 01-17-92 GJF Changed default handling under Win32 - unhandled
+* exceptions are now passed to UnhandledExceptionFilter.
+* Dosx32 behavior in unchanged. Also, used a couple of
+* local macros to simplify handling of single-thread vs
+* multi-thread code [_Win32_].
+* 02-16-93 GJF Changed for new _getptd().
+* 04-27-93 GJF Removed (commented out) entries in _XcptActTab which
+* corresponded to C RTEs. These will now simply be
+* passed on through to the system exception handler.
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <float.h>
+#include <os2dll.h>
+#include <oscalls.h>
+#include <signal.h>
+#include <stddef.h>
+
+
+/*
+ * special code denoting no signal.
+ */
+#define NOSIG -1
+
+
+struct _XCPT_ACTION _VARTYPE1 _XcptActTab[] = {
+
+/*
+ * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped
+ * together.
+ *
+ * XcptNum SigNum XcptAction
+ * -------------------------------------------------------------------
+ */
+ { (unsigned long)STATUS_ACCESS_VIOLATION, SIGSEGV, SIG_DFL },
+
+ { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, SIGILL, SIG_DFL },
+
+ { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, SIGILL, SIG_DFL },
+
+/* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE },
+ */
+/* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE },
+ */
+ { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_OVERFLOW, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_STACK_CHECK, SIGFPE, SIG_DFL },
+
+ { (unsigned long)STATUS_FLOAT_UNDERFLOW, SIGFPE, SIG_DFL },
+
+/* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG, SIG_DIE },
+ */
+/* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG, SIG_DIE }
+ */
+};
+
+/*
+ * size of the exception-action table (in bytes)
+ */
+int _CRTVAR1 _XcptActTabSize = sizeof _XcptActTab;
+
+/*
+ * number of entries in the exception-action table
+ */
+int _CRTVAR1 _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);
+
+
+#ifdef MTHREAD
+
+/*
+ * the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of
+ * single vs multi-thread code in the filter function. basically, each macro
+ * is conditionally defined to be a global variable or the corresponding
+ * field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE
+ * _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!!
+ */
+
+#define FPECODE ptd->_tfpecode
+
+#define PXCPTINFOPTRS ptd->_tpxcptinfoptrs
+
+#else
+
+/*
+ * global variable containing the floating point exception code
+ */
+int _VARTYPE1 _fpecode = _FPE_EXPLICITGEN;
+
+#define FPECODE _fpecode
+
+/*
+ * global variable holding _PEXCEPTION_INFO_PTRS value
+ */
+void * _VARTYPE1 _pxcptinfoptrs = NULL;
+
+#define PXCPTINFOPTRS _pxcptinfoptrs
+
+#endif /* MTHREAD */
+
+/*
+ * function to look up the exception action table (_XcptActTab[]) corresponding
+ * to the given exception
+ */
+
+#ifdef MTHREAD
+
+static struct _XCPT_ACTION * _CRTAPI3 xcptlookup(
+ unsigned long,
+ struct _XCPT_ACTION *
+ );
+
+#else /* ndef MTHREAD */
+
+static struct _XCPT_ACTION * _CRTAPI3 xcptlookup(
+ unsigned long
+ );
+
+#endif /* MTHREAD */
+
+#ifdef DEBUG
+
+/*
+ * prototypes for debugging routines
+ */
+void prXcptActTabEntry(struct _XCPT_ACTION *);
+void prXcptActTab(void);
+
+#endif /* DEBUG */
+
+/***
+*int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to
+* be taken with it
+*
+*Purpose:
+* _XcptFilter() is called by the exception filter expression of the
+* _try - _except statement, in the startup code, which guards the call
+* to the user's main(). _XcptFilter() consults the _XcptActTab[] table
+* to identify the exception and determine its disposition. The
+* is disposition of an exception corresponding to a C signal may be
+* modified by a call to signal(). There are three broad cases:
+*
+* (1) Unrecognized exceptions and exceptions for which the XcptAction
+* value is SIG_DFL.
+*
+#ifndef DOSX32
+* In both of these cases, UnhandledExceptionFilter() is called and
+* its return value is returned.
+#else
+* In both of these cases, EXCEPTION_CONTINUE_SEARCH is returned to
+* cause the OS exception dispatcher to pass the exception onto the
+* next exception handler in the chain (usually a system default
+* handler).
+#endif
+*
+* (2) Exceptions corresponding to C signals with an XcptAction value
+* NOT equal to SIG_DFL.
+*
+* These are the C signals whose disposition has been affected by a
+* call to signal() or whose default semantics differ slightly from
+* from the corresponding OS exception. In all cases, the appropriate
+* disposition of the C signal is made by the function (e.g., calling
+* a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU-
+* TION is returned to cause the OS exception dispatcher to dismiss
+* the exception and resume execution at the point where the
+* exception occurred.
+*
+* (3) Exceptions for which the XcptAction value is SIG_DIE.
+*
+* These are the exceptions corresponding to fatal C runtime errors.
+* _XCPT_HANDLE is returned to cause control to pass into the
+* _except-block of the _try - _except statement. There, the runtime
+* error is identified, an appropriate error message is printed out
+* and the program is terminated.
+*
+*Entry:
+*
+*Exit:
+*
+*Exceptions:
+* That's what it's all about!
+*
+*******************************************************************************/
+
+int _CRTAPI1 _XcptFilter (
+ unsigned long xcptnum,
+ PEXCEPTION_POINTERS pxcptinfoptrs
+ )
+{
+ struct _XCPT_ACTION * pxcptact;
+ _PHNDLR phandler;
+ void *oldpxcptinfoptrs;
+ int oldfpecode;
+
+#ifdef MTHREAD
+ _ptiddata ptd = _getptd();
+#endif /* MTHREAD */
+
+ /*
+ * first, take care of all unrecognized exceptions and exceptions with
+ * XcptAction values of SIG_DFL.
+ */
+#ifdef MTHREAD
+ if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL)
+ || (pxcptact->XcptAction == SIG_DFL) )
+#else /* not MTHREAD */
+ if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
+ (pxcptact->XcptAction == SIG_DFL) )
+#endif /* MTHREAD */
+
+#ifndef DOSX32
+ /*
+ * pass the buck to the UnhandledExceptionFilter
+ */
+ return( UnhandledExceptionFilter(pxcptinfoptrs) );
+#else
+ /*
+ * pass the buck to the next level exception handler
+ */
+ return(EXCEPTION_CONTINUE_SEARCH);
+#endif
+
+#ifdef DEBUG
+ prXcptActTabEntry(pxcptact);
+#endif /* DEBUG */
+
+ /*
+ * next, weed out all of the exceptions that need to be handled by
+ * dying, perhaps with a runtime error message
+ */
+ if ( pxcptact->XcptAction == SIG_DIE ) {
+ /*
+ * reset XcptAction (in case of recursion) and drop into the
+ * except-clause.
+ */
+ pxcptact->XcptAction = SIG_DFL;
+ return(EXCEPTION_EXECUTE_HANDLER);
+ }
+
+ /*
+ * next, weed out all of the exceptions that are simply ignored
+ */
+ if ( pxcptact->XcptAction == SIG_IGN )
+ /*
+ * resume execution
+ */
+ return(EXCEPTION_CONTINUE_EXECUTION);
+
+ /*
+ * the remaining exceptions all correspond to C signals which have
+ * signal handlers associated with them. for some, special setup
+ * is required before the signal handler is called. in all cases,
+ * if the signal handler returns, -1 is returned by this function
+ * to resume execution at the point where the exception occurred.
+ *
+ * before calling the signal handler, the XcptAction field of the
+ * exception-action table entry must be reset.
+ */
+ phandler = pxcptact->XcptAction;
+
+ /*
+ * reset the action to be the default
+ */
+ pxcptact->XcptAction = SIG_DFL;
+
+ /*
+ * save the old value of _pxcptinfoptrs (in case this is a nested
+ * exception/signal) and store the current one.
+ */
+ oldpxcptinfoptrs = PXCPTINFOPTRS;
+ PXCPTINFOPTRS = pxcptinfoptrs;
+
+ /*
+ * call the user-supplied signal handler
+ *
+ * floating point exceptions must be handled specially since, from
+ * the C point-of-view, there is only one signal. the exact identity
+ * of the exception is passed in the global variable _fpecode.
+ */
+ if ( pxcptact->SigNum == SIGFPE ) {
+ /*
+ * Save the current _fpecode in case it is a nested floating
+ * point exception (not clear that we need to support this,
+ * but it's easy).
+ */
+ oldfpecode = FPECODE;
+
+ /*
+ * there are no exceptions corresponding to
+ * following _FPE_xxx codes:
+ *
+ * _FPE_UNEMULATED
+ * _FPE_SQRTNEG
+ *
+ * futhermore, STATUS_FLOATING_STACK_CHECK is
+ * raised for both floating point stack under-
+ * flow and overflow. thus, the exception does
+ * not distinguish between _FPE_STACKOVERLOW
+ * and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode
+ * is set to the former value.
+ *
+ * the following should be a switch statement but, alas, the
+ * compiler doesn't like switching on unsigned longs...
+ */
+ if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO )
+
+ FPECODE = _FPE_ZERODIVIDE;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION )
+
+ FPECODE = _FPE_INVALID;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW )
+
+ FPECODE = _FPE_OVERFLOW;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW )
+
+ FPECODE = _FPE_UNDERFLOW;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND )
+
+ FPECODE = _FPE_DENORMAL;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT )
+
+ FPECODE = _FPE_INEXACT;
+
+ else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK )
+
+ FPECODE = _FPE_STACKOVERFLOW;
+
+ /*
+ * call the SIGFPE handler. note the special hack to support
+ * old MS-C programs whose SIGFPE handlers expect two args.
+ *
+ * NOTE: THE CAST AND CALL BELOW DEPEND ON _CRTAPI1 BEING
+ * CALLER CLEANUP!
+ */
+ (*(void (* _CRTAPI1)(int, int))phandler)(SIGFPE, FPECODE);
+
+ /*
+ * restore the old value of _fpecode
+ */
+ FPECODE = oldfpecode;
+ }
+ else
+ (*phandler)(pxcptact->SigNum);
+
+ /*
+ * restore the old value of _pxcptinfoptrs
+ */
+ PXCPTINFOPTRS = oldpxcptinfoptrs;
+
+ return(EXCEPTION_CONTINUE_EXECUTION);
+
+}
+
+
+/***
+*struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action
+* table entry for xcptnum
+*
+*Purpose:
+* Find the in _XcptActTab[] whose Xcptnum field is xcptnum.
+*
+*Entry:
+* unsigned long xcptnum - exception type
+*
+* _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record
+* (used only to distinguish different types of XCPT_SIGNAL)
+*
+*Exit:
+* If successful, pointer to the table entry. If no such entry, NULL is
+* returned.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef MTHREAD
+
+static struct _XCPT_ACTION * _CRTAPI3 xcptlookup (
+ unsigned long xcptnum,
+ struct _XCPT_ACTION * pxcptacttab
+ )
+
+#else /* not MTHREAD */
+
+static struct _XCPT_ACTION * _CRTAPI3 xcptlookup (
+ unsigned long xcptnum
+ )
+
+#endif /* MTHREAD */
+
+{
+#ifdef MTHREAD
+ struct _XCPT_ACTION *pxcptact = pxcptacttab;
+#else /* ndef MTHREAD */
+ struct _XCPT_ACTION *pxcptact = _XcptActTab;
+#endif /* MTHREAD */
+
+ /*
+ * walk thru the _xcptactab table looking for the proper entry
+ */
+#ifdef MTHREAD
+
+ while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
+ pxcptacttab + _XcptActTabCount) ) ;
+
+#else /* not MTHREAD */
+
+ while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
+ _XcptActTab + _XcptActTabCount) ) ;
+
+#endif /* MTHREAD */
+
+ /*
+ * if no table entry was found corresponding to xcptnum, return NULL
+ */
+ if ( pxcptact->XcptNum != xcptnum )
+ return(NULL);
+
+ return(pxcptact);
+}
+
+#ifdef DEBUG
+
+/*
+ * DEBUGGING TOOLS!
+ */
+struct xcptnumstr {
+ unsigned long num;
+ char *str;
+};
+
+struct xcptnumstr XcptNumStr[] = {
+
+ { (unsigned long)STATUS_DATATYPE_MISALIGNMENT,
+ "STATUS_DATATYPE_MISALIGNMENT" },
+
+ { (unsigned long)STATUS_ACCESS_VIOLATION,
+ "STATUS_ACCESS_VIOLATION" },
+
+ { (unsigned long)STATUS_ILLEGAL_INSTRUCTION,
+ "STATUS_ILLEGAL_INSTRUCTION" },
+
+ { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION,
+ "STATUS_NONCONTINUABLE_EXCEPTION" },
+
+ { (unsigned long)STATUS_INVALID_DISPOSITION,
+ "STATUS_INVALID_DISPOSITION" },
+
+ { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND,
+ "STATUS_FLOAT_DENORMAL_OPERAND" },
+
+ { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO,
+ "STATUS_FLOAT_DIVIDE_BY_ZERO" },
+
+ { (unsigned long)STATUS_FLOAT_INEXACT_RESULT,
+ "STATUS_FLOAT_INEXACT_RESULT" },
+
+ { (unsigned long)STATUS_FLOAT_INVALID_OPERATION,
+ "STATUS_FLOAT_INVALID_OPERATION" },
+
+ { (unsigned long)STATUS_FLOAT_OVERFLOW,
+ "STATUS_FLOAT_OVERFLOW" },
+
+ { (unsigned long)STATUS_FLOAT_STACK_CHECK,
+ "STATUS_FLOAT_STACK_CHECK" },
+
+ { (unsigned long)STATUS_FLOAT_UNDERFLOW,
+ "STATUS_FLOAT_UNDERFLOW" },
+
+ { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO,
+ "STATUS_INTEGER_DIVIDE_BY_ZERO" },
+
+ { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION,
+ "STATUS_PRIVILEGED_INSTRUCTION" },
+
+ { (unsigned long)_STATUS_STACK_OVERFLOW,
+ "_STATUS_STACK_OVERFLOW" }
+};
+
+#define XCPTNUMSTR_SZ ( sizeof XcptNumStr / sizeof XcptNumStr[0] )
+
+/*
+ * return string mnemonic for exception
+ */
+char * XcptNumToStr (
+ unsigned long xcptnum
+ )
+{
+ int indx;
+
+ for ( indx = 0 ; indx < XCPTNUMSTR_SZ ; indx++ )
+ if ( XcptNumStr[indx].num == xcptnum )
+ return(XcptNumStr[indx].str);
+
+ return(NULL);
+}
+
+struct signumstr {
+ int num;
+ char *str;
+};
+
+struct signumstr SigNumStr[] = {
+ { SIGINT, "SIGINT" },
+ { SIGILL, "SIGILL" },
+ { SIGFPE, "SIGFPE" },
+ { SIGSEGV, "SIGSEGV" },
+ { SIGTERM, "SIGTERM" },
+ { SIGBREAK, "SIGBREAK" },
+ { SIGABRT, "SIGABRT" }
+};
+
+#define SIGNUMSTR_SZ ( sizeof SigNumStr / sizeof SigNumStr[0] )
+
+/*
+ * return string mnemonic for signal
+ */
+char * SigNumToStr (
+ int signum
+ )
+{
+ int indx;
+
+ for ( indx = 0 ; indx < SIGNUMSTR_SZ ; indx++ )
+ if ( SigNumStr[indx].num == signum )
+ return(SigNumStr[indx].str);
+
+ return(NULL);
+}
+
+struct actcodestr {
+ _PHNDLR code;
+ char *str;
+};
+
+struct actcodestr ActCodeStr[] = {
+ { SIG_DFL, "SIG_DFL" },
+ { SIG_IGN, "SIG_IGN" },
+ { SIG_DIE, "SIG_DIE" }
+};
+
+#define ACTCODESTR_SZ ( sizeof ActCodeStr / sizeof ActCodeStr[0] )
+
+/*
+ * return string mnemonic for action code
+ */
+char * ActCodeToStr (
+ _PHNDLR action
+ )
+{
+ int indx;
+
+ for ( indx = 0 ; indx < ACTCODESTR_SZ ; indx++ )
+ if ( ActCodeStr[indx].code == action)
+ return(ActCodeStr[indx].str);
+
+ return("FUNCTION ADDRESS");
+}
+
+/*
+ * print out exception-action table entry
+ */
+void prXcptActTabEntry (
+ struct _XCPT_ACTION *pxcptact
+ )
+{
+ printf("XcptNum = %s\n", XcptNumToStr(pxcptact->XcptNum));
+ printf("SigNum = %s\n", SigNumToStr(pxcptact->SigNum));
+ printf("XcptAction = %s\n", ActCodeToStr(pxcptact->XcptAction));
+}
+
+/*
+ * print out all entries in the exception-action table
+ */
+void prXcptActTab (
+ void
+ )
+{
+ int indx;
+
+ for ( indx = 0 ; indx < _XcptActTabCount ; indx++ ) {
+ printf("\n_XcptActTab[%d] = \n", indx);
+ prXcptActTabEntry(&_XcptActTab[indx]);
+ }
+}
+
+#endif /* DEBUG */
+
+#endif /* _POSIX_ */
diff --git a/private/crt32/misc/wrt2err.c b/private/crt32/misc/wrt2err.c
new file mode 100644
index 000000000..40ebe675a
--- /dev/null
+++ b/private/crt32/misc/wrt2err.c
@@ -0,0 +1,84 @@
+/***
+*wrt2err.c - write an LSTRING to stderr (OS/2 version)
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains a routine __wrt2err that writes an LSTRING
+* (one byte length followed by the several bytes of the string)
+* to the standard error handle (2). This is a helper routine used
+* for MATH error messages (and also FORTRAN error messages). It
+* is in the C library rather than the math library because there
+* are separate MS-DOS and MS OS/2 versions.
+*
+*Revision History:
+* 06-30-89 PHG module created, based on asm version
+* 03-16-90 GJF Made calling type _CALLTYPE1, added #include
+* <cruntime.h> and fixed the copyright. Also, cleaned
+* up the formatting a bit.
+* 07-24-90 SBM Removed '32' from API names
+* 10-04-90 GJF New-style function declarator.
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 04-26-91 SRW Removed level 3 warnings
+* 07-18-91 GJF Replaced call to DbgPrint with WriteFile to standard
+* error handle [_WIN32_].
+*
+*******************************************************************************/
+
+#ifndef _POSIX_
+
+#include <cruntime.h>
+#include <oscalls.h>
+#include <internal.h>
+
+/***
+*__wrt2err(msg) - write an LSTRING to stderr
+*
+*Purpose:
+* Takes a near pointer in BX, which is a pointer to an LSTRING which
+* is to be written to standard error. An LSTRING is a one-byte length
+* followed by that many bytes for the character string (as opposed to
+* a null-terminated string).
+*
+*Entry:
+* char *msg = pointer to LSTRING to write to standard error.
+*
+*Exit:
+* Nothing returned.
+*
+*Exceptions:
+* None handled.
+*
+*******************************************************************************/
+
+void __wrt2err (
+ char *msg
+ )
+{
+ unsigned long length; /* length of string to write */
+ unsigned long numwritten; /* number of bytes written */
+
+ length = *msg++; /* 1st byte is length */
+
+ /* write the message to stderr */
+#ifdef _CRUISER_
+
+ DOSWRITE(2, msg, length, &numwritten);
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ WriteFile((HANDLE)_osfhnd[2], msg, length, &numwritten, NULL);
+
+#else /* ndef _WIN32_ */
+
+#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+}
+
+#endif /* _POSIX_ */
+