/*++

Copyright (c) 1991-2000 Microsoft Corporation

Module Name:

    basesys.cxx

--*/

#include <pch.cxx>

#define _ULIB_MEMBER_
#include "ulib.hxx"
#include "basesys.hxx"

ULIB_EXPORT
BOOLEAN
BASE_SYSTEM::QueryResourceString(
    OUT PWSTRING    ResourceString,
    IN  MSGID       MsgId,
    IN  PCSTR       Format ...
    )
/*++

Routine Description:

    This routine computes the resource string identified by the resource
    identifier 'MsgId'.  In addition to the 'printf' format strings
    supported, 'QueryResourceString' supports :

        1. '%W' - Expects a pointer to a WSTRING.

Arguments:

    ResourceString  - Returns the resource string.
    MsgId           - Supplies the message id of the resource string.
    Format          - Supplies a 'printf' style format descriptor for the
                        arguments to the resource string.
    ...             - Supplies the arguments to the resource string.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
    va_list ap;
    BOOLEAN r;

    va_start(ap, Format);
    r = QueryResourceStringV(ResourceString, MsgId, Format, ap);
    va_end(ap);

    return r;
}


ULIB_EXPORT
BOOLEAN
BASE_SYSTEM::QueryResourceStringV(
    OUT PWSTRING    ResourceString,
    IN  MSGID       MsgId,
    IN  PCSTR       Format,
    IN  va_list     VarPointer
    )
/*++

Routine Description:

    This is a 'varargs' implementation of 'QueryResourceString'.

Arguments:

    ResourceString  - Returns the resource string.
    MsgId           - Supplies the message id of the resource string.
    Format          - Supplies a 'printf' style format descriptor for the
                        arguments to the resource string.
    VarPointer      - Supplies a varargs pointer to the arguments of the
                        resource string.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
#define NUMBER_OF_ARGS      20

    STATIC HANDLE   lib_handle = 0;
    PWSTR           args[NUMBER_OF_ARGS];
    WSTR            fmt[20];
    INT             i, j;
    PWSTR           p;
    PWSTRING        gstring;
    DSTRING         UnicodeFormat;
    WSTR            display_buffer[4096];
    BOOL            found;
    NTSTATUS        Status;
    ULONG           Result;

    for (i = 0; i < NUMBER_OF_ARGS; i++) {
        args[i] = NULL;
    }

    if (!UnicodeFormat.Initialize(Format)) {
        return FALSE;
    }

    // convert args into an array for RtlFormatMessage.
    i = 0;
    for (p = (PWSTR) UnicodeFormat.GetWSTR(); *p; p++) {

        // if we have a %
        if (*p == '%') {

            // perform W substitutions
            if (*(p + 1) == 'W') {

                p++;
                gstring = va_arg(VarPointer, PWSTRING);
                gstring->QueryWSTR(0, TO_END, display_buffer, 4096);

            } else {
                // convert other substutitions as appropriate by building a fmt string
                j = 0;
                // copy the %
                fmt[j++] = *p++;
                // copy the next character as long at its not a % and not NULL
                while (*p && *p != '%') {
                    if ((*p == 's') && *(p - 1) != 'w') {
                        //if its an ANSI string
                        fmt[j++] = L'a';
                        p++;
                        continue;
                    } else if ((*p == 'c') && *(p - 1) != 'w') {
                        // if its an ANSI character
                        fmt[j++] = L'c'; // BUGBUG hack for now
                        p++;
                        continue;
                    } else if ((*p == 'w' ) && *(p + 1) == 's') {
                        // if its a wide string (%ws->%s)
                        fmt[j++] = L's';
                        p++;
                        p++; // skip the second char
                        continue;
                    } else if ((*p == 'w' ) && *(p + 1) == 'c') {
                        // if its a wide char (%wc->%c)
                        fmt[j++] = L'c';
                        p++;
                        p++; // skip the second char
                        continue;
                    } else if ((*p == 'u' )) {
                        // BUGBUG sprint doesn't seem to work with %u, replace with %d
                        fmt[j++] = L'd';
                        p++;
                    } else if (isdigit(*p)) {
                        // BUGBUG: HACK we skip digit format stuff since Sprint doesn't seem to like em.
                        p++;
                    } else {
                        // otherwise just copy the format indicator
                        fmt[j++] = *p++;
                    }
                }
                p--;
                fmt[j] = 0;

                if (wcsncmp(fmt, TEXT("%I64"), 4) == 0) {
                    // if its a 64 bit integer
                    // do some special stuff to handle LARGE_INTEGERS before telling SPrint to do its thing.
                    ULONGLONG t = (va_arg(VarPointer,LARGE_INTEGER)).QuadPart;
                    fmt[0]='%';
                    fmt[1]='l';
                    fmt[2]='d';
                    fmt[3]=NULL;
//                    Print(L"QueryResourceStringV: fmt: %s\n",fmt);
                    SPrint(display_buffer, 4096, fmt, t);
                } else {
                    // otherwise tell SPrint to do its thing
                    PVOID   voidptr = va_arg(VarPointer, PVOID);
//                    Print(L"QueryResourceStringV: fmt: %s\n",fmt);
                    SPrint(display_buffer, 4096,fmt,voidptr );
                }
            }

            // allocate a buffer and copy the converted string into it.
            args[i] = (PWSTR)MALLOC(wcslen(display_buffer) * sizeof(WCHAR) + sizeof(WCHAR));
            if (NULL == args[i]) {
                return FALSE;
            }
            wcscpy( args[i], display_buffer);

//            Print(L"QueryResourceStringV: args[%d]: %s\n",i,args[i]);

            i++;
        }
    }

    found = FALSE;
    // locate the right message in our table
    for(i=0;i<EFI_MESSAGE_COUNT;i++) {
        if(MessageTable[i].msgId == MsgId ){
            found = TRUE;
            break;
        }
    }

    if (found == FALSE) {
        return FALSE;
    }

    WCHAR *MessageFormat = MessageTable[i].string;

    // shove it through RtlFormatMessage.
    Status = RtlFormatMessage( MessageFormat,
                               0,
                               FALSE,
                               FALSE,
                               TRUE,
                               (va_list *)args,
                               (PWSTR)display_buffer,
                               sizeof( display_buffer ),
                               &Result
                             );

    for (i = 0; i < NUMBER_OF_ARGS; i++) {
        FREE(args[i]);
    }

    if (!NT_SUCCESS( Status )) {
        return FALSE;
    }

    return ResourceString->Initialize(display_buffer);
}