/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDZTRAC
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION   Printer Device Driver Trace
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                   /* CON3201 */
#define INCL_DOSPROCESS           /* CON3201 */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#include <os2.h>
#undef INCL_DOSPROCESS            /* CON3201 */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_32                    /* CON3201 */

/* CON3201 *******************/
//#define INCL_WINP_SELECTIVE
//#define INCL_WINP_SEI
//#define INCL_WINP_MISC
//#define INCL_WINP_SELSERVER
//#include <pmwinx.h>
//#undef INCL_WINP_SELECTIVE
//#undef INCL_WINP_SEI
//#undef INCL_WINP_MISC
//#undef INCL_WINP_SELSERVER

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI


#include <prdconse.h>
#include <prddcone.h>

#define NO_SYS
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef NO_SYS

#include <prdztrce.h>
#include <prdgextf.h>
#include <prdyextf.h>
#include <prduextf.h>



#define TrcWrite( A, B)                                                \
    (void)DosWrite( (HFILE)prdz_TraceFile, (A), (B),                   \
                    &Done);


/**********************************************************************/
/* Profiling data.                                                    */
/**********************************************************************/
ProcessEntryType  ProcessTable[5] = {0,0,0,0,0,0,0,0,0,0};
#define PRF_ENTRIES    1

#if defined(PRD_TRACE)
#if PRD_TRACE != 0

/**********************************************************************/
/* VAR, conv, hexarr and hexstr are used by prdz_hex to avoid calls   */
/* to the ltoa library routine.                                       */
/**********************************************************************/

typedef union { ULONG number; CHAR ch[4]; } VAR;

CHAR conv[16][32] = {
 "000102030405060708090A0B0C0D0E0F",
 "101112131415161718191A1B1C1D1E1F",
 "202122232425262728292A2B2C2D2E2F",
 "303132333435363738393A3B3C3D3E3F",
 "404142434445464748494A4B4C4D4E4F",
 "505152535455565758595A5B5C5D5E5F",
 "606162636465666768696A6B6C6D6E6F",
 "707172737475767778797A7B7C7D7E7F",
 "808182838485868788898A8B8C8D8E8F",
 "909192939495969798999A9B9C9D9E9F",
 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF",
 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF",
 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF",
 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF",
 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF",
 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF" };

USHORT    (*hexarr)[256] = (USHORT (*)[256])conv;
USHORT    hexstr[5];

/**********************************************************************/
/* Blanks is used by prdztrac to align output (to max of 25 widths).  */
/**********************************************************************/
CHAR   Blanks[25] = "                         ";
CHAR * prdz_hex(long);

extern USHORT           prdz_TraceFile;
extern BOOL             prdz_On;
extern HMTX             lpTraceFileSem;


#endif
#endif

/**********************************************************************/
/* prdz_SSAllocSeg replaces SSAllocSeg, and writes to the debugger    */
/**********************************************************************/
/* CON3201 Use SSAllocMem */
#if 0
*USHORT prdz_SSALLOC( Length, pSel, Share, tfunc)
*USHORT  Length;
*PUSHORT pSel;
*USHORT  Share;
*PCHAR   tfunc;
#endif

ULONG prdz_SSALLOC(PVOID Buff, ULONG Size, ULONG Flag, PCHAR tfunc)
{
#ifdef DEBUG_SEGMENTS
/*  USHORT DosResult              CON3201 */
    ULONG DosResult;

    OutputString( "ALLOC mem : Called from");
    OutputString( tfunc );

    DosResult = SafeSSAllocMem( &Buff, Size, Flag);

    if (DosResult != DOS_OK)
    {
        OutputPair( "ALLOC mem : ERROR ", DosResult, HEX );
    }
    else
    {
        OutputPair( "ALLOC mem : BuffAddr is ", (ULONG)(Buff), HEX );
    }
    return( DosResult );
#else
    /******************************************************************/
    /* Should never be called!                                        */
    /******************************************************************/
    return( SafeSSAllocMem( &Buff, Size, Flag ) );
#endif
}

/* CON3201 NO MORE ALLOCHUGE : using flat memory model */
//
/**********************************************************************/
/* SSALLOCHUGE for AllocHugeSeg                                       */
/**********************************************************************/
//USHORT prdz_SSALLOCHUGE(NumSeg, Partial, pSel, MaxN, Share, tfunc)
//USHORT  NumSeg;
//USHORT  Partial;
//PUSHORT pSel;
//USHORT  MaxN;
//USHORT  Share;
//PCHAR   tfunc;
//{
//#ifdef DEBUG_SEGMENTS
//
//    USHORT DosResult;
//
//    OutputString( "ALLOC HUGE: Called from");
//    OutputString( tfunc );
//
//    DosResult = SSAllocHuge( NumSeg, Partial, pSel, MaxN, Share );
//
//    if (DosResult != DOS_OK)
//    {
//        OutputPair( "ALLOC HUGE: ERROR ", (ULONG)DosResult, HEX );
//    }
//    else
//    {
//        OutputPair( "ALLOC HUGE: SELECTOR is ", (ULONG)(*pSel), HEX );
//    }
//    return( DosResult );
//#else
//    /******************************************************************/
//    /* Should never be called!                                        */
//    /******************************************************************/
//    return( SSAllocHuge( NumSeg, Partial, pSel, MaxN, Share ) );
//#endif
//}

/* CON3201 Now using SSFreeMem          */

/**********************************************************************/
/* prdz_SSFREE replaces SSFreeSeg, and writes to the debugger    */
/**********************************************************************/
/* CON3201 Replace SSFreeSeg with SSFreeMem          */
//USHORT prdz_SSFREE( Sel, tfunc)
//USHORT Sel;
//PCHAR   tfunc;

ULONG prdz_SSFREE(PVOID BaseAddr, PCHAR tfunc)
{
#ifdef DEBUG_SEGMENTS

    ULONG DosResult;

    OutputString( "FREE mem : Called from");
    OutputString( tfunc );
    OutputPair( "FREE mem  : BaseAddr is ", (ULONG)BaseAddr, HEX );

    DosResult = SSFreeMem( BaseAddr );

    if (DosResult != DOS_OK)
    {
        OutputPair( "FREE mem : ERROR ", (ULONG)DosResult, HEX );
    }
    return( DosResult );
#else
    /******************************************************************/
    /* Should never be called!                                        */
    /******************************************************************/
    return( SSFreeMem( BaseAddr ) );
#endif
}


/**********************************************************************/
/* prdz_Init initialises the trace level and opens trace file.        */
/**********************************************************************/
USHORT prdz_Init (BOOL FirstTime)

{
#if defined(PRD_TRACE)
#if PRD_TRACE != 0
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG         DosAction;
    USHORT        Result;
    ULONG         NewFilePtr;

    /******************************************************************/
    /* Open the trace file. The main file characteristics are:        */
    /* - name      : fixed name defined in PRDZTRCE.H                 */
    /* - open flag : specifies create or replace                      */
    /* - open mode : specifies normal path/ asynchronous write/ errors*/
    /*               reported via system/ shared read/ read and write.*/
    /******************************************************************/
    if (FirstTime == TRUE)
    {
        Result = DosOpen( PRDTRACEFILE,
                          (PHFILE)&prdz_TraceFile,
                          &DosAction,
                          0L, 0L, 0X0012,
                          0X4041, 0L );

        TRACE4("prdz_Init", "Opened Trace File", &Result, 1);
    }
    else
    {
        TRACE4("prdz_Init", "Next Open Trace", FNULL, 0);

        Result = DosOpen( PRDTRACEFILE,
                          (PHFILE)&prdz_TraceFile,
                          &DosAction,
                          0L, 0, 0X0011,
                          0X4041, 0L );

        TRACE4("prdz_Init", "Opened Trace File", &Result, 1);

        if (Result == DOS_OK)
        {
            Result = DosSetFilePtr( (HFILE)prdz_TraceFile,
                                    0L, 2,
                                     &NewFilePtr);

            TRACE4("prdz_Init", "Changed FilePtr to EOF", &Result, 1);
        }
    }

    TRACE4("prdz_Init", "Trace File Handle", &prdz_TraceFile, 1);

#endif
#endif
    return(DOS_OK);
}




/**********************************************************************/
/* prdz_Trace outputs a trace message plus data to trace file.        */
/**********************************************************************/
void prdz_Trace( PBYTE  caller,
                 PBYTE  messg,
                 PBYTE  info,
                 USHORT  num)



{
#ifdef PRD_TRACE
#if PRD_TRACE != 0
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG      Done;
    int       Leng;
    PLONG     Linfo;
    CHAR     *Str;
    USHORT      OutCnt;
    USHORT      ProcessID;
    ULONG       NewFilePtr;
    ULONG       DosAction;
    USHORT      Result;

    /******************************************************************/
    /* Don't trace if tracing not switched on                         */
    /******************************************************************/
    if ( ! prdz_On )
        return;

    /**************************************************************/
    /* Request the trace file semaphore to ensure all the data    */
    /* is output without being split up                           */
    /**************************************************************/
    (VOID)prdg_RequestSemaphore( lpTraceFileSem, 0);

    /******************************************************************/
    /* Open the trace file here                                       */
    /******************************************************************/
    Result = DosOpen( PRDTRACEFILE,
                      (PHFILE)&prdz_TraceFile,
                      &DosAction,
                      0L, 0L, 0X0011, 0X0041, 0L );

    if (Result != DOS_OK)
        goto Error_clear_semaphore;

    Result = DosSetFilePtr( (HFILE)prdz_TraceFile, 0L, 2,
                            &NewFilePtr );

    if (Result != DOS_OK)
        goto Error_close_file;

    /**************************************************************/
    /* Put the process ID in the trace file - change to the       */
    /* thread ID ( JPB )                                          */
    /**************************************************************/
//  ProcessID = lpTraceFileSem->tid;
    ProcessID = 10;

    Str = prdz_hex((long)ProcessID);
    TrcWrite( Str, 4);
    TrcWrite( ": ", 2);

    /**************************************************************/
    /* Put the two strings provided into the trace file.          */
    /**************************************************************/
    Leng = min(prdu_strlen(caller),15);
    TrcWrite( caller, Leng);
    TrcWrite( Blanks, 15-Leng);
    TrcWrite( ": ", 2);

    Leng = min(prdu_strlen(messg),20);
    TrcWrite( messg, Leng);
    TrcWrite( Blanks, 20-Leng);
    TrcWrite( ": ", 2);

    /**************************************************************/
    /* Put the 32-bit words provided into the trace file, as      */
    /* hex strings.                                               */
    /* Loop below puts out four 32-bit words on the first line,   */
    /* with eight 32-bit words on subsequent lines.               */
    /**************************************************************/
    if ( info != FNULL )
    {
        for ( Leng = num, Linfo = (PLONG)info, OutCnt = 1;
              Leng > 0;
              --Leng, ++Linfo, ++OutCnt )
        {
            Str = prdz_hex(*Linfo);
            TrcWrite( Str, 8);
            TrcWrite( " ", 1);

            if (((OutCnt % 4) == 0) && (Leng > 1))
            {
                TrcWrite( "\015\n", 2);
                TrcWrite( Blanks, 20);
                TrcWrite( Blanks, 25);
            }
        }
    }

    TrcWrite( "\015\n", 2);

 Error_close_file:
    /******************************************************************/
    /* Close trace file here to flush data                            */
    /******************************************************************/
    CloseTraceFile;

 Error_clear_semaphore:
    /**************************************************************/
    /* release the trace file semaphore                           */
    /**************************************************************/
    prdg_ClearSemaphore (lpTraceFileSem);

#endif
#endif
}




/**********************************************************************/
/* prdz_Term closes the trace file.                                   */
/**********************************************************************/
#ifdef PRD_TRACE
#if PRD_TRACE != 0

void prdz_Term()
{
    CloseTraceFile;
}

#endif
#endif


#if defined(PRD_TRACE)
#if PRD_TRACE != 0

/**********************************************************************/
/* prdz_hex converts a long to a hex ascii string.                    */
/**********************************************************************/
CHAR * prdz_hex( lnum )
long   lnum;

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    VAR   innum;
    USHORT  i;

    innum.number = lnum;
    hexstr[4] = 0;

    for ( i = 0; i < 4; ++i )
        hexstr[i] = (*hexarr)[(int)innum.ch[i]];

    return((CHAR *)&hexstr[0]);
}
#endif
#endif




#ifdef PRD_DEBUG

/**********************************************************************/
/* LogErr routines...                                                 */
/**********************************************************************/

void prdz_LogErr( PBYTE   Func,
                  PBYTE   Text,
                  USHORT  ErrCode)

{
     DebugOutput(Func);
     DebugOutput(": ");
     DebugOutput(Text);
     DebugOutput("\n\r");

     WinSetErrorInfo( MAKEERRORID(SEVERITY_SEVERE,ErrCode),
                      SEI_NOBEEP | SEI_NOPROMPT );
}



void prdz_LogDosErr( PBYTE   Func,
                     PBYTE   Text,
                     USHORT  ErrCode)

{
     DebugOutput(Func);
     DebugOutput(": ");
     DebugOutput(Text);
     DebugOutput("\n\r");

     WinSetErrorInfo( MAKEERRORID(SEVERITY_SEVERE,PMERR_BASE_ERROR),
                      SEI_NOBEEP | SEI_NOPROMPT | SEI_DOSERROR,
                      ErrCode );
}

#endif /* PRD_DEBUG */




/**********************************************************************/
/* Debug routines...                                                  */
/* The functions available all write to the debug terminal and only   */
/* work if the value of the global variable DebugOn is TRUE           */
/* (non-zero). This can be changed using the debugger to easily turn  */
/* on or off the output.                                              */
/*                                                                    */
/* CrLf(VOID)  -  Writes a carriage return/line feed sequence to the  */
/*                the debug terminal.                                 */
/*                                                                    */
/* OutputValue(ULONG Value,USHORT Base) -                             */
/*                Writes the value to the debug terminal in the       */
/*                specified base.                                     */
/*                e.g. OutputValue(DecimalValue, 10);                 */
/*                e.g. OutputValue(BinaryValue, 2);                   */
/*                                                                    */
/* OutputString(PCHAR String) -                                       */
/*                Outputs the specified string to the debug terminal, */
/*                followed by a CrLf.                                 */
/*                                                                    */
/* OutputPair(PCHAR String,ULONG Value,USHORT Base) -                 */
/*                This combines the above two functions by            */
/*                writing the specified string, along with the given  */
/*                value in the given base(s), followed by a CrLf.     */
/*                Note that the bases are specified by pre-defined    */
/*                constants( BINARY, DECIMAL, HEX) and they can       */
/*                be combined using a binary OR.                      */
/*                e.g. OutputPair("Number = ", Number, DECIMAL);      */
/*                e.g. OutputPair("Address = ", Address, BINARY|HEX); */
/*                                                                    */
/**********************************************************************/
BOOL DebugOn = 0;
BOOL WaitForKey = 0;
USHORT debug_nobands = 1;

VOID  CrLf(VOID)
{
    if (DebugOn)
        DebugOutput("\n\r");
}

VOID  OutputValue(ULONG Value,USHORT Base)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    LONG     NextValue;
    CHAR     Digit;
    CHAR     String[2];
    if (!DebugOn)
    {
        return;
    }

    if ( (Base == 10) && ((LONG)Value < 0) )
    {
        DebugOutput("-");
        OutputValue( -(LONG)Value,10 );
        return;
    }

    if (Value > Base-1)
    {
        OutputValue(Value/Base,Base);
    }

    Digit = (CHAR)(Value % Base);
    String[0] = (Digit < 10) ? (Digit + '0') : (Digit + 'A'-10);
    String[1] = 0;
    DebugOutput(String);
}

VOID  OutputValueLen(ULONG Value,USHORT Base, USHORT NumDigits)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    USHORT   i;
    CHAR     Digit;
    CHAR     String[2];

    if (!DebugOn)
    {
        return;
    }

    if ( (Base == 10) && ((LONG)Value < 0) )
    {
        DebugOutput("-");
        OutputValueLen( -(LONG)Value,10, NumDigits );
        return;
    }

    if ( (Value > Base-1) && (NumDigits > 1) )
    {
        OutputValueLen(Value/Base,Base, NumDigits - 1);
        OutputValueLen(Value%Base,Base, 1);
        return;
    }

    Digit = (CHAR)(Value % Base);
    String[0] = '0';
    String[1] = 0;
    for ( i = 1; i < NumDigits ; i++ )
    {
        DebugOutput(String);
    }
    String[0] = (Digit < 10) ? (Digit + '0') : (Digit + 'A'-10);
    DebugOutput(String);
}



VOID OutputString(PCHAR String)
{
    if (DebugOn)
    {
        DebugOutput(String);
        CrLf();
    }
}

VOID OutputStringNoCRLF(PCHAR String)
{
    if (DebugOn)
    {
        DebugOutput(String);
    }
}



VOID OutputPrompt(PCHAR String)
{
    if (DebugOn)
    {
        DebugOutput(String);
        CrLf();
        if (WaitForKey)
            haltproc();
    }
}



VOID OutputPair(PCHAR String,ULONG Value,USHORT Base)
{
    if (DebugOn)
    {
        DebugOutput(String);
        DebugOutput("  ");
        if (Base & DECIMAL)
        {
            OutputValue(Value,10);
            DebugOutput("  ");
        }
        if (Base & HEX)
        {
            DebugOutput("0x");
            OutputValue(Value,16);
            DebugOutput("  ");
        }
        if (Base & BINARY)
        {
            DebugOutput("0b");
            OutputValue(Value,2);
        }
        CrLf();
    }
}
#ifdef OMIT
#define TFUNC "prdz_ProfileInit"
/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdz_ProfileInit                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   DCIData : Used to associate profiling information with a         */
/*             specific process.                                      */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function initialises the Profile Array.                     */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
SHORT prdz_ProfileInit ( ULONG DCIData )


{
#define TFUNC "prdz_ProfileInit"
     /*****************************************************************/
     /* Local variables.                                              */
     /*****************************************************************/
     USHORT          Index    = 0;
     ULONG           NumBytes;
     BOOL            Found    = FALSE;
     SHORT           Result   = ERROR_NEG;
     lpProfileEntry  lpProfileTable;

     /*****************************************************************/
     /* Find a free entry in the ProcessTable.                        */
     /*****************************************************************/
     for ( Index=0; Index<5 && !Found; Index++ )
     {
         Found = !ProcessTable[Index].ProcessID;
     }

     if (!Found)
     {
         /*************************************************************/
         /* No more free entries.                                     */
         /*************************************************************/
         goto EXIT;
     }

     /*****************************************************************/
     /* Found a free entry.                                           */
     /*****************************************************************/
     NumBytes = PRF_ENTRIES * sizeof(ProfileEntryType);

     if (SafeSSALLOCMEM( &lpProfileTable, NumBytes, 0L) != DOS_OK)
/*                   &SELECTOROF(lpProfileTable), 0) != DOS_OK) CON3201 ***/
/*                     lpProfileTable, 0L) != DOS_OK)   CON3201 ***********/
     {
         goto EXIT;
     }
/*   OFFSETOF(lpProfileTable) = 0;      CON3201    */

     /*****************************************************************/
     /* Reset the memory                                              */
     /*****************************************************************/
     Prdu_memset ( lpProfileTable, 0x00, NumBytes );

     /*****************************************************************/
     /* Assign string values so that this information makes some      */
     /* sense later on.                                               */
     /*****************************************************************/
     lpProfileTable[0].Function = "Prdl_PolyLine";

     /*****************************************************************/
     /* Store in the ProcessTable.                                    */
     /*****************************************************************/
     ProcessTable[Index].ProcessID = DCIData;
     ProcessTable[Index].lpTable   = lpProfileTable;
     Result = Index;

     /*****************************************************************/
     /* Finished                                                      */
     /*****************************************************************/
EXIT:
     Return(Result);

#undef TFUNC
}

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdz_ProfileTerm                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   DCIData : Used to associate profiling information with a         */
/*             specific process.                                      */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function outputs the profile array to a file.               */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
SHORT prdz_ProfileTerm ( ULONG DCIData )


{
#define TFUNC "prdz_ProfileTerm"
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    USHORT           i;
    USHORT           Index;
    BOOL             Found  = FALSE;
    SHORT            Result = ERROR_NEG;
    SHORT            DosResult;
    USHORT           ProfileFile;
    ULONG            DosAction;
    ULONG            NewFilePtr;
    ULONG           Done;

    /******************************************************************/
    /* Locate the correct process table.                              */
    /******************************************************************/
    for ( Index=0; Index<5 && !Found; Index++ )
    {
        Found = (ProcessTable[Index].ProcessID == DCIData);
    }

    if (!Found)
    {
        /**************************************************************/
        /* No process assigned so do nothing.                         */
        /**************************************************************/
        goto EXIT;
    }

    /******************************************************************/
    /* Open the file for append                                       */
    /******************************************************************/
    DosResult = DosOpen( PRDPROFILEFILE,
                         (PHFILE)&ProfileFile,
                         &DosAction,
                         0L, 0, 0X0011,
                         0X4041, 0L );

    if (Result != DOS_OK)
        goto EXIT;

    DosResult = DosChgFilePtr( (HFILE)ProfileFile,
                                0L, 2,
                                &NewFilePtr);

    if (Result != DOS_OK)
        goto EXIT;

    /******************************************************************/
    /* Output the data in the profiling table                         */
    /******************************************************************/
    for (i=0;i<PRF_ENTRIES;i++)
    {
        DosResult = DosWrite( (HFILE)ProfileFile,
                             (PVOID)ProcessTable[Index].lpTable,
                              16,
                              &Done);

        if (Result != DOS_OK)
            goto CLOSE_EXIT;
    }

    /******************************************************************/
    /* Exiting OK if we have reached here.                            */
    /******************************************************************/
    Result = OK;

    /******************************************************************/
    /* Close the file                                                 */
    /******************************************************************/
CLOSE_EXIT:
    DosResult = DosClose((HFILE)ProfileFile);

    /******************************************************************/
    /* Free the memory used for the profile array and reset it for    */
    /* use again.                                                     */
    /******************************************************************/
    if (ProcessTable[Index].lpTable)
       SSFREEMEM(ProcessTable[Index].lpTable);

    ProcessTable[Index].lpTable     = FNULL;
    ProcessTable[Index].ProcessID = 0;

    /******************************************************************/
    /* Finished                                                       */
    /******************************************************************/
EXIT:
    return(Result);
#undef TFUNC
}
#endif
