/*
 *  ReactOS test program -
 *
 *  loadlib.c
 *
 *  Copyright (C) 2002  Robert Dickenson <robd@reactos.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <windows.h>
#include "loadlib.h"
#include <string.h>
#include <stdlib.h>
#include <wchar.h>

#define APP_VERSION 1
#define MAX_LIBS    25

#ifdef UNICODE
#define TARGET  "UNICODE"
BOOL bUseAnsi = FALSE;
#else
#define TARGET  "MBCS"
BOOL bUseAnsi = TRUE;
#endif
BOOL verbose_flagged = FALSE;
BOOL debug_flagged = FALSE;
BOOL loop_flagged = FALSE;
BOOL recursive_flagged = FALSE;

HANDLE OutputHandle;
HANDLE InputHandle;


void dprintf(char* fmt, ...)
{
   va_list args;
   char buffer[255];

   va_start(args, fmt);
   wvsprintfA(buffer, fmt, args);
   WriteConsoleA(OutputHandle, buffer, lstrlenA(buffer), NULL, NULL);
   va_end(args);
}

long getinput(char* buf, int buflen)
{
    DWORD result;

    ReadConsoleA(InputHandle, buf, buflen, &result, NULL);
    return (long)result;
}

DWORD ReportLastError(void)
{
    DWORD dwError = GetLastError();
    if (dwError != ERROR_SUCCESS) {
        PSTR msg = NULL;
        if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
            0, dwError, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PSTR)&msg, 0, NULL)) {
            if (msg != NULL) {
                dprintf("ReportLastError() %d - %s\n", dwError, msg);
            } else {
                dprintf("ERROR: ReportLastError() %d - returned TRUE but with no msg string!\n", dwError);
            }
        } else {
            dprintf("ReportLastError() %d - unknown error\n", dwError);
        }
        if (msg != NULL) {
            LocalFree(msg);
        }
    }
    return dwError;
}

const char* appName(const char* argv0)
{
    const char* name;

    name = (const char*)strrchr(argv0, '\\');
    if (name != NULL)
        return name + 1;
    return argv0;
}

int usage(const char* appName)
{
    dprintf("USAGE: %s libname [libname ...] [unicode]|[ansi] [loop][recurse]\n", appName);
    dprintf("\tWhere libname(s) is one or more libraries to load.\n");
    dprintf("\t[unicode] - perform tests using UNICODE api calls\n");
    dprintf("\t[ansi] - perform tests using ANSI api calls\n");
    dprintf("\t    default is %s\n", TARGET);
    dprintf("\t[loop] - run test process in continuous loop\n");
    dprintf("\t[recurse] - load libraries recursively rather than sequentually\n");
    dprintf("\t[debug] - enable debug mode (unused)\n");
    dprintf("\t[verbose] - enable verbose output (unused)\n");
    return 0;
}

DWORD LoadLibraryList(char** libnames, int counter, BOOL bUseAnsi)
{
    HMODULE hModule;

    dprintf("Attempting to LoadLibrary");
    if (bUseAnsi) {
        dprintf("A(%s) - ", *libnames);
        hModule = LoadLibraryA(*libnames);
    } else {
        int len;
        wchar_t libnameW[500];
        len = mbstowcs(libnameW, *libnames, strlen(*libnames));
        if (len) {
            libnameW[len] = L'\0';
            dprintf("W(%S) - ", libnameW);
            hModule = LoadLibraryW(libnameW);
        } else {
            return ERROR_INVALID_PARAMETER;
        }
    }
    if (hModule == NULL) {
        dprintf("\nERROR: failed to obtain handle to module %s - %x\n", *libnames, hModule);
        return ReportLastError();
    }
    dprintf("%x\n", hModule);

    if (counter--) {
        LoadLibraryList(++libnames, counter, bUseAnsi);
    }

    if (!FreeLibrary(hModule)) {
        dprintf("ERROR: failed to free module %s - %x\n", *libnames, hModule);
        return ReportLastError();
    } else {
        dprintf("FreeLibrary(%x) - successfull.\n", hModule);
    }
    return 0L;
}

int __cdecl main(int argc, char* argv[])
{
    char* libs[MAX_LIBS];
    int lib_count = 0;
    int result = 0;
    int i = 0;

    AllocConsole();
    InputHandle = GetStdHandle(STD_INPUT_HANDLE);
    OutputHandle =  GetStdHandle(STD_OUTPUT_HANDLE);

    dprintf("%s application - build %03d (default: %s)\n", appName(argv[0]), APP_VERSION, TARGET);
    if (argc < 2) {
        /*return */usage(appName(argv[0]));
    }
    memset(libs, 0, sizeof(libs));
    for (i = 1; i < argc; i++) {
        if (lstrcmpiA(argv[i], "ansi") == 0) {
            bUseAnsi = TRUE;
        } else if (lstrcmpiA(argv[i], "unicode") == 0) {
            bUseAnsi = FALSE;
        } else if (lstrcmpiA(argv[i], "loop") == 0) {
            loop_flagged = 1;
        } else if (lstrcmpiA(argv[i], "recurse") == 0) {
            recursive_flagged = 1;
        } else if (lstrcmpiA(argv[i], "verbose") == 0) {
            verbose_flagged = 1;
        } else if (lstrcmpiA(argv[i], "debug") == 0) {
            debug_flagged = 1;
        } else {
            if (lib_count < MAX_LIBS) {
                libs[lib_count] = argv[i];
                ++lib_count;
            }
        }
    }
    if (lib_count) {
        do {
            if (recursive_flagged) {
                result = LoadLibraryList(libs, lib_count - 1, bUseAnsi);
            } else {
                for (i = 0; i < lib_count; i++) {
                    result = LoadLibraryList(&libs[i], 0, bUseAnsi);
                    //if (result != 0) break;
                }
            }
        } while (loop_flagged);
    } else {
        int len;
        char buffer[500];
        do {
            dprintf("\nEnter library name to attempt loading: ");
            len = getinput(buffer, sizeof(buffer) - 1);
            if (len > 2) {
                char* buf = buffer;
                buffer[len-2] = '\0';
                result = LoadLibraryList(&buf, 0, bUseAnsi);
            } else break;
        } while (!result && len);
    }
    dprintf("finished\n");
    return result;
}


#ifdef _NOCRT
char* args[] = { "loadlib.exe", "advapi32.dll", "user32.dll", "recurse"};
int __cdecl mainCRTStartup(void)
{
    return main(3, args);
}
#endif /*__GNUC__*/