/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    lcompat.c

Abstract:

    This module implements the _l and l compatability functions
    like _lread, lstrlen...

Author:

    Mark Lucovsky (markl) 13-Mar-1991

Revision History:

--*/

#include "basedll.h"

int
WINAPI
_lopen(
    LPCSTR lpPathName,
    int iReadWrite
    )
{

    HANDLE hFile;
    DWORD DesiredAccess;
    DWORD ShareMode;
    DWORD CreateDisposition;

    SetLastError(0);
    //
    // Compute Desired Access
    //

    if ( iReadWrite & OF_WRITE ) {
        DesiredAccess = GENERIC_WRITE;
        }
    else {
        DesiredAccess = GENERIC_READ;
        }
    if ( iReadWrite & OF_READWRITE ) {
        DesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
        }

    //
    // Compute ShareMode
    //

    ShareMode = BasepOfShareToWin32Share((DWORD)iReadWrite);

    CreateDisposition = OPEN_EXISTING;

    //
    // Open the file
    //

    hFile = CreateFile(
                lpPathName,
                DesiredAccess,
                ShareMode,
                NULL,
                CreateDisposition,
                0,
                NULL
                );

    return (HFILE)HandleToUlong(hFile);
}

HFILE
WINAPI
_lcreat(
    LPCSTR lpPathName,
    int  iAttribute
    )
{
    HANDLE hFile;
    DWORD DesiredAccess;
    DWORD ShareMode;
    DWORD CreateDisposition;

    SetLastError(0);

    //
    // Compute Desired Access
    //

    DesiredAccess = (GENERIC_READ | GENERIC_WRITE);

    ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;;

    //
    // Compute Create Disposition
    //

    CreateDisposition = CREATE_ALWAYS;

    //
    // Open the file
    //

    hFile = CreateFile(
                lpPathName,
                DesiredAccess,
                ShareMode,
                NULL,
                CreateDisposition,
                iAttribute & FILE_ATTRIBUTE_VALID_FLAGS,
                NULL
                );

    return (HFILE)HandleToUlong(hFile);
}

UINT
WINAPI
_lread(
    HFILE hFile,
    LPVOID lpBuffer,
    UINT uBytes
    )
{
    DWORD BytesRead;
    BOOL b;

    b = ReadFile((HANDLE)IntToPtr(hFile),lpBuffer,(DWORD)uBytes,&BytesRead,NULL);
    if ( b ) {
        return BytesRead;
        }
    else {
        return (DWORD)0xffffffff;
        }
}


UINT
WINAPI
_lwrite(
    HFILE hFile,
    LPCSTR lpBuffer,
    UINT uBytes
    )
{
    DWORD BytesWritten;
    BOOL b;

    if ( uBytes ) {
        b = WriteFile((HANDLE)IntToPtr(hFile),(CONST VOID *)lpBuffer,(DWORD)uBytes,&BytesWritten,NULL);
        }
    else {
        BytesWritten = 0;
        b = SetEndOfFile((HANDLE)IntToPtr(hFile));
        }

    if ( b ) {
        return BytesWritten;
        }
    else {
        return (DWORD)0xffffffff;
        }
}

HFILE
WINAPI
_lclose(
    HFILE hFile
    )
{
    BOOL b;

    b = CloseHandle((HANDLE)IntToPtr(hFile));
    if ( b ) {
        return (HFILE)0;
        }
    else {
        return (HFILE)-1;
        }
}

LONG
WINAPI
_llseek(
    HFILE hFile,
    LONG lOffset,
    int iOrigin
    )
{
    DWORD SeekType;

    switch ( iOrigin ) {
        case 0:
            SeekType = FILE_BEGIN;
            break;
        case 1:
            SeekType = FILE_CURRENT;
            break;
        case 2:
            SeekType = FILE_END;
            break;
        default:
            return -1;
            }

    return (int)SetFilePointer((HANDLE)IntToPtr(hFile), lOffset, NULL, SeekType);
}

#if defined(_AMD64_) || defined(_IA64_)

int
WINAPI
MulDiv (
    int nNumber,
    int nNumerator,
    int nDenominator
    )

{

    LONG Negate;
    union {
        LARGE_INTEGER Product;
        struct {
            ULONG Quotient;
            ULONG Remainder;
        };
    } u;

    //
    // Compute the size of the result.
    //

    Negate = nNumber ^ nNumerator ^ nDenominator;

    //
    // Get the absolute value of the operand values.
    //

    if (nNumber < 0) {
        nNumber = - nNumber;
    }

    if (nNumerator < 0) {
        nNumerator = - nNumerator;
    }

    if (nDenominator < 0) {
        nDenominator = - nDenominator;
    }

    //
    // Compute the 64-bit product of the multiplier and multiplicand
    // values and round.
    //

    u.Product.QuadPart =
        Int32x32To64(nNumber, nNumerator) + ((ULONG)nDenominator / 2);

    //
    // If there are any high order product bits, then the quotient has
    // overflowed.
    //

    if ((ULONG)nDenominator > u.Remainder) {

        //
        // Divide the 64-bit product by the 32-bit divisor forming a 32-bit
        // quotient and a 32-bit remainder.
        //

        u.Quotient = RtlEnlargedUnsignedDivide(*(PULARGE_INTEGER)&u.Product,
                                               (ULONG)nDenominator,
                                               &u.Remainder);

        //
        // Compute the final signed result.
        //

        if ((LONG)u.Quotient >= 0) {
            if (Negate >= 0) {
                return (LONG)u.Quotient;

            } else {
                return - (LONG)u.Quotient;
            }
        }
    }

    return - 1;
}

#endif

int
APIENTRY
lstrcmpA(
    LPCSTR lpString1,
    LPCSTR lpString2
    )
{
    int retval;

    retval = CompareStringA( GetThreadLocale(),
                             LOCALE_USE_CP_ACP,
                             lpString1,
                             -1,
                             lpString2,
                             -1 );
    if (retval == 0)
    {
        //
        // The caller is not expecting failure.  Try the system
        // default locale id.
        //
        retval = CompareStringA( GetSystemDefaultLCID(),
                                 LOCALE_USE_CP_ACP,
                                 lpString1,
                                 -1,
                                 lpString2,
                                 -1 );
    }

    if (retval == 0)
    {
        if (lpString1 && lpString2)
        {
            //
            // The caller is not expecting failure.  We've never had a
            // failure indicator before.  We'll do a best guess by calling
            // the C runtimes to do a non-locale sensitive compare.
            //
            return strcmp(lpString1, lpString2);
        }
        else if (lpString1)
        {
            return (1);
        }
        else if (lpString2)
        {
            return (-1);
        }
        else
        {
            return (0);
        }
    }

    return (retval - 2);
}

int
APIENTRY
lstrcmpiA(
    LPCSTR lpString1,
    LPCSTR lpString2
    )
{
    int retval;

    retval = CompareStringA( GetThreadLocale(),
                             LOCALE_USE_CP_ACP | NORM_IGNORECASE,
                             lpString1,
                             -1,
                             lpString2,
                             -1 );
    if (retval == 0)
    {
        //
        // The caller is not expecting failure.  Try the system
        // default locale id.
        //
        retval = CompareStringA( GetSystemDefaultLCID(),
                                 LOCALE_USE_CP_ACP | NORM_IGNORECASE,
                                 lpString1,
                                 -1,
                                 lpString2,
                                 -1 );
    }
    if (retval == 0)
    {
        if (lpString1 && lpString2)
        {
            //
            // The caller is not expecting failure.  We've never had a
            // failure indicator before.  We'll do a best guess by calling
            // the C runtimes to do a non-locale sensitive compare.
            //
            return ( _stricmp(lpString1, lpString2) );
        }
        else if (lpString1)
        {
            return (1);
        }
        else if (lpString2)
        {
            return (-1);
        }
        else
        {
            return (0);
        }
    }

    return (retval - 2);
}

LPSTR
APIENTRY
lstrcpyA(
    LPSTR lpString1,
    LPCSTR lpString2
    )
{
    __try {
        return strcpy(lpString1, lpString2);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }
}


LPSTR
APIENTRY
lstrcpynA(
    LPSTR lpString1,
    LPCSTR lpString2,
    int iMaxLength
    )
{
    LPSTR src,dst;

    __try {
        src = (LPSTR)lpString2;
        dst = lpString1;

        if ( iMaxLength ) {
            while(iMaxLength && *src){
                *dst++ = *src++;
                iMaxLength--;
                }
            if ( iMaxLength ) {
                *dst = '\0';
                }
            else {
                dst--;
                *dst = '\0';
                }
            }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }

   return lpString1;
}

LPSTR
APIENTRY
lstrcatA(
    LPSTR lpString1,
    LPCSTR lpString2
    )
{
    __try {
        return strcat(lpString1, lpString2);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }
}

int
APIENTRY
lstrlenA(
    LPCSTR lpString
    )
{
    if (!lpString)
        return 0;
    __try {
        return strlen(lpString);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return 0;
    }
}

int
APIENTRY
lstrcmpW(
    LPCWSTR lpString1,
    LPCWSTR lpString2
    )
{
    int retval;

    retval = CompareStringW( GetThreadLocale(),
                             0,
                             lpString1,
                             -1,
                             lpString2,
                             -1 );
    if (retval == 0)
    {
        //
        // The caller is not expecting failure.  Try the system
        // default locale id.
        //
        retval = CompareStringW( GetSystemDefaultLCID(),
                                 0,
                                 lpString1,
                                 -1,
                                 lpString2,
                                 -1 );
    }
    if (retval == 0)
    {
        if (lpString1 && lpString2)
        {
            //
            // The caller is not expecting failure.  We've never had a
            // failure indicator before.  We'll do a best guess by calling
            // the C runtimes to do a non-locale sensitive compare.
            //
            return ( wcscmp(lpString1, lpString2) );
        }
        else if (lpString1)
        {
            return (1);
        }
        else if (lpString2)
        {
            return (-1);
        }
        else
        {
            return (0);
        }
    }

    return (retval - 2);
}

int
APIENTRY
lstrcmpiW(
    LPCWSTR lpString1,
    LPCWSTR lpString2
    )
{
    int retval;

    retval = CompareStringW( GetThreadLocale(),
                             NORM_IGNORECASE,
                             lpString1,
                             -1,
                             lpString2,
                             -1 );
    if (retval == 0)
    {
        //
        // The caller is not expecting failure.  Try the system
        // default locale id.
        //
        retval = CompareStringW( GetSystemDefaultLCID(),
                                 NORM_IGNORECASE,
                                 lpString1,
                                 -1,
                                 lpString2,
                                 -1 );
    }
    if (retval == 0)
    {
        if (lpString1 && lpString2)
        {
            //
            // The caller is not expecting failure.  We've never had a
            // failure indicator before.  We'll do a best guess by calling
            // the C runtimes to do a non-locale sensitive compare.
            //
            return ( _wcsicmp(lpString1, lpString2) );
        }
        else if (lpString1)
        {
            return (1);
        }
        else if (lpString2)
        {
            return (-1);
        }
        else
        {
            return (0);
        }
    }

    return (retval - 2);
}

LPWSTR
APIENTRY
lstrcpyW(
    LPWSTR lpString1,
    LPCWSTR lpString2
    )
{
    __try {
        return wcscpy(lpString1, lpString2);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }
}

LPWSTR
APIENTRY
lstrcpynW(
    LPWSTR lpString1,
    LPCWSTR lpString2,
    int iMaxLength
    )
{
    LPWSTR src,dst;

    __try {
        src = (LPWSTR)lpString2;
        dst = lpString1;

        if ( iMaxLength ) {
            while(iMaxLength && *src){
                *dst++ = *src++;
                iMaxLength--;
                }
            if ( iMaxLength ) {
                *dst = '\0';
                }
            else {
                dst--;
                *dst = '\0';
                }
            }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }

    return lpString1;
}

LPWSTR
APIENTRY
lstrcatW(
    LPWSTR lpString1,
    LPCWSTR lpString2
    )
{
    __try {
        return wcscat(lpString1, lpString2);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return NULL;
    }
}

int
APIENTRY
lstrlenW(
    LPCWSTR lpString
    )
{
    if (!lpString)
        return 0;
    __try {
        return wcslen(lpString);
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return 0;
    }
}
