/*
    Copyright (C) 1995-1997
        Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld
        email: rainer@mathematik.uni-bielefeld.de

    All rights reserved
*/

#include <rsxnt.h>

/* ------------------------------------------------------------------------ *\
    process tables

    NT and Win95 only need one   - dll is local to process
    Win32s needs one per process - dll is global
\* ------------------------------------------------------------------------ */

static EMXPROCESS win32_process;

#ifdef EMX_SYS_LIB

EMXPROCESS * _rsxnt_get_process_ptr(void)
{
    return &win32_process;
}

#else

static EMXPROCESS *win32s_pptr[MAX_PROCESS];

static EMXPROCESS * get_empty_process_ptr(void)
{
    EMXPROCESS *pptr;

    if (_rsxnt_win32_version > WIN32S) {
        pptr = &win32_process;
    }
    else {
        DWORD i;
        for (i = 0; i < MAX_PROCESS; i++)
            if (win32s_pptr[i] == NULL)
                break;
        if (i >= MAX_PROCESS)
            return NULL;

        pptr = (EMXPROCESS *) HeapAlloc(
                GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EMXPROCESS));
        if (!pptr)
            return NULL;
        win32s_pptr[i] = pptr;
    }
    pptr->pid = pptr->dwProcessId = GetCurrentProcessId();
    pptr->hProcess = GetCurrentProcess();

    if (pptr->pid < 0) /* win95 uses negative values */
        pptr->pid = - pptr->pid;

    return pptr;
}

static void remove_process_ptr(void)
{
    if (_rsxnt_win32_version > WIN32S) {
        memset (&win32_process, 0, sizeof(EMXPROCESS));
    }
    else {
        DWORD i;
        DWORD dwProcessId;

        dwProcessId = GetCurrentProcessId();
        for (i = 0; i < MAX_PROCESS; i++)
            if (win32s_pptr[i]->dwProcessId == dwProcessId) {
                win32s_pptr[i] = 0;
                break;
            }
    }
}

EMXPROCESS * _rsxnt_get_process_ptr(void)
{
    if (_rsxnt_win32_version > WIN32S)
        return &win32_process;
    else {
        DWORD i;
        DWORD dwProcessId;

        dwProcessId = GetCurrentProcessId();
        for (i = 0; i < MAX_PROCESS; i++)
            if (win32s_pptr[i]->dwProcessId == dwProcessId)
                return (win32s_pptr[i]);
    return NULL;
    }
}

/* ------------------------------------------------------------------------ *\
    DLL Entry:

    - get win32 version
    - allocate process pointer
\* ------------------------------------------------------------------------ */

#ifdef __WATCOMC__
#pragma aux (__stdcall) LibMain "_LibMain"
#endif

int APIENTRY LibMain(HANDLE hInst, DWORD fdwReason, LPVOID lpReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH) {
        EMXPROCESS *pptr;

        if (_rsxnt_win32_version == EMPTY) {
            DWORD rc = GetVersion();

            if (!(rc & 0x80000000))         /* bit 31: 1=Win16 0=Win32 */
                _rsxnt_win32_version = WIN32;
            else if (rc & 0x40000000)       /* bit 30: 1=Win95 ??? */
                _rsxnt_win32_version = WIN32C;
            else
                _rsxnt_win32_version = WIN32S;
        }
        if ((pptr = get_empty_process_ptr()) == NULL)
            return FALSE;

        _rsxnt_init_sockets();
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        remove_process_ptr();
        _rsxnt_exit_sockets();
    }
    return TRUE;
}

/* ------------------------------------------------------------------------ *\
    Entry for emx syscalls

    - check for dos or emx system calls
    - check signals
\* ------------------------------------------------------------------------ */

#ifdef DEBUG
#include <stdio.h>
#endif

void __cdecl sys_call(SYSCALL_FRAME * regs)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();

    if (p->syscall_state == SYSCALL_STATE_NONE) {

        MessageBox(NULL,
            "Warning: This standalone DLL is not supported",
            "RSXNT", MB_OK|MB_ICONERROR|MB_APPLMODAL|MB_SETFOREGROUND);

        regs->e.eax = -1;
        regs->e.ecx = -1;
        regs->e.eflags |= 1;
        return;
    }

#ifdef DEBUG
printf(" in: ax=%04X bx=%08lX cx=%08lX dx=%08lX si=%08lX di=%08lX \n",
        regs->x.ax,regs->e.ebx,regs->e.ecx,regs->e.edx,regs->e.esi,regs->e.edi);
#endif

    if (regs->h.ah == 0x7f)
        _rsxnt_emx_call(regs);
    else
        _rsxnt_dos_call(regs);

#ifdef DEBUG
printf("out: ax=%08lX bx=%08lX cx=%08lX dx=%08lX si=%08lX di=%08lX \n",
        regs->e.eax,regs->e.ebx,regs->e.ecx,regs->e.edx,regs->e.esi,regs->e.edi);
#endif

    _rsxnt_check_signals();
}
#endif
