/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    mcutil.c

Abstract:

    This file contains utility functions for the Win32 Message Compiler (MC)

Author:

    Steve Wood (stevewo) 22-Aug-1991

Revision History:

--*/

#include "mc.h"

typedef BOOL (*PISTEXTUNICODE_ROUTINE)(
    CONST LPVOID lpBuffer,
    int cb,
    LPINT lpi
    );

PISTEXTUNICODE_ROUTINE OptionalIsTextUnicode = NULL;

BOOL
DefaultIsTextUnicode(
    CONST LPVOID lpBuffer,
    int cb,
    LPINT lpi
    )
{
    return FALSE;
}

PNAME_INFO
McAddName(
    PNAME_INFO *NameListHead,
    WCHAR *Name,
    ULONG Id,
    PVOID Value
    )
{
    PNAME_INFO p;
    int n;

    while (p = *NameListHead) {
        if (!(n = _wcsicmp( p->Name, Name ))) {
            if (p->Id != Id) {
                McInputErrorW( L"Redefining value of %s", FALSE, Name );
            }

            p->Id = Id;
            p->Value = Value;
            p->Used = FALSE;
            return( p );
        } else if (n < 0) {
            break;
        }

        NameListHead = &p->Next;
    }

    p = malloc( sizeof( *p ) + ( wcslen( Name ) + 1 ) * sizeof( WCHAR ) );
    p->LastId = 0;
    p->Id = Id;
    p->Value = Value;
    p->Used = FALSE;
    p->CodePage = GetOEMCP();
    wcscpy( p->Name, Name );
    p->Next = *NameListHead;
    *NameListHead = p;
    return( p );
}


PNAME_INFO
McFindName(
    PNAME_INFO NameListHead,
    WCHAR *Name
    )
{
    PNAME_INFO p;

    p = NameListHead;
    while (p) {
        if (!_wcsicmp( p->Name, Name )) {
            p->Used = TRUE;
            break;
        }

        p = p->Next;
    }

    return( p );
}


BOOLEAN
McCharToInteger(
    WCHAR *String,
    int Base,
    PULONG Value
    )
{
    WCHAR c;
    ULONG Result, Digit, Shift;

    c = *String++;
    if (!Base) {
        Base = 10;
        Shift = 0;
        if (c == L'0') {
            c = *String++;
            if (c == L'x') {
                Base = 16;
                Shift = 4;
            } else if (c == L'o') {
                Base = 8;
                Shift = 3;
            } else if (c == L'b') {
                Base = 2;
                Shift = 1;
            } else {
                String--;
            }

            c = *String++;
        }
    } else {
        switch( Base ) {
            case 16:    Shift = 4;  break;
            case  8:    Shift = 3;  break;
            case  2:    Shift = 1;  break;
            case 10:    Shift = 0;  break;
            default:    return( FALSE );
        }
    }

    Result = 0;
    while (c) {
        if (c >= L'0' && c <= L'9') {
            Digit = c - L'0';
        }
        else if (c >= L'A' && c <= L'F') {
            Digit = c - L'A' + 10;
        }
        else if (c >= L'a' && c <= L'f') {
            Digit = c - L'a' + 10;
        } else {
            break;
        }

        if ((int)Digit >= Base) {
            break;
        }

        if (Shift == 0) {
            Result = (Base * Result) + Digit;
        } else {
            Result = (Result << Shift) | Digit;
        }

        c = *String++;
    }

    *Value = Result;
    return( TRUE );
}


WCHAR *
McMakeString(
    WCHAR *String
    )
{
    WCHAR *s;

    s = malloc( ( wcslen( String ) + 1 ) * sizeof( WCHAR ) );
    wcscpy( s, String );
    return( s );
}


BOOLEAN
IsFileUnicode (char * fName)
{
#define CCH_READ_MAX  200
    WORD     cbRead;
    INT      value = 0xFFFFFFFF;
    FILE    *fp;
    LPVOID   lpBuf;
    BOOLEAN  result;

    if (OptionalIsTextUnicode == NULL) {
        OptionalIsTextUnicode = (PISTEXTUNICODE_ROUTINE)GetProcAddress( LoadLibrary( "ADVAPI32.DLL" ), "IsTextUnicode" );
        if (OptionalIsTextUnicode == NULL) {
            OptionalIsTextUnicode = DefaultIsTextUnicode;
        }
    }

    if ( ( fp = fopen( fName, "rb" ) ) == NULL )
        return (FALSE);

    lpBuf = malloc( CCH_READ_MAX + 10 );
    if (!lpBuf) {
        fclose( fp );
        return( FALSE );
    }

    cbRead = fread( lpBuf, 1, CCH_READ_MAX, fp );
    result = (BOOLEAN) (*OptionalIsTextUnicode)( lpBuf, cbRead, &value );

    fclose( fp );
    free( lpBuf );

    return( result );
}

BOOLEAN
MyIsDBCSLeadByte(UCHAR c)
{
    int i;
    CPINFO* PCPInfo = &CPInfo;

    if (PCPInfo == NULL) {
        return FALSE;
    }

    if (!PCPInfo->MaxCharSize) {
        return(IsDBCSLeadByte(c));
    }

    if (PCPInfo->MaxCharSize == 1) {
        return FALSE;
    }

    for (i=0 ; i<MAX_LEADBYTES ; i+=2) {
        if (PCPInfo->LeadByte[i] == 0 && PCPInfo->LeadByte[i+1] == 0)
            return FALSE;
        if (c >= PCPInfo->LeadByte[i] && c <= PCPInfo->LeadByte[i+1])
            return TRUE;
    }
    return FALSE;
}

WCHAR *
fgetsW (WCHAR * string, long count, FILE * fp)
{
    UCHAR ch[2];
    WCHAR *pch = string;
    DWORD nBytesRead;

    assert (string != NULL);
    assert (fp != NULL);

    if (count <= 0)
        return (NULL);

    while (--count) {
        if (UnicodeInput) {
            nBytesRead = fread (ch, 1, sizeof(WCHAR), fp);
        } else {
            nBytesRead = fread (ch, 1, 1, fp);
            ch[1] = '\0';
        }

        //
        //  if there are no more characters, end the line
        //

        if (feof (fp)) {
            if (pch == string)
                return (NULL);
            break;
        }

        if (ch[0] < 128 || UnicodeInput) {
            *pch = *(WCHAR*)&ch[0];
        } else if (MyIsDBCSLeadByte(ch[0])) {
            nBytesRead = fread (&ch[1], 1, 1, fp);
            MultiByteToWideChar(CurrentLanguageName->CodePage, 0, ch, 2, pch, 1);
        } else {
            MultiByteToWideChar(CurrentLanguageName->CodePage, 0, ch, 1, pch, 1);
        }

        pch++;
        if (*(pch-1) == L'\n') {
            break;
        }
    }

    *pch = L'\0';

    return (string);
}