
/*
 *@@sourcefile procstat.c:
 *      functions for querying process information.
 *
 *      Function prefixes (new with V0.81):
 *      --  prc*   Query Process helper functions
 *
 *@@include #include <os2.h>
 *@@include #include "procstat.h"
 */

/*
 *      Based on Kai Uwe Rommel's "dosqproc" package
 *      available at Hobbes.
 *      This file Copyright (C) 1992-99 Ulrich M”ller,
 *                                      Kai Uwe Rommel.
 *      This file is part of the XFolder source package.
 *      XFolder 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, in version 2 as it comes in the
 *      "COPYING" file of the XFolder main distribution.
 *      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.
 */

#define INCL_DOS
#define INCL_DOSMODULEMGR
#include <os2.h>

#include <stdlib.h>      // already #include'd
#include <string.h>      // already #include'd
#include <stdio.h>

#include "procstat.h"

/********************************************************************
 *                                                                  *
 *   Functions for querying process information                     *
 *                                                                  *
 ********************************************************************/

/*
 * prcTimestr:
 *
 */

/* void prcTimestr(ULONG time, char *buffer)
{
  ULONG seconds, hundredths;

  seconds = time / 32;
  hundredths = (time % 32) * 100 / 32;

  sprintf(buffer, "%ld:%02ld.%02ld", seconds / 60, seconds % 60, hundredths);
} */

/*
 * prcSearchProcTree:
 *
 */

/* BOOL prcSearchProcTree(PQPROCSTAT pps, USHORT usSearchPID, USHORT usCheckPID, PPRCPROCESS pprcp)
{
    PQPROCESS pProcess;

    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3; // not sure if there isn't another termination method
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        if (    (pProcess->usParentPID == usCheckPID)
            &&  (pProcess->ulType != 0)
           )
        {
            if (usSearchPID == pProcess->usPID) {
                prcReport(pProcess, pprcp);
                return (TRUE);
            }
            pProcess->ulType = 0;  // kludge, mark it as already printed
            if (prcSearchProcTree(pps, usSearchPID, pProcess->usPID, pprcp))
                return (TRUE);
        }
    }

    if ( usCheckPID != 0 )
        return (FALSE);

    // if at the root level, check for those processes that have lost
    // their parent process and show them as if they were childs of 0

    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3; // not sure if there isn't another termination method
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        if ( pProcess->ulType != 0 )
        {
            if (usSearchPID == pProcess->usPID) {
                prcReport(pProcess, pprcp);
                return (TRUE);
            }
            if (prcSearchProcTree(pps, usSearchPID, pProcess->usPID, pprcp))
                return (TRUE);
        }

        pProcess->ulType = 1;    // kludge, reset mark
    }
    return (FALSE);
} */

/*
 * prcListThreads:
 *
 */

/* void prcListThreads(PQPROCSTAT pps)
{
    PQPROCESS pProcess;
    PQTHREAD pThread;
    UCHAR aucName[256], aucSysTime[32], aucUserTime[32];
    USHORT usCount;
    char *pcStatus;

    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3;
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        DosQueryModuleName(pProcess->usHModule, sizeof(aucName), aucName);
        // printf("%s\n", aucName);

        for ( usCount = 0, pThread = PTR(pProcess->ulThreadList, 0);
              usCount < pProcess->usThreads;
              usCount++, pThread++ )
        {
          prcTimestr(pThread->ulSysTime, aucSysTime);
          prcTimestr(pThread->ulUserTime, aucUserTime);
          // pcStatus = threadstat[pThread->ucStatus];
          printf("%5d  %5d  %04lX %-7.7s %08lX %10s %10s\n",
             pThread->usTID, pThread->usThreadSlotID, pThread->ulPriority,
             pcStatus ? pcStatus : "Unknown", pThread->ulBlockID, aucSysTime, aucUserTime);
        }
    }
} */

/*
 * prcListModules:
 *
 */

/* void prcListModules(PQPROCSTAT pps, int imports)
{
  PQMODULE pModule;
  UCHAR name[256];
  ULONG ulCount;

  for ( pModule = PTR(pps->ulModules, 0); ;
        pModule = PTR(pModule->nextmodule, 0)
      )
  {
    if ( !imports || pModule->submodules )
      if ( imports )
      {
        // printf("%04X  %s\n", pModule->modhandle, (char *) PTR(pModule->namepointer, 0));

        for ( ulCount = 0; ulCount < pModule->submodules; ulCount++ )
        {
          DosQueryModuleName(pModule->submodule[ulCount], sizeof(name), name);
          // printf("  %04X  %s\n", pModule->submodule[ulCount], name);
        }
      }
      else
        printf(" %04X   %2d  %7ld  %6ld  %s\n", pModule->modhandle,
               pModule->modtype ? 32 : 16, pModule->segments,
               pModule->submodules, (char *) PTR(pModule->namepointer, 0));

    if ( pModule->nextmodule == 0L )
      break;
  }
} */

/*
 * prcListSemaphores:
 *
 */

/* void prcListSemaphores(PQPROCSTAT pps)
{
  PQSEMAPHORE pSemaphore;

  for ( pSemaphore = PTR(pps->ulSemaphores, 16);
        pSemaphore->nextsem != 0L;
        pSemaphore = PTR(pSemaphore->nextsem, 0)
      )
    printf("%3d  %3d   %02X  %4d   %04X  \\SEM%s\n",
           pSemaphore->refs, pSemaphore->requests, pSemaphore->flag,
           pSemaphore->owner, pSemaphore->index, pSemaphore->name);
    ;
} */


/*
 * prcListSharedMem:
 *
 */

/* void prcListSharedMem(PQPROCSTAT pps)
{
    PQSHAREDMEM pSharedMem;
    UCHAR name[256];
    ULONG size;
    ULONG attrib;
    PVOID base;

    for ( pSharedMem = PTR(pps->ulSharedMem, 0);
          pSharedMem->nextseg != 0L;
          pSharedMem = PTR(pSharedMem->nextseg, 0)
        )
    {
        strcpy(name, "\\SHAREMEM\\");
        strcat(name, pSharedMem->name);

        DosGetNamedSharedMem(&base, name, PAG_READ);
        size = -1;
        attrib = PAG_SHARED | PAG_READ;
        if ( DosQueryMem(base, &size, &attrib) )
          size = 0;
        DosFreeMem(base);

        printf(" %04X   %04X   %08lX  %4d  %s\n", pSharedMem->handle,
               pSharedMem->selector, size,
               pSharedMem->refs, name);
    }
}  */

/*
 * prcReport:
 *      fill PRCPROCESS structure
 */

VOID prcReport(PQPROCESS pProcess, PPRCPROCESS pprcp)
{
    USHORT usPriority = 0;
    PQTHREAD pThread;
    int i;

    DosQueryModuleName(pProcess->usHModule, sizeof(pprcp->szModuleName), pprcp->szModuleName);
    // DosGetPrty(PRTYS_PROCESS, &(pprcp->usPriority), pProcess->usPID);

    // sum up CPU time for process
    for ( pprcp->ulCPU = 0, i = 0, pThread = PTR(pProcess->ulThreadList, 0);
              i < pProcess->usThreads;
              i++, pThread++ )
        pprcp->ulCPU += (pThread->ulSysTime + pThread->ulUserTime);

    pprcp->usPID            = pProcess->usPID;
    pprcp->usParentPID      = pProcess->usParentPID;
    pprcp->usThreads        = pProcess->usThreads;
    pprcp->ulSID            = pProcess->ulSID;
    pprcp->ulSessionType    = pProcess->ulSessionType;
    pprcp->ulStatus         = pProcess->ulStatus;
}

/*
 *@@ prcQueryProcessInfo:
 *      this searches for a given process ID (usPID) and
 *      fills a given PRCPROCESS structure with lots of
 *      information about this process.
 *      Returns FALSE upon errors.
 */

BOOL prcQueryProcessInfo(USHORT usPID, PPRCPROCESS pprcp)
{
    BOOL rc = FALSE;
    PQPROCESS pProcess;
    PQPROCSTAT pps = malloc(0x8000);
    DosQProcStatus(pps, 0x8000);

    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3;
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        if (pProcess->usPID == usPID) {
            prcReport(pProcess, pprcp);
            rc = TRUE;
            break;
        }
    }

    free(pps);
    return (rc);
}

/*
 *@@ prcForEachProcess:
 *      this calls a given callback func for each running
 *      process. The callback must be a FNWP, which will be
 *      passed the following parameters for each call:
 * <BR>     HWND hwnd       like hwnd passed to prcForEachProcess
 * <BR>     ULONG msg       like msg passed to prcForEachProcess
 * <BR>     MPARAM mp1      like mp1 passed to prcForEachProcess
 * <BR>     PPRCPROCESS mp2 pointer to a PRCPROCESS struct for each process
 *
 *      This function returns the number of running processes on the
 *      system. If pfnwpCallback is NULL, only this number will be
 *      returned.
 */

ULONG prcForEachProcess(PFNWP pfnwpCallback, HWND hwnd, ULONG ulMsg, MPARAM mp1)
{
    ULONG ulrc = 0;
    PQPROCESS pProcess;
    PRCPROCESS prcp;
    PQPROCSTAT pps = malloc(0x8000);
    DosQProcStatus(pps, 0x8000);

    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3;
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        if (pfnwpCallback) {
            prcReport(pProcess, &prcp);
            (*pfnwpCallback)(hwnd, ulMsg, mp1, &prcp);
        }
        ulrc++;
    }

    free(pps);
    return (ulrc);
}

/*
 *@@ prcQueryThreadCount:
 *      returns the total number of running threads
 *      in the given process. If pid == 0, the
 *      total thread count for the system is returned.
 */

ULONG prcQueryThreadCount(USHORT usPID)
{
    ULONG       ulrc = 0;
    PQPROCSTAT  pps = malloc(0x8000);
    DosQProcStatus(pps, 0x8000);

    if (usPID)
    {
        // process query:
        PQPROCESS pProcess;
        for ( pProcess = PTR(pps->ulProcesses, 0);
              pProcess->ulType != 3;
              pProcess = PTR(pProcess->ulThreadList,
                         pProcess->usThreads * sizeof(QTHREAD))
            )
        {
            if (pProcess->usPID == usPID) {
                ulrc = pProcess->usThreads;
                break;
            }
        }
    } else
    {
        // global query:
        PQGLOBAL   pg;
        pg = PTR(pps->ulGlobal, 0);
        ulrc = pg->ulThreads;
    }

    free(pps);
    return (ulrc);
}

/*
 *@@ prcQueryThreadInfo:
 *      this searches for a given thread in a given process
 *      and fills a given PRCTHREAD structure with lots of
 *      information about that thread.
 *
 *      Returns FALSE upon errors.
 *
 *      Note: This function loops thru all processes which
 *      are currently running and is therefore not terribly
 *      fast. Use economically.
 */

BOOL prcQueryThreadInfo(USHORT usPID, USHORT usTID, PPRCTHREAD pprct)
{
    BOOL        brc = FALSE;
    PQPROCSTAT  pps = malloc(0x8000);
    PQPROCESS pProcess;
    DosQProcStatus(pps, 0x8000);

    // find process:
    for ( pProcess = PTR(pps->ulProcesses, 0);
          pProcess->ulType != 3;
          pProcess = PTR(pProcess->ulThreadList,
                     pProcess->usThreads * sizeof(QTHREAD))
        )
    {
        if (pProcess->usPID == usPID) {
            PQTHREAD pThread;
            int i;
            // process found: find thread
            for ( i = 0, pThread = PTR(pProcess->ulThreadList, 0);
                  i < pProcess->usThreads;
                  i++, pThread++ )
            {
                if (pThread->usTID == usTID) {
                    // thread found:
                    pprct->usTID          = pThread->usTID;
                    pprct->usThreadSlotID = pThread->usThreadSlotID;
                    pprct->ulBlockID      = pThread->ulBlockID;
                    pprct->ulPriority     = pThread->ulPriority;
                    pprct->ulSysTime      = pThread->ulSysTime;
                    pprct->ulUserTime     = pThread->ulUserTime;
                    pprct->ucStatus       = pThread->ucStatus;

                    brc = TRUE;

                    break; // thread-for loop
                }
            } // end for thread
            break; // process-for loop
        }
    } // end for process

    free(pps);
    return (brc);
}

/*
 *@@ prcQueryPriority:
 *      shortcut to prcQueryThreadInfo if you want the priority only.
 *
 *      Returns -1 upon errors.
 *
 *      Note: This function loops thru all processes which
 *      are currently running and is therefore not terribly
 *      fast. Use economically.
 */

ULONG prcQueryThreadPriority(USHORT usPID, USHORT usTID)
{
    PRCTHREAD prct;
    ULONG ulrc = -1;
    if (prcQueryThreadInfo(usPID, usTID, &prct))
        ulrc = prct.ulPriority;
    return (ulrc);
}



