/**
 * =========================================================================
 * File        : wposix.cpp
 * Project     : 0 A.D.
 * Description : emulate a subset of POSIX on Win32.
 * =========================================================================
 */

// license: GPL; see lib/license.txt

#include "precompiled.h"
#include "wposix.h"

#include "wposix_internal.h"
#include "crt_posix.h"      // _getcwd
#include "lib/bits.h"

WINIT_REGISTER_CRITICAL_INIT(wposix_Init);  // wposix -> error handling

//-----------------------------------------------------------------------------
// sysconf

// used by _SC_PAGESIZE and _SC_*_PAGES
static DWORD pageSize;
static DWORD numProcessors;
static BOOL (WINAPI *pGlobalMemoryStatusEx)(MEMORYSTATUSEX*);  

static void InitSysconf()
{
    SYSTEM_INFO si;
    GetSystemInfo(&si); // can't fail
    pageSize      = si.dwPageSize;  // used by _SC_PAGESIZE and _SC_*_PAGES
    numProcessors = si.dwNumberOfProcessors;

    // import GlobalMemoryStatusEx - it's not defined by the VC6 PSDK.
    // used by _SC_*_PAGES if available (provides better results).
    const HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");  
    *(void**)&pGlobalMemoryStatusEx = GetProcAddress(hKernel32Dll, "GlobalMemoryStatusEx"); 
    FreeLibrary(hKernel32Dll);
}

long sysconf(int name)
{
    // called before InitSysconf => winit/wstartup are broken. this is
    // going to cause a hard crash because debug.cpp's error reporting
    // code requires the page size to be known. we'll raise an exception
    // with a unique value so that this issue is immediately noticed.
    if(!pageSize)
        RaiseException(0xFA57FA57, 0, 0, 0);

    switch(name)
    {
    case _SC_PAGESIZE:
    // note: no separate case for _SC_PAGE_SIZE - they are
    // different names but have the same value.
        return pageSize;

    case _SC_PHYS_PAGES:
    case _SC_AVPHYS_PAGES:
        {
        u64 total_phys_mem;
        u64 avail_phys_mem;

        // first query GlobalMemoryStatus - cannot fail.
        // override its results if GlobalMemoryStatusEx is available.
        {
        MEMORYSTATUS ms;
        GlobalMemoryStatus(&ms);
        total_phys_mem = ms.dwTotalPhys;
        avail_phys_mem = ms.dwAvailPhys;
        }

        // newer API is available: use it to report correct results
        // (no overflow or wraparound) on systems with > 4 GB of memory.
        {
        MEMORYSTATUSEX mse = { sizeof(mse) };
        if(pGlobalMemoryStatusEx && pGlobalMemoryStatusEx(&mse))
        {
            total_phys_mem = mse.ullTotalPhys;
            avail_phys_mem = mse.ullAvailPhys;
        }
        // else: not an error, since this isn't available before Win2k / XP.
        // we have results from GlobalMemoryStatus anyway.
        }

        // Richter, "Programming Applications for Windows": the reported
        // value doesn't include non-paged pool reserved during boot;
        // it's not considered available to kernel. (size is 528 KiB on
        // a 512 MiB WinXP/Win2k machine)
        // something similar may happen on other OSes, so it is fixed
        // by cpu.cpp instead of here.

        if(name == _SC_PHYS_PAGES)
            return (long)(total_phys_mem / pageSize);
        else
            return (long)(avail_phys_mem / pageSize);
        }

    case _SC_NPROCESSORS_CONF:
        return numProcessors;

    default:
        return -1;
    }
}


//-----------------------------------------------------------------------------

#ifdef REDEFINED_NEW
#include "lib/nommgr.h"
#endif
char* getcwd(char* buf, size_t buf_size)
{
    return _getcwd(buf, (int)buf_size);
}
#ifdef REDEFINED_NEW
#include "lib/mmgr.h"
#endif


//-----------------------------------------------------------------------------

static LibError wposix_Init()
{
    InitSysconf();
    return INFO::OK;
}